I think that Parse::RecDescent is the wrong tool for this. You could use Text::CSV_XS instead, with a little massaging of the input to take care of condition 3:
#!/usr/bin/perl -wl
use Text::CSV_XS;
use strict;
my $csv = Text::CSV_XS->new({sep_char => ';',
escape_char => '?'});
my $line = 'ABC???;DE;ABC??;ABC?DE';
$line =~ s/(\?[^?;])/?$1/g;
$csv->parse($line);
print join "|", $csv->fields();
__END__
prints: ABC?;DE|ABC?|ABC?DE
This will be signifcantly faster than a P::RD parser. You could also have a look at Text::xSV.
John.
--
|