Documenti di Didattica
Documenti di Professioni
Documenti di Cultura
Yacc es un programa para generar analizadores sintcticos. Las siglas del nombre
significan Yet Another Compiler-Compiler, es decir, "Otro generador de
compiladores ms". Genera un analizador sintctico (la parte de un compilador
que comprueba que la estructura del cdigo fuente se ajusta a la especificacin
sintctica del lenguaje) basado en una gramtica analtica escrita en una notacin
similar a la BNF. Yacc genera el cdigo para el analizador sintctico en el
Lenguaje de programacin C.
Fue desarrollado por Stephen C. Johnson en AT&T para el sistema operativo Unix.
Despus se escribieron programas compatibles, por ejemplo Berkeley Yacc, GNU
bison, MKS yacc y Abraxas yacc (una versin actualizada de la versin original de
AT&T que tambin es software libre como parte del proyecto de OpenSolaris de
Sun). Cada una ofrece mejoras leves y caractersticas adicionales sobre el Yacc
original, pero el concepto ha seguido siendo igual. Yacc tambin se ha reescrito
para otros lenguajes, incluyendo Ratfor, EFL, ML, Ada, Java, y Limbo.
Puesto que el analizador sintctico generado por Yacc requiere un analizador
lxico, se utiliza a menudo conjuntamente con un generador de analizador lxico,
en la mayora de los casos lex o Flex, alternativa del software libre. El estndar de
IEEE POSIX P1003.2 define la funcionalidad y los requisitos a Lex y Yacc.
La versin Yacc de AT&T se convirti en software libre; el cdigo fuente est
disponible con las distribuciones estndares del Plan 9 y de OpenSolaris.
Es correcto decir que yacc es una herramienta que sirve para generar un
programa, capaz de analizar gramaticalmente una entrada dada por lex, a partir de
una especificacin. Esta especificacin, debe contener los tokens reconocidos y
Jose Alfredo Jimenez Cornejo
Romeo H. Vazquez Velazquez
03/06/2015
los tipos de datos de los mismos si es que se ocupan para realizar operaciones
sobre ellos, y una especificacin de gramtica en un formato similar a BNF
(Backus Naus Form), que va desde el smbolo no terminal ms general a cada una
de las opciones terminales.
Ejemplo:
<Expresion>
Numero + <Expresion>
Numero - <Expresion>
Numero
En el ejemplo podemos ver que <Expresion> es un smbolo no terminal que est
compuesto por un "Numero" terminal seguido de un smbolo '+' o '-' terminales
seguido por un <Expresion> no terminal, que a su vez puede ser otro nmero u
otra expresin ms compleja.
Es importante notar que esta especificacin es recursiva sobre <Expresion> pero
no es ambigua, es decir, siempre se llegara a un terminal.
Una especificacin yacc se divide en tres secciones diferentes de manera similar a
lex, la de definiciones, la de reglas, y la de subrutinas, que van igualmente
separadas por un '%%', mismas que pueden incluir cdigo de C encerrado entre
un %{ y un %}.
03/06/2015
}
%token
%token
%token
%token
<dval> NUMBER
PLUS MINUS TIMES DIVIDE POWER
LEFT_PARENTHESIS
RIGHT_PARENTHESIS
END
{ printf("Result: %f\n",$1); }
{ $$=$1; }
03/06/2015
Definiciones
En esta primera seccin, al igual que en lex, incluimos las libreras que usaremos
en el programa, definiciones de los tokens, tipos de datos y precedencia de la
gramtica.
%union
Esta definicin, se traduce a una unin de C que a su vez dar el tipo de dato a
una variable global de nombre yylval que ser de donde yacc tomara los datos a
procesar, en la unin se definen miembros cuyos correspondientes tipos de datos
sern usados para dar el tipo de dato a los tokens como se explicara en la
siguiente seccin. %union se traduce de la siguiente forma:
En yacc :
%union{
double dval;
}
En C :
typedef union
{
double dval;
} YYSTYPE;
Con esta definicin, yacc declara algunas uniones de este tipo, de las cuales la
ms importante es:
YYSTYPE yylval;
que ser usada en la especificacin de lex, del mismo programa para asignarle
valor a los tokens que yacc usara para realizar operaciones. Esta estructura puede
llegar a ser muy compleja, y para saber de qu tipo es cada token devuelto por
yylex(), se usan las definiciones %token y %type.
Jose Alfredo Jimenez Cornejo
Romeo H. Vazquez Velazquez
03/06/2015
%token y %type
%token sirve para definir los tokens que hay, y si es necesario, el tipo de dato que
usan, todos los tokens son tomados como smbolos terminales, lo cual veremos
mejor reflejado en la seccin de reglas, estos tambin tienen el objetivo de servir
como etiquetas que yylex() regresa a yacc para identificar el token que se ha ledo
recientemente.
Su uso es como sigue:
%token [<miembro_de_union>] ETIQUETA1 [ETIQUETA2 ... ETIQUETAn]
ETIQUETAS: Estos son los nombres con los que se identificaran los tokens
mismos, que sern traducidos en C como nmeros en instrucciones #define del
preprocesador de C.
%type es anlogo a %token, solo que este define el tipo de dato para smbolos no
terminales de nuestra gramtica, la nica diferencia es que el tipo de dato a usar
es obligatorio.
En nuestro ejemplo:
%token LEFT_PARENTHESIS
RIGHT_PARENTHESIS
%token END
%type <dval> Expression
Jose Alfredo Jimenez Cornejo
Romeo H. Vazquez Velazquez
03/06/2015
La primera lnea indica que el token NUMERO ser del tipo de miembro de dval,
es decir, un double.
Las siguientes tres lneas, son para definir algunos tokens mas que sern usados
en la gramtica, pero no necesitan un tipo de dato ni un miembro en yylval
asociado.
En la ltima lnea definimos el tipo de dato que usara nuestro no terminal
Expression.
%left y %right
Precedencia
La precedencia es asignada en orden inverso al que aparecen, es decir, el ltimo
operador declarado, tiene mayor precedencia que el anterior y as sucesivamente.
Asociatividad
Buscamos que
4^3^5^2^9
Sea evaluado as :
4^(3^(5^(2^9)))
03/06/2015
Buscamos que
4-3+5+2-9
Sea evaluado as:
(((4-3)+5)+2)-9
Reglas
Ejemplo:
Si tomamos la gramtica que definimos al principio de esta seccin:
03/06/2015
<Expresion>
Numero + <Expresion>
Numero - <Expresion>
Numero
Y la transformamos a una regla de yacc, se vera como esto:
Ejemplo:
Expresion equivale a $$
NUMERO equivale a $1
'+' equivale a $2
y
Expresion (la parte recursiva) equivale a $3
03/06/2015
Todo esto claro, en la parte de acciones en C para cada lnea de la regla en yacc.
En el ejemplo tambin podemos encontrar el uso de %prec que sirve para cambiar
la precedencia de un operador dependiendo del contexto en el ejemplo, le
estamos dando una ms alta precedencia a la operacin "menos" cuando est en
un contexto unario, que a la mayora de los operadores excepto el POWER
(exponente):
.
.
.
| MINUS Expression %prec NEG
{ $$=-$2; }
.
.
Reduccin
03/06/2015
10
Para que el Ejemplo1.1 pueda funcionar, al igual que cualquier otro programa en
yacc,
necesita
un
tokenizer,
continuacin
tenemos
su
tokenizer
%{
#include "y.tab.h"
#include <stdlib.h>
#include <stdio.h>
%}
white
digit
integer
[ \t]+
[0-9]
{digit}+
%%
{white}
{ /* Ignoramos espacios en blanco */ }
"exit"|"quit"|"bye" {printf("Terminando programa\n");exit(0);}
{integer}
{
yylval.dval=atof(yytext);
return(NUMBER);
}
"+"
return(PLUS);
"-"
return(MINUS);
"*"
return(TIMES);
"/"
return(DIVIDE);
"^"
return(POWER);
"("
return(LEFT_PARENTHESIS);
")"
return(RIGHT_PARENTHESIS);
"\n" return(END);
%%
03/06/2015
11
En la seccin de reglas, en la parte del cdigo, podemos ver como al final de cada
regla, se hace un return especificando la etiqueta que fue declarada como %token
o cmo %left/%rigth en la especificacin yacc.
03/06/2015
12
03/06/2015
13
03/06/2015
14
03/06/2015
15
Opciones_javacc
PARSER_BEGIN (<IDENTIFICADOR>)
Unidad de compilacin java
PARSER_END (<IDENTIFICADOR>)
(reglas de produccion)*
<EOF>
Nombre que especificamos nosotros en el cdigo, sino que a cada uno de ellos le
asigna un nmero. En este archivo se encuentra cada uno de los tokens junto con
el nmero que le ha sido asignado por el analizador lxico.
OPCIONES
1
La seccin options, si est presente, comienza con la palabra reservada options
seguida de una lista de una o ms opciones entre llaves. La misma opcin no
debe establecerse ms de una vez. En el ejemplo 2.1. Slo se ha usado una de
las opciones
(
LOOKAHEAD=1).
03/06/2015
16
03/06/2015
17
03/06/2015
18
REGLAS DE PRODUCCIN
Las reglas de produccin JAVACODE son una forma de escribir cdigo Java para
una regla de produccin en lugar de las tpicas expansiones EBNF. Esto suele ser
til cuando tenemos la necesidad de reconocer algo que no es de contexto libre o
algo para lo cual es difcil escribir una gramtica que lo reconozca. Para ello nos
serviremos de los mtodos que el propio parser nos proporciona con tal fin, a
saber:
getToken(),
jj_concume_token(), getNextToken(),etc. A continuacin se muestra un ejemplo de
uso de JAVACODE. En el ejemplo 2.3., el no terminal skipToMatchingBrace
consume tokens de la entrada hasta que encuentra una }.
JAVACODE
void skipToMatchingBrace(){
Token tok;
int nesting=1;
while(true){
tok=getToken(1);
if(tok.kind==LBRACE)
nesting++;
if(tok.kind==RBRACE){
nesting--;
if(nesting==0)
Jose Alfredo Jimenez Cornejo
Romeo H. Vazquez Velazquez
03/06/2015
19
break;
}
tok=getNextToken();
}
}
Cuando usamos este tipo de reglas de produccin tenemos que tener muchsimo
cuidado ya que es muy fcil especificar bastante ms de lo que realmente se
quiere.
Este tipo de reglas son problemticas cuando las utilizamos en lugares donde el
analizador sintctico tiene que hacer una eleccin. Supongamos que la regla de
produccin anterior es referenciada desde sta:
Reglas de produccin BNF
Las reglas de produccin BNF son la forma estndar de especificar gramticas en
JavaCC. Sobre ella diferenciaremos cada uno de los puntos que a continuacin se
exponen:
void unario() :
{}
{
}
<MENOS> elemento()
elemento()
Cada regla de produccin BNF consta de una parte izquierda la cual consiste en la
especificacin de un no terminal. Las reglas de produccin BNF definen este no
terminal en funcin de expansiones BNF que se encuentran en la parte derecha.
El no terminal se escribe exactamente de la misma forma en que se declara un
mtodo en
Java, (en el ejemplo 2.6. void unario():) . Ya que cada no terminal se traduce a
un mtodo en el analizador sintctico, la forma de escribir el no terminal hace que
esta asociacin sea obvia. El nombre del no terminal es el nombre del mtodo, y
Jose Alfredo Jimenez Cornejo
Romeo H. Vazquez Velazquez
03/06/2015
20
los parmetros y el valor de retorno son los medios para pasar valores arriba y
abajo dentro del rbol sintctico. parse tree- (Esto se mostrar ms adelante).
La parte derecha de una regla de produccin BNF tiene dos partes: La primera
parte es un conjunto de declaraciones y cdigo Java ( bloque Java). Este cdigo
es generado al principio del mtodo relacionado con el no terminal. Por lo tanto,
cada vez que el no terminal es usado en el proceso de anlisis, este cdigo es
ejecutado.
La segunda parte est formada por las expansiones BNF.
bnf_production::= java_return_type java_identifier ( java_parameter_list ) :
java_block
{ expansion_choices }
Reglas de produccin mediante expresiones regulares
Las expresiones regulares se usan para definir entidades lxicas las cuales van a
ser procesadas por el token manager. Una regla de produccin de este tipo
comienza con la especificacin de los estados lxicos a los cuales es aplicable.
regular_expr_production::= [lista_de_estados_lexicos]
regexpr_kind[ [ IGNORE CASE ] ] :
{ regexpr_spec ( | regexpr_spec )* }
Existe un estado lxico estndar llamado DEFAULT. Si la lista de estados lxicos
se omite, la expresin regular se aplica al estado DEFAULT.
lista_de_estados_lexicos::= < * >
| < identificador_java (, identificador_java)* >
La lista de estados lxicos describe el conjunto de estados lxicos, para los cuales
la expresin regular es aplicable. Si sta es < * >, entonces la expresin
Jose Alfredo Jimenez Cornejo
Romeo H. Vazquez Velazquez
03/06/2015
21
regular se puede aplicar a todos los estados lxicos. En otro caso se aplicar a
todos los estados lxicos cuyo identificador se encuentre en la lista de
identificadores del interior de los parntesis angulares.
A continuacin se especifica el tipo de regla de produccin. Existen cuatro tipos
basadas en expresiones regulares:
o TOKEN: La expresin regular de esta regla de produccin describe tokens
de la gramtica. El token manager crea un objeto de tipo Token para cada
una de las entradas que se ajusten a dicha expresin regular, y luego lo
retorna al analizador sintctico.
o SPECIAL_TOKEN: La expresin regular de esta regla de produccin
describe tokens especiales.
del tipo de
VERSIONES:
03/06/2015
22
Updated
Size
Title + Description + Tags
Actions
Date
beta
contrib
oldversions
releases
JavaCC releases
Tags: --
javacc-5.0.tar.gz
461.6
KB
627.3
KB
791.1
KB
1.1 MB
726.7
KB
1.2 MB
javacc-5.0.tar.gz
Tags: -javacc-5.0.zip
javacc-5.0.zip
Tags: -javacc-5.0src.tar.gz
javacc-5.0src.tar.gz
Tags: -javacc-5.0src.zip
javacc-5.0src.zip
Tags: -javacc-6.0.zip
This is the binary distribution of JavaCC 6.0.1 - with
few bug fixes.
Tags: javacc 6.0 c++ code parser lexer 6.0.1
JavacCC-6.0src.zip
JavaCC 6.0 source distribution
Tags: javacc c++ parser lexer genertor
03/06/2015
23
Conclusin
Como hemos visto un generador de analizadores sintcticos es un programa que
toma como su entrada una especificacin de la sintaxis de un lenguaje en alguna
forma, y produce como su salida un procedimiento de anlisis sintctico para ese
lenguaje, tambin sabemos ahora que un generador de analizadores sintcticos
ampliamente utilizado que incorpora el algoritmo de anlisis sintctico LR(1) se
conoce como Yacc, este no es directamente un analizador sino un generador de
analizadores. A partir de un fichero fuente en yacc, se genera un fichero fuente en
C que contiene el analizador sintctico.
Por otra parte el generador de analizadores sintcticos JavaCC integra las
funciones de anlisis lxico y anlisis sintctico en una sola herramienta,
obteniendo a la salida cdigo java a diferencia de lex/yacc cuya salida es cdigo
C.
La principal diferencia con lex/yacc es que los analizadores sintcticos generados
por JavaCC son analizadores sintcticos descendentes de tipo LL(k), mientras que
los analizadores sintcticos generados por yacc son de tipo ascendente LALR.
Otra diferencia bastante importante es que las especificaciones lxicas pueden
estar incluidas dentro de la especificacin de la gramtica.
De manera general JavaCC es similar a Yacc en que genera un parser para una
gramtica presentada en notacin BNF, con la diferencia de que la salida es en
cdigo Java. A diferencia de Yacc, JavaCC genera analizadores descendentes
(top-down), lo que lo limita a la clase de gramticas LL(K) (en particular, la
recursin desde izquierda no se puede usar).
Otra diferencia bastante importante es que las especificaciones lxicas pueden
estar incluidas dentro de la especificacin de la gramtica.
JavaCC es quiz el generador de parsers usado con aplicaciones Java ms
popular.
Referencias:
http://www.lcc.uma.es/~galvez/theme/IntroduccionAJavaCC.pdf
http://www.udb.edu.sv/udb/archivo/guia/informatica-ingenieria/compiladores/2014/ii/guia-5.pdf
http://es.wikipedia.org/wiki/JavaCC
http://es.wikipedia.org/wiki/Yacc
Jose Alfredo Jimenez Cornejo
Romeo H. Vazquez Velazquez
03/06/2015
24