next up previous contents index practicapracticaPP2moodleLHPmoodlepserratacpanmodulospauseperlgoogleetsiiullpcgull
Sig: Comprobando el Analizador Léxico Sup: La Estructura de los Ant: Práctica: Cadenas y Comentarios Err: Si hallas una errata ...


Haciendo mas Modular el Analizador Léxico

Queremos separar/aislar las diferentes fases del compilador en diferentes módulos. 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 (/\G\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



Subsecciones
next up previous contents index practicapracticaPP2moodleLHPmoodlepserratacpanmodulospauseperlgoogleetsiiullpcgull
Sig: Comprobando el Analizador Léxico Sup: La Estructura de los Ant: Práctica: Cadenas y Comentarios Err: Si hallas una errata ...
Casiano Rodríguez León
2006-02-21