 
 
 
 
 
 
 
 
 
 










 
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.
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.
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"; }
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' )
];
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' )
];
 
 
 
 
 
 
 
 
 
 
 










