El módulo Generado por yapp

La ejecución de la orden yapp -m Calc Calc.yp produce como salida el módulo Calc.pm el cual contiene las tablas LALR(1) para la gramática descrita en Calc.yp. Estas tablas son las que dirigen al analizador LR. Puede ver el código completo del módulo en el apéndice que se encuentra en la página [*]. La estructura del módulo Calc.pm es como sigue:

 1 package Calc;
 2 use vars qw ( @ISA );
 3 use strict;
 4 @ISA= qw ( Parse::Yapp::Driver );
 5 use Parse::Yapp::Driver;
 6 
 7 sub new {
 8    my($class)=shift;
 9    ref($class) and $class=ref($class);
10 
11     my($self)=$class->SUPER::new( 
12        yyversion => '1.05',
13        yystates => [ 
..          ...
32        ], # estados
33        yyrules  => [
..       	# ... mas reglas
70        ], # final de las reglas
71        @_); # argumentos pasados
72   bless($self,$class);
73 }

La clase Calc hereda de Parse::Yapp::Driver, pero el objeto creado será bendecido en la clase Calc (Línea 4, véanse también la figura 35.3 y la línea 72 del fuente). Por tanto, el constructor llamado en la línea 11 es el de Parse::Yapp::Driver. Se utiliza la estrategia de llamada con parámetros con nombre. El valor para la clave yystates es una referencia anónima al array de estados y el valor para la clave yyrules es una referencia anónima a las reglas.

10 
11     my($self)=$class->SUPER::new( 
12        yyversion => '1.05',
13        yystates => [
14         {#State 0
15           DEFAULT => -1, GOTOS => { 'input' => 1 }
16         },
17         {#State 1
18           ACTIONS => {
19             'NUM' => 6, '' => 4, "-" => 2, "(" => 7,
20             'VAR' => 8, "\n" => 5, 'error' => 9
21           },
22           GOTOS => { 'exp' => 3, 'line' => 10 }
23         },
24         # ...  mas estados
25         {#State 27
26           ACTIONS => {
27             "-" => 12, "+" => 13, "/" => 15, "^" => 16,
28             "*" => 17
29           },
30           DEFAULT => -8
31         }
32        ], # estados
Se ve que un estado se pasa como un hash anónimo indexado en las acciones y los saltos.

Para consultar los números asociados con las reglas de producción vea el apéndice en la página [*] conteniendo el fichero Calc.output.

A continuación vienen las reglas:

33        yyrules  => [
34        [#Rule 0
35              '$start', 2, undef ],
36        [#Rule 1
37              'input', 0, undef ],
38        [#Rule 2
39              'input', 2, sub
40 #line 17 "Calc.yp"
41              { push(@{$_[1]},$_[2]); $_[1] }
42        ],
43        [#Rule 3
44              'line', 1, sub
45 #line 20 "Calc.yp"
46              { $_[1] }
47        ],
48        [#Rule 4
49              'line', 2, sub
50 #line 21 "Calc.yp"
51              { print "$_[1]\n" }
52        ],
53   # ... mas reglas
54     [#Rule 11
55             'exp', 3, sub
56 #line 30 "Calc.yp"
57 { $_[1] * $_[3] }
58    ],
59   [#Rule 12
60             'exp', 3, sub
61 #line 31 "Calc.yp"
62   {
63     $_[3] and return($_[1] / $_[3]);
64     $_[0]->YYData->{ERRMSG} =   "Illegal division by zero.\n";
65     $_[0]->YYError;
66     undef
67   }
68     ],
69   # ... mas reglas
70   ], # final de las reglas
Las reglas son arrays anónimos conteniendo el nombre de la regla o variable sintáctica (exp), el número de símbolos en la parte derecha y la subrutina anónima con el código asociado.

Vemos como la acción es convertida en una subrutina anónima. Los argumentos de dicha subrutina son los atributos semánticos asociados con los símbolos en la parte derecha de la regla de producción. El valor retornado por la acción/subrutina es el valor asociado con la reducción.

Para hacer que el compilador Perl diagnostique los errores relativos al fuente Calc.yp se usa una directiva #line.

71   @_);
72   bless($self,$class);
73 }
74

la bendición con dos argumentos hace que el objeto pertenezca a la clase Calc. A continuación siguen las subrutinas de soporte:

75 #line 44 "Calc.yp" 
76 
77 
78 sub _Error {
79   # ...
80 }
81 
82 sub _Lexer {
83   my($parser)=shift;
84   # ...
85 }
86 
87 sub Run {
88     my($self)=shift;
89     $self->YYParse( yylex => \&_Lexer, yyerror => \&_Error );
90 }
91 
92 my($calc)=new Calc;
93 $calc->Run;
94 
95 1;

Casiano Rodríguez León
2013-04-23