Otra Herramienta para el Reconocimiento de Lenguaje

3 02 2011

ANTLR significa “ANother Tools for Language Recognition”, que  significa  es “Otra Herramienta para el Reconocimiento de Lenguaje”. Esta realiza los análisis: léxico, sintáctico y semántica  para seguidamente generar seguidamente el código intermedio,permitiendo optimizar el código intermedio.

Además genera un programa que determina si una sentencia o palabra pertenece a dicho lenguaje, utilizando algoritmos LL(*) de parsing. Si a dicha gramática, se le añaden acciones escritas en un lenguaje de programación, el reconocedor se transforma en un traductor o intérprete.

Los ficheros con los que trabaja ANTLR tienen la terminación *.g, y en adelante los llamaremos ficheros de especificación de gramáticas o, directamente, ficheros de gramáticas.

ANTLR es un proyecto bajo licencia BSD, viniendo con todo el código fuente disponible, y preparado para su instalación bajo plataformas Linux, Windows y Mac OS X.

Ejemplo:

El siguiente fragmento muestra el fichero de configuración de un determinado sistema. El lenguaje es extremadamente simple y sólo permite asociar valores numéricos a una serie de variables:

max_users = 50;

time_out = 120;

memory = 512;

max_sessions = 200;

Especificación del analizador

En este primer ejemplo optaremos por utilizar un único fuente aunque a medida que los analizadores sean más complejos será recomendable especificar cada uno por separado. El analizador para nuestro lenguaje tendría un aspecto como este en ANTLR:

///////////////////////////////

// Analizador léxico

///////////////////////////////

class Analex extends Lexer;

BLANCO: (‘ ‘|’\t’|”\r\n”) {$setType(Token.SKIP);};

protected LETRA : (‘a’..’z’)|’_’;

protected DIGITO : ‘0’..’9′;

NUMERO : (DIGITO)+;

IDENT : LETRA(LETRA|DIGITO)*;

SEPARADOR: ‘;’;

OPERADOR: ‘=’;

///////////////////////////////

// Analizador sintáctico

///////////////////////////////

class Anasint extends Parser;

entrada : (asignacion)* ;

asignacion : IDENT “=” NUMERO “;” ;

La estructura de un fuente ANTLR

Los ficheros de gramáticas tienen la siguiente estructura:

header{

/* código de cabecera */

}

options{

/* opciones comunes a toda la especificación */

}

//////////////////////////////

// Definición de analizadores

//////////////////////////////

Las dos primeras secciones son opcionales. La sección header sirve para incluir código de cabecera, fundamentalmente instrucciones import o definición del paquete al que pertenecerá la clase del analizador. La sección options permite configurar algunos aspectos de ANTLR a través de opciones, que se representan mediante asignaciones del tipo nombre_opcion = valor;. Tras estas secciones se incluye la definición de los analizadores, ANTLR permite especificar todos los analizadores en una única fuente o dedicar un fichero independiente para cada uno.

La definición de un analizador sigue la siguiente estructura:

class nombre_analizador extends tipo_analizador;

options {

/* opciones específicas del analizador */

}

tokens {

/* definición de tokens */

}

{

/* código propio del analizador */

}

//—————————

// Zona de reglas

//—————————

Donde:

La primera instrucción sirve para establecer cual será el nombre del analizador y de qué clase heredará (tipo_analizador). En el caso de analizadores léxicos se extenderá la clase Lexer, para los sintácticos se usará Parser y TreeParser para los recorridos de árboles de sintaxis abstracta.

La sección options será opcional y servirá para especificar opciones propias del analizador. Se puede, por ejemplo, definir el número de símbolos de anticipación en el reconocimiento LL(k), importar tokens, etc.

La sección tokens también es opcional, permite definir nuevos tokens que se añaden a los definidos en otros analizadores.

La zona de código nativo sirve para incluir declaraciones de atributos y métodos que se añaden a las que de forma automática se generan para la clase que implementa el analizador.

Por último la zona de reglas constituye el núcleo de la especificación. En los ejemplos previos ya hemos mostrado el aspecto que tienen estas reglas.

Los comentarios se pueden incluir en cualquier parte del fuente, permitiéndose comentarios de una sola línea (con el símbolo //) y de varias líneas (con los símbolos /* y */ para marcar el comienzo y final respectivamente).

Ejecutando el intérprete

Hasta ahora hemos especificado los distintos analizadores, pero aún nos queda por escribir un último fuente para poder ejecutarlos, el que describe la clase que contiene el

método main:

/////////////////////////////////////

// Procesador.java (clase principal)

/////////////////////////////////////

import java.io.*;

import antlr.collections.AST;

import antlr.ANTLRException;

public class Procesador {

public static void main(String args[]) {

try {

FileInputStream fis =

new FileInputStream(“entrada.txt”);

Analex analex = null;

Anasint anasint = null;

analex = new Analex(fis);

anasint = new Anasint(analex);

anasint.entrada();

}catch(ANTLRException ae) {

System.err.println(ae.getMessage());

}catch(FileNotFoundException fnfe) {

System.err.println(“No se encontró el fichero”);

}

}

}

El código es bastante claro y en general se limita a:

  • Abrir el fichero “entrada.txt“.
  • Crear un objeto de cada analizador.
  • Lanzar el método anasint.entrada() para realizar el análisis sintáctico.
  • Capturar las distintas excepciones que se hayan podido lanzar durante el proceso.

Lectura de flujos de bytes y flujos de caracteres

Los reconocedores generados por ANTLR pueden adaptarse con facilidad para leer desde distintos flujos de entrada. La clase que implementa el análisis léxico (en nuestro ejemplo Analex) es la encargada de recibir ese flujo de entrada y su constructor puede recibir tantos objetos de la clase InputStream para recibir flujos de bytes, como de la clase Reader para recibir flujos de caracteres.

Como ya hemos visto en el ejemplo anterior, FileInputStream (una subclase de InputStream) nos sirve para procesar entradas almacenadas en un fichero. En el siguiente ejemplo veremos cómo StringReader (una subclase de Reader) nos permitirá aplicar el análisis léxico al contenido de una cadena de caracteres que a su vez ha sido leída desde el teclado:

/////////////////////////////////////

// Procesador.java (clase principal)

/////////////////////////////////////

import java.io.*;

import antlr.collections.AST;

import antlr.ANTLRException;

public class Procesador {

public static void main(String args[]) {

try {

InputStreamReader isr =

new InputStreamReader(System.in);

BufferedReader br = new BufferedReader(isr);

String linea = br.readLine();

while (!linea.equals(“$”)) {

Analex analex = null;

Anasint anasint = null;

analex = new Analex(new StringReader(linea));

anasint = new Anasint(analex);

anasint.asignacion();

linea = br.readLine();

}

}catch(ANTLRException ae) {

System.err.println(ae.getMessage());

}catch(IOException ioe) {

Los aspectos más interesantes de este programa son:

Se construye el flujo de caracteres isr aplicando InputStreamReader sobre el flujo de bytes System.in.

A partir del flujo isr se obtiene br, un flujo de caracteres con buffer (BufferedReader) que puede leerse línea a línea.

La entrada del teclado se lee línea a línea en la variable linea en un bucle que se repite hasta que se introduce $, el carácter elegido para indicar el fin del proceso.

Para analizar el contenido de la variable línea basta con crear a partir de ella un flujo de entrada con el constructor StringReader. Dicho flujo se utilizará en la construcción del analizador léxico.

Ejemplo de aplicación:

En el ejemplo siguiente se describe un programa de análisis en ANTLR, que puede reconocer expresiones de la suma en la forma “1+2+3”:

opciones generales de //, por ejemplo la opción de la lengua

objetivo

{

LENGUA = “CSharp”;

}

// que sigue que la clase

SumParser del programa de análisis amplía programa de análisis;

opción

{

k = 1;

}

definición de // de una declaración

de la expresión: NÚMERO ENTERO (NÚMERO ENTERO DE PLUS^) *;

// aquí la clase

SumLexer de Lexer amplía Lexer;

opción

{

k = 1;

}

MÁS    : ‘+’;

DÍGITO   : (“0”… “9”);

NÚMERO ENTERO: (DÍGITO) +;

El listado siguiente demuestra la llamada de los programas de análisis en un programa:

Lector del lector del texto;

el lector del texto de // (…) con indicaciones llena

SumLexer más lexer = SumLexer nuevo (lector);

SumParser más programa de análisis = SumParser nuevo (más lexer);

parser.expression ();

ANTLRWorks es un entorno de desarrollo con interfaz gráfica que permite el desarrollo de gramáticas para la versión 3.0 o superior de ANTLR. Consiste en una aplicación independiente Java, que se puede ejecutar directamente desde un jar. De quererse incorporar las funcionalidades de ANTLR en ambientes de desarrollo ya existentes, existen plug-ins que se pueden bajar directamente de la web del autor, habilitando el poder trabajar en IntelliJ, gUnit, Eclipse, NetBeans, etc.

VIDEO  ILUSTRATIVO

Fuente: Sitio oficial, Pluing

Documentos: Leer, Ocio

 


Actions

Information

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s




%d bloggers like this: