ANTLR

jueves, 3 de febrero de 2011

ANTLR es un generador de lenguajes, a partir de la especificación de un lenguaje a partir de una gramática podemos:
• Reconocer si un programa (o palabra) cumple una especificación.

• Traducir el programa (o palabra) a otro lenguaje.

• Realizar alguna serie de órdenes.

A veces nos interesara definir el lenguaje de una forma más laxa. Admitimos palabras/programas que en principio no tengan mucho sentido porque:


• Es más fácil definir la gramática.

• La estructura que define expresa la estructura que buscamos.

Ejemplo de utilización de ANTLR

Definamos una gramática para el lenguaje de los paréntesis.

gramar prueba;


principal

:’(’principal’)’|;

Primera prueba, ¿Cómo definir una gramática para que acepte lo mismo añadiendo los corchetes?

gramar prueba;

principal

: SI principal1 (CONTRA principal) ? |ALGO;

principal1


: SI principal1|ALGO;

SI :’sib’;

CONTRA: ’en_otro_caso’;

ALGO: ’algo’;

WS:(’\n’|’\t’|’\r’|’’) +{ skip ();};


gramar suma;


start: expresion;

expresion

: NUMERO OPERADOR expresión |NUMERO;

NUMERO: ’0’..’9’+;

OPERADOR: ’+’;


ESPACIOS: (’\n’|’\r’|’\t’){skip();};

El EBNF define reglas de producción donde las secuencias de símbolos se asignan respectivamente a a no terminal:


dígito excepto cero:: = “1” | “2” | “3” | “4” | “5” | “6” | “7” | “8” | “9” ;

dígito :: = “0”
dígito excepto cero;

Esta regla de producción define el no terminal dígito cuál está en el lado izquierdo de la asignación. La barra vertical representa un alternativa y los símbolos terminales se incluyen con las comillas seguidas por un punto y coma como terminar el carácter. Por lo tanto a Dígito es a 0 o a dígito excepto cero eso puede ser 1 o 2 o 3 y así sucesivamente hasta 9.


ANTLR

http://personales.unican.es/gomezd/Talf/antlr.pdf

Generador JavaCC

Principios básicos del generador JavaCC


El generador JavaCC (Java Compiler Compiler) es una herramienta para generar programas escritos en lenguaje Java; acepta como entrada una especificación de un determinado lenguaje y produce como salida un analizador para ese lenguaje. En la manera más simple de funcionamiento, 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; pero también es posible completar una especificación léxico-sintáctica con la inclusión adecuada de código para que el programa generado llegue a ser un analizador completo del lenguaje.

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

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



• Ejecución 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 análisis, en vez de presentarse por pantalla, queden grabados en un 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 constantes son números enteros de una o más cifras. El espacio y el tabulador pueden estar presentes, pero no tienen ningún significado; los finales de línea tampoco son significativos (una expresión puede codificarse ocupando una o más líneas).

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

::= { + }


::= { * }

::= variable


| constante


| ( )

• 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 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("Análisis terminado:");

    System.out.println

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

   }

}

PARSER_END (ExprMin)

void unaExpresion() :

    { }

   {

       expresion()

   }

void expresion() :

   { }

  {

     termino() ( "+" termino() )*

  }

void termino() :

   { }

   {

       factor() ( "*" factor() )*

   }

void factor() :

    { }

    {

     

      |


      | "(" 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 el analizador:

- se ejecuta el generador: javacc Ejemplo.jj

- se compila el analizador generado: javac ExprMin.java

• Ejecución del analizador


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 un aná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 consulta de k símbolos por adelantado; si la gramática proporcionada cumple la condición LL(1), se genera un analizador sintáctico descendente-predictivo-recursivo. Más adelante se hacen algunas precisiones sobre esta afirmación.

Si la especificación léxico-sintáctica de un lenguaje codificada en JavaCC tiene dado (como indicativo que acompaña 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 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 primeros nombres citados no dependen del nombre de la especificación considerada, los otros nombres de ficheros se forman a partir del nombre dado a la especificación.


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

Sección de opciones


Sección de ejecución

Sección de sintaxis

Sección de lexicografía.


SITIO OFICIAL JAVACC