1 #!/usr/local/bin/perl5.8.0 -w 2 use strict; 3 use warnings; 4 5 use Parse::RecDescent; 6 7 8 my $grammar = q { 9 10 start: seq_1 seq_2 11 12 seq_1 : 'A' 'B' 'C' 'D' 13 { print "seq_1: " . join (" ", @item[1..$#item]) . "\n" } 14 | 'A' 'B' 'C' 'D' 'E' 'F' 15 { print "seq_1: " . join (" ", @item[1..$#item]) . "\n" } 16 17 seq_2 : character(s) 18 19 character: /\w/ 20 { print "character: $item[1]\n" } 21 22 }; 23 24 my $parser=Parse::RecDescent->new($grammar); 25 26 $parser->start("A B C D E F");En la línea 5 se declara el uso del módulo. En la línea 8 se guarda la gramática en la variable escalar
$grammar
.
La variable sintáctica start
es considerada de arranque de la gramática.
Las partes derechas de las producciones se separan mediante la barra |
,
y las acciones se insertan entre llaves.
El contenido de las acciones es código Perl.
Dentro de esas acciones es posible
hacer alusión a los atributos de los símbolos de la producción a través
del array @item
. Así $item[1]
contendrá el atributo asociado
al primer símbolo (el carácter A
en este caso).
Para que una producción tenga éxito es necesario
que la acción devuelva un valor definido (no necesariamente verdadero).
El valor asociado con una producción es el valor retornado por
la acción, o bien el valor asociado con la variable $return
(si aparece en la acción)
o con el item asociado con el último símbolo que casó con éxito.
Es posible indicar una o mas repeticiones de una forma sentencial como en la línea 17. La regla:
seq_2 : character(s)
indica que el lenguaje seq_2
se forma por la repetición de uno
o mas caracteres (character
). El valor
asociado con una pluralidad de este tipo es una referencia a un array
conteniendo los valores individuales de cada uno de los elementos que
la componen, en este caso de los character
.
Es posible introducir un patrón de separación que
indica la forma en la que se deben separar los elementos:
seq_2 : character(s /;/)
lo cual especifica que entre character
y character
el analizador debe saltarse un punto y coma.
Como se ve en la línea 19 es legal usar expresiones regulares
en la parte derecha. La llamada al constructor en la línea 24
deja en $parser
un analizador sintáctico recursivo descendente.
El analizador así construido dispone de un método por cada una de
las variables sintácticas de la gramática. El método asociado con una
variable sintáctica reconoce el lenguaje generado por esa variable sintáctica.
Así, la llamada de la línea 26 al método start
reconoce el lenguaje generado por start
.
Si la variable sintáctica tiene éxito el método
retorna el valor asociado. En caso contrario
se devuelve undef
. Esto hace posible
retornar valores como 0, "0", or ""
.
La siguiente ejecución muestra el orden de recorrido de las producciones.
$ ./firstprodnolongest.pl seq_1: A B C D character: E character: F
¿Que ha ocurrido?
RD es perezoso en la evaluacion de las producciones.
Como la primera regla tiene éxito y es evaluada antes que la segunda,
retorna el control a la aprte derecha de la regla de start
.
A continuación se llama a seq2
.
En este otro ejemplo invertimos el orden de las reglas
de producción de seq_1
:
#!/usr/local/bin/perl5.8.0 -w use strict; use warnings; use Parse::RecDescent; my $grammar = q { start: seq_1 seq_2 seq_1 : 'A' 'B' 'C' 'D' 'E' 'F' { print "seq_1: " . join (" ", @item[1..$#item]) . "\n" } | 'A' 'B' 'C' 'D' { print "seq_1: " . join (" ", @item[1..$#item]) . "\n" } seq_2 : character(s) character: /\w/ { print "character: $item[1]\n" } }; my $parser=Parse::RecDescent->new($grammar); $parser->start("A B C D E F");La ejecución resultante da lugar al éxito de la primera regla, que absorbe toda la entrada:
$ ./firstprodnolongest2.pl seq_1: A B C D E F