domingo, 6 de febrero de 2011

Uso de JLex sin usar Cup




Este es un ejemplo de como usar JLex sin Cup, es decir sin usar una gramática, espero que les pueda ayudar.

Vamos a crear un archivo .jlex que contendrá nuestro scanner,  eso lo creamos en una carpeta por ejemplo en C:\Ejemplo.   También necesitamos copiar las carpetas JLex que tenemos en nuestra carpeta del jdk\bin que compilamos anteriormente y pegarlas en la carpeta Ejemplo que acabamos de crear.




El código del archivo jlex nos reconocerá entradas para una calculadora simple, el código es el siguiente:



  1. import java.lang.System;
  2.  
  3. /* Esta clase llama a la clase Yylex y pasa como parametro un archive de entrada o algo introducido por el usuario desde consola
  4. */
  5. class Analex {
  6. public static void main(String argv[])
  7. throws java.io.IOException {
  8. Yylex yy = new Yylex(System.in);
  9. while (yy.yylex() != null) {}
  10. }
  11. }
  12. class Yytoken {
  13. Yytoken () {}
  14. }
  15.  
  16. %%
  17. /*Directivas de JLex */
  18. %eofval{
  19. { System.exit(0); }
  20. %eofval}
  21. %line //defnimos el uso de contador de lineas
  22. %char //definimos el uso de contador de caracteres
  23. /*creamos un estado llamado COMENTARIO, existe un estado por default que se llama YYINITIAL */
  24. %state COMENTARIO
  25. NUMBER = [1-9][0-9]*
  26. %%
  27.  
  28. /* Las acciones se hacen dentro de los {} y escritas en java */
  29. {NUMBER} { System.out.println ("NUMERO "); }
  30. "+" { System.out.println ("MAS ");}
  31. "-" { System.out.println ("MENOS "); }
  32. "*" { System.out.println ("POR "); }
  33. "/" { System.out.println ("DIV "); }
  34. "(" { System.out.println ("PARA "); }
  35. ")" { System.out.println ("PARC "); }
  36. ";" { System.out.println ("PUNTOCOMA "); }
  37. " " {System.out.println ("ESPACIO ");}
  38.  
  39. /* cuando tenemos “//”, se pasa al estado COMENTARIO */
  40. "//" {yybegin(COMENTARIO);} [^\n] {}
  41. /* cuando tenemos un enter y estamos en el estado comentario, nos pasamos nuevamente al estado inicial */
  42. [\n] {yybegin(YYINITIAL); yychar=0;}
  43. /* En la siguiente linea se defnine lo que se hace en caso de que no venga nada de lo que hemos definido arriba, que es cuando ocurre un error lexico, yyline es el contador de linea, yychar es el contador de caracteres, que lo inicializamos a 0 para que reinicie cada vez que encuentre un enter */
  44. .|\n { if(!(yytext().equals("\n")))
  45. System.out.println("error lexico en " + yyline + "," + yychar + " No se reconoce " + yytext());
  46. yychar=0;}




Ahora sí, ya teniendo todo esto, compilamos con el siguiente comando

java JLex.Main léxico.jlex



Si existe algún error, nos lo mostrara en la consola, en este caso no existe ningún error por lo que nos genera un archivo que se llama léxico.jlex.java, que tenemos que renombrar como Yylex.java.  La verdad, renombrarlo  a Yylex no es importante, pero si no lo renombramos, usar el nombre original cuando compilemos en los pasos más adelante.

Para renombrar el archivo desde consola usamos el comando

rename lexico.jlex.java Yylex.java

Muchas veces tienes que modificar tu código del .jlex, cada vez que lo modifiques hay que compilar y renombrar nuevamente, pero no puedes renombrar a YYlex.java si existe este archivo, por lo que se tiene que eliminar el archivo Yylex.java con el siguiente comando

del Yylex.java

Todo este proceso se puede observar en la siguiente imagen






Esto nos genera archivos .class que se utilizaran al ejecutar el Analex

Ahora ya tenemos todo listo, para probar nuestro parser, vamos a crear un archivos de entrada con varias líneas de entrada, por ejemplo

3+2; // Este es un comentario
5+3)/2;  //otro comentario
2+8/4;
// otro comentario ()**^
6*2+8;

Guardamos este archivo como entrada.txt que es el que le pasamos al Analex como parámetro, para eso usamos el siguiente comando

java Analex 0<entrada.txt

Como salidas obtendremos lo que para nosotros representa cada lexema de entrada (Numero, Operador, etc) que llamaremos Tokens.  Estos Tokens son los que usara cup, en el siguiente post veremos como usar cup y pasar estos Tokens para  que los utilice. 




Si en el archivo de entrada existe un carácter que no lo reconoce nuestro lenguaje, nos mostrar un error léxico, mostrando la fila y columna donde encontró el error.

Como es tedioso en escribir todos los comandos para compilar cada vez que haces una modificación a tu archivo .jlex, se puede crear un script, para que al dar doble clic, lo ejecute y el proceso sea mas rápido.  Para eso pega las siguientes instrucciones en un archivo y guardarlo como compilar.bat

java JLex.Main lexico.jlex
pause
DEL Yylex.java
rename lexico.jlex.java Yylex.java
pause
javac -d . Yylex.java
pause

Igual para ejecutar nuestro proyecto, podemos usar un archivo .bat para que se ejecute al darle doble ckik, guardamos el archivo como ejecutar.bat, las instrucciones dentro de este archivo son los siguientes:

java Analex 0<entrada.txt
pause

3 comentarios:

  1. Como puedo usar de esta forma el JLex con NetBeans?, lo que deseo es agregar Yylex.java a mis librerias y pasarle como parametro el valor de un jtextfield

    ResponderEliminar
  2. Muchas gracias ya lo he hecho correr, solo una duda por que cuando lo corremos se le pone un <0 ?

    ResponderEliminar
  3. Gracias por los ejemplos, me han sido de mucha ayuda!!!!
    solo tengo una duda, la creación de la clase Yytoken siempre se hace?
    Lo que pasa es que en un ejemplo que me proporcionaron no incluyen esa clase y si corre bien, pero al hacer un ejercicio propio tomando como base ese ejemplo que te comento, me da un error y cabal es ese de crear la clase Yytoken. Que función tiene realmente este Yytoken y por qué se dará eso que te comento? que en un ejemplo si funciona mientras que en el otro no?

    ResponderEliminar