

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

