$yatw_object->m($t)
permite la búsqueda
de los nodos que casan con una expresión regular árbol dada.
En un contexto de lista devuelve una
lista con nodos del
tipo Parse::Eyapp::Node::Match que referencian
a los nodos que han casado. Los nodos en la lista
se estructuran según un árbol (atributos children
y father
)
de manera que el padre
de un nodo $n
del tipo Parse::Eyapp::Node::Match
es el
nodo $f
que referencia al inmediato antecesor
en el árbol que ha casado.
Los nodos Parse::Eyapp::Node::Match
son a su vez nodos (heredan de)
Parse::Eyapp::Node
y se estructuran según un árbol.
Los nodos
aparecen en la lista retornada en orden primero profundo de
recorrido del árbol $t
.
Un nodo $r
de la clase
Parse::Eyapp::Node::Match
dispone de varios atributos
y métodos:
$r->node
retorna el nódo del árbol $t
que ha casado
$r->father
retorna el nodo padre en el árbol the matching.
Se cumple que $r->father->node
es
una referencia al antepasado mas cercano en $t
de $r->node
que casa con el patrón árbol ($SimpleTrans::blocks
en el ejemplo que sigue).
$r->coord
retorna las coordenadas del nódo del árbol que ha casado
usando una notación con puntos. Por ejemplo la coordenada
".1.3.2"
denota al nodo $t->child(1)->child(3)->child(2)
, siendo $t
la raíz del árbol de búsqueda.
$r->depth
retorna la profundidad del nódo del árbol que ha casado
Parse::Eyapp::Node::Match
hereda de
Parse::Eyapp::Node
. Dispone además de otros métodos
para el caso en que se usan varios patrones en la misma búsqueda.
Por ejemplo, método $r->names
retorna una referencia a los nombres de los patrones
que han casado con el nodo.
En un contexto escalar m
devuelve el primer
elemento de la lista de nodos Parse::Eyapp::Node::Match
.
La siguiente expresión regular árbol casa con los nodos bloque:
nereida:~/doc/casiano/PLBOOK/PLBOOK/code/Simple-Types/lib/Simple> sed -ne '2p' Trans.trg blocks: /BLOCK|FUNCTION|PROGRAM/
Utilizaremos el siguiente programa de entrada:
nereida:~/doc/casiano/PLBOOK/PLBOOK/code/Simple-Types/script> cat -n blocks.c 1 test (int n) 2 { 3 while (1) { 4 if (1>0) { 5 int a; 6 break; 7 } 8 else if (2> 0){ 9 char b; 10 continue; 11 } 12 } 13 }Ejecutamos la versión con análisis de tipos de nuestro compilador de simple C. SimpleC es una versión simplificada de C (véase el capítulo 12 y las secciones 12.3 y 12.4), bajo el control del depurador:
nereida:~/doc/casiano/PLBOOK/PLBOOK/code/Simple-Types/script> perl -wd usetypes.pl blocks.c Loading DB routines from perl5db.pl version 1.28 Editor support available. Enter h or `h h' for help, or `man perldebug' for more help. main::(usetypes.pl:6): my $filename = shift || die "Usage:\n$0 file.c\n"; DB<1> b Simple::Types::compile DB<2> c Simple::Types::compile(Types.eyp:529): 529: my($self)=shift; DB<2> l 540,545 540: our $blocks; 541: my @blocks = $blocks->m($t); 542: $_->node->{fatherblock} = $_->father->{node} for (@blocks[1..$#blocks]); 543 544 # Type checking 545: set_types($t); DB<3> c 545 Simple::Types::compile(Types.eyp:545): 545: set_types($t);Nos detenemos en la línea 545 justo después de la llamada a
m
(línea 541) y de actualizar el atributo fatherblock
de los nodos bloque. La línea 542 crea una jerarquía árbol
con los nodos bloque que se superpone a la jerarquía del árbol
sintáctico abstracto.
En esta línea $_->father->{node}
es el nodo del AST
que es un ancestro de $_->node
y que ha casado con la expresión
regular árbol.
Este sub-árbol de bloques puede ayudarnos en la fase de ubicar que declaración se aplica a una aparición de un objeto dado en el texto del programa. Para cada ocurrencia debemos determinar si fué declarada en el bloque en el que ocurre o bien en uno de los nodos bloque antepasados de este.
DB<4> $Parse::Eyapp::Node::INDENT = 2 DB<5> x $blocks[0]->str 0 ' Match[[PROGRAM:0:blocks]]( Match[[FUNCTION:1:blocks:test]]( Match[[BLOCK:6:blocks:8:4:test]], Match[[BLOCK:5:blocks:4:4:test]] ) ) # Parse::Eyapp::Node::Match'La orden
x $blocks[0]->str
nos permite visualizar el árbol de
casamientos.
El método coord nos devuelve una cadena
con las coordenadas del nodo que ha casado. Las coordenadas
son una secuencia de puntos y números que describe
el camino para llegar al nodo desde la raíz del árbol.
Veamos las coordenadas de los nodos en el AST del ejemplo:
DB<6> x map {$_->coord} @blocks 0 '' 1 '.0' 2 '.0.0.1.0.1' 3 '.0.0.1.0.2.1' DB<7> x $t->child(0)->child(0)->child(1)->child(0)->child(2)->child(1)->str 0 ' BLOCK[8:4:test]^{0}( CONTINUE[10,10] ) DB<8> x $t->descendant('.0.0.1.0.2.1')->str 0 ' BLOCK[8:4:test]^{0}( CONTINUE[10,10] ) DB<9> x $t->descendant('.0.0.1.0.1')->str 0 ' BLOCK[4:4:test]^{0}( BREAK[6,6] )El método descendant es un método de los objetos
Parse::Eyapp::Node
y retorna una referencia al nodo descrito por la cadena de coordenadas
que se le pasa como argumento. En este sentido el método
child es una especialización de descendant .
La profundidad de los nodos que han casado puede conocerse con el método depth :
DB<9> x map {$_->depth } @blocks 0 0 1 1 2 5 3 6 DB<16> x map {ref($_->node) } @blocks 0 'PROGRAM' 1 'FUNCTION' 2 'BLOCK' 3 'BLOCK' DB<17> x map {ref($_->father) } @blocks 0 '' 1 'Parse::Eyapp::Node::Match' 2 'Parse::Eyapp::Node::Match' 3 'Parse::Eyapp::Node::Match' DB<19> x map {ref($_->father->node) } @blocks[1..3] 0 'PROGRAM' 1 'FUNCTION' 2 'FUNCTION'