GAP.pm
que provea una subrutina gap
para
la generación automática de un APDR supuesto que la gramática de entrada es
LL(1).
La subrutina gap
recibe como entrada la gramática según la estructura de
datos generada por la función Grammar::Parse
de la versión 0.3 del módulo
Grammar.
Dicha estructura de datos se explicó en la práctica
11.6.8.
La estructura de datos generada por Grammar::Parse
ha sido extendida
en esta versión para incluir el código que se sitúe en la zona de cola.
Por ejemplo, dada la gramática de entrada:
Grammar/03/scripts$ cat -n aSb.yp 1 %% 2 S: 3 | 'a' S 'b' 4 ; 5 %% 6 7 sub Lex { 8 local $_ = shift; # input 9 my @tokens; 10 11 12 while ($_) { 13 s/^\s*//; # fuera blancos 14 push @tokens, $1, $1 if s/^(.)//s 15 } 16 @tokens; 17 } 18 19 sub main { 20 my $filename = shift; 21 my $input; 22 23 if (defined($filename)) { 24 local $/ = undef; 25 open FILE, $filename or die "No se pudo abrir $filename\n"; 26 $input = <FILE>; 27 close(FILE); 28 } 29 else { $input = <STDIN> } 30 31 my @tokens = Lex($input); 32 Parse(@tokens); # Llamada al analizador generado 33 print "Sintácticamente correcto\n"; 34 }se genera la siguiente estructura de datos:
{ 'SYMS' => { 'S' => 2, '\'b\'' => 3, '\'a\'' => 3 }, 'NULL' => { 'S' => 1 }, 'RULES' => [ [ 'S', [] ], [ 'S', [ '\'a\'', 'S', '\'b\'' ] ] ], 'START' => 'S', 'TERM' => [ '\'b\'', '\'a\'' ], 'NTERM' => { 'S' => [ 0, 1 ] } 'TAIL' => [ ' sub Lex { local $_ = shift; # input my @tokens; while ($_) { s/^\\s*//; # fuera blancos push @tokens, $1, $1 if s/^(.)//s } @tokens; } sub main { my $filename = shift; my $input; if (defined($filename)) { local $/ = undef; open FILE, $filename or die "No se pudo abrir $filename\\n"; $input = <FILE>; close(FILE); } else { $input = <STDIN> } my @tokens = Lex($input); my $ok = Parse(@tokens); # Llamada al analizador generado print "Sintácticamente correcto\\n" if $ok; } ', 5 ], # línea en la que está el segundo %% };
Asi pues la entrada con clave TAIL
contiene el código auxiliar de
cola. Este código debe ser incluido por su programa dentro del texto del
paquete generado por gap
.
La función gap
también recibe como entrada el nombre
del package:
$package_text = &gap($grammar, 'Package_name');La función
gap
retorna
una cadena conteniendo el package
en el que estan las subrutinas del
analizador sintáctico. La idea es que dicha cadena se salvará en un fichero
con nombre Package_name.pm
que podrá posteriormente ser usado
(use Package_name
) por un programa que necesite analizar entradas
que se conforman de acuerdo a la especificación de la gramática.
La rutina principal del paquete generado se ha de llamar
Parser
(esto es, su nombre completo es: Package_name::Parser
.
Evidentemente Package_name
debe ser un nombre Perl válido).
Ninguna subrutina deberá ser exportada sino que deberán ser llamadas
por su nombre completo.
La subrutina Parser
recibe como argumento el array de
terminales, obtiene el primer terminal y llama a la subrutina
asociada con el símbolo de arranque. Los terminales están representados
como parejas
.
Observe que, una vez que la cadena $package_text
conteniendo el paquete ha sido
generada y salvada en un fichero con nombre Package_name.pm
, podemos escribir
un programa cliente:
use strict; use Package_name.pm; &Package_name::main;
Este programa espera una entrada desde fichero o STDIN
e
informa si dicha entrada es sintácticamente correcta o no
para la gramática en cuestión.
Para la escritura de GAP.pm
haga uso del módulo que
calcula los y los que
desarrolló durante la práctica 11.6.8.