# ( a OR b ) AND ( c ) NOT ( d ) AND ( e OR f )
[
[ 'a', 'b' ],
[ AND => 'c' ],
[ NOT => 'd' ],
[ AND => 'e', 'f' ],
]
####
# make_parser.pl
use strict;
use warnings;
use Parse::RecDescent ();
my $grammar = <<'__END_OF_GRAMMAR__';
{
use strict;
use warnings;
}
parse : expr /^\Z/ { $item[1] }
expr : terms expr_ { [ $item[1], $item[2] ] }
expr_ : AND terms expr_ { [ [ $item[1], @{$item[2]} ], @{$item[3]} ] }
| NOT terms expr_ { [ [ $item[1], @{$item[2]} ], @{$item[3]} ] }
| { [] }
terms : '(' terms_ ')' { $item[2] }
terms_ : IDENT OR terms_ { [ $item[1], @{$item[3]} ] }
| IDENT { [ $item[1] ] }
IDENT : /\S+/
AND : IDENT { $item[1] eq 'AND' ?1:undef } { $item[1] }
NOT : IDENT { $item[1] eq 'NOT' ?1:undef } { $item[1] }
OR : IDENT { $item[1] eq 'OR' ?1:undef } { $item[1] }
__END_OF_GRAMMAR__
Parse::RecDescent->Precompile($grammar, "QueryParser")
or die("Bad grammar\n");
####
# query_parser.pl
use strict;
use warnings;
use Data::Dumper qw( );
use QueryParser qw( );
sub display {
my ($expr, $tree) = @_;
local $Data::Dumper::Indent = 0;
print(Data::Dumper->Dump([$tree], [$expr]), "\n");
}
{
my $parser = QueryParser->new();
foreach my $expr (
'( keyword1 )',
'( keyword1 ) AND ( keyword2 )',
'( keyword1 ) AND ( keyword2 ) AND ( keyword3 )',
'( keyword1 ) NOT ( keyword2 )',
'( keyword1 ) NOT ( keyword2 ) NOT ( keyword3 )',
'( keyword1 ) AND ( keyword2 ) NOT ( keyword3 )',
'( keyword1 ) NOT ( keyword2 ) AND ( keyword3 )',
'( keyword1 OR keyword2 )',
'( keyword1 ) AND ( keyword2 OR keyword3 )',
'( keyword1 ) NOT ( keyword2 OR keyword3 )',
) {
my $tree = $parser->parse($expr);
display($expr, $tree);
}
}