tutorial jlex cup

Upload: edgar-patzan

Post on 11-Oct-2015

43 views

Category:

Documents


0 download

TRANSCRIPT

  • 5/20/2018 Tutorial Jlex Cup

    1/12

    Tutorial Jlex Y Java Cup

    Tutorial Jlex y Java Cuphttp://openfecks.wordpress.com/

    por JosuOrtega

    http://openfecks.wordpress.com/

    http://openfecks.wordpress.com/http://openfecks.wordpress.com/http://openfecks.wordpress.com/http://openfecks.wordpress.com/
  • 5/20/2018 Tutorial Jlex Cup

    2/12

    Tutorial Jlex Y Java Cup

    JLex y Java CUP

    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 sintcticosLALR 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.

    Deciddividir el tutorial en varias secciones para hacer ms fcil

    el aprendizaje de estas herramientas.

    INDEX

    Estructura de un Archivo Jlex

    Estructura de un archivo Cup

    Integracin Jlex con Cup

    Compilacion y Ejecucion

    Estructura Archivo JLex

    Estructura del Archivo Jlex

    Un archivo de entrada Jlex, es un archivo plano con la siguiente

    estructura:

    codigo del usuario

    %%

    Directivas Jlex%%

    Reglas para las Expresiones Regulares

    Cdigo del Usuario

    Es la parte del archivo de entrada donde se coloca el codigo java

    que deseamos usar en la clase que sergenerada, esto quiere decir

    que Jlex copiardirectamente el codigo a la clase generada, aqui

    deben ir los importes a otras librerias. TODO ESTO ANTES DE LOS

    PRIMEROS (%%).

    http://openfecks.wordpress.com/

    http://openfecks.wordpress.com/jlex-y-cup/http://en.wikipedia.org/wiki/Lex_programming_toolhttp://en.wikipedia.org/wiki/LALR_parserhttp://openfecks.wordpress.com/jlex-y-cup/plantilla-archivo-jlex/http://openfecks.wordpress.com/jlex-y-cup/estructura-de-archivo-cup/http://openfecks.wordpress.com/jlex-y-cup/integracion-jlex-con-cup/http://openfecks.wordpress.com/jlex-y-cup/integracion-jlex-con-cup/http://openfecks.wordpress.com/jlex-y-cup/integracion-jlex-con-cup/http://openfecks.wordpress.com/jlex-y-cup/compilacion-y-ejecucion/http://openfecks.wordpress.com/jlex-y-cup/plantilla-archivo-jlex/http://openfecks.wordpress.com/http://en.wikipedia.org/wiki/Lex_programming_toolhttp://en.wikipedia.org/wiki/LALR_parserhttp://openfecks.wordpress.com/jlex-y-cup/plantilla-archivo-jlex/http://openfecks.wordpress.com/jlex-y-cup/estructura-de-archivo-cup/http://openfecks.wordpress.com/jlex-y-cup/integracion-jlex-con-cup/http://openfecks.wordpress.com/jlex-y-cup/compilacion-y-ejecucion/http://openfecks.wordpress.com/jlex-y-cup/plantilla-archivo-jlex/http://openfecks.wordpress.com/http://openfecks.wordpress.com/jlex-y-cup/
  • 5/20/2018 Tutorial Jlex Cup

    3/12

    Tutorial Jlex Y Java Cup

    Directivas JLex

    En esta seccon irn las directivas, o especificaciones para que

    opere JLEX, para obtener la salida deseada.

    Reglas para las Expresiones Regulares

    En esta seccion del archivo Jlex, es donde se definen las reglas

    para obtener los tokens de la cadena que se esta leyendo.

    Con un ejemplo explicare mejor cada una de estas secciones.

    Para el ejemplo escribun programa que reconoce las siguientes

    palabras reservadas:

    int, string, if, then, else, for, while

    Reconoce identificadores, y enteros.

    El codigo para hacer Jlex para genera el analizador lexico del

    ejemplo es el siguiente:

    /*AQUI PUEDEN IR LOS IMPORTS */

    %%

    %{

    /*CODIGO USUARIO*/

    /*Pequea funcion para imprimir en pantalla*/

    public void imprime(String foo){

    System.out.println(foo)

    }

    %}

    /*DIRECTIVAS JLEX*/

    %class Yylex

    %public

    %full

    %char%line

    %cup

    %eofval{

    System.out.println("FIN DEL ARCHIVO");

    %eofval}

    entero=[0-9]

    Id=[a-zA-Z][a-zA-Z0-9]*

    %%

    /* MANEJO DE LAS PALABRAS RESERVADAS*/

    "while" {imprime("while");

    }

    http://openfecks.wordpress.com/

    http://openfecks.wordpress.com/http://openfecks.wordpress.com/
  • 5/20/2018 Tutorial Jlex Cup

    4/12

    Tutorial Jlex Y Java Cup

    "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

    Estructura de Archivo Cup

    A continuacin detallarcomo se estructura un archivo de entradapara Cup.

    Bsicamente un archivo para Cup tiene la siguiente estructura:

    < imports java >

    < codigo del usuario para el parser>

    < Declaracion de Variables para la gramatica>

    Imports: En esta seccin creo que no tengo que ampliar mucho

    desde que programamos Java sabemos como son los imports de

    librerias.Cdigo del Usuario para el Parser: Como el cdigo Java es generado

    por la herramienta es muy difcil modificar lo en el archivo de

    salida. Asque aqupodemos declarar mtodos y variables que

    pensamos usar en la clase resultante. Si se declaran variables o

    mtodos pblicos en esta seccin estos podran ser accedidos por

    otras clases.

    Se declara:

    parser code {: /* Codigo del parser*/:}

    Cdigo del Usuario para las Acciones de la Gramtica: Como

    nuestro propsito es el de generar un Compilador con estas

    http://openfecks.wordpress.com/

    http://openfecks.wordpress.com/jlex-y-cup/estructura-de-archivo-cup/http://openfecks.wordpress.com/http://openfecks.wordpress.com/jlex-y-cup/estructura-de-archivo-cup/http://openfecks.wordpress.com/
  • 5/20/2018 Tutorial Jlex Cup

    5/12

    Tutorial Jlex Y Java Cup

    herramientas o un interprete, necesitamos generar una salida ya sea

    esta errores semnticos, sintcticos o traduccin a un cdigo

    equivalente, para esto tenemos que hacer uso de traducciones

    dirigidas por sintaxis.

    Sera muy engorroso programar largas funciones en

    cada accin del gramtica asque estas las podemos declarar en

    esta seccin y solo mandarlas a llamar en cada accin gramatical.

    Se declara de la siguiente manera:

    action code {:/*Codigo para las acciones*/:}

    Declaracin de Variables para la Gramtica : En esta seccin toca

    declarar las variables que se utilizaran en la gramtica, estas

    variables pueden ser de dos tipos:

    Variables Terminales < terminal>

    Variables No Terminales

    Las variables terminales sern todos los smbolos terminales de la

    gramtica y las variables No-Terminales sern todas

    las variables que representaran producciones.

    La sintaxis para la declaracin es la siguiente:

    < tipo de dato > < id de la variable >

    Donde puede ser Terminal o No terminal 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 trabajarcomo un tipo de dato Symbol.

    aquse 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 escribiremosnuestra gramatica. La gramatica tiene la siguiente sintaxis :

    ::= < terminales o No terminales > ;

    Como un no terminal puede tener mas de un lado derecho en Cup se

    utiliza el simbolo |

    ::= < terminales o No terminales >

    | ;

    Como es esperado se pueden escribir muchas producciones.

    Ejemplo de un archivo cup para una Expresion Booleana:

    /*Por el momento dejaremos el action code y parser code vacios esto

    se

    http://openfecks.wordpress.com/

    http://openfecks.wordpress.com/http://openfecks.wordpress.com/
  • 5/20/2018 Tutorial Jlex Cup

    6/12

    Tutorial Jlex Y Java Cup

    explicara mas a detalle en otra seccion del tutorial*/

    action code{::}

    parser code{::}

    /*Declaracion de variables no terminales*/

    non terminal COND,

    OREXP,ANDEXP,IGEXP,CMP,SIMBOLOSCOMPARAR,TIPO_DATO;

    /*DECLARACION DE VARIABLES TERMINALES */

    terminal or_,and_,igual_igual,no_igual,mayor, menor,

    mayor_igual,menor_igual,

    open_par,close_par,id,numero,true,false;

    Start with COND; // start with sirve para indicarle al parser con

    que produccion empezar

    COND::=OREXP;

    OREXP::=OREXP or_ ANDEXP |ANDEXP;

    ANDEXP::=ANDEXP and_ IGEXP

    |IGEXP;

    IGEXP::= IGEXP igual_igual CMP

    |IGEXP no_igual CMP

    |CMP;

    SIMBOLOS_COMPARAR::=mayor

    |menor |mayor_igual

    |menor_igual;

    CMP::= CMP SIMBOLOS_COMPARAR TIPO_DATO

    |TIPO_DATO

    |open_par COND close_par ;

    TIPO_DATO::= id

    |numero

    |true

    |false;

    Integracin Jlex con Cup

    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 servirpara almacenar informacin de cada token

    que se esta leyendo. Llamaremos a esta clase token

    class token(){

    int posicionX;

    int posicionY;

    String valor;

    http://openfecks.wordpress.com/

    http://openfecks.wordpress.com/jlex-y-cup/integracion-jlex-con-cup/http://openfecks.wordpress.com/jlex-y-cup/integracion-jlex-con-cup/http://openfecks.wordpress.com/jlex-y-cup/integracion-jlex-con-cup/http://openfecks.wordpress.com/http://openfecks.wordpress.com/jlex-y-cup/integracion-jlex-con-cup/http://openfecks.wordpress.com/
  • 5/20/2018 Tutorial Jlex Cup

    7/12

    Tutorial Jlex 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.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+"-"+yyline);

    }

    %}

    %class lexc

    %public

    %char%line

    %ignorecase

    %cup

    %full

    %type java_cup.runtime.Symbol

    %implements java_cup.runtime.Scanner

    %eofval{

    System.out.println("FIN DEL ARCHIVO");

    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));

    http://openfecks.wordpress.com/

    http://openfecks.wordpress.com/http://openfecks.wordpress.com/
  • 5/20/2018 Tutorial Jlex Cup

    8/12

    Tutorial Jlex Y Java Cup

    "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("mayor igual");

    return new Symbol(csym.mayor_igual,new

    token(yytext(),yychar,yyline));

    }

    "||" {imprime("or");

    return new Symbol(csym.or_,new

    token(yytext(),yychar,yyline));

    }

    "&&" {imprime("and");

    return new Symbol(csym.and_,newtoken(yytext(),yychar,yyline));

    }

    "==" {imprime("igual_igual");

    return new Symbol(csym.igual_igual,new

    token(yytext(),yychar,yyline));

    }

    "!=" {imprime("no igual");

    return new Symbol(csym.no_igual,new

    token(yytext(),yychar,yyline));

    }

    ({id})+("_")*({id})* {imprime("id");

    return new Symbol(csym.id,new

    token(yytext(),yychar,yyline));

    }

    {entero}+ {imprime("entero");

    return new Symbol(csym.entero,new

    token(yytext(),yychar,yyline));

    }

    [\t\r\f] {}

    [\n] {yychar=0;}

    " " {}

    http://openfecks.wordpress.com/

    http://openfecks.wordpress.com/http://openfecks.wordpress.com/
  • 5/20/2018 Tutorial Jlex Cup

    9/12

    Tutorial Jlex Y Java Cup

    . {imprime("error: "+yytext());

    }

    Explicarel fragmento de cdigo que se utilizal lado derecho:

    ")" {imprime("Cierra Parentesis");

    return new Symbol(csym.close_par,new

    token(yytext(),yychar,yyline));}

    Se llama la funcin imprime que se definial inicio del archivo.

    Ahora bien, el scanner es construido de tal manera que dentro de

    el existe una funcion con una sentencia de control donde se decide

    que tipo de token se esta leyendo y que valor retornar. Allreside

    el hecho de escribir 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 (Explicarmas 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("el valor 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);

    :}

    /*Declaracion de variables no terminales*/

    non terminal token COND,

    OREXP,ANDEXP,IGEXP,CMP,SIMBOLOSCOMPARAR,TIPO_DATO;

    /*DECLARACION DE VARIABLES TERMINALES */

    terminal token or_,and_,igual_igual,no_igual,mayor, menor,

    mayor_igual,menor_igual,

    open_par,close_par,id,numero,true,false;

    Start with COND; // start with sirve para indicarle al parser con

    que produccion empezar

    COND::=OREXP;

    OREXP::=OREXP or_ ANDEXP

    http://openfecks.wordpress.com/

    http://openfecks.wordpress.com/http://openfecks.wordpress.com/
  • 5/20/2018 Tutorial Jlex Cup

    10/12

    Tutorial Jlex Y Java Cup

    |ANDEXP;

    ANDEXP::=ANDEXP and_ IGEXP

    |IGEXP;

    IGEXP::= IGEXP igual_igual CMP

    |IGEXP no_igual CMP

    |CMP;

    SIMBOLOS_COMPARAR::=mayor:m{:RESULT=m:}

    |menor:m{:RESULT=m:}

    |mayor_igual:m{:RESULT=m:}

    |menor_igual:m{:RESULT=m:};

    CMP::= CMP:c SIMBOLOS_COMPARAR:sc TIPO_DATO:t{:

    String val1=c.getValor();

    String val2=t.getValor();

    if(sc.getValor().equals(">")){

    ImprimeValor(val1+"mayor"+val2);

    }

    if(sc.getValor().equals("=")){

    ImprimeValor(val1+">="+val2);

    }

    :}

    |TIPO_DATO:T{:RESULT=T;:}

    |open_par COND:c close_par{:RESULT=c;:} ;

    TIPO_DATO::= id:i{:RESULT=i; :}

    |numero:n{:RESULT=n;:}

    |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 expliquanteriormente se definen

    las funciones que que utilizaran cuando se este recorriendo

    la gramtica, en este caso definla 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.

    http://openfecks.wordpress.com/

    http://openfecks.wordpress.com/http://openfecks.wordpress.com/
  • 5/20/2018 Tutorial Jlex Cup

    11/12

    Tutorial Jlex Y Java Cup

    Esta funcin nos permite ejecutar una accin cuando el parser

    encuentra un error sintctico.

    En la declaracin de terminales y no terminales se definen como

    tipo token para poder manejar usarlos de una forma mas cmoda en

    las acciones de la gramtica.

    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.

    La variable RESULT es usada por CUP para devolver el valor al

    padre de la produccin, bsicamente devuelve el valor asignado al

    no terminal del lado derecho. Este valor debe ser el mismo tipo de

    dato que el no terminal obviamente.

    En el ejemplo se imprimirn los operadores relacionales en forma de

    texto junto con los valores de cada miembro de la expresin.

    Compilacin y Ejecucin

    Es la hora del paso final compilar y ejecutar nuestro scanner y

    parser.

    Compilacion Jlex:

    Para compilar el Jlex solo basta con escribir en consola:

    $ jlex

    Y si todo se genera bien creara nuestra salida en cdigo Java.

    Compilacion Cup:

    Para compilar Cup se presentan mas opciones como especificar la

    clase que lleva las constantes de los simbolos, el paquete de la

    clase, el nombre que deseamos para la salida del parser entre

    otras. Para nuestro ejemplo modificaremos el nombre de la clase con

    los simbolos y el nombre que recibira el parser:

    $ cup -parser -symbols

    Para ver las demas opciones:

    $ man cup

    Cdigo de ejecucin:

    http://openfecks.wordpress.com/

    http://openfecks.wordpress.com/jlex-y-cup/compilacion-y-ejecucion/http://openfecks.wordpress.com/jlex-y-cup/compilacion-y-ejecucion/http://openfecks.wordpress.com/jlex-y-cup/compilacion-y-ejecucion/http://openfecks.wordpress.com/jlex-y-cup/compilacion-y-ejecucion/http://openfecks.wordpress.com/jlex-y-cup/compilacion-y-ejecucion/http://openfecks.wordpress.com/http://openfecks.wordpress.com/jlex-y-cup/compilacion-y-ejecucion/http://openfecks.wordpress.com/
  • 5/20/2018 Tutorial Jlex Cup

    12/12

    Tutorial Jlex Y Java Cup

    Supongamos que nuestra salida de jlex tiene el nombre: scanner.java

    y nuestra salida de Cup Parser.java. Para poder hacer que el

    scanner y el parser funcionen conjuntamente las siguientes lineas

    de cdigo son tiles:

    En el caso que leamos un archivo de entrada:

    File file=new File("url del archivo");

    try{

    FileReader fr=new FileReader(file);

    scanner lex=new scanner(fr);

    Parser miParser=new Parser(lex);

    miParser.parse();

    }catch(Exception e){

    System.out.println(e);

    }

    }

    La clase del scanner recibe en el constructor un Stream de

    caracteres en este caso lo que se leydel archivo.

    scanner lex=new scanner(fr);

    Y para integrarlo al parser solo debemos enviarlo al constructor

    del nuevo objeto parser creado

    Parser miParser=new Parser(lex);

    Para que nuestro objeto empiece a ejecutar el parser llamamos a su

    metodo parse();

    miParser.parse();

    Si nuestra entrada no es un archivo si no un texto ledo de un

    TextArea o algo parecido podemos usar la clase StringReader de Java

    en lugar del FileReader.

    http://openfecks.wordpress.com/

    http://openfecks.wordpress.com/http://openfecks.wordpress.com/