Documente Academic
Documente Profesional
Documente Cultură
JLEX
Jlex no es ms que un generador de un analizador lxico parecido a LEX, el cual toma una
cadena como entrada una cadena de caracteres, y lo convierte en una secuencia de tokens.
CUP
Cup es un generador de analizadores sintcticos LALR en Java el cual recibe de entrada un
archivo con la estructura de la gramtica y su salida es un parser escrito en Java listo para
usarse.
Decid dividir el tutorial en varias secciones para hacer ms fcil el aprendizaje de estas
herramientas.
Directivas JLex
En esta seccon irn las directivas, o especificaciones para que opere JLEX, para obtener la salida
deseada.
%cup
%eofval{
System.out.println("FINARCHIVO");
%eofval}
entero=[0-9]
Id=[a-zA-Z][a-zA-Z0-9]*
%%
/* MANEJO DE LAS PALABRAS RESERVADAS*/
"while"
{imprime("while");
}
"int"
{imprime("int");}
"if" {imprime("if");}
"then" {imprime("then");}
"for"{imprime("for");}
/*expresion regular para un entero, tomando el conjunto definiddo
anteriormente como entero*/
/*un entero 1 o mas veces*/
({entero})+
{imprime("entero"+}
{Id} {imprime("Identificador");}
/*con la siguiente linesa ignoramos los espacios en blanco*/
(" ") {System.out.println("espacio/*con esta ignoramos los saltos de
linea, tabulaciones,*/
[\t\r\n\f] {}
/*error lexico:*/
. {System.out.println("error
}/*error lexico:*/. {System.out.println("error
El cdigo escrito dentro de los corchetes es el el cdigo que queremos que se ejecute cada vez
que el scanner encuentra los tokens a su izquierda. Este cdigo queda sin modificar a la hora de
generar el archivo de salida java
Las variables terminales sern todos los smbolos terminales de la gramtica y las variables NoTerminales sern todas las variables que representaran producciones.
La sintaxis para la declaracin es la siguiente:
<tipo de variable> < tipo de dato > < id de la variable >
Donde <tipo de variable > puede ser Terminal o No terminal
<tipo de dato> puede ser cualquier tipo de dato primitivo de Java o uno creado por nosotros
mismos. Si se no se especifica el tipo de dato Cup lo trabajar como un tipo de dato Symbol.
<id de la variable > aqu se especifica el id de la variable, se puede usar una lista de
identificadores separadas por coma si deseamos variables del mismo tipo.
Gramtica: En esta seccin del archivo es donde escribiremos nuestra gramatica. La gramatica
tiene la siguiente sintaxis :
Como un no terminal puede tener mas de un lado derecho en Cup se utiliza el simbolo |
SIMBOLOS_COMPARAR::=mayor
|menor
|mayor_igual
|menor_igual;
Ya que sabemos como hacer archivos de entrada para Jlex y Cup ahora es hora de hacer que
funcionen en conjunto. Para hacer de mas ilustrativo el ejemplo usaremos una clase externa al
scanner y al parser que nos servir para almacenar informacin de cada token que se esta
leyendo. Llamaremos a esta clase token
class token(){
int posicionX;
int posicionY;
String valor;
public token(String val,int x,int y){
this.valor=val;
this.posicionX=x;
this.posicionY=y;
}
public int getX(){return this.posicionX;}
public int getY(){ return this.posicionY;}
public String getValor(){return this.valor;}
}
Seguiremos con el ejemplo de la expresin condicional , para esto debemos escribir el archivo
jlex para que reconozca las palabras reservadas terminales del lenguaje. El archivo quedara
de la siguiente forma:
import java_cup.runtime.Symbol;
%%
%{
public void imprime(String str){
System.out.println(str+"-"+yychar+"-"+yylinec
%public
%char
%line
%ignorecase
%cup
%full
%type java_cup.runtime.Symbol
%implements java_cup.runtime.Scanner
%eofval{
System.out.println("FINARCHIVO");
return null;
%eofval}
letra=[a-zA-Z]
entero=[0-9]
id=[a-zA-Z][A-Za-z0-9]*
%%
"(" {imprime("Abre Parentesis");
return new Symbol(csym.open_par,new token(yytext(),yychar,yyline));
}
")" {imprime("Cierra Parentesis");
return new Symbol(csym.close_par,new
token(yytext(),yychar,yyline));
"true" {
imprime("true");
return new Symbol(csym.true_,new token(yytext(),yychar,yyline));
}
"false" {
imprime("false");
return new Symbol(csym.false_,new
token(yytext(),yychar,yyline));
}
"<=" {imprime("menor igual");
return new Symbol(csym.menor_igual,new
token(yytext(),yychar,yyline));
}
">=" {imprime("mayor igual");
return new Symbol(csym.mayor_igual,new
token(yytext(),yychar,yyline));
}
"||" {imprime("or");
{}
[\n] {yychar=0;}
" " {}
. {imprime("error: "+yytext());
}
Explicar el fragmento de cdigo que se utiliz al lado derecho:
el return. Como podemos ver se retorna un tipo de dato Symbol, este en su constructor recibe
dos parmetros :
El primero que es un entero que es declarado en la clase sym generada por cup
(Explicar mas adelante)
El segundo que recibe es de tipo Object, esto nos facilita poder enviar cualquier tipo de
dato que deseemos., en este caso fue un tipo token, el que hemos definido al inicio de
esta seccin
.Una vez terminado nuestro archivo jlex es hora de escribir el archivo cup:
action code{:
public void ImprimeValor(String str){
System.out.println("elr del token"+str) ;
}
:}
parser code{:
public void syntax_error(Symbol st){
token t=(token)st.value;
report_error("Error Sintactico:"+ t.getValue()+"- "+t.getX()
+"-"+t.getY(),null);
:}
SIMBOLOS_COMPARAR::=mayor:m{:RESULT=m:}
|menor:m{:RESULT=m:}
|mayor_igual:m{:RESULT=m:}
|menor_igual:m{:RESULT=m:};
|true:t {:RESULT=t;:}
|false:f{:RESULT=t;:};
Llego la hora de explicar cada parte de el archivo cup:
En la seccin action code como expliqu anteriormente se definen las funciones que que
utilizaran cuando se este recorriendo la gramtica, en este caso defin la funcin ImprimeValor
que recibe de parmetro una cadena, lo nico que hace es imprimir el valor de la cadena que
recibe de parmetro.
En la seccin parser code se encuentran los mtodos propios del parser, aqui hice un
override de la funcin syntax_error. Esta funcin nos permite ejecutar una accin cuando el
parser encuentra un error sintctico.
Ahora vamos con las acciones en la gramatica, Cup permite agregar acciones como las
que podemos ver en el ejemplo anterior estas pueden ir en cualquier lugar del lado derecho de
la produccin en este tipo de herramientas se sugiere ponerlas al final para evitar
ambigedades ya que Cup toma la produccin como un smbolo las en la gramtica y al estar
en el medio pueden haber errores de reduccin o de movimiento del parser. La sintaxis para
para las acciones es: {: /*acciones*/ :} donde acciones puede ser cualquier sentencia
de cdigo.