Sei sulla pagina 1di 18

Tecnolgico Nacional de Mxico

Instituto Tecnolgico de Pachuca


Ingeniera en Sistemas Computacionales
Materia: Lenguaje Y Autmatas I
Alumno: Miguel Castillo Lpez
No. De control: 14200855
Unidad 6: Investigacin sobre el generador de
analizador sintctico YACC y JavaCC

GENERADOR DE ANALIZADOR SINTCTICO YACC

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
visn, 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;
VERSIONES

Versin Yacc de AT&T


ML-Yacc, una versin de yacc para el lenguaje Standard ML.
Yecc, una versin de yacc para Erlang.
MODO DE USO

Construccin de un traductor usando Yacc:

Partes de las que consta un programa fuente en Yacc:

{declaraciones}
%%
{reglas}
%%
{rutinas de apoyo en C}
-Declaraciones
1) Declaraciones ordinarias en C, delimitadas por %{ y %}.
2) Declaraciones de los componentes lxicos de la gramtica (esto se explica
ms adelante).
Podra estar vaca
-Reglas de traduccin
Cada una de ellas consta de una produccin de la gramtica y la accin semntica
asociada.
Es decir,
<lado izquierdo> <alt 1> | <alt 2> | ... | <alt n>
pasara a ser en Yacc:
<lado izquierdo> : <alt 1> {accin semntica 1}
| <alt 2> {accin semntica 2}
...
| <alt n> {accin semntica n}
;
Un carcter simple entre comillas c se considera como el smbolo terminal
c.
Las cadenas sin comillas de letras y dgitos no declaradas como
componentes lxicos se consideran no terminales.
El primer lado izquierdo se considera como smbolo inicial por defecto, o
bien se declara : %start smbolo
Una accin semntica es una secuencia de proposiciones en C, dnde $$
se refiere al valor del atributo asociado con el no terminal del lado izquierdo,
mientras que $i se refiere al valor asociado con el i-simo smbolo
gramatical del lado derecho. Se ejecuta siempre que se reduzca por la
produccin asociada. Por defecto es {$$=$1;}.
Una accin semntica no tiene por qu venir al final de su regla. Yacc
permite que una accin sea escrita en mitad de una regla. Esta regla
devuelve un valor, accesible de forma normal por las acciones que estn a

su derecha, que pueden acceder a los valores devueltos por los smbolos a
su izquierda
Ejemplo: A:B
{$$=1;}
C
{x=$2; y=$3;}
El efecto es poner x a 1 e y al valor devuelto por C.
Las acciones que no terminan una regla son manejadas por Yacc como si
fueran un nuevo nombre de no-terminal, con una nueva regla para l con el
String vaco en su parte derecha, y, como accin de esa regla, ella misma.
Es decir, el ejemplo anterior lo maneja como si se hubiera escrito as:
$ACT : /* empty */
{$$=1;};
A : B $ACT C
{x=$2; y=$3;};
NOTA: Puede haber conflictos cuando ocurre una accin interior en una
regla antes de que el parser pueda estar seguro de qu regla est siendo
reducida.
En muchas aplicaciones, la salida no viene dada directamente con las
acciones; en su lugar, una estructura de datos, tal como un rbol de
anlisis, se construye en memoria y se aplican transformaciones en l antes
de que la salida sea generada.
Los rboles de anlisis son particularmente fciles de construir, si se tienen
rutinas para realizar y mantener la estructura de rbol deseada.
Ejemplo.- Tenemos una funcin C que se llama nodo, de forma que
nodo(L,n1,n2)
crea un nodo con etiqueta L y descendientes n1 y n2, y devuelve el ndice
del nuevo nodo.
El rbol de anlisis podra ser realizado suministrando acciones en la
especificacin como
expr : expr '+' expr
{$$=nodo('+',$1,$3);}
Pueden definirse tambin otras variables para ser usadas por las acciones.
Tanto las declaraciones como las definiciones deben aparecer en la seccin
de declaraciones, entre %{ y %}. Tienen mbito global.
Deben evitarse los nombres de variables que empiecen por yy, pues los
nombres de variables internas de Yacc comienzan de esta forma todos.

EJEMPLOS
Mini calculadora
A continuacin, vamos a analizar un ejemplo sencillo de una verdadera
especificacin de yacc, que es la gramtica para una calculadora sencilla que
permite hacer operaciones como suma, resta, multiplicacin, divisin y exponente.
%{
#include <math.h>
%}
%union{
double dval;
}
%token
%token
%token
%token

<dval> NUMBER
PLUS MINUS TIMES DIVIDE POWER
LEFT_PARENTHESIS
RIGHT_PARENTHESIS
END

%left PLUS MINUS


%left TIMES DIVIDE
%left NEG
%right POWER
%type <dval> Expression
%start Input
%%
Input: Line
| Input Line
;
Line: END
| Expression END
;
Expression: NUMBER

{ printf("Result: %f\n",$1); }
{ $$=$1; }

| Expression PLUS Expression { $$=$1+$3; }


| Expression MINUS Expression { $$=$1-$3; }

| Expression TIMES Expression { $$=$1*$3; }


| Expression DIVIDE Expression { $$=$1/$3; }
| MINUS Expression %prec NEG { $$=-$2; }
| Expression POWER Expression { $$=pow($1,$3); }
| LEFT_PARENTHESIS Expression RIGHT_PARENTHESIS { $$=$2; }
;
%%
int yyerror(char *s) {
printf("%s\n",s);
}
int main(void) {
yyparse();
}
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 union 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 union 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
mas 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 que tipo es cada token devuelto por
yylex(), se usan las definiciones %token y %type.
%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]
Donde todo lo que esta entre [ y ] es opcional.
<miembro_de_union> : Indica el miembro al que sern mapeados los tokens en la
union yylval dentro de lex.
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
%token
%token
%token

<dval> NUMBER
PLUS MINUS TIMES DIVIDE POWER
LEFT_PARENTHESIS
RIGHT_PARENTHESIS
END

.
.
.
%type <dval> Expresin
La primera lnea indica que el token NUMERO ser del tipo de miembro de dval,
es decir, un doubl.
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 ultima lnea definimos el tipo de dato que usara nuestro no terminal
Expresin.

%left y %right
El siguiente paso, es definir el tipo de precedencia de nuestros tokens operadores,
en este punto tenemos dos factores, la precedencia por si misma, y la agrupacin
de los operadores.
Precedencia
La precedencia es asignada en orden inverso al que aparecen, es decir, el ultimo
operador declarado, tiene mayor precedencia que el anterior y as sucesivamente.
Asociatividad
%left y %right indican si el operador se agrupa a la derecha o a la izquierda, por
ejemplo, en el caso de POWER (Exponente) debe asociarse a la derecha, por que
buscamos que se resuelva de ese modo, de derecha a izquierda, por ejemplo :
Buscamos que
4^3^5^2^9
sea evaluado as :
4^(3^(5^(2^9)))
Por lo contrario, las sumas y restas queremos resolverlas de izquierda a derecha:
Buscamos que
4-3+5+2-9
sea evaluado as :
(((4-3)+5)+2)-9
Usar este tipo de declaraciones es importante para disminuir la posibilidad de
ambigedades en el lenguaje generado.
%start
En algunos casos es conveniente indicarle a yacc cual es el smbolo (no terminal)
inicial a la hora de hacer el parseo, es decir, el smbolo que se trata de reducir, si
esta opcin no es especificada, yacc toma al primer smbolo de la seccin de
reglas como smbolo inicial.
En nuestro ejemplo, se presentan ambos casos, nuestro smbolo inicial "Input" se
encuentra al inicio del archivo y tambin esta declarado como smbolo inicial.
%start Input
Reglas

En esta parte finalmente llegamos a la definicin de la gramtica, ac podemos


observar que cada smbolo se define con su nombre, seguido de dos puntos ":"
seguidos de varios smbolos que conformaran su composicin gramatical que en
caso de tener varias opciones, son separados por "|" (or) indicando que se tienen
varias opciones para reducir ese smbolo y para terminar cada regla, un ";".
Ejemplo :
Si tomamos la gramtica que definimos al principio de esta seccin :
<Expresion>
Numero + <Expresion>
Numero - <Expresion>
Numero
Y la transformamos a una regla de yacc, se vera como esto:
Expresion: NUMERO '+' Expresion
{$$ = $1 + $3;}
| NUMERO '-' Expresion
{$$ = $1 - $3;}
| NUMERO
{$$ = $1;}
;
en el ejemplo ya transformado a una regla gramatical de yacc, podemos ver que
ya se especifica que hacer con los smbolos de la gramtica una vez que son
resueltos en la parte de cdigo de C. En este ejemplo, Expresion es el smbolo no
terminal que se esta definiendo de manera recursiva, el valor que tomara una vez
resuelto es el valor asignado a la variable $$, que traducida a C es una variable
mapeada al smbolo no terminal, $1, $2 y $3 son variables que son mapeadas al
valor de los smbolos de cada lnea de cada regla, estas son numeradas de
izquierda a derecha.
Ejemplo :
En este segmento de regla :
Expresion: NUMERO '+' Expresion
Expresion equivale a $$
NUMERO equivale a $1
'+' equivale a $2
y
Expresion (la parte recursiva) equivale a $3
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 esta en
un contexto unario, que a la mayora de los operadores excepto el POWER
(exponente) :
.

.
.
| MINUS Expression %prec NEG
.
.
.
Reduccin

{ $$=-$2; }

Yacc reduce sus reglas generando un parse tree (no literalmente), y va


resolviendo cada regla completa tan pronto como puede, lo cual nos trae un
detalle de diseo de gramaticas en yacc, y es la diferencia entre especificar la
recursividad por la derecha o por la izquierda, para expresiones muy sencillas que
generen un parse tree pequeo no hay ningn problema pero para casos donde la
reduccin es compleja, puede desbordar la pila ya que cuando la recursin es
derecha, para resolverla, tiene que guardar los datos de la izquierda, y si estos
son demasiados, no puede manejarlos.
Por lo contrario, cuando la recursin es izquierda, no tiene que guardar datos que
no va a utilizar por que recorre el rbol de izquierda a derecha y resuelve las
reglas tan pronto como puede.
En el ejemplo anterior tenemos la recursin por la derecha, un anlogo recurrente
por la izquierda seri como este :
Expresion: Expresion '+' NUMERO
{$$ = $1 + $3;}
| Expresion '-' NUMERO
{$$ = $1 - $3;}
| NUMERO
{$$ = $1;}
;
Especificacin de Lex para el ejemplo
Para que el Ejemplo pueda funcionar, al igual que cualquier otro programa en
yacc, necesita un tokenizer, y a continuacin tenemos su tokenizer
correspondiente escrito en lex.
%{
#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);
%%
Acerca de la seccin de definiciones de este lexer, lo nico relevante que
podemos mencionar es la lnea de C que dice :
#include "y.tab.h"
esta lnea incluye al archivo y.tab.h que contiene algunas de las definiciones de
yacc que lex necesita para poder interactuar con el, entre las mas importantes se
encuentran definidas todas las etiquetas de los tokens, como PLUS, MINUS,
NUMBER, etctera. Estas constantes son los valores que yylex() regresara a
yyparse() (la funcin del parser de yacc) para identificar el tipo de token que recin
se ha ledo.
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 como %left/%rigth en la especificacin yacc.
Para compilar y correr este ejemplo en sistemas UNIX o similares :
$ lex ejem1.1.l
$ yacc -d ejem1.1.y
$ cc -o ejem1.1 lex.yy.c y.tab.c -ly -ll -lm
$ ejem1.1
25*5-5
Result: 120.000000
5^2*2
Result: 50.000000
5^(2*2)
Result: 625.000000
bye
Terminando programa
$
Subrutinas

En esta ultima seccin, es posible reimplementar, siguiendo la misma idea de lex,


algunas funciones que pueden ser tiles en algn momento dado o declarar
nuevas funciones para usar dentro de nuestro cdigo o nuestras reglas, no hay
mucho que reimplementat a este nivel (yacc) a menos que sea con propsitos
realmente especficos. Las funciones mas comnmente implementadas son main()
e yyerror(), la primera se usa para personalizar el programa con mensajes antes o
despus del parser, o para llamarlo varias veces en el cdigo y la segunda la
ocupa yyparse() cada vez ue encuentra un error de sintaxis, en este ejemplo, se
incluyen ambas con su contenido mnimo.
GENERADOR DE ANALIZADOR SINTCTICO JAVACC
JavaCC (Java Compiler Compiler) es un generador de analizadores sintcticos de
cdigo abierto para el lenguaje de programacin Java. 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). El
constructor de rboles que lo acompaa, JJTree, construye rboles de abajo hacia
arriba (bottom-up).
JavaCC est licenciado bajo una licencia BSD.
En 1996, Sun Microsystems liber un parser llamado Jack. Los desarrolladores
responsables de Jack crearon su propia compaa llamada Metamata y cambiaron
el nombre Jack a JavaCC. Metamata se convirti en WebGain. Despus de que
WebGain finalizara sus operaciones, JavaCC se traslad a su ubicacin actual.
VERSIONES
todas las modificaciones que han tenido lugar desde
LA LIBERACIN DE LA VERSIN 0.5 DE OCTUBRE DE 1996 .
Durante la transicin de 0,5 a 6,0 , se han producido
LAS SIGUIENTES VERSIONES INTERMEDIOS :
0.6. - 10
0.6. - 9
0.6. - 8
0.6 ( Beta1 )
0.6 ( Beta 2 )
0.6
0.6.1
0.7pre1
0.7pre2
0.7pre3
0.7pre4
0.7pre5
0.7pre6

0.7pre7
0.7
0.7.1
0.8pre1
0.8pre2
1.0
1.2
2.0
2.1
3.0
3.1
3.2
4.0
4.1
4.2
6.0
MODO DE USO
ESTRUCTURA GENERAL DE UN PROGRAMA EN JAVACC
Cualquier cdigo escrito para JavaCC obedece a la siguiente estructura:

El fichero de entrada comienza con una lista de opciones, la cual es opcional.


Seguidamente nos encontramos la unidad de compilacin java la cual se
encuentra encerrada entre PARSER_BEGIN(nombre) y PARSER_END(nombre).
Despus nos encontramos con una lista de reglas de produccin (cada una de
estas partes son claramente distinguibles en el ejemplo).
El nombre que sigue a PARSER_BEGIN y a PARSER_END debe ser el mismo, y
ste identifica al analizador sintctico que va a ser generado con posterioridad.
Por ejemplo si nuestro nombre es Gramtica, se generan los siguientes archivos:
Gramatica.java: El analizador sintctico.
GramaticaTokenManager.java: gestor de tokens para el analizador lxico.
GramaticaConstants.java: El analizador lxico no maneja los tokens por el
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.
Adems de stos, tambin se generan otros ficheros (Token.java y
ParseException.java, ASCII_CharStream.java, TokenMgrError.java), pero estos

ficheros son los mismos para cualquier gramtica y pueden conservarse de una
para otra.

Entre PARSER_BEGIN y PARSER_END, se encuentra una unidad de compilacin


Java (el contenido completo de un archivo escrito en Java). sta puede ser
cualquier cdigo Java siempre que contenga una declaracin de clase cuyo
nombre sea el mismo que el analizador sintctico que va a ser generado.
(Gramtica en el ejemplo anterior). Esta parte del archivo de gramtica tiene esta
forma:

JavaCC no realiza un chequeo minucioso de la unidad de compilacin por lo que


es posible que un fichero de gramtica pase el test de JavaCC y genere los
archivos correspondientes y luego produzca errores al ser compilados.
El archivo correspondiente al analizador sintctico que es generado por JavaCC
contiene la unidad de compilacin Java en su totalidad, adems del cdigo
generado por el analizador sintctico, el cual se incluye al final de su clase. En el
caso del ejemplo la siguiente forma:

El cdigo del analizador sintctico incluye la declaracin de un mtodo pblico


correspondiente a cada no terminal de la gramtica. La realizacin del anlisis
sintctico a partir de un no terminal se consigue invocando al mtodo
correspondiente a ese no terminal.
EJEMPLOS
Construir un analizador lxico con JavaCC.
En la programacin, un analizador lxico es la parte de un compilador o analizador
(parser) que trata de descomponer el lenguaje proporcionado como entrada en
tokens.
Un token es la unidad mnima con significado. Tokens habituales son los
identificadores, enteros, flotantes, constantes, etc.
Para el desarrollo, utilizaremos una herramienta increblemente til, JavaCC.
Mediante expresiones regulares podemos definir cmodamente los tokens de
nuestro lenguaje.
Caso prctico, construir analizador lxico para un determinado lenguaje de
programacin:
Las especificaciones de nuestro lenguaje son:

Tokens:

Constantes:
Cadenas: Caracteres entrecomillados, ejemplo: "cadena"
Enteros: Nmeros positivos, ejemplo: 234 o 0
Lgicas: TRUE y FALSE
Identificadores: Todos los identificadores son una secuencia de letras (a-zA-Z) y
nmeros que obligatoriamente deben comenzar con una letra (y no un
nmero). Los identificadores que se refieran a cadenas terminarn en "$".

Palabras reservadas: En el lenguaje hay palabras reservadas que darn vida al


lenguaje, estas sern: "not, if, end, let, call, then, case, else, input, print, select
y static".
Adems el lenguaje ser "case insensitive" o lo que es lo mismo, un identificador
llamado "id" apuntar al mismo lugar que "Id", "iD" o "ID". De igual forma ser
para las palabras reservadas.
Cdigo JavaCC (exparser.jj):
options {
IGNORE_CASE = true;
}
PARSER_BEGIN(ExampleParser)
public class ExampleParser {
//Ejecucin del analizador
public static void main ( String args [ ] ) {
//Inicializacin del analizador
ExampleParser parser;
if(args.length == 0){
System.out.println ("ExampleParser: Leyendo de la entrada estandar ...");
parser = new ExampleParser(System.in);
}
else if(args.length == 1){
System.out.println ("ExampleParser: Leyendo de fichero " + args[0] + " ..." );
try {
parser = new ExampleParser(new java.io.FileInputStream(args[0]));
}
catch(java.io.FileNotFoundException e) {
System.out.println ("ExampleParser: El fichero " + args[0] + " no ha sido
encontrado.");
return;
}
}
else {
System.out.println ("ExampleParser: Debes utilizarlo de una de las
siguientes formas:");
System.out.println ("
java ExampleParser < fichero");
System.out.println ("Or");
System.out.println ("
java ExampleParser fichero");
return ;
}
try {

compilador.Start();
System.out.println ("ExampleParser: La entrada ha sido leida con xito.");
}
catch(ParseException e){
System.out.println ("ExampleParser: Ha ocurrido un error durante el
anlisis.");
System.out.println (e.getMessage());
}
catch(TokenMgrError e){
System.out.println ("ExampleParser: Ha ocurrido un error.");
System.out.println (e.getMessage());
}
}
}
PARSER_END(ExampleParser)
//ESTRUCTURAS Y CARACTERES DE ESCAPE
SKIP : {
""
| "\t"
| "\n"
| "\r"
| <"rem" (~["\n","\r"])* ("\n" | "\r" | "\r\n")>
}
//TOKENS ESTTICOS
TOKEN : {
<INTEGER_CONSTANT: (<DIGIT>)+>
| <LOGIC_CONSTANT: "true" | "false" | "-1">
| <STRING_CONSTANT: "\"" ( ~["\"","\\","\n","\r"] | "\\" ( ["n","t","b","r","f","\\","\'","\""] |
( ["\n","\r"] | "\r\n")))* "\"">
| <#DIGIT: ["0"-"9"]>
}
//PALABRAS RESERVADAS
TOKEN : {
<NOT: "not">
| <IF: "if">
| <END: "end">
| <SUB: "sub">
| <LET: "let">
| <CALL: "call">
| <THEN: "then">
| <CASE: "case">
| <ELSE: "else">
| <INPUT: "input">
| <PRINT: "print">
| <SELECT: "select">
| <STATIC: "static">

}
//TOKEN IDENTIFICADOR
TOKEN : {
<IDENTIFIER: <LETTER>(<LETTER>|<DIGIT>)*(["$"])?>
| <#LETTER: (["a"-"z","A"-"Z"])>
}
//UNIDAD PRINCIPAL
void Start () : {}
{
(
INTEGER_CONSTANT | STRING_CONSTANT | LOGIC_CONSTANT |
NOT | IF | END | SUB | LET | CALL | THEN | CASE | ELSE | INPUT | PRINT |
SELECT | STATIC |
IDENTIFIER
)*
<EOF>
}
Para compilar este fichero, se debe hacer con "javacc" y posteriormente con
"javac":
javacc exparser.jj
javac *.java
Para ejecutar el programa:
java ExampleParser fichero
CONCLUSIN
El analizador sintctico ya se a YACC o JavaCC recibe los tokens o palabras
generadas por el analizador lxico y determina si la secuencia u orden que
presentan es correcta y permitida por el lenguaje. La salida que generar ser el
rbol sintctico. Gracias a estas excelentes herramientas, nosotros como
programadores no tenemos que reinventar la rueda cuando de crear un analizador
sintctico se trate, las numerosas opciones que nos brindan los generadores
hacen que esta tarea sea mas fcil.
REFERENCIAS
http://es.wikipedia.org/wiki/Yacc
http://www.lcc.uma.es/~galvez/theme/IntroduccionAJavaCC.pdf
http://kiwwito.com/construir-un-analizador-lexico-con-javacc

Potrebbero piacerti anche