next up previous contents index PLPL moodlepserratamodulosperlmonksperldocapuntes LHPgoogleetsiiullpcgull
Sig: Práctica Sup: RecDescent Ant: El Hash %item Err: Si hallas una errata ...

Usando la directiva autotree

La directiva <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


next up previous contents index PLPL moodlepserratamodulosperlmonksperldocapuntes LHPgoogleetsiiullpcgull
Sig: Práctica Sup: RecDescent Ant: El Hash %item Err: Si hallas una errata ...
Casiano Rodríguez León
2012-05-22