86 lines
2.4 KiB
Plaintext
86 lines
2.4 KiB
Plaintext
|
|
|
|
###
|
|
### regex-parser
|
|
###
|
|
|
|
## Chapter 8 section 5
|
|
|
|
use Lexer ':all';
|
|
use Stream 'node';
|
|
|
|
my ($regex, $alternative, $atom, $qatoms);
|
|
|
|
sub regex_to_stream {
|
|
my @input = @_;
|
|
my $input = sub { shift @input };
|
|
|
|
my $lexer = iterator_to_stream(
|
|
make_lexer($input,
|
|
['PAREN', qr/[()]/,],
|
|
['QUANT', qr/[*+?]/ ],
|
|
['BAR', qr/[|]/, ],
|
|
['ATOM', qr/\\x[0-9a-fA-F]{0,2} # hex escape
|
|
|\\\d+ # octal escape
|
|
|\\. # other \
|
|
|. # other char
|
|
/x, ],
|
|
)
|
|
);
|
|
|
|
my ($result) = $regex->($lexer);
|
|
return $result;
|
|
}
|
|
|
|
|
|
## Chapter 8 section 5
|
|
|
|
use Parser ':all';
|
|
|
|
my $Regex = parser { $regex ->(@_) };
|
|
my $Alternative = parser { $alternative->(@_) };
|
|
my $Atom = parser { $atom ->(@_) };
|
|
my $QAtom = parser { $qatom ->(@_) };
|
|
|
|
|
|
## Chapter 8 section 5
|
|
|
|
use Regex;
|
|
|
|
# regex -> alternative 'BAR' regex | alternative
|
|
$regex = alternate(T(concatenate($Alternative,
|
|
lookfor('BAR'),
|
|
$Regex),
|
|
sub { Regex::union($_[0], $_[2]) }),
|
|
$Alternative);
|
|
# alternative -> qatom alternative | (nothing)
|
|
$alternative = alternate(T(concatenate($QAtom, $Alternative),
|
|
\&Regex::concat),
|
|
T(\¬hing, sub { Regex::literal("") }));
|
|
my %quant;
|
|
|
|
# qatom -> atom ('QUANT' | (nothing))
|
|
$qatom = T(concatenate($Atom,
|
|
alternate(lookfor('QUANT'),
|
|
\¬hing),
|
|
),
|
|
sub { my ($at, $q) = @_;
|
|
defined $q ? $quant{$q}->($at) : $at });
|
|
|
|
%quant = ('*' => \&Regex::star,
|
|
'+' => \&Regex::plus,
|
|
'?' => \&Regex::query,
|
|
);
|
|
sub query {
|
|
my $s = shift;
|
|
union(literal(""), $s);
|
|
}
|
|
# atom -> 'ATOM' | '(' regex ')'
|
|
$atom = alternate(lookfor("ATOM", sub { Regex::literal($_[0][1]) }),
|
|
T(concatenate(lookfor(["PAREN", "("]),
|
|
$Regex,
|
|
lookfor(["PAREN", ")"]),
|
|
),
|
|
sub { $_[1] }),
|
|
);
|