Está en la página 1de 6

Procesadores del Lenguaje

Prctica 1: Ejemplo sencillo



ANTLR es una herramienta que integra la generacin de analizadores lxicos,
sintcticos, rboles de sintaxis abstracta y evaluadores de atributos. ANTLR est escrita en
Java y genera Java, C++ y C#. Todos los detalles de esta herramienta se encuentran en su
pgina oficial http://www.antlr.org/.
En esta prctica trabajaremos con un lenguaje muy sencillo, que nos servir para
presentar la notacin que usa ANTLR para la especificacin de analizadores lxicos y
sintcticos. Aunque haremos algunas modificaciones sobre la solucin propuesta en el
enunciado, no ser hasta las prcticas 2 y 3 cundo estudiemos en profundidad los
problemas asociados a los analizadores lxicos y sintcticos. Todas las herramientas
necesarias para realizar la prctica estn instaladas en las aulas de laboratorio.

Un lenguaje ejemplo

El siguiente fragmento muestra el fichero de configuracin de un determinado
sistema. El lenguaje es extremadamente simple y slo permite asociar valores numricos a
una serie de variables:

max_robots = 50;
tiempo_combate = 120;
municion = 512;
max_ataques = 200;

Especificacin del analizador

ANTLR permite especificar cada analizador (lxico, sintctico, semntico) en un
fuente independiente o en un nico fuente. En este primer ejemplo optaremos por utilizar
un solo fuente. A medida que los analizadores sean ms complejos ser recomendable
especificar cada uno por separado. El analizador para nuestro lenguaje tendra un aspecto
como este en ANTLR:

///////////////////////////////
// Analizador lxico /////
//////////////////////////

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 sintctico
///////////////////////////////

class Anasint extends Parser;
entrada : (asignacion)* ;
asignacion : IDENT "=" NUMERO ";" ;

La estructura de un fichero fuente ANTLR

Los ficheros de gramticas tienen la siguiente estructura:

header{
/* cdigo de cabecera */
}
options{
/* opciones comunes a toda la especificacin */
}
//////////////////////////////
// Definicin de analizadores
//////////////////////////////
...

Las dos primeras secciones son opcionales. La seccin header sirve para incluir
cdigo de cabecera, fundamentalmente instrucciones import o definicin del paquete al
que pertenecer la clase del analizador. La seccin options permite configurar algunos
aspectos de ANTLR a travs de opciones, que se representan mediante asignaciones del
tipo nombre_opcion = valor;. Tras estas secciones se incluye la definicin de los
analizadores, ANTLR permite especificar todos los analizadores en un nico fuente o
dedicar un fichero independiente para cada uno. La definicin de un analizador sigue la
siguiente estructura:

class nombre_analizador extends tipo_analizador;
options {
/* opciones especficas del analizador */
}
tokens {
/* definicin de tokens */
}
{
/* cdigo propio del analizador */
}

//---------------------------
// Zona de reglas
//---------------------------
...




donde:

La primera instruccin sirve para establecer cual ser el nombre del analizador y de qu
clase heredar (tipo_analizador). En el caso de analizadores lxicos se extender la
clase Lexer, para los sintcticos se usar Parser y TreeParser para los recorridos
de rboles de sintaxis abstracta.
La seccin options ser opcional y servir para especificar opciones propias del
analizador. Se puede, por ejemplo, definir el nmero de smbolos de anticipacin en el
reconocimiento LL(k), importar tokens, etc.
La seccin tokens tambin es opcional, permite definir nuevos tokens que se aaden a
los definidos en otros analizadores.
La zona de cdigo nativo sirve para incluir declaraciones de atributos y mtodos que se
aaden a las que de forma automtica se generan para la clase que implementa el
analizador.
Por ltimo la zona de reglas constituye el ncleo de la especificacin. En los ejemplos
previos ya hemos mostrado el aspecto que tienen estas reglas.
Los comentarios se pueden incluir en cualquier parte del fuente, permitindose
comentarios de una sola lnea (con el smbolo //) y de varias lneas (con los smbolos /*
y */ para marcar el comienzo y final respectivamente).

Ejecutando el intrprete

Hasta ahora hemos especificado los distintos analizadores, pero an nos queda por
escribir un ltimo fuente para poder ejecutarlos, el que describe la clase que contiene el
mtodo 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 cdigo es bastante claro y en general se limita a:
Abrir el fichero "entrada.txt".
Crear un objeto de cada analizador.
Lanzar el mtodo anasint.entrada()para realizar el anlisis sintctico.
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 anlisis lxico (en nuestro
ejemplo Analex) es la encargada de recibir ese flujo de entrada y su constructor puede
recibir tanto 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 cmo StringReader (una subclase de Reader) nos
permitir aplicar el anlisis lxico al contenido de una cadena de caracteres que a su vez ha
sido leda 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) {

System.err.println(ioe.getMessage());
}
}
}

Los aspectos ms 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 lnea a lnea.
La entrada del teclado se lee lnea a lnea en la variable linea en un bucle que se repite
hasta que se introduce $, el carcter elegido para indicar el fin del proceso.
Para analizar el contenido de la variable lnea basta con crear a partir de ella un flujo de
entrada con el constructor StringReader. Dicho flujo se utilizar en la construccin del
analizador lxico.

EJERCICIOS

1. Compilar los fuentes presentados en el enunciado y comprobar el funcionamiento del
reconocedor de expresiones propuesto.

2. Modificar la clase principal de manera que en lugar de leer siempre del fichero
"entrada.txt" reciba el nombre del fichero a procesar a travs del parmetro
args[0] del mtodo main.

3. Adaptar el reconocedor de manera que la entrada se lea del teclado y no de un fichero. La
entrada se procesar lnea a lnea y por tanto no ser necesario tener en cuenta el smbolo
";" como separador. El proceso terminar cuando se introduzca la entrada $. Ante
entradas correctas el intrprete no emitir ningn mensaje mientras que para entradas
incorrectas se mostrar el mensaje de error generado por ANTLR.
Se detecta bien una entrada incorrecta de la forma max_robots = 12 12?
Cmo se puede solucionar este problema?


4. Ampliar el lenguaje del apartado 2 con los siguientes elementos:

Valores tipo booleano (true, false), cadenas y rutas de ficheros (siempre empiezan con
"/"):
disparo_efectuado = TRUE;
directorio_ficheros_cfg_robots = /home/robot/work;
mensaje = "el robot ha hecho blanco";

Variables de usuario definidas con la palabra instruccin SET, los nombres empezarn
con "$":

SET $nombre_robot = Legolas;

5. Ampla el lenguaje anterior de manera con una instruccin condicional if, que permita
decidir si se ejecuta una parte del fichero en funcin del valor de una variable booleana
(predefinida o de usuario):

SET $multi_robot = TRUE;
IF ($multi_robot) {
max_robots = 10;
}

También podría gustarte