next up previous contents index PLPL moodlepserratamodulosperlmonksperldocapuntes LHPgoogleetsiiullpcgull
Sig: Traducción de Infijo a Sup: Análisis Sintáctico con Parse::Eyapp Ant: Depuración de Errores Err: Si hallas una errata ...


Acciones y Acciones por Defecto

En el ejemplo anterior la acción semántica asociada con cada una de las reglas de producción es básicamente la misma: escribir la regla. Parece lógico intentar factorizar todo ese código común.

Las Acciones en eyapp

En Parse::Eyapp las acciones semánticas son convertidas en subrutinas anónimas. Mas bien en métodos anónimos dado que el primer argumento ($_[0]) de toda acción semántica es una referencia al objeto analizador sintáctico. Los restantes parámetros se corresponden con los atributos de los símbolos en la parte derecha de la regla de producción ($_[1] ...). Esto es, si la regla es:

$ A \rightarrow X_1 X_2 \ldots X_n $ { action(@_) }

cuando se ''reduzca'' por la regla $ A \rightarrow X_1 X_2 \ldots X_n $ la acción será llamada con argumentos

action(parserref, $X_1, $X_2, ..., $X_n)

donde $X_1, $X_2, etc. denotan los atributos de $ X_1$ , $ X_2$ , etc. y parserref es una referencia al objeto analizador sintáctico.

El valor retornado por la acción semántica es asignado como valor del atributo del lado izquierdo de la regla $ A$ .

Cuando una regla $ A \rightarrow X_1 X_2 \ldots X_n $ no tiene acción semántica asociada se ejecuta la acción por defecto. La acción por defecto en eyapp es { $_[1] }:

$ A \rightarrow X_1 X_2 \ldots X_n $ { $_[1] }

El efecto de tal acción es asignar al atributo de la variable sintáctica en la parte izquierda el atributo del primer símbolo en la parte derecha. Si la parte derecha fuera vacía se asigna undef.

La Directiva %defaultaction

La directiva %defaultaction permite especificar una acción por defecto alternativa. Observe esta nueva versión del programa anterior:

pl@nereida:~/LEyapp/examples$ cat -n CalcSyntaxDefaultWithHOPLexer.eyp
 1  # CalcSyntaxDefaultWithHOPLexer.eyp
 2  %right  '='
 3  %left   '-' '+'
 4  %left   '*' '/'
 5  %left   NEG
 6  %right  '^'
 7
 8  %defaultaction {
 9    my $parser = shift;
10
11    print $parser->YYLhs." --> ";
12    my $i = 0;
13    for ($parser->YYRightside) {
14       print "$_";
15       print "[$_[$i]]" if /NUM|VAR/;
16       print " ";
17       $i++;
18    }
19    print "\n";
20  }
21
22  %{
23  use HOP::Lexer qw(string_lexer);
24  %}
25  %%
26  line: (exp '\n')*
27  ;
28
29  exp:
30      NUM
31    | VAR
32    | VAR '=' exp
33    | exp '+' exp
34    | exp '-' exp
35    | exp '*' exp
36    | exp '/' exp
37    | '-' exp %prec NEG
38    | exp '^' exp
39    | '(' exp ')'
40  ;

El método YYLhs (línea 11) retorna el nombre de la variable sintáctica asociada con la regla actual. El método YYRightside (línea 13) devuelve la lista de nombres de los símbolos de la parte derecha de la regla de producción actual.

Observe como la modificación de la acción con defecto nos permite eliminar todas las acciones del cuerpo de la gramática.

Al ejecutar el cliente obtenemos una salida similar a la del programa anterior:

pl@nereida:~/LEyapp/examples$ eyapp CalcSyntaxDefaultWithHOPLexer.eyp
pl@nereida:~/LEyapp/examples$ cat -n prueba4.exp
     1  4*3
pl@nereida:~/LEyapp/examples$ usecalcsyntaxdefaultwithhoplexer.pl prueba4.exp | cat -n
     1  exp --> NUM[4]
     2  exp --> NUM[3]
     3  exp --> exp * exp
     4  line --> STAR-2

La Opción -v de eyapp

Posiblemente llame su atención la línea line --> STAR-2 en la salida. Es consecuencia de la existencia de la línea 26 que contiene una aplicación del operador de repetición * a una expresión entre paréntesis:

26  line: (exp '\n')*
De hecho la gramática anterior es desplegada como se indica en el fichero CalcSyntaxDefaultWithHOPLexer.output obtenido al compilar usando la opción -v de eyapp:
pl@nereida:~/LEyapp/examples$ eyapp -v CalcSyntaxDefaultWithHOPLexer.eyp
pl@nereida:~/LEyapp/examples$ ls -ltr | tail -1
-rw-r--r-- 1 pl users   8363 2007-10-30 11:45 CalcSyntaxDefaultWithHOPLexer.output
pl@nereida:~/LEyapp/examples$ sed -ne '/Rules/,/^$/p' CalcSyntaxDefaultWithHOPLexer.output
Rules:
------
0:      $start -> line $end
1:      PAREN-1 -> exp '\n'
2:      STAR-2 -> STAR-2 PAREN-1
3:      STAR-2 -> /* empty */
4:      line -> STAR-2
5:      exp -> NUM
6:      exp -> VAR
7:      exp -> VAR '=' exp
8:      exp -> exp '+' exp
9:      exp -> exp '-' exp
10:     exp -> exp '*' exp
11:     exp -> exp '/' exp
12:     exp -> '-' exp
13:     exp -> exp '^' exp
14:     exp -> '(' exp ')'

Análisis Léxico con HOP::Lexer

En esta ocasión hemos elegido un método alternativo para construir el analizador léxico: Usar el módulo HOP::Lexer.

El módulo HOP::Lexer es cargado en las líneas 22-24. Los delimitadores %{ y %} permiten introducir código Perl en cualquier lugar de la sección de cabecera.

Estudie la documentación del módulo HOP::Lexer y compare la solución que sigue con la dada en la sección anterior ( véase 8.2). Este es el código en la sección de cola:

42  %%
43
44  sub _Error {
..      ..................................
52  }
53
54  sub Run {
55      my($self)=shift;
56      my $input = shift;
57
58      my @lexemes = (
59        ['SPACE', qr{[ \t]+}, sub { () } ],
60        ['NUM',   qr{[0-9]+(?:\.[0-9]+)?}],
61        ['VAR',   qr{[A-Za-z][A-Za-z0-9_]*}],
62        ["\n",    qr{\n}],
63        ['ANY',   qr{.},
64                    sub {
65                      my ($label, $val) = @_;
66                      return [ $val, $val ];
67                    }
68        ]
69
70      );
71      my $lexer = string_lexer($input, @lexemes);
72
73      return $self->YYParse(
74        yylex => sub {
75          my $parser = shift;
76          my $token = $lexer->();
77          return @$token if defined($token);
78          return ('', undef);
79        },
80        yyerror => \&_Error,
81        #yydebug => 0xF
82      );
83  }

La Opción yydebug

Cuando YYParse se llama con la opción yydebug activada (descomente la línea 81 si quiere ver el efecto) la ejecución del analizador produce un informe detallado (version de eyapp 0.83 o superior) de su avance durante el análisis:

pl@nereida:~/LEyapp/examples$ usecalcsyntaxdefaultwithhoplexer.pl prueba4.exp >& warn
pl@nereida:~/LEyapp/examples$ head -30 warn
----------------------------------------
In state 0:
Stack:[0]
Don't need token.
Reduce using rule 3 (STAR-2 --> /* empty */): Back to state 0, then go to state 1.
----------------------------------------
In state 1:
Stack:[0,1]
Need token. Got >NUM<
Shift and go to state 4.
----------------------------------------
In state 4:
Stack:[0,1,4]
Don't need token.
Reduce using rule 5 (exp --> NUM): Back to state 1, then go to state 5.
----------------------------------------
In state 5:
Stack:[0,1,5]
Need token. Got >*<
Shift and go to state 13.
----------------------------------------
In state 13:
Stack:[0,1,5,13]
Need token. Got >NUM<
Shift and go to state 4.
----------------------------------------
In state 4:
Stack:[0,1,5,13,4]
Don't need token.
Reduce using rule 5 (exp --> NUM): Back to state 13, then go to state 21.



Subsecciones
next up previous contents index PLPL moodlepserratamodulosperlmonksperldocapuntes LHPgoogleetsiiullpcgull
Sig: Traducción de Infijo a Sup: Análisis Sintáctico con Parse::Eyapp Ant: Depuración de Errores Err: Si hallas una errata ...
Casiano Rodríguez León
2012-05-22