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 7.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 ], # estadosSe 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 reglasLas 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;