next up previous contents index PLPL moodlepserratamodulosperlmonksperldocapuntes LHPgoogleetsiiullpcgull
Sig: AAA: Otros tipos de Sup: Árbol de Análisis Abstracto Ant: Lenguajes Árbol y Gramáticas Err: Si hallas una errata ...

Realización del AAA para Tutu en Perl

En la sección 4.6.1 nos limitamos a realizar un recorrido del árbol de análisis sintáctico concreto. En esta sección construimos un árbol de análisis sintáctico abstracto. Este proceso puede verse como la traducción desde el lenguaje de árboles concretos hasta el lenguaje de árboles abstractos.

Definición 4.9.7   La gramática árbol extendida que especifica los árboles AAA para el compilador de Tutu es esta:

1 $ prog$ $ \rightarrow PROGRAM(decls, sts)$
2 $ decls$ $ \rightarrow$ list $ decl$
3 $ sts$ $ \rightarrow$ list $ st$
4 $ decl$ $ \rightarrow INT(idlist)$
5 $ decl$ $ \rightarrow STRING(idlist)$
6 $ idlist$ $ \rightarrow$ list $ SIMPLEID$
7 $ st$ $ \rightarrow ASSIGN(LEFTVALUE, expr)$
8 $ st$ $ \rightarrow PRINT(expr)$
9 $ expr$ $ \rightarrow PLUS(expr, expr)$
10 $ expr$ $ \rightarrow TIMES(expr, expr)$
11 $ expr$ $ \rightarrow NUM$
12 $ expr$ $ \rightarrow ID$
13 $ expr$ $ \rightarrow STR$

Hemos extendido el concepto de gramática árbol con el concepto de lista de no terminales. A la hora de construir las estructuras de datos las listas de variables se van a traducir por listas de árboles.

Por ejemplo, un árbol abstracto para el programa

int a,b;
string c, d;
a = 4;
p a

Sería de la forma:

PROGRAM(
         DECLS[INT[ID, ID], STRING[ID, ID]], 
         STS[ASSIGN(LEFTVALUE, NUM), PRINT(ID)]
       )

Donde los corchetes indican listas y los paréntesis tuplas.

Para llevar a cabo la traducción deberemos tomar decisiones sobre que forma de representación nos conviene. Cada nodo del AAA va a ser un objeto y la clase indicará si es un nodo suma, producto, una declaración, una asignación, etc.

Cada nodo del árbol AAA va a ser un objeto. De este modo el acceso a los atributos del nodo se hará a través de los métodos asociados. Además, el procedimiento de traducción al lenguaje objetivo depende del tipo de nodo. Así por ejemplo, el método traducción es diferente para un nodo de tipo $ PLUS$ que para otro de tipo $ ASSIGN$ .

Resumamos antes de entrar en detalle, la forma de manejar los objetos en Perl:

Volviendo a nuestro problema de crear el AAA, para crear los objetos de las diferentes clases de nodos usaremos el módulo Class::MakeMethods::Emulator::MethodMaker (véase la línea 9):

 1 package PL::Syntax::Analysis;
 2
 3 use 5.006;
 4 use strict;
 5 use warnings;
 6 use Data::Dumper;
 7 use IO::File;
 8 use Class::MakeMethods::Emulator::MethodMaker '-sugar';
 9
10 require Exporter;
11 our @ISA = qw(Exporter);
12 our @EXPORT = qw( );
13 our $VERSION = '0.02';
14
15 #######################################################
16
17 # Grammar:
18 # P : DD L      | L
19 # DD: D ';' DD  | D ';'
20 # D : int I     | string I
21 # L : S         | S ; L
22 # S : ID '=' E  | p E  | epsilon
23 # E : T '+' E   | T
24 # T : F '*' T   | F
25 # F : '(' E ')' | id | num | str
26 # I : id ',' I  | id

Hemos aislado la fase de análisis sintáctica en un módulo aparte denominado PL::Syntax::Analysis. La dependencia se actualiza en Makefile.PL:

PL0506/04sintactico/PL-Tutu$ cat -n Makefile.PL
  1  use 5.008004;
  2  use ExtUtils::MakeMaker;
  3  WriteMakefile(
  4      NAME              => 'PL::Tutu',
  5      VERSION_FROM      => 'lib/PL/Tutu.pm', # finds $VERSION
  6      PREREQ_PM         => {Class::MakeMethods::Emulator::MethodMaker => 0},1
  7      EXE_FILES         => [ 'scripts/tutu.pl', 'scripts/tutu' ],
  8      ($] >= 5.005 ?     ## Add these new keywords supported since 5.005
  9        (ABSTRACT_FROM  => 'lib/PL/Tutu.pm', # retrieve abstract from module
 10         AUTHOR         => 'Casiano Rodriguez Leon <casiano@ull.es>') : ()),
 11  );
Se actualiza también MANIFEST:
$ cat -n MANIFEST
 1  Changes
 2  lib/PL/Error.pm
 3  lib/PL/Lexical/Analysis.pm
 4  lib/PL/Syntax/Analysis.pm
 5  lib/PL/Tutu.pm
 6  Makefile.PL
 7  MANIFEST
 8  MANIFEST.SKIP
 9  README
10  scripts/test01.tutu
11  scripts/tutu
12  scripts/tutu.pl
13  t/01Lexical.t

Ahora compile llama a Syntax::Analysis::parser pasándole como argumento la lista de terminales @tokens. La función parser devuelve el AAA:

04sintactico/PL-Tutu/lib/PL$ sed -ne '/sub compile\>/,/^}/p' Tutu.pm | cat -n
  1  sub compile {
  2    my ($input) = @_;
  3    #my %symbol_table = ();
  4    #my $data = ""; # Contiene todas las cadenas en el programa fuente
  5    my $target = ""; # target code
  6    my @tokens = ();
  7    my $tree = undef; # abstract syntax tree
  8    #my $global_address = 0;
  9
 10
 11    ########lexical analysis
 12    @tokens = scanner($input);
 13    #print "@tokens\n";
 14
 15    ########syntax (and semantic) analysis
 16    $tree = &Syntax::Analysis::parser(@tokens);
 17    print Dumper($tree);
 18
 19    ########machine independent optimizations
 20    &Machine::Independent::Optimization::Optimize;
 21
 22    ########code generation
 23    &Code::Generation::code_generator;
 24
 25    ########peephole optimization
 26    &Peephole::Optimization::transform($target);
 27
 28    return \$target;
 29  }
El módulo Class::MakeMethods::Emulator::MethodMaker permite crear constructores y métodos de acceso. El módulo no viene con la distribución de Perl, así que, en general, deberá descargarlo desde CPAN e instalarlo. Así definimos que existe una clase de nodos TYPE que nuestro AAA va a tener:

package TYPE;
make methods
  get_set       => [ 'NAME', 'LENGTH' ],
  new_hash_init => 'new';

El uso de los argumentos get_set => [ 'NAME', 'LENGTH' ] hace que se cree un objeto de tipo hash con claves 'NAME' y 'LENGTH' así como métodos NAME y LENGTH que cuando se llaman con un argumento devuelven el valor y cuando se llaman con dos argumentos modifican el valor correspondiente. La clave get_set produce métodos de acceso y modificación de los atributos del objeto que tienen la forma:

sub TYPE::NAME {
  my ($self, $new) = @_;
  defined($new) and $self->{NAME} = $new;
  return $self->{NAME};
}

Asi mismo el uso de new_hash_init => 'new' genera un constructor cuyo nombre será 'new' y que cuando es llamado inicializará el objeto con los argumentos con nombre especificados en la llamada. El constructor construído (vaya retruécano) cuando se usa la clave new_hash_init tiene el siguiente aspecto:

sub TYPE::new {
  my ($class, %args) = @_;
  my $self = {};

  bless $self, $class;
  foreach my $attribute (keys %args) {
    $self->$attribute($args{$attribute});
  }
  return $self;
}

Ahora podemos crear objetos de la clase TYPE haciendo:

my $int_type = TYPE->new(NAME => 'INTEGER', LENGTH => 1); 
my $string_type = TYPE->new(NAME => 'STRING', LENGTH => 2);
my $err_type = TYPE->new(NAME => 'ERROR', LENGTH => 0);
Cada uno de estos objetos es un hash con las correspondientes claves para el nombre y el tipo.

Otros tipos de nodos del AAA son:

package PROGRAM; # raíz del AAA
make methods
  get_set       => [ 'DECLS', 'STS' ],
  new_hash_init => 'new';

package STRING; # tipo
make methods
  get_set       => [ 'TYPE', 'IDLIST' ],
  new_hash_init => 'new';

package INT; # tipo
make methods
  get_set       => [ 'TYPE', 'IDLIST' ],
  new_hash_init => 'new';

package ASSIGN; #sentencia
make methods
  get_set       => [ 'LEFT', 'RIGHT' ],
  new_hash_init => 'new';

package PRINT; #sentencia
make methods
  get_set       => [ 'EXPRESSION' ],
  new_hash_init => 'new';

package NUM; # para los números
make methods
  get_set       => [ 'VAL', 'TYPE' ],
  new_hash_init => 'new';

package ID; # Nodos identificador. Parte derecha
make methods
  get_set       => [ 'VAL', 'TYPE' ],
  new_hash_init => 'new';

package STR; # Clase para las constantes cadena
make methods
  get_set       => [ 'OFFSET', 'LENGTH', 'TYPE' ],
  new_hash_init => 'new';

package PLUS; # Nodo suma
make methods
  get_set       => [ 'LEFT', 'RIGHT', 'TYPE' ],
  new_hash_init => 'new';

package TIMES;
make methods
  get_set       => [ 'LEFT', 'RIGHT', 'TYPE' ],
  new_hash_init => 'new';

package LEFTVALUE; # Identificador en la parte izquierda
make methods       # de una asignación
  get_set       => [ 'VAL', 'TYPE' ],
  new_hash_init => 'new';

Hemos extendido el concepto de gramática árbol con el concepto de lista de no terminales. A la hora de construir las estructuras de datos las listas de variables se van a traducir por listas de árboles. Los tipos de nodos ($ ASSIGN$ , $ PRINT$ , ...) se traducen en nombres de clases. Hemos hecho una excepción con $ SIMPLEID$ el cual es simplemente una variable cadena conteniendo el identificador correspondiente.

El siguiente esquema de traducción resume la idea para una gramática simplificada: cada vez que encontremos un nodo en el árbol sintáctico concreto con una operación crearemos un nodo en el AAA cuya clase viene definida por el tipo de operación. Para los terminales creamos igualmente nodos indicando de que clase de terminal se trata. El atributo nodo lo denotaremos por n:



$ e \rightarrow\ e_1 + f$ { $e{n} = PLUS->new(LEFT=>$e_1{n}, RIGHT=>$f{n}) }
$ f \rightarrow NUM$ { $f{n} = NUM->new(VAL => $NUM{VAL}) }
$ f \rightarrow ID$ { $f{n} = ID->new(VAL => $ID{VAL}) }


La estructura de cada rutina sigue siendo la misma, sólo que ampliada con las acciones para la construcción de los correspondientes nodos. Veamos por ejemplo, como modificamos la subrutina factor:

sub factor() {
  my ($e, $id, $str, $num);

  if ($lookahead eq 'NUM') {
    $num = $value;
    match('NUM');
    return NUM->new(VAL => $num, TYPE => $int_type);
  }
  elsif ($lookahead eq 'ID') {
    $id = $value;
    match('ID');
    return ID->new( VAL => $id, TYPE => undef);
  }
  elsif ($lookahead eq 'STR') {
    $str = $value;
    match('STR');
    return STR->new(OFFSET => undef, LENGTH => undef, TYPE => $string_type);
  }
  elsif ($lookahead eq '(') {
    match('(');
    $e = expression;
    match(')');
    return $e;
  }
  else {
    Error::fatal("Se esperaba (, NUM o ID");
  }
}


next up previous contents index PLPL moodlepserratamodulosperlmonksperldocapuntes LHPgoogleetsiiullpcgull
Sig: AAA: Otros tipos de Sup: Árbol de Análisis Abstracto Ant: Lenguajes Árbol y Gramáticas Err: Si hallas una errata ...
Casiano Rodríguez León
2012-05-22