<autotree>
hace que RD construya automáticamente
una representación del árbol sintáctico concreto.
Cada nodo del árbol, correspondiendo a una parte
derecha de una regla de producción es bendecido (usando bless
)
en una clase cuyo nombre es el de la variable sintáctica que
produce: viene a ser equivalente a { bless \%item, $item[0] }
.
$ cat ./infixautotree.pl #!/usr/local/bin/perl5.8.0 -w use strict; use Parse::RecDescent; use Data::Dumper; #$::RD_TRACE = 1; my $grammar = q{ <autotree> expre : <leftop: prods '+' prods> prods : <leftop: unario '*' unario> unario: "(" expre ")" | numero numero : /\d+(\.\d+)?/ }; my $parse = new Parse::RecDescent($grammar); my $line = shift; my $result = $parse->expre($line); if (defined($result)) { print "Válida:\n", Dumper($result); } else { print "Cadena no válida\n"; }
Las reglas que consisten en un sólo terminal, como la de número, llevan un tratamiento especial. En ese caso el código ejecutado es:
{ bless {__VALUE__=>$item[1]}, $item[0] }
La estructura resultante es relativamente compleja. Cada nodo es bendecido en la clase con nombre el de la variable sintáctica, esto es, con nombre el de la regla. Podemos sacar ventaja de esta aproximación si asociamos métodos de procesamiento con cada tipo de nodo. Por ejemplo, para hacer un recorrido del árbol sintáctico, podríamos extender el ejemplo anterior como sigue:
$ cat infixautotree2.pl ... sub expre::traverse { my $root = shift; my $level = shift; process($root, $level, '__RULE__'); foreach (@{$root->{__DIRECTIVE1__}}) { $_->traverse($level+1); } } sub prods::traverse { my $root = shift; my $level = shift; process($root, $level, '__RULE__'); foreach (@{$root->{__DIRECTIVE1__}}) { $_->traverse($level+1); } } sub unario::traverse { my $root = shift; my $level = shift; process($root, $level, '__RULE__'); my $child = $root->{numero} || $root->{expre}; $child->traverse($level+1); } sub numero::traverse { my $root = shift; my $level = shift; process($root, $level, '__VALUE__'); } sub process { my $root = shift; my $level = shift; my $value = shift; print " "x($width*$level),$root->{$value},"\n"; }Sigue un ejemplo de ejecución:
$ ./infixautotree2.pl '2+3*(5+2)+9' 6 Válida: expre prods unario 2 prods unario 3 unario expre prods unario 5 prods unario 2 prods unario 9