

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 | accesscode
Las 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

