8
Javacc Descripción inicial El generador JavaCC (Java Compiler Compiler) es una herramienta para generar analizadores de lenguajes; acepta como entrada una especificación de un determinado lenguaje y produce como salida un analizador para ese lenguaje; el analizador generado está escrito en Java. La especificación proporcionada al generador JavaCC puede contemplar distintos aspectos del lenguaje para el que se quiere obtener el analizador: - Características lexicográficas y sintácticas es la forma más frecuente de uso del generador; la especificación proporcionada define las características sintácticas y lexicográficas de un lenguaje y se genera un analizador léxico-sintáctico del lenguaje especificado. - Características lexicográficas en la especificación proporcionada al generador sólo se definen características lexicográficas del lenguaje; con el código generado se puede obtener un analizador lexicográfico. - Características lexicográficas y sintácticas y comprobaciones semánticas también es posible completar una especificación léxico-sintáctica con la inclusión de código Java complementario para que el programa generado (que incorpora adecuadamente ese código auxiliar) pueda hacer un análisis completo (léxico, sintáctico y semántico) del lenguaje especificado. Obtención de un analizador léxico-sintáctico • Pasos para la generación del analizador 1.- Edición de la especificación (editor de texto plano) vi | edit |∙ ∙ ∙ NombreFichero.jj (el nombre del fichero puede tener cualquier extensión; suele usarse .jj) 2.- Ejecución del generador javacc NombreFichero.jj Si el nombre elegido para la especificación es NombreDeLaEspecif (más adelante se indica la manera de dar un nombre a la especificación), como resultado de la generación se obtiene (además de otros ficheros auxiliares) el fichero NombreDeLaEspecif.java 3.- Compilación del analizador generado javac NombreDeLaEspecif.java Como resultado de la compilación se obtiene (además de otras clases auxiliares) el fichero NombreDeLaEspecif.class • Ejecución del analizador generado

Javacc Tutorial

Embed Size (px)

Citation preview

Page 1: Javacc Tutorial

JavaccDescripción inicial

El generador JavaCC (Java Compiler Compiler) es una herramienta para generaranalizadores de lenguajes; acepta como entrada una especificación de un determinadolenguaje y produce como salida un analizador para ese lenguaje; el analizadorgenerado está escrito en Java. La especificación proporcionada al generador JavaCCpuede contemplar distintos aspectos del lenguaje para el que se quiere obtener elanalizador:

- Características lexicográficas y sintácticas

es la forma más frecuente de uso del generador; la especificación proporcionadadefine las características sintácticas y lexicográficas de un lenguaje y se genera unanalizador léxico-sintáctico del lenguaje especificado.

- Características lexicográficas

en la especificación proporcionada al generador sólo se definen característicaslexicográficas del lenguaje; con el código generado se puede obtener un analizadorlexicográfico.

- Características lexicográficas y sintácticas y comprobaciones semánticas

también es posible completar una especificación léxico-sintáctica con la inclusión decódigo Java complementario para que el programa generado (que incorporaadecuadamente ese código auxiliar) pueda hacer un análisis completo (léxico,sintáctico y semántico) del lenguaje especificado.

Obtención de un analizador léxico-sintáctico

• Pasos para la generación del analizador

1.- Edición de la especificación (editor de texto plano)

vi | edit |∙ ∙ ∙ NombreFichero.jj

(el nombre del fichero puede tener cualquier extensión; suele usarse .jj)

2.- Ejecución del generador

javacc NombreFichero.jj

Si el nombre elegido para la especificación es NombreDeLaEspecif (más adelante se indica lamanera de dar un nombre a la especificación), como resultado de la generación se obtiene (ademásde otros ficheros auxiliares) el fichero

NombreDeLaEspecif.java

3.- Compilación del analizador generado

javac NombreDeLaEspecif.java

Como resultado de la compilación se obtiene (además de otras clases auxiliares) el fichero

NombreDeLaEspecif.class

• Ejecución del analizador generado

Page 2: Javacc Tutorial

Si el nombre del fichero donde se encuentra el texto fuente (escrito en el lenguaje para el que se hagenerado el analizador) que se pretende analizar es Programa.len

java NombreDeLaEspecif < Programa.len

Si se desea que los resultados del análisis, en vez de presentarse por pantalla, queden grabados enun fichero de nombre Salida.dat

java NombreDeLaEspecif < Programa.len > Salida.dat

◊ Ejemplo de presentación

• Descripción 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 (minúscula o mayúscula); las constantesson números enteros de una o más cifras. El espacio y el tabulador pueden estar presentes, pero notienen ningún significado; los finales de línea tampoco son significativos (una expresión puedecodificarse ocupando una o más líneas).

La sintaxis de las expresiones se especifica mediante la siguiente gramática:

<Expresion> ::= <Termino> { + <Termino> }

<Termino> ::= <Factor> { * <Factor> }

<Factor> ::= variable

| constante

| ( <Expresion> )

• Especificación léxico-sintáctica codificada con la notación JavaCC

Una manera de escribir la especificación (para la que se ha elegido el nombre ExprMin) de formaque 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("Análisis terminado:");

System.out.println

("no se han hallado errores léxico-sintácticos");

}

}

PARSER_END (ExprMin)

void unaExpresion() :

Page 3: Javacc Tutorial

{ }

{

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" }

• Obtención del analizador

Si la especificación precedente se tiene grabada en un fichero de nombre Ejemplo.jj, para obtener elanalizador:

- se ejecuta el generador: javacc Ejemplo.jj

- se compila el analizador generado: javac ExprMin.java

• Ejecución del analizador

Page 4: Javacc Tutorial

Si se quiere analizar una expresión grabada en un fichero de nombre PruebaExp.txt:

- se ejecuta el analizador obtenido: java ExprMin < PruebaExp.txt

◊ Analizadores generados

En su funcionamiento más sencillo y habitual, JavaCC genera un analizador sintáctico,complementado con un analizador lexicográfico, para que, conjuntamente, se pueda realizar unanálisis léxico-sintáctico de un texto de entrada.

El analizador sintáctico obtenido es, en general, LL(k): descendente y determinista con la consultade k símbolos por adelantado; si la gramática proporcionada cumple la condición LL(1), se generaun analizador sintáctico descendente-predictivo-recursivo. Más adelante se hacen algunasprecisiones sobre esta afirmación.

Si la especificación léxico-sintáctica de un lenguaje codificada en JavaCC tiene dado (comoindicativo que acompaña a las palabras reservadas PARSER_BEGIN y PARSER_END) el nombreEspLexSin y se tiene grabada en un fichero de nombre Lenguaje.jj, cuando se ejecuta el generadortomando como entrada ese fichero

javacc Lenguaje.jj

se obtienen los siguientes ficheros (clases) con código Java:

▫ Token.java

descripciones para la comunicación entre los analizadores léxico y sintáctico

▫ TokenMgrError.java

tratamiento de errores para el análisis lexicográfico

▫ ParseException.java

tratamiento de errores para el análisis sintáctico

▫ SimpleCharStream.java

componentes para la realización de las tareas de entrada/salida del analizador

▫ EspLexSinConstants.java

definición de la representación interna de las piezas sintácticas

▫ EspLexSinTokenManager.java

analizador lexicográfico

▫ EspLexSin.java

analizador sintáctico

Puede apreciarse que hay dos categorías de nombres de ficheros generados: los cuatro primerosnombres citados no dependen del nombre de la especificación considerada, los otros nombres deficheros se forman a partir del nombre dado a la especificación.\

Forma de una especificación JavaCC (versión simplificada)

La forma que se describe en lo que sigue es una versión simplificada; el generador JavaCC admiteespecificaciones con otras muchas posibilidades no mencionadas en esta introducción.

Una especificación para el generador JavaCC puede considerarse dividida en cuatro secciones:

Page 5: Javacc Tutorial

Sección de opciones

En esta sección, cuya presencia es optativa, se pueden asignar valores a diversos parámetros(llamados opciones) que sirven para configurar ciertas características del funcionamiento delgenerador o del analizador generado. Cada parámetro (opción) tiene un valor por defecto, que es elque toma cuando no se le asigna explícitamente un valor. Los valores de las opciones también sepueden fijar en la línea de comandos cuando se ejecuta el generador (lo indicado en la línea decomandos tiene prioridad sobre lo especificado en esta sección 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 minúsculas y mayúsculas

Build_Parser (valor por defecto: true)

indica si se genera el analizador sintáctico o no

Build_Token_Manager (valor por defecto: true)

indica si se genera el analizador lexicográfico o no

Sanity_Check (valor por defecto: true)

indica si se realizan comprobaciones sobre la gramática sintáctica

Debug_Parser (valor por defecto: false)

indica si se genera una traza para el análisis léxico-sintáctico

Error_Reporting (valor por defecto: true)

indica si los mensajes de error emitidos son más o menos explicativos

Static (valor por defecto: true)

con el valor por defecto, los métodos de los analizadores léxico y sintáctico se generan con el des-criptor estático (static)

Los nombres de las opciones pueden escribirse con letras minúsculas o mayúsculas; los valores delas opciones son, en la mayoría de los casos, un valor entero o un valor lógico. Si se incluye lasección, se empieza poniendo la palabra reservada options; en este caso, al menos ha de ponerse unaopción.

La forma de esta sección es:

Page 6: Javacc Tutorial

options {

nombreOpcion1 = valorOpcion1;

nombreOpcion2 = valorOpcion2;

∙ ∙ ∙ ∙

nombreOpcionk = valorOpcionk;

}

◊ Sección de ejecución

En esta sección se pone el código Java que contiene la llamada al analizador generado para que serealice el análisis de un determinado texto de entrada. También se establece aquí el nombre de laespecificación, que es el nombre que se toma para formar los nombres de parte de los ficheros(clases) generados.

La sección está delimitada por dos palabras reservadas, ambas acompañadas por un mismo nombre(puesto entre paréntesis); ese nombre es el que se da a la especificación. Entre esas dos palabras hade ponerse una clase directora para el proceso de análisis; el nombre de esa clase directora ha decoincidir con el nombre dado a la especificación.

PARSER_BEGIN (NombreDeLaEspecif)

∙ ∙ ∙ ∙

public class NombreDeLaEspecif {

∙ ∙ ∙ ∙

}

∙ ∙ ∙ ∙

PARSER_END (NombreDeLaEspecif)

Una posible versión 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 métodos de análisis,

▫ se asocia la entrada standard ( System.in ) a la entrada para el analizador generado,

▫ se aplica al objeto creado el método de análisis correspondiente al símbolo inicial de la gramática.

◊ Sección de sintaxis

En esta sección se describe la sintaxis del lenguaje para el que se desea generar el analizador,usándose para ello una notación parecida a la BNF. En lo que sigue se expone la forma de lasproducciones tal y como se escriben en JavaCC, poniéndolas en comparación con las produccionesde la notación BNF-Ampliada.

• Reglas sintácticas

El conjunto de reglas que definen un símbolo no terminal

Page 7: Javacc Tutorial

<NombreSimb> ::= α1

| α2

∙ ∙ ∙

| αn

se codifica de la siguiente manera:

void nombreSimb () :

{ }

{

α1-jcc

| α2-jcc

∙ ∙ ∙

| αn-jcc

}

- el nombre del símbolo no terminal (parte izquierda de las reglas) se escribe como el encabeza-miento de un método en Java, sin argumentos y sin valor de devolución (método de tipo void); sesigue, como en Java, la costumbre de escribir los nombres de los métodos empezando con letra mi-núscula,

- el símbolo dos puntos representa la separación entre las partes izquierda y derechas de las reglas(en vez del símbolo ::= de la notación BNF),

- el símbolo barra vertical representa la separación entre distintas partes derechas con la mismaparte izquierda (igual que en la notación BNF),

- después del símbolo dos puntos se pone un bloque de código Java; este código se suele dedicar ala realización de tareas semánticas; si se pretende hacer sólo un análisis sintáctico, el bloque que-dará vacío (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 código Java,

- αi-jcc representa la codificación de una alternativa (parte derecha), empleándose una notación que

se describe a continuación.

• Símbolos no terminales en las partes derechas

En la notación BNF se pone <NombreSimb>; en la notación JavaCC se escribe

nombreSimb()

esto es, se pone como si fuese una llamada en Java a un método sin argumentos.

• Símbolos terminales en las partes derechas

Se considera una clasificación en las piezas sintácticas (símbolos terminales de una gramáticasintáctica), distinguiéndose entre piezas sintácticas nominales y anónimas:

▫ son nominales las piezas sintácticas a las que se asocia un nombre en otra parte de laespecificación (más adelante se describe la manera de indicar esta asociación); ese nombre asociadoa la pieza es el que se usa al escribir las partes derechas de las producciones. En la notación JavaCCun símbolo terminal nominal se escribe poniendo el nombre delimitado por los caracteres < y >

Page 8: Javacc Tutorial

<nombreTerminal>

▫ son anónimas las piezas sintácticas que no tienen nombre asociado; no se precisa porque la piezase representa por su propia secuencia de caracteres (lexema). En la notación JavaCC, un símboloterminal anónimo se escribe poniendo su lexema delimitado por comillas; por ejemplo

";" ":=" "<" "<=" "END"

• Metasímbolos de opcionalidad y de repetición

En la notación BNF se emplean los corchetes para indicar opcionalidad; en la notación JavaCC seutilizan también esos mismos símbolos

[ α ] en ambas notaciones

En la notación BNF se emplean las llaves para indicar una repetición de cero o más veces; en lanotación JavaCC se utilizan los paréntesis y un asterisco detrás del paréntesis de cerrar

{ α } en notación BNF-Ampliada

( α )* en notación JavaCC