Javacc Tutorial
Javacc Tutorial
Javacc Tutorial
Descripcin inicial
El generador JavaCC (Java Compiler Compiler) es una herramienta para generar analizadores de lenguajes; acepta como entrada una especificacin de un determinado lenguaje y produce como salida un analizador para ese lenguaje; el analizador generado est escrito en Java. La especificacin proporcionada al generador JavaCC puede contemplar distintos aspectos del lenguaje para el que se quiere obtener el analizador: - Caractersticas lexicogrficas y sintcticas es la forma ms frecuente de uso del generador; la especificacin proporcionada define las caractersticas sintcticas y lexicogrficas de un lenguaje y se genera un analizador lxico-sintctico del lenguaje especificado. - Caractersticas lexicogrficas en la especificacin proporcionada al generador slo se definen caractersticas lexicogrficas del lenguaje; con el cdigo generado se puede obtener un analizador lexicogrfico. - Caractersticas lexicogrficas y sintcticas y comprobaciones semnticas tambin es posible completar una especificacin lxico-sintctica con la inclusin de cdigo Java complementario para que el programa generado (que incorpora adecuadamente ese cdigo auxiliar) pueda hacer un anlisis completo (lxico, sintctico y semntico) del lenguaje especificado.
Obtencin de un analizador lxico-sintctico Pasos para la generacin del analizador 1.- Edicin de la especificacin (editor de texto plano) vi | edit | NombreFichero.jj (el nombre del fichero puede tener cualquier extensin; suele usarse .jj) 2.- Ejecucin del generador javacc NombreFichero.jj Si el nombre elegido para la especificacin es NombreDeLaEspecif (ms adelante se indica la manera de dar un nombre a la especificacin), como resultado de la generacin se obtiene (adems de otros ficheros auxiliares) el fichero NombreDeLaEspecif.java 3.- Compilacin del analizador generado javac NombreDeLaEspecif.java Como resultado de la compilacin se obtiene (adems de otras clases auxiliares) el fichero NombreDeLaEspecif.class Ejecucin del analizador generado
Si el nombre del fichero donde se encuentra el texto fuente (escrito en el lenguaje para el que se ha generado el analizador) que se pretende analizar es Programa.len java NombreDeLaEspecif < Programa.len Si se desea que los resultados del anlisis, en vez de presentarse por pantalla, queden grabados en un fichero de nombre Salida.dat java NombreDeLaEspecif < Programa.len > Salida.dat Ejemplo de presentacin Descripcin del lenguaje El lenguaje L est formado por las expresiones en las que pueden aparecer: - variables - constantes - operadores + y * Las variables son nombres formados por una nica letra (minscula o mayscula); las constantes son nmeros enteros de una o ms cifras. El espacio y el tabulador pueden estar presentes, pero no tienen ningn significado; los finales de lnea tampoco son significativos (una expresin puede codificarse ocupando una o ms lneas). La sintaxis de las expresiones se especifica mediante la siguiente gramtica: <Expresion> ::= <Termino> { + <Termino> } <Termino> ::= <Factor> { * <Factor> } <Factor> ::= variable | constante | ( <Expresion> ) Especificacin lxico-sintctica codificada con la notacin JavaCC Una manera de escribir la especificacin (para la que se ha elegido el nombre ExprMin) de forma que sea aceptada por el generador es: options { Ignore_Case = true; } PARSER_BEGIN (ExprMin) public class ExprMin { public static void main (String[] argum) throws ParseException { ExprMin anLexSint = new ExprMin (System.in); anLexSint.unaExpresion(); System.out.println("Anlisis terminado:"); System.out.println ("no se han hallado errores lxico-sintcticos"); } } PARSER_END (ExprMin) void unaExpresion() :
{} { expresion() <EOF> } void expresion() : {} { termino() ( "+" termino() )* } void termino() : {} { factor() ( "*" factor() )* } void factor() : {} { <constante> | <variable> | "(" expresion() ")" } TOKEN: { < variable : ["a"-"z"] > } TOKEN: { < constante : ( ["0"-"9"] ) + > } SKIP: { " " | "\t" | "\n" | "\r" } Obtencin del analizador Si la especificacin precedente se tiene grabada en un fichero de nombre Ejemplo.jj, para obtener el analizador: - se ejecuta el generador: javacc Ejemplo.jj - se compila el analizador generado: javac ExprMin.java Ejecucin del analizador
Si se quiere analizar una expresin grabada en un fichero de nombre PruebaExp.txt: - se ejecuta el analizador obtenido: java ExprMin < PruebaExp.txt Analizadores generados En su funcionamiento ms sencillo y habitual, JavaCC genera un analizador sintctico, complementado con un analizador lexicogrfico, para que, conjuntamente, se pueda realizar un anlisis lxico-sintctico de un texto de entrada. El analizador sintctico obtenido es, en general, LL(k): descendente y determinista con la consulta de k smbolos por adelantado; si la gramtica proporcionada cumple la condicin LL(1), se genera un analizador sintctico descendente-predictivo-recursivo. Ms adelante se hacen algunas precisiones sobre esta afirmacin. Si la especificacin lxico-sintctica de un lenguaje codificada en JavaCC tiene dado (como indicativo que acompaa a las palabras reservadas PARSER_BEGIN y PARSER_END) el nombre EspLexSin y se tiene grabada en un fichero de nombre Lenguaje.jj, cuando se ejecuta el generador tomando como entrada ese fichero javacc Lenguaje.jj se obtienen los siguientes ficheros (clases) con cdigo Java: Token.java descripciones para la comunicacin entre los analizadores lxico y sintctico TokenMgrError.java tratamiento de errores para el anlisis lexicogrfico ParseException.java tratamiento de errores para el anlisis sintctico SimpleCharStream.java componentes para la realizacin de las tareas de entrada/salida del analizador EspLexSinConstants.java definicin de la representacin interna de las piezas sintcticas EspLexSinTokenManager.java analizador lexicogrfico EspLexSin.java analizador sintctico Puede apreciarse que hay dos categoras de nombres de ficheros generados: los cuatro primeros nombres citados no dependen del nombre de la especificacin considerada, los otros nombres de ficheros se forman a partir del nombre dado a la especificacin.\ Forma de una especificacin JavaCC (versin simplificada) La forma que se describe en lo que sigue es una versin simplificada; el generador JavaCC admite especificaciones con otras muchas posibilidades no mencionadas en esta introduccin. Una especificacin para el generador JavaCC puede considerarse dividida en cuatro secciones:
Seccin de opciones En esta seccin, cuya presencia es optativa, se pueden asignar valores a diversos parmetros (llamados opciones) que sirven para configurar ciertas caractersticas del funcionamiento del generador o del analizador generado. Cada parmetro (opcin) tiene un valor por defecto, que es el que toma cuando no se le asigna explcitamente un valor. Los valores de las opciones tambin se pueden fijar en la lnea de comandos cuando se ejecuta el generador (lo indicado en la lnea de comandos tiene prioridad sobre lo especificado en esta seccin de opciones). Algunas de las opciones para las que se puede fijar un valor son: Ignore_Case (valor por defecto: false) indica si en el texto analizado ha de distinguirse o no entre letras minsculas y maysculas Build_Parser (valor por defecto: true) indica si se genera el analizador sintctico o no Build_Token_Manager (valor por defecto: true) indica si se genera el analizador lexicogrfico o no Sanity_Check (valor por defecto: true) indica si se realizan comprobaciones sobre la gramtica sintctica Debug_Parser (valor por defecto: false) indica si se genera una traza para el anlisis lxico-sintctico Error_Reporting (valor por defecto: true) indica si los mensajes de error emitidos son ms o menos explicativos Static (valor por defecto: true) con el valor por defecto, los mtodos de los analizadores lxico y sintctico se generan con el descriptor esttico (static) Los nombres de las opciones pueden escribirse con letras minsculas o maysculas; los valores de las opciones son, en la mayora de los casos, un valor entero o un valor lgico. Si se incluye la seccin, se empieza poniendo la palabra reservada options; en este caso, al menos ha de ponerse una opcin. La forma de esta seccin es:
options { nombreOpcion1 = valorOpcion1; nombreOpcion2 = valorOpcion2; nombreOpcionk = valorOpcionk; } Seccin de ejecucin En esta seccin se pone el cdigo Java que contiene la llamada al analizador generado para que se realice el anlisis de un determinado texto de entrada. Tambin se establece aqu el nombre de la especificacin, que es el nombre que se toma para formar los nombres de parte de los ficheros (clases) generados. La seccin est delimitada por dos palabras reservadas, ambas acompaadas por un mismo nombre (puesto entre parntesis); ese nombre es el que se da a la especificacin. Entre esas dos palabras ha de ponerse una clase directora para el proceso de anlisis; el nombre de esa clase directora ha de coincidir con el nombre dado a la especificacin. PARSER_BEGIN (NombreDeLaEspecif) public class NombreDeLaEspecif { } PARSER_END (NombreDeLaEspecif) Una posible versin sencilla de la clase directora es: public class NombreDeLaEspecif { public static void main (String[] argum) throws ParseException { NombreDeLaEspecif anLeSi = new NombreDeLaEspecif (System.in); anLeSi.simboloPrograma(); } } se crea el objeto anLeSi para poder aplicar los mtodos de anlisis, se asocia la entrada standard ( System.in ) a la entrada para el analizador generado, se aplica al objeto creado el mtodo de anlisis correspondiente al smbolo inicial de la gramtica. Seccin de sintaxis En esta seccin se describe la sintaxis del lenguaje para el que se desea generar el analizador, usndose para ello una notacin parecida a la BNF. En lo que sigue se expone la forma de las producciones tal y como se escriben en JavaCC, ponindolas en comparacin con las producciones de la notacin BNF-Ampliada. Reglas sintcticas El conjunto de reglas que definen un smbolo no terminal
<NombreSimb> ::= 1 | 2 | n se codifica de la siguiente manera: void nombreSimb () : {} { 1-jcc | 2-jcc | n-jcc } - el nombre del smbolo no terminal (parte izquierda de las reglas) se escribe como el encabezamiento de un mtodo en Java, sin argumentos y sin valor de devolucin (mtodo de tipo void); se sigue, como en Java, la costumbre de escribir los nombres de los mtodos empezando con letra minscula, - el smbolo dos puntos representa la separacin entre las partes izquierda y derechas de las reglas (en vez del smbolo ::= de la notacin BNF), - el smbolo barra vertical representa la separacin entre distintas partes derechas con la misma parte izquierda (igual que en la notacin BNF), - despus del smbolo dos puntos se pone un bloque de cdigo Java; este cdigo se suele dedicar a la realizacin de tareas semnticas; si se pretende hacer slo un anlisis sintctico, el bloque quedar vaco (aunque siempre es obligada su presencia), - el conjunto de las alternativas (partes derechas de las reglas) est delimitado mediante llaves, como si constituyese un bloque de cdigo Java, - i-jcc representa la codificacin de una alternativa (parte derecha), emplendose una notacin que se describe a continuacin. Smbolos no terminales en las partes derechas En la notacin BNF se pone <NombreSimb>; en la notacin JavaCC se escribe nombreSimb() esto es, se pone como si fuese una llamada en Java a un mtodo sin argumentos. Smbolos terminales en las partes derechas Se considera una clasificacin en las piezas sintcticas (smbolos terminales de una gramtica sintctica), distinguindose entre piezas sintcticas nominales y annimas: son nominales las piezas sintcticas a las que se asocia un nombre en otra parte de la especificacin (ms adelante se describe la manera de indicar esta asociacin); ese nombre asociado a la pieza es el que se usa al escribir las partes derechas de las producciones. En la notacin JavaCC un smbolo terminal nominal se escribe poniendo el nombre delimitado por los caracteres < y >
<nombreTerminal> son annimas las piezas sintcticas que no tienen nombre asociado; no se precisa porque la pieza se representa por su propia secuencia de caracteres (lexema). En la notacin JavaCC, un smbolo terminal annimo se escribe poniendo su lexema delimitado por comillas; por ejemplo ";" ":=" "<" "<=" "END" Metasmbolos de opcionalidad y de repeticin En la notacin BNF se emplean los corchetes para indicar opcionalidad; en la notacin JavaCC se utilizan tambin esos mismos smbolos [ ] en ambas notaciones En la notacin BNF se emplean las llaves para indicar una repeticin de cero o ms veces; en la notacin JavaCC se utilizan los parntesis y un asterisco detrs del parntesis de cerrar { } en notacin BNF-Ampliada ( )* en notacin JavaCC