next up previous contents index PLPL moodlepserratamodulosperlmonksperldocapuntes LHPgoogleetsiiullpcgull
Sig: Orden de Recorrido del Sup: RecDescent Ant: RecDescent Err: Si hallas una errata ...

Introducción

Parse::RecDescent es un módulo, escrito por Damian Conway, que permite construir analizadores sintácticos descendentes con vuelta atrás. No forma parte de la distribución estándar de Perl, por lo que es necesario descargarlo desde CPAN (consulte la sección [*] [4] para una descripción de como hacerlo). En lo que sigue, y por brevedad, nos referiremos a el como RD.

 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


next up previous contents index PLPL moodlepserratamodulosperlmonksperldocapuntes LHPgoogleetsiiullpcgull
Sig: Orden de Recorrido del Sup: RecDescent Ant: RecDescent Err: Si hallas una errata ...
Casiano Rodríguez León
2013-03-05