Language::AttributeGrammar provee un constructor
new
que recibe la cadena describiendo la
gramática atribuída y un método apply que recibe
como argumentos el árbol AST y el atributo a evaluar.
Language::AttributeGrammar toma como entrada un AST en vez de
una descripción textual (línea 36).
nereida:~/src/perl/attributegrammar/Language-AttributeGrammar-0.08/examples> cat -n atg.pl 1 #!/usr/bin/perl -w 2 use strict; 3 use Language::AttributeGrammar; 4 use Data::Dumper; 5 6 my $grammar = new Language::AttributeGrammar <<'EOG'; 7 8 # find the minimum from the leaves up 9 Leaf: $/.min = { $<value> } 10 Branch: $/.min = { 11 $<left>.min <= $<right>.min ? $<left>.min : $<right>.min; 12 } 13 14 # propagate the global minimum downward 15 ROOT: $/.gmin = { $/.min } 16 Branch: $<left>.gmin = { $/.gmin } 17 Branch: $<right>.gmin = { $/.gmin } 18 19 # reconstruct the minimized result 20 Leaf: $/.result = { bless { value => $/.gmin } => 'Leaf' } 21 Branch: $/.result = { bless { left => $<left>.result, 22 right => $<right>.result } => 'Branch' } 23 24 EOG 25 26 sub Leaf { bless { value => $_[0] } => 'Leaf' } 27 sub Branch { bless { left => $_[0], right => $_[1] } => 'Branch' } 28 29 my $tree = Branch( 30 Branch(Leaf(2), Leaf(3)), 31 Branch(Leaf(1), Branch(Leaf(5), Leaf(9)))); 32 my $result = Branch( 33 Branch(Leaf(1), Leaf(1)), 34 Branch(Leaf(1), Branch(Leaf(1), Leaf(1)))); 35 36 my $t = $grammar->apply($tree, 'result'); 37 38 $Data::Dumper::Indent = 1; 39 print Dumper($t);El objeto representando a la gramática atribuída es creado mediante la llamada a Language::AttributeGrammar::new en la línea 6. La gramática es una secuencia de reglas semánticas. Cada regla semántica tiene la forma:
nodetype1 : $/.attr_1 = { CÓDIGO PERL($<hijo_i>.attr_k )} | $<hijo_1>.attr_2 = { CÓDIGO PERL($<hijo_i>.attr_k, $/.attr_s )} | $<hijo_2>.attr_3 = { CÓDIGO PERL } .... nodetype2 : $/.attr_1 = { CÓDIGO PERL($<hijo_i>.attr_k )} | $<hijo_1>.attr_2 = { CÓDIGO PERL($<hijo_i>.attr_k, $/.attr_s )} | $<hijo_2>.attr_3 = { CÓDIGO PERL } ....
Dentro de la especificación de la gramática es posible hacer uso de las notaciones especiales:
$/
se refiere al nodo que esta siendo visitado
$/.attr
se refiere al atributo attr
del nodo que esta siendo visitado
$<ident>
se refiere al hijo del nodo visitado denominado ident
.
Se asume que el nodo dispone de un método con ese nombre para obtener el hijo.
La notación $<ident>.attr
se refiere al atributo attr
del hijo ident
del nodo visitado.
La llamada al método $grammar->apply($tree, 'result')
en la línea 36 dispara la computación
de las reglas para el cálculo
del atributo result
sobre el árbol $tree
.
Cuando ejecutamos el programa obtenemos la salida:
nereida:~/src/perl/attributegrammar/Language-AttributeGrammar-0.08/examples> atg.pl $VAR1 = bless( { 'left' => bless( { 'left' => bless( { 'value' => 1 }, 'Leaf' ), 'right' => bless( { 'value' => 1 }, 'Leaf' ) }, 'Branch' ), 'right' => bless( { 'left' => bless( { 'value' => 1 }, 'Leaf' ), 'right' => bless( { 'left' => bless( { 'value' => 1 }, 'Leaf' ), 'right' => bless( { 'value' => 1 }, 'Leaf' ) }, 'Branch' ) }, 'Branch' ) }, 'Branch' );
Sigue una descripción en estilo Parse::Eyapp
de la gramática aceptada por
Language::AttributeGrammar :
grammar: rule * rule: nodetype ':' (target '.' attr '=' '{' BLOQUE DE CÓDIGO PERL '}') <* '|'> target: self | child | accesscodeLas variables
nodetype
, attr
, self
, child
y accesscode
viene definidas por las siguientes expresiones regulares:
nodetype: /(::)?\w+(::\w+)*/ # identificador Perl del tipo de nodo (PLUS, MINUS, etc.) attr: /\w+/ # identificador del atributo self: '$/' # Se refiere al nodo visitado child: /\$<\w+>/ # Hijo del nodo visitado accesscode: /`.*?`/ # Código explícito de acceso al hijo del nodo