next up previous contents index PLPL moodlepserratamodulosperlmonksperldocapuntes LHPgoogleetsiiullpcgull
Sig: Construyendo el Arbol de Sup: Análisis Sintáctico con Parse::Eyapp Ant: Práctica: Gramática Simple en Err: Si hallas una errata ...

El Método YYName y la Directiva %name

Construyendo una Representación del Árbol

En eyapp toda regla de producción tiene un nombre. El nombre de una regla puede ser dado explícitamente por el programador mediante la directiva %name. Por ejemplo, en el fragmento de código que sigue se da el nombre ASSIGN a la regla exp: VAR '=' exp. Si no se da un nombre explícito, la regla tendrá un nombre implícito. El nombre implícito de una regla se forma concatenando el nombre de la variable sintáctica en la parte izquierda con un subguión y el número de orden de la regla de producción: Lhs_#. Evite dar nombres con ese patrón a sus reglas de producción. Los patrones de la forma /${lhs}_\d+$/ donde ${lhs} es el nombre de la variable sintáctica estan reservados por eyapp.

pl@nereida:~/LEyapp/examples$ cat -n Lhs.eyp
 1  # Lhs.eyp
 2
 3  %right  '='
 4  %left   '-' '+'
 5  %left   '*' '/'
 6  %left   NEG
 7
 8  %defaultaction {
 9    my $self = shift;
10    my $name = $self->YYName();
11    bless { children => [ grep {ref($_)} @_] }, $name;
12  }
13
14  %%
15  input:
16              /* empty */
17                { [] }
18          |   input line
19                {
20                  push @{$_[1]}, $_[2] if defined($_[2]);
21                  $_[1]
22                }
23  ;
24
25  line:     '\n'       { }
26          | exp '\n'   {  $_[1] }
27  ;
28
29  exp:
30              NUM   { $_[1] }
31          |   VAR   { $_[1] }
32          |   %name ASSIGN
33              VAR '=' exp
34          |   %name PLUS
35              exp '+' exp
36          |   %name MINUS
37              exp '-' exp
38          |   %name TIMES
39              exp '*' exp
40          |   %name DIV
41              exp '/' exp
42          |   %name UMINUS
43              '-' exp %prec NEG
44          |  '(' exp ')'  { $_[2] }
45  ;

Dentro de una acción semántica el nombre de la regla actual puede ser recuperado mediante el método YYName del analizador sintáctico.

La acción por defecto (lineas 8-12) computa como atributo de la parte izquierda una referencia a un objeto que tiene como clase el nombre de la regla. Ese objeto tiene un atributo children que es una referencia a la lista de hijos del nodo. La llamada a grep

11    bless { children => [ grep {ref($_)} @_] }, $name;
tiene como efecto obviar (no incluir) aquellos hijos que no sean referencias. Observe que el analizador léxico sólo retorna referencias a objetos para los terminales NUM y VAR.

La Cola

47  %%
48
49  sub _Error {
50          exists $_[0]->YYData->{ERRMSG}
51      and do {
52          print $_[0]->YYData->{ERRMSG};
53          delete $_[0]->YYData->{ERRMSG};
54          return;
55      };
56      print "Syntax error.\n";
57  }
58
59  sub _Lexer {
60      my($parser)=shift;
61
62      for ($parser->YYData->{INPUT}) {
63          s/^[ \t]+//;
64          return('',undef) unless $_;
65          s/^([0-9]+(?:\.[0-9]+)?)//
66                  and return('NUM', bless { attr => $1}, 'NUM');
67          s/^([A-Za-z][A-Za-z0-9_]*)//
68                  and return('VAR',bless {attr => $1}, 'VAR');
69          s/^(.)//s
70                  and return($1, $1);
71      }
72      return('',undef);
73  }
74
75  sub Run {
76      my($self)=shift;
77
78      $self->YYData->{INPUT} = <>;
79      return $self->YYParse( yylex => \&_Lexer, yyerror => \&_Error  );
80  }

Para los terminales NUM y VAR el analizador léxico devuelve una referencia a un objeto. No así para el resto de los terminales.

El Programa Cliente

pl@nereida:~/LEyapp/examples$ cat -n uselhs.pl
     1  #!/usr/bin/perl -w
     2  use Lhs;
     3  use Data::Dumper;
     4
     5  $parser = new Lhs();
     6  my $tree = $parser->Run;
     7  $Data::Dumper::Indent = 1;
     8  if (defined($tree)) { print Dumper($tree); }
     9  else { print "Cadena no válida\n"; }

Ejecución

Al darle la entrada a=(2+3)*b el analizador produce el árbol

 
ASSIGN(TIMES(PLUS(NUM[2],NUM[3]), VAR[b]))

Veamos el resultado de una ejecución:

pl@nereida:~/LEyapp/examples$ uselhs.pl
a=(2+3)*b
$VAR1 = [
  bless( {
    'children' => [
      bless( { 'attr' => 'a' }, 'VAR' ),
      bless( {
        'children' => [
          bless( {
            'children' => [
              bless( { 'attr' => '2' }, 'NUM' ),
              bless( { 'attr' => '3' }, 'NUM' )
            ]
          }, 'PLUS' ),
          bless( { 'attr' => 'b' }, 'VAR' )
        ]
      }, 'TIMES' )
    ]
  }, 'ASSIGN' )
];

Cambiando el Nombre de la Regla Dinámicamente

Es posible cambiar en tiempo de ejecución el nombre de una regla. Observe la siguiente variante del ejemplo anterior en el que se cambia - en tiempo de ejecución - el nombre de la regla del menos binario.

29  exp:
30              NUM   { $_[1] }
31          |   VAR   { $_[1] }
32          |   %name ASSIGN
33              VAR '=' exp
34          |   %name PLUS
35              exp '+' exp
36          |   %name MINUS
37              exp '-' exp
38                {
39                  my $self = shift;
40                  $self->YYName('SUBSTRACT'); # rename it
41                  $self->YYBuildAST(@_); # build the node
42                }
43          |   %name TIMES
44              exp '*' exp
45          |   %name DIV
46              exp '/' exp
47          |   %name UMINUS
48              '-' exp %prec NEG
49          |  '(' exp ')'  { $_[2] }
50  ;

Al ejecutar el cliente observamos como los nodos han sido bendecidos en la clase SUBSTRACT:

pl@nereida:~/LEyapp/examples$ useyynamedynamic.pl
2-b
$VAR1 = [
  bless( {
    'children' => [
      bless( {
        'attr' => '2'
      }, 'NUM' ),
      bless( {
        'attr' => 'b'
      }, 'VAR' )
    ]
  }, 'SUBSTRACT' )
];



Subsecciones
next up previous contents index PLPL moodlepserratamodulosperlmonksperldocapuntes LHPgoogleetsiiullpcgull
Sig: Construyendo el Arbol de Sup: Análisis Sintáctico con Parse::Eyapp Ant: Práctica: Gramática Simple en Err: Si hallas una errata ...
Casiano Rodríguez León
2012-05-22