[~/jison/jison-aSb(master)]$ sudo cpan Parse::Eyapp
[~/src/perl/parse-eyapp/examples/MatchingTrees]$ pwd -P /Users/casiano/local/src/perl/parse-eyapp/examples/MatchingTrees
s
)
my $grammar = q{ %lexer { m{\G\s+}gc; m{\G([0-9]+(?:\.[0-9]+)?)}gc and return('NUM',$1); m{\G([A-Za-z][A-Za-z0-9_]*)}gc and return('VAR',$1); m{\G(.)}gcs and return($1,$1); } %right '=' # Lowest precedence %left '-' '+' # + and - have more precedence than = Disambiguate a-b-c as (a-b)-c %left '*' '/' # * and / have more precedence than + Disambiguate a/b/c as (a/b)/c %left NEG # Disambiguate -a-b as (-a)-b and not as -(a-b) %tree # Let us build an abstract syntax tree ... %% line: exp <%name EXPRESSION_LIST + ';'> { $_[1] } /* list of expressions separated by ';' */ ; /* The %name directive defines the name of the class to which the node being built belongs */ exp: %name NUM NUM | %name VAR VAR | %name ASSIGN VAR '=' exp | %name PLUS exp '+' exp | %name MINUS exp '-' exp | %name TIMES exp '*' exp | %name DIV exp '/' exp | %name UMINUS '-' exp %prec NEG | '(' exp ')' { $_[2] } /* Let us simplify a bit the tree */ ; %% }; # end grammar
El trozo de código: \begin{verbatim} $parser->input(\"2*-3+b*0;--2\n"); # Set the input my $t = $parser->YYParse;da lugar a este árbol:
[~/src/perl/parse-eyapp/examples/MatchingTrees]$ ./synopsis.pl Syntax Tree: EXPRESSION_LIST( PLUS( TIMES( NUM( TERMINAL[2]), UMINUS( NUM( TERMINAL[3])) # UMINUS ) # TIMES, TIMES( VAR( TERMINAL[b]), NUM( TERMINAL[0])) # TIMES ) # PLUS, UMINUS( UMINUS( NUM( TERMINAL[2])) # UMINUS ) # UMINUS ) # EXPRESSION_LISTAl aplicar las transformaciones:
# Let us transform the tree. Define the tree-regular expressions .. my $p = Parse::Eyapp::Treeregexp->new( STRING => q{ { # Example of support code my %Op = (PLUS=>'+', MINUS => '-', TIMES=>'*', DIV => '/'); } constantfold: /TIMES|PLUS|DIV|MINUS/:bin(NUM($x), NUM($y)) => { my $op = $Op{ref($bin)}; $x->{attr} = eval "$x->{attr} $op $y->{attr}"; $_[0] = $NUM[0]; } uminus: UMINUS(NUM($x)) => { $x->{attr} = -$x->{attr}; $_[0] = $NUM } zero_times_whatever: TIMES(NUM($x), .) and { $x->{attr} == 0 } => { $_[0] = $NUM } whatever_times_zero: TIMES(., NUM($x)) and { $x->{attr} == 0 } => { $_[0] = $NUM } }, OUTPUTFILE=> 'main.pm' ); $p->generate(); # Create the tranformations $t->s($uminus); # Transform UMINUS nodes $t->s(@all); # constant folding and mult. by zeroObtenemos el árbol:
Syntax Tree after transformations: EXPRESSION_LIST(NUM(TERMINAL[-6]),NUM(TERMINAL[2]))
[~/src/perl/parse-eyapp/examples/MatchingTrees]$ cat synopsis.pl #!/usr/bin/perl -w use strict; use Parse::Eyapp; use Parse::Eyapp::Treeregexp; sub TERMINAL::info { $_[0]{attr} } my $grammar = q{ %lexer { m{\G\s+}gc; m{\G([0-9]+(?:\.[0-9]+)?)}gc and return('NUM',$1); m{\G([A-Za-z][A-Za-z0-9_]*)}gc and return('VAR',$1); m{\G(.)}gcs and return($1,$1); } %right '=' # Lowest precedence %left '-' '+' # + and - have more precedence than = Disambiguate a-b-c as (a-b)-c %left '*' '/' # * and / have more precedence than + Disambiguate a/b/c as (a/b)/c %left NEG # Disambiguate -a-b as (-a)-b and not as -(a-b) %tree # Let us build an abstract syntax tree ... %% line: exp <%name EXPRESSION_LIST + ';'> { $_[1] } /* list of expressions separated by ';' */ ; /* The %name directive defines the name of the class to which the node being built belongs */ exp: %name NUM NUM | %name VAR VAR | %name ASSIGN VAR '=' exp | %name PLUS exp '+' exp | %name MINUS exp '-' exp | %name TIMES exp '*' exp | %name DIV exp '/' exp | %name UMINUS '-' exp %prec NEG | '(' exp ')' { $_[2] } /* Let us simplify a bit the tree */ ; %% }; # end grammar our (@all, $uminus); Parse::Eyapp->new_grammar( # Create the parser package/class input=>$grammar, classname=>'Calc', # The name of the package containing the parser ); my $parser = Calc->new(); # Create a parser $parser->input(\"2*-3+b*0;--2\n"); # Set the input my $t = $parser->YYParse; # Parse it! local $Parse::Eyapp::Node::INDENT=2; print "Syntax Tree:",$t->str; # Let us transform the tree. Define the tree-regular expressions .. my $p = Parse::Eyapp::Treeregexp->new( STRING => q{ { # Example of support code my %Op = (PLUS=>'+', MINUS => '-', TIMES=>'*', DIV => '/'); } constantfold: /TIMES|PLUS|DIV|MINUS/:bin(NUM($x), NUM($y)) => { my $op = $Op{ref($bin)}; $x->{attr} = eval "$x->{attr} $op $y->{attr}"; $_[0] = $NUM[0]; } uminus: UMINUS(NUM($x)) => { $x->{attr} = -$x->{attr}; $_[0] = $NUM } zero_times_whatever: TIMES(NUM($x), .) and { $x->{attr} == 0 } => { $_[0] = $NUM } whatever_times_zero: TIMES(., NUM($x)) and { $x->{attr} == 0 } => { $_[0] = $NUM } }, OUTPUTFILE=> 'main.pm' ); $p->generate(); # Create the tranformations $t->s($uminus); # Transform UMINUS nodes $t->s(@all); # constant folding and mult. by zero local $Parse::Eyapp::Node::INDENT=0; print "\nSyntax Tree after transformations:\n",$t->str,"\n";
El código de s
está en
lib/Parse/Eyapp/Node.pm:
sub s { my @patterns = @_[1..$#_]; # Make them Parse::Eyapp:YATW objects if they are CODE references @patterns = map { ref($_) eq 'CODE'? Parse::Eyapp::YATW->new( PATTERN => $_, #PATTERN_ARGS => [], ) : $_ } @patterns; my $changes; do { $changes = 0; foreach (@patterns) { $_->{CHANGES} = 0; $_->s($_[0]); $changes += $_->{CHANGES}; } } while ($changes); }
s
)
Casiano Rodríguez León