Para ello comenzamos creando un módulo conteniendo las rutinas de tratamiento de errores:
lhp@nereida:~/Lperl/src/topdown/PL0506/03lexico/PL-Tutu/lib/PL$ pwd /home/lhp/Lperl/src/topdown/PL0506/03lexico/PL-Tutu/lib/PL lhp@nereida:~/Lperl/src/topdown/PL0506/03lexico/PL-Tutu/lib/PL$ cat -n Error.pm 1 package Error; 2 use strict; 3 use warnings; 4 use Carp; 5 6 require Exporter; 7 8 our @ISA = qw(Exporter); 9 our @EXPORT = qw( error fatal); 10 our $VERSION = '0.01'; 11 12 sub error { 13 my $msg = join " ", @_; 14 if (!$PL::Tutu::errorflag) { 15 carp("Error: $msg\n"); 16 $PL::Tutu::errorflag = 1; 17 } 18 } 19 20 sub fatal { 21 my $msg = join " ", @_; 22 croak("Error: $msg\n"); 23 }Observa como accedemos a la variable
errorflag
del paquete
PL::Tutu
.
Para usar este módulo desde PL::Tutu
, tenemos que declarar su uso:
lhp@nereida:~/Lperl/src/topdown/PL0506/03lexico/PL-Tutu/lib/PL$ cat -n Tutu.pm | head -8 1 package PL::Tutu; 2 3 use 5.008004; 4 use strict; 5 use warnings; 6 use IO::File; 7 use Carp; 8 use PL::Error;En la línea 8 hacemos
use PL::Error
y no use Error
ya que el módulo
lo hemos puesto en el directorio PL
.
No olvides hacer make manifest
para actualizar el fichero MANIFEST
.
Supongamos que además de modularizar el grupo de rutinas de tratamiento de errores
queremos hacer lo mismo con la parte del análisis léxico. Parece lógico que el
fichero lo pongamos en un subdirectorio de PL/
por lo que cambiamos
el nombre del módulo a PL::Lexical::Analysis
quedando la jerarquía de ficheros
asi:
lhp@nereida:~/Lperl/src/topdown/PL0506/03lexico/PL-Tutu/lib/PL$ tree . |-- Error.pm |-- Lexical | `-- Analysis.pm `-- Tutu.pm
Por supuesto debemos modificar las correspondientes líneas en Tutu.pm
:
1 package PL::Tutu; 2 3 use 5.008004; 4 use strict; 5 use warnings; 6 use IO::File; 7 use Carp; 8 use PL::Error; 9 use PL::Lexical::Analysis; 10 ... 11 12 sub compile { 13 my ($input) = @_; 14 local %symbol_table = (); 15 local $data = ""; # Contiene todas las cadenas en el programa fuente 16 local $target = ""; # target code 17 my @tokens = (); 18 local $errorflag = 0; 19 local ($lookahead, $value) = (); 20 local $tree = undef; # abstract syntax tree 21 local $global_address = 0; 22 23 24 ########lexical analysis 25 @tokens = &PL::Lexical::Analysis::scanner($input); 26 print "@tokens\n"; 27 28 ... 29 30 return \$target; 31 }Observe que ahora
PL::Lexical::Analysis::scanner
devuelve
ahora la
lista con los terminales y que @tokens
se ha ocultado en
compile
como una variable léxica (línea 17).
En la línea 26 mostramos el contenido de la lista de terminales.
Sigue el listado del módulo conteniendo el analizador léxico. Obsérve las líneas 6, 16 y 44.
lhp@nereida:~/Lperl/src/topdown/PL0506/03lexico/PL-Tutu/lib/PL/Lexical$ cat -n Analysis.pm 1 # Lexical analyzer 2 package PL::Lexical::Analysis; 3 use strict; 4 use warnings; 5 use Carp; 6 use PL::Error; 7 8 require Exporter; 9 10 our @ISA = qw(Exporter); 11 our @EXPORT = qw( scanner ); 12 our $VERSION = '0.01'; 13 14 sub scanner { 15 local $_ = shift; 16 my @tokens; 17 18 { # Con el redo del final hacemos un bucle "infinito" 19 if (m{\G\s*(\d+)}gc) { 20 push @tokens, 'NUM', $1; 21 } .. ... 37 elsif (m{\G\s*([+*()=;,])}gc) { 38 push @tokens, 'PUN', $1; 39 } 40 elsif (m{\G\s*(\S)}gc) { 41 Error::fatal "Caracter invalido: $1\n"; 42 } 43 else { 44 return @tokens; 45 } 46 redo; 47 } 48 }
Puesto que en el paquete PL::Lexical::Analysis
exportamos scanner
no es necesario llamar la rutina por el nombre
completo desde compile
. Podemos simplificar la línea en la
que se llama a scanner
que queda así:
########lexical analysis @tokens = &scanner($input); print "@tokens\n";De la misma forma, dado que
PL::Tutu
exporta la función compile_from_file
,
no es necesario llamarla por su nombre completo desde el guión tutu
. Reescribimos
la línea de llamada:
lhp@nereida:~/Lperl/src/topdown/PL0506/03lexico/PL-Tutu/scripts$ cat tutu #!/usr/bin/perl -w use lib ('../lib'); use PL::Tutu; &compile_from_file(@ARGV);
Como siempre que se añaden o suprimen archivos es necesario actualizar
MANIFEST
:
lhp@nereida:~/Lperl/src/topdown/PL0506/03lexico/PL-Tutu$ make manifest /usr/bin/perl "-MExtUtils::Manifest=mkmanifest" -e mkmanifest Added to MANIFEST: lib/PL/Lexical/Analysis.pm lhp@nereida:~/Lperl/src/topdown/PL0506/03lexico/PL-Tutu$ cat -n MANIFEST 1 Changes 2 lib/PL/Error.pm 3 lib/PL/Lexical/Analysis.pm 4 lib/PL/Tutu.pm 5 Makefile.PL 6 MANIFEST 7 MANIFEST.SKIP 8 README 9 scripts/test01.tutu 10 scripts/tutu 11 scripts/tutu.pl 12 t/PL-Tutu.t