next up previous contents index PLPL moodlepserratamodulosperlmonksperldocapuntes LHPgoogleetsiiullpcgull
Sig: Práctica: Análisis Sintáctico Sup: Análisis Sintáctico con Parse::Eyapp Ant: La Maniobra de bypass Err: Si hallas una errata ...


Salvando la Información en los Terminales Sintácticos

La directiva %tree

La directiva %tree permite que Parse::Eyapp genere al árbol sintáctico. Haciendo uso de las directivas adecuadas podemos controlar la forma del árbol. La directiva %tree es una alternativa a la directiva %metatree y es incompatible con esta última. El objetivo es lograr una representación adecuada del árbol sintáctico y dejar para fases posteriores la decoración del mismo.

nereida:~/src/perl/YappWithDefaultAction/examples> cat -n Rule6.yp
 1  %{
 2  use Data::Dumper;
 3  %}
 4  %right  '='
 5  %left   '-' '+'
 6  %left   '*' '/'
 7  %left   NEG
 8  %tree
 9
10  %%
11  line: exp  { $_[1] }
12  ;
13
14  exp:      %name NUM
15              NUM
16          | %name VAR
17            VAR
18          | %name ASSIGN
19            VAR '=' exp
20          | %name PLUS
21            exp '+' exp
22          | %name MINUS
23            exp '-' exp
24          | %name TIMES
25            exp '*' exp
26          | %name DIV
27            exp '/' exp
28          | %name UMINUS
29            '-' exp %prec NEG
30          |   '(' exp ')'  { $_[2] } /* Let us simplify a bit the tree */
31  ;
32
33  %%
34
35  sub _Error {
..    ..........
43  }
44
45  sub _Lexer {
..    ..........
62  }
63
64  sub Run {
65      my($self)=shift;
66      $self->YYParse( yylex => \&_Lexer, yyerror => \&_Error,
67                      #yyprefix => "Rule6::",
68                      #yydebug =>0xFF
69                    );
70  }

Compilación Separada

Para compilar un programa separado Parse::Eyapp usamos el guión eyapp :

nereida:~/src/perl/YappWithDefaultAction/examples> eyapp Rule6
nereida:~/src/perl/YappWithDefaultAction/examples> ls -ltr | tail -1
-rw-rw----  1 pl users   5475 2006-11-06 13:53 Rule6.pm

Terminales sintácticos y Terminales Semánticos

A diferencia de lo que ocurre cuando se usa la directiva %metatree la construcción del árbol solicitado mediante la directiva %tree implícitamente considera token sintácticos aquellos terminales que aparecen en definidos en el programa eyapp mediante el uso de apóstrofes. Los token sintácticos no forman parte del árbol construido. Asi pues -en el ejemplo que nos ocupa - los terminales '=', '-', '+', '*' y '/' serán -por defecto - eliminados del árbol sintáctico. Por ejemplo, para la entrada a=b*32 el siguiente árbol es construido:

nereida:~/src/perl/YappWithDefaultAction/examples> useruleandshift.pl
a=b*32
$VAR1 = bless( { 'children' => [
    bless( { 'children' => [], 'attr' => 'a', 'token' => 'VAR' }, 'TERMINAL' ),
    bless( { 'children' => [
        bless( { 'children' => [
            bless( { 'children' => [], 'attr' => 'b', 'token' => 'VAR' }, 'TERMINAL' )
          ]
        }, 'VAR' ),
        bless( { 'children' => [
            bless( { 'children' => [], 'attr' => '32', 'token' => 'NUM' }, 'TERMINAL' )
          ]
        }, 'NUM' )
      ]
    }, 'TIMES' )
  ]
}, 'ASSIGN' );
Esta conducta puede cambiarse usando la directiva %semantic token la cual declara una lista de terminales como semánticos. En tal caso dichos terminales formarán parte del árbol construido. Si por el contrario lo que queremos es cambiar el estatus de un terminal - por ejemplo NUM o ID - a sintáctico usaremos la directiva %syntactic token .

Salvando la Información de los %syntactic token

Si bien la funcionalidad de un %syntactic token es determinar la forma del AST, en ocasiones la diferencia entre terminal sintáctico y semántico es difusa. Un terminal fundamentalmente sintáctico pueden acarrear alguna información útil para las restantes fases de procesado.

Por ejemplo, el atributo número de línea asociado con el terminal sintáctico '+' puede ser útil posteriormente: Si en la fase de comprobación de tipos se observa un error de tipos incompatibles con el operador, disponer de la línea asociada con '+' nos permitirá emitir mensajes de error mas precisos.

En Parse::Eyapp el programador puede proveer a la clase TERMINAL de un método

TERMINAL::save_attributes

el cuál será ejecutado durante la construcción del AST cada vez que un syntaxtic token es eliminado. El método recibe como argumento - además de la referencia al nodo terminal - una referencia al nodo padre del terminal. Sigue un ejemplo:

sub TERMINAL::save_attributes {
  # $_[0] is a syntactic terminal
  # $_[1] is the father.
  push @{$_[1]->{lines}}, $_[0]->[1]; # save the line!
}

La tabla 8.1 muestra como el nodo PLUS recoge la información del número de línea del terminal +.

El árbol fué generado usando el método str. La información sobre los atributos se hizo mediante la siguiente subrutina:

sub generic_info {
  my $info;

  $info = "";
  $info .= $_[0]->type_info if $_[0]->can('type_info');

  my $sep = $info?":":"";

  $info .= $sep.$_[0]->{line} if (defined $_[0]->{line});
  local $" = ',';
  $info .= "$sep@{$_[0]->{lines}}" if (defined $_[0]->{lines});
  return $info;
}

*PLUS::info = =\&generic_info;


Tabla: El nodo PLUS recoge el número de línea del terminal+
Programa y Footnotes AST generado por $t->str
int f(int a, int b) {
 return a+b;
}
-------footnotes-----------
0)
Symbol Table:
$VAR1 = {
  'f' => {
    'type' => 'F(X_2(INT,INT),INT)',
    'line' => 1
  }
};
---------------------------
1) etc.
PROGRAM^{0}(
  FUNCTION[f]^{1}(
    RETURN[2,2](
      PLUS[INT:2](
        VAR[INT](
          TERMINAL[a:2]
        ),
        VAR[INT](
          TERMINAL[b:2]
        )
      ) # PLUS
    ) # RETURN
  ) # FUNCTION
) # PROGRAM



Subsecciones
next up previous contents index PLPL moodlepserratamodulosperlmonksperldocapuntes LHPgoogleetsiiullpcgull
Sig: Práctica: Análisis Sintáctico Sup: Análisis Sintáctico con Parse::Eyapp Ant: La Maniobra de bypass Err: Si hallas una errata ...
Casiano Rodríguez León
2012-05-22