next up previous contents index PLPL moodlepserratamodulosperlmonksperldocapuntes LHPgoogleetsiiullpcgull
Sig: Comprobación de Tipos: Las Sup: Análisis de Tipos Ant: Comprobación Ascendente de los Err: Si hallas una errata ...


Análisis de Tipos: Mensajes de Error

El Problema

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.

El método TERMINAL::save_attributes

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 Función insert_method

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 Lexema Asociado con Una Clase

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  );

Listas y save_attributes

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.



Subsecciones
next up previous contents index PLPL moodlepserratamodulosperlmonksperldocapuntes LHPgoogleetsiiullpcgull
Sig: Comprobación de Tipos: Las Sup: Análisis de Tipos Ant: Comprobación Ascendente de los Err: Si hallas una errata ...
Casiano Rodríguez León
2012-05-22