 
 
 
 
 
 
 
 
 
 










 
Durante esta fase pasamos a asignar un tipo a los nodos del AST. Pueden producirse errores de tipo y es importante que los mensajes de diagnóstico sea precisos. Por ejemplo, dado el programa:
nereida:~/doc/casiano/PLBOOK/PLBOOK/code/Simple-Types/script> cat -n prueba17.c
     1  int c[20][30], d;
     2
     3  int f(int a, int b) {
     4    return
     5       (a+b)*
     6       d*
     7       c[5];
     8  }
queremos producir un mensaje de error adecuado como:
nereida:~/doc/casiano/PLBOOK/PLBOOK/code/Simple-Types/script> usetypes.pl prueba17.c Type Error at line 6: Incompatible types with operator '*'indicando asi que el error se produce en la multiplicación de la línea 6, ya que
c[5] es de tipo array.
El problema que tenemos a estas alturas de la construcción de nuestro compilador
es que el número de línea asociado con la multiplicación de la línea 6
no figura como atributo del nodo TIMES: fue obviado por la directiva  %tree 
ya que el terminal * fué tratado como un syntactic token.
Afortunadamente Parse::Eyapp provee un mecanismo para permitir
guardar la información 
residente en un terminal sintáctico 
en el nodo padre del mismo. Si el programador
provee a la clase  TERMINAL  de un método
 save_attributes  dicho método será llamado
durante la construcción del AST en el momento de la
eliminación del terminal:
| TERMINAL::save_attributes($terminal, $lhs) | 
El primer argumento es la referencia al nodo TERMINAL
y el segundo al node padre del terminal.
Por tanto, para resolver el problema de conocer 
el número de línea en el que ocurre un operador,
proveeremos a los nodos TERMINAL
del siguiente método save_attributes:
620 sub TERMINAL::save_attributes {
621   # $_[0] is a syntactic terminal
622   # $_[1] is the father.
623   push @{$_[1]->{lines}}, $_[0]->[1]; # save the line!
624 }
La subrutina de mensajes de error de tipo type_error
la llamaremos proporcionando el mensaje y el número de línea. 
Sigue un ejemplo de llamada:
type_error("Incompatible types with operator '".($_[0]->lexeme)."'", $_[0]->line);
El método line para este tipo de nodos tiene la forma:
pl@nereida:~/doc/casiano/PLBOOK/PLBOOK/code/Simple-Types/lib/Simple$ \
                      sed -ne '/sub P.*ne/,/^)/p' Types.eyp | cat -n
     1  sub PLUS::line {
     2    $_[0]->{lines}[0]
     3  }
     4
     5  insert_method(
     6    qw{TIMES DIV MINUS ASSIGN GT IF RETURN},
     7    'line',
     8    \&PLUS::line
     9  );
La función  insert_method  es proveída por Parse::Eyapp::Base
(versiones de Parse::Eyapp posteriores a la 1.099).
Recibe como argumentos una lista de clases, el nombre del método ('line'
en el ejemplo) y la referencia a
la función que la implementa. Dotará a 
cada una de las clases especificadas
en la lista (TIMES, DIV etc.) con métodos
line implantados a través de la función especificada (\&PLUS::line).
pl@nereida:~/doc/casiano/PLBOOK/PLBOOK/code/Simple-Types/lib/Simple$ \
                            sed -ne '/use/,/^$/p' Types.eyp | cat -n
     1  use strict;
     2  use Carp;
     3  use warnings;
     4  use Data::Dumper;
     5  use List::MoreUtils qw(firstval);
     6  use Simple::Trans;
     7  use Parse::Eyapp::Scope qw(:all);
     8  use Parse::Eyapp::Base qw(insert_function insert_method);
     9  our $VERSION = "0.4";
    10
El método lexeme que aparece 
en la llamada a type_error devuelve 
para un tipo de nodo dado 
el lexema asociado con ese nodo.
Por ejemplo, para los nodos TIMES 
retorna la cadena *. 
Para implantarlo se usan los hashes lexeme y 
rlexeme:
pl@nereida:~/doc/casiano/PLBOOK/PLBOOK/code/Simple-Types/lib/Simple$ \
                                 sed -ne '31,64p' Types.eyp | cat -n
     1  my %lexeme = (
     2    '='  => "ASSIGN",
     3    '+'  => "PLUS",
     4    '-'  => "MINUS",
     5    '*'  => "TIMES",
     6    '/'  => "DIV",
     7    '%'  => "MOD",
     8    '|'  => "OR",
     9    '&'  => "AND",
    10    '{'  => "LEFTKEY",
    11    '}'  => "RIGHTKEY",
    12    ','  => "COMMA",
    13    ';'  => "SEMICOLON",
    14    '('  => "LEFTPARENTHESIS",
    15    ')'  => "RIGHTPARENTHESIS",
    16    '['  => "LEFTBRACKET",
    17    ']'  => "RIGHTBRACKET",
    18    '==' => "EQ",
    19    '+=' => "PLUSASSIGN",
    20    '-=' => "MINUSASSIGN",
    21    '*=' => "TIMESASSIGN",
    22    '/=' => "DIVASSIGN",
    23    '%=' => "MODASSIGN",
    24    '!=' => "NE",
    25    '<'  => "LT",
    26    '>'  => "GT",
    27    '<=' => "LE",
    28    '>=' => "GE",
    29    '++' => "INC",
    30    '--' => "DEC",
    31    '**' => "EXP"
    32  );
    33
    34  my %rlexeme = reverse %lexeme;
Cada una de las clases implicadas es dotada de un método lexeme 
mediante una llamada a insert_method:
pl@nereida:~/doc/casiano/PLBOOK/PLBOOK/code/Simple-Types/lib/Simple$ \
                      sed -ne '/sub.*xeme/,/^)/p' Types.eyp | cat -n
 1  sub lexeme {
 2    return $rlexeme{ref($_[0])} if defined($rlexeme{ref($_[0])});
 3    return ref($_[0]);
 4  }
 5
 6  insert_method(
 7    # Gives the lexeme for a given operator
 8    qw{
 9      PLUS TIMES DIV MINUS
10      GT  EQ NE
11      IF
12      IFELSE
13      WHILE
14      VARARRAY VAR ASSIGN
15      FUNCTIONCALL
16    },
17    'lexeme',
18    \&lexeme
19  );
El método save_attributes no se ejecuta automáticamente en las reglas que usan 
los operadores de listas +, * y ?. En tales casos el programador
deberá proveer código explícito que salve el número de línea:
nereida:~/doc/casiano/PLBOOK/PLBOOK/code/Simple-Types/lib/Simple> \
    sed -ne '353,363p' Types.eyp  | cat -n
 1  Variable:
 2      %name VAR
 3      ID
 4    | %name  VARARRAY
 5      $ID ('[' binary ']') <%name INDEXSPEC +>
 6        {
 7          my $self = shift;
 8          my $node =  $self->YYBuildAST(@_);
 9          $node->{line} = $ID->[1];
10          return $node;
11        }
En el ejemplo se pone explícitamente como atributo line del
nodo VARARRAY el número de línea del terminal ID.
 
 
 
 
 
 
 
 
 
 
 










