Está en la página 1de 13

T to l u ria

J x le

Y Java

Cup

Tutorial Jlex y Java Cup


http://open fecks.w ordpress. com / por Josu Ortega

m/

T to l u ria

J x le

Y Java

Cup
JLex y Java CUP

JLEX Jlex no es ms que un gen erador de un analizador lxico parecido a LEX, el cual toma una cadena como entrada una cadena de car acter es, y lo convie rte en una secuencia de tokens. CUP Cup es un gen er ador de analizad or es sintcticos LALR en Java el cual recibe de en trada un archivo con la estruct ura de la gr am tica y su salida es un parser es crito en Java listo par a usa rse. Decid dividir el tutorial en varias secciones para hacer ms fcil el aprendi zaje de estas herram nt as. ie IN EX D E ructura de un Archivo Jlex st E ructura de un archivo Cup st Integracin Jlex con Cup Compilacion y Ejecucion

E tructura Arch vo JLe x s i E ructura del Archivo Jlex st Un archi vo de entrada Jlex, es un archi vo plano con la siguie nte estruct ura: codigo del usua rio % % Direct ivas Jlex % % Reglas para las Ex presiones Regul ares Cdigo del Usuario Es la parte del archivo de ent rada donde se coloca el codigo java que deseam os usar en la clase que ser gen er ada, esto quiere decir que Jlex copiar d irectam en te el codigo a la clase gen erada, aqui deben ir los importes a otras libr erias. TODO ESTO ANTES DE LOS PRIME ROS (% ). %

m/

T to l u ria

J x le

Y Java

Cup

Directivas JLex En esta seccon irn las direct ivas, o especi ficaciones opere JLEX, para obtener la salida deseada. Reglas para las Ex re siones Regulares p En esta seccion del archi vo Jlex, es donde se definen las reglas para obtener los tokens de la cadena que se esta leyendo. Con un eje mplo explic ar e mejor cada una de estas secciones. Para el ejemplo esc rib un progr am que reconoce las a siguien tes pala br as rese rvadas: int, string, if, then, else, for, while Reconoce ident ificad ores, y enteros. lexico del para que

El codigo para hacer Jlex para genera el analizador eje mplo es el siguie nte: /*AQUI PUEDEN IR LOS IMPO RTS */ % % % { /*CODIGO USU ARIO*/ /*Pequea funcion para imprim en pan talla*/ ir public void imprim String foo) e( { S ystem .out. println (foo) } % } /*DIRECTIVAS JLEX*/ %class Yylex % public % full % char % line % cup % eofval{ System.out. println("FIN DEL ARCHIVO"); % eofval} enter o=[09] Id=[azAZ][azAZ09]* % % /* MANEJO DE LAS PALABRAS RES ERVADAS*/ "while" {i mprime("while"); }

m/

T to l u ria

J x le

Y Java

Cup

"int" {i mprime("int");} "if" {i mprim e("if");} "then" {imprim "then");} e( "for"{i mprim e(" for");} /*ex presion regular para un entero, tom ando el conjun to de finiddo anteriorm nte como enter o*/ e /*un entero 1 o mas veces*/ ({e nter o})+ {imprim e("e nter o"+} {Id} {i mprim e("Ident ificador");} /*con la siguie nte linesa ign or am os los espacios en blanco*/ (" ") {S ystem .out. println("espacio");} /*con esta igno ram os los saltos de linea, tabulaciones,*/ [\t\r\n\f] {} /*e rror lexico:*/ . {S ystem .out. println(" er ror");} }/*e rror lexico:*/. {S ystem .out. println(" error");} El cdigo esc rito dentro de los corchet es es el el cdigo que querem os que se ejec ute cada vez que el scanner encuen tra los tokens a su izquie rda. Este cdigo queda sin m ificar a la hora de od gen erar el archi vo de salida java E tructura de Arc iv o Cup s h A continuacin detallar como se es truct ur a un archivo de en trada para Cup. Bsicam nte un archivo para Cup tiene la siguie nte es truct ur a: e < impo rts java > < codigo del usua rio para el parser> <codigo del usua rio para las acciones de la gram atica> < Decl ar acion de Variables para la gr am atica> <Gr am atica> Imports: En esta seccin creo que no tengo que ampliar m ucho desde que progr am os Java sabem am os como son los impo rts de librerias. Cdigo del Usua rio para el Parser: Como el cdigo Java es gen er ado por la he rram ien ta es muy difcil m odi ficar lo en el archi vo de salida. As que aqu podem decl ar ar mtodos y variables que os pensam os usar en la clase resu ltante. Si se decl ar an variables o m todos pblicos en esta seccin estos podran ser accedidos por otras clases. Se decl ar a: parser code {: /* Codigo del pa rser*/:} Cdigo del Usua rio para las Acciones de la Gram tica: Com o nue str o pr ops ito es el de gen er ar un Compilador con estas

m/

T to l u ria

J x le

Y Java

Cup

he rram ien tas o un interpr ete, neces itam os gener ar una salida ya sea esta error es sem nticos, sintcticos o traduccin a un cdigo equivale nte, para esto tenem os que hacer uso de traducciones di rigidas por sint axis. Sera muy engo rroso prog ram ar largas funciones en cada accin del gr am tica as que estas las podem decl ar ar en os esta seccin y solo m anda rlas a llamar en cada accin gram atical. Se decl ar a de la siguie nte m era: an action code {:/*Codigo para las acciones*/:} Decl ar acin de Variables para la Gr am tica : En esta seccin toca decl ar ar las variables que se utiliz ar an en la gram tica, estas variables pueden ser de dos tipos: Variables Term inales < term inal> Variables No Term inales <non term inal> Las variables term inales sern todos los sm bolos term inales gr am tica y las variables No Term inales sern todas las variables que represe ntar an pr oducciones. La sint axis para la decl aracin es la siguie nte: <tipo de variable> < tipo de dato > < id de la variable > Donde <tipo de variable > puede ser Term inal o No term inal <tipo de dato> puede ser cual quier tipo de dato prim ivo de Java o it uno creado por no sotros m ism os. Si se no se espec ifica el tipo de dato Cup lo trab ajar como un tipo de dato Sym bol. <id de la variable > aqu se especi fica el id de la variable, se puede usar una lista de identi ficad ores sep ar adas por coma si deseam v ariables del mismo tipo. os Gr am tica: En esta seccin del archivo es donde esc ribirem nue stra gram os atica. La gr am atica tiene la siguie nte sin taxis : <non term inal > ::= < term inales o No term inales > ; Como un no term inal puede tener mas de un lado der echo en Cup se utiliza el sim bolo | <non term inal > ::= < term inales o No term inales > |<term inales o No term inales> ; Como es esp erado se pueden es cribir muchas producciones. Eje mplo de un archivo cup para una Ex presion Booleana: /*Por el m e nto dej arem om os el action code y parser code vacios esto se de la

m/

T to l u ria

J x le

Y Java

Cup

explic ar a mas a detalle en otra seccion del tutorial*/ action code{::} parser code{::} /*Decl ar acion de variables no term inales*/ non term inal COND, OREX P,ANDE XP,IGE XP,CM P,SI MBOLOSCOM PARAR ,TIPO_ DAT O; /*DEC LAR ACION DE VARIABLES TERMINALES */ term inal or_,and_,igual_igual,no_igual, mayor, m eno r, mayor_igual,menor_igual, open_pa r,close_p ar,id,num ero,t rue ,false; Start with COND; // start with sirve para indica rle al parser con que produccion empezar COND::=OREXP; OREXP::=OREXP or_ ANDEXP | ANDEXP ; ANDEXP::=ANDEXP |IGEXP; and_ IGEXP CMP

IGEXP::= IGEXP igual_igual |IGEXP no_igual CMP |CMP;

SIM BOLOS _COMPARAR::= mayor |m enor |mayor_igual |m enor_igual; CMP::= CMP SIM BOLOS _COMPARAR TIPO _DATO |TIPO_ DAT O |open_par COND close_par ; TIPO_ DAT O::= id |num ro e |true |false; Inte r cin Jlex con Cup ga Ya que sabem os como hacer archi vos de ah or a es hora de hacer que funcionen en m ilu strati vo el eje mplo usarem as os una al parser que nos servir para alm acenar i que se esta leyendo. Llam ar em os a esta class token(){ int posicionX; int posicion Y; String valo r;
m/

en trada para Jlex y Cup conju nto. Para hacer de clase externa al scanner y nform acin de cada token clase token

T to l u ria

J x le

Y Java

Cup

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.posicio nY;} public String getValor() {r eturn this.val or;} } Segu irem os con el eje mplo de la expresin condicional , para es to debem esc ribir el archi vo jlex para que reconozca las pala bras os rese rvadas term inales del leng uaje. El archi vo q uedara de la siguie nte form a: import java_cup. runtim e.Sym bol; % % % { public void imprim String str) e( { S ystem .out. println (str+" "+yychar+" "+yyline); } % } %class lexc % public % char % line % ign orecase % cup % full %type java_cup. runtime.Sym bol %i mplem ents java_cup. runtime.Scanner % eofval{ System.out. println("FIN DEL ARCHIVO"); return null; % eofval} letra=[azAZ] enter o=[09] id=[azAZ][AZaz09]* % % "(" {i mprim "Abre Parentesis"); e( return new Sym bol(csym.open_pa r,new token(y ytext(), yycha r,yyline)); } ")" {i mprim e("Ci erra Parentesis"); return new Sym bol(csym.close_pa r,new token(y ytext(), yycha r,yyline));
m/

T to l u ria
"true" {

J x le

Y Java

Cup

imprim e("t rue"); return new Sym bol(csym.t rue_, ne w token(y ytext(), yycha r,yyline)); } "false" { imprim "false"); e( return new Sym bol(csym. false_, new token(y ytext(), yycha r,yyline)); } "<=" {i mprim e("m enor igual"); return new Sym bol(csym enor_igual, .m new token(y ytext(), yycha r,yyline)); } ">=" {i mprim e(" mayor igual"); return new Sym bol(csym .m ayor_igual, new token(y ytext(), yycha r,yyline)); } "||" {i mprim e("or"); return new Sym bol(csym .or_, new token(y ytext(), yycha r,yyline)); } "&&" {i mprim e("and"); return new Sym bol(csym .and_, new token(y ytext(), yycha r,yyline)); } "==" {i mprime("igual_igual"); return new Sym bol(csym .igual_igual, new token(y ytext(), yycha r,yyline)); } "!=" {i mprim e("no igual"); return new Sym bol(csym .no_igual, new token(y ytext(), yycha r,yyline)); } ({id})+("_")*({id})* {i mprim e("id"); return new Sym bol(csym .id, new token(y ytext(), yycha r,yyline)); } {e nter o}+ {imprim e("e ntero"); return new Sym bol(csym.e nter o, new token(y ytext(), yycha r,yyline)); } [\t\r\f] {} [\n] {y ychar=0;} " " {}

m/

. {i mprim e(" er ror: "+yy text()); } Explicar el fragm nto de cdigo que se utiliz al lado derecho: e ")" {i mprim e("Ci erra Parentesis"); return new Sym bol(csym .close_pa r,new token(y ytext(), yycha r,yyline));} Se llama la funcin i mprim que se defini al inicio del archi vo. e Ahora bien, el scanner es co ns truido de tal manera que dentro de el existe una funcion con una sentencia de con trol donde se decide que tipo de token se esta leyendo y que valor retorna r. All reside el hecho de es cribir el return. Como podem os ver se retorna un tipo de dato Sym bol, este en su co ns truc tor recibe dos par metros : El primero que es un entero que es decl ar ado en la clase sym gene rada por cup (Explicar mas adela nte) El segundo que recibe es de tipo Object, esto nos facil ita poder enviar cual quier tipo de dato que deseem os., en este caso fue un tipo token, el que hemos definido al inicio de esta seccin .Una vez term inado nue archi vo cup: str o archivo jlex es hora de es cribir el

action code{: public void Imprim Valor( String str) e { S ystem .out. println("el valor del token"+ str) ; } :} parser code{: public void synt ax_ error(Sym bol st){ token t=( token) st.value; repo rt_error("E rror Sintactico:"+ t.getValue()+" "+t. getX() +""+t.getY(),null); :} /*Decl ar acion de variables no term inales*/ non term inal token COND, OREX P,ANDE XP,IGE XP,CM P,SI MBOLOSCOM PARAR ,TIPO_ DAT O; /*DEC LAR ACION DE VARIABLES TERMINALES */ term inal token or_,and_,igual_igual,no_igual, mayor, m eno r, mayor_igual,menor_igual, open_pa r,close_p ar,id,num ero,t rue ,false ; Start with COND; // start with sirve para indica rle al parser con que produccion empezar COND::=OREXP; OREXP::=OREXP or_ ANDEXP

| ANDEXP ; ANDEXP::=ANDEXP |IGEXP; and_ IGEXP CMP

IGEXP::= IGEXP igual_igual |IGEXP no_igual CMP |CMP;

SIM BOLOS _COMPARAR::= mayor:m {:RES ULT=m :} |m eno r:m {:RES ULT=m :} |mayor_igual:m{:RES ULT=m :} |m enor_igual:m {:RESU LT=m :}; CMP::= CMP:c SIM BOLOS _COMPARAR:sc TIPO _DATO:t{: String val1=c. getValor(); String val2=t. getValor(); if(sc. getValor().e quals(">")){ ImprimeValor (val1+" mayor" +val2); } if(sc. getValor().e quals("<")){ ImprimeValor (val1+"m enor" +va l2); } if(sc. getValor().e quals("<=")){ ImprimeValor (val1+"menor igual" +val2); } if(sc. getValor().e quals(">=")){ ImprimeValor (val1+">=" +val 2); } :} |TIPO_ DAT O:T{:RES ULT=T;:} |open_par COND:c close_par{:RES ULT=c;:} ; TIPO_ DAT O::= id:i{:RES ULT=i; :} |num ro:n{:RES ULT=n;:} e |true:t {:RESU LT=t;:} |false:f{:RES ULT=t;:}; Llego la hora de explicar cada parte de el archi vo cup: En la seccin action code como expli qu anteriorm nte se e definen las funciones que que utiliz aran cuando se este recorriendo la gram tica, en este caso defin la funcin Imprim Valor que e recibe de par metro una cadena, lo nico que hace es imprim el ir valor de la cadena que recibe de par metro.

En la seccin parser code se encuen tran los mtodos propios del p arser, aqui hice un override de la funcin sy ntax_e rror.

Esta funcin nos pe rmite ejecu tar una accin cuando el pa rser encuen tra un error sintctico. En la decl aracin de term inales y no term inales se definen com o tipo token para poder m anejar usa rlos de una forma mas cmoda en las acciones de la gram tica. Ahora vamos con las acciones en la gram atica, Cup pe rm te i agregar acciones como las que podem os ver en el eje mplo anterior estas pueden ir en cual quier lugar del lado der echo de la produccin en este tipo de her ram nt as se sugi er e pone rlas al ie final para evitar am bigedades ya que Cup toma la produccin como un sm bolo las en la gram tica y al estar en el medio pueden haber error es de reduccin o de movim nto del pa rser. La sintaxis para para las ie acciones es: {: /*acciones*/ :} donde acciones puede ser cual quier sentencia de cdigo. La variable RESULT es usada por CUP para devolver el valor al padre de la produccin, bsicam nte devue lve el valor asignado al e no term inal del lado de recho. Este valor debe ser el mismo tipo de dato que el no term inal obviam nte. e En el eje mplo se imprim irn los operadores relacionales en forma de texto junto con los val ores de cada m iem bro de la ex presin. Compilacin y Ejecucin Es la hora del paso final compilar y ejecu tar nue stro scanner y pa rser. Co mpilacion Jlex: Para compilar el Jlex solo basta con esc ribir en consola: $ jlex <a rchi voj lex> Y si todo se genera bien creara nue stra salida en cdigo Java. Co mpilacion Cup:

Para compilar Cup se prese nt an mas opciones como espec ificar la clase que lleva las con stantes de los sim bolos, el pa quete de la clase, el nombre que deseam os para la salida del parser entre otras. Para nuestro eje mplo mod ificar emos el nombre de la clase con los sim bolos y el nombre que recib ira el pa rser: $ cup parser <nomb redelaclasedelpa rser> symbols <nom breclaseconsim bolos> <archivode netradacup> Para ver las demas opciones: $ man cup Cdigo de ejecucin:

Supon gam os que nue stra salida de jlex tiene el nom bre: scann er.java y nue stra salida de Cup Parser.java. Para poder hacer que el scanner y el parser funcionen conjun tam nte las siguie ntes lineas e de cdigo son tiles: En el caso que leamos un archi vo de en trada: File file=n ew File(" url del archi vo"); try{ FileR eader fr=new File Reader( file); scanner lex= ne w scanner(fr); Parser m Parser=n ew Parser(lex); i m Parser.pa rse(); i }catch( Exception e) { S ystem .out. println(e ); }

La clase del scanner recibe en el cons truc tor un Stream de car acter es en este caso lo que se ley del archi vo. scanner lex= new scanner(fr); Y para integrarlo al parser solo debem os del nuevo objeto parser creado Parser m Parser=n ew Parser(lex); i envia rlo al cons truc tor

Para que nu es tro objeto empiece a ejec utar el parser llam os am su metodo pa rse(); m Parser.pa rse(); i

Si nue stra ent rada no es un archi vo si no un texto ledo de un Text Area o algo parecido podem os usar la clase String Reader de Java en lugar del FileRead er.