まず、最低の優先順位から最高の優先順位に移動します。
parse : expr /\Z/
expr : list
list : unary(s?)
unary : unary '?'
| term
term : '(' expr ')'
| STRING
STRING : /\w+/
もちろん、
unary : unary '?'
| term
左再帰であるため、機能しません。演算子の結合性とParse::RecDescentでの左再帰の排除は、それを取り除くのに役立ちます。我々が得る
unary : term unary_(s?)
unary_ : '?'
しかし、それは私たちにとって正しいツリーを構築することにはなりません。それでは、「(s?)
」をフラット化することから始めましょう。
unary : term unary_
unary_ : '?' unary_
|
次に、サブルール引数を使用して適切なツリーを作成できます。
unary : term unary_[ $item[1] ]
unary_ : '?' unary_[ [ 'postfix?' => $arg[0] ] ]
| { $arg[0] }
すべて一緒に:
use strict;
use warnings;
use Data::Dumper qw( Dumper );
use Parse::RecDescent qw( );
my $grammar = <<'END';
{
use strict;
use warnings;
}
parse : expr /\Z/ { $item[1] }
expr : list
list : unary(s?) { [ $item[0] => @{ $item[1] } ] }
unary : term unary_[ $item[1] ]
unary_ : '?' unary_[ [ 'postfix?' => $arg[0] ] ]
| { $arg[0] }
term : '(' expr ')' { $item[2] }
| STRING { [ string => $item[1] ] }
STRING : /\w+/
END
my $parser = Parse::RecDescent->new($grammar)
or die "Invalid grammar\n";
my $tree = $parser->parse("((foo bar)? baz)\n")
or die "Invalid text\n";
print(Dumper($tree));