

$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'

