You are on page 1of 6

Práctica Lenguajes de Programación UN

UNIVERSIDAD NACIONAL DE COLOMBIA
Departamento de Ingeniería de Sistemas e Industrial
Lenguajes de Programación
Grupo 04
Felipe Restrepo Calle ferestrepoca@unal.edu.co

PRÁCTICA
Introducción a ANTLR

Contenido

1. Antecedentes
2. ¿Qué es ANTLR?
3. Instalación
4. Reglas (analizadores léxicos y sintácticos)
5. Ejemplo
6. ANTLRWorks


1. Antecedentes

Ya sea para ensamblador o para un lenguaje intermedio, el problema de escribir un compilador “a mano” es que hay que
realizar muchas tareas de forma repetitiva. Uno no puede evitar tener la impresión de que todo se podría automatizar
enormemente.

Debido a esta necesidad de automatización aparecieron las primeras herramientas de ayuda a la construcción de
procesadores de lenguajes. Lo que hacen estas herramientas es generar código en un lenguaje de programación (C, C++,
JAVA, etc.) para ahorrar al programador la parte repetitiva de la programación de compiladores, pudiendo éste
dedicarse al diseño.

Varias universidades construyeron herramientas de este tipo, pero fueron YACC y LEX las que más se han extendido. Al
principio de los 70, Stephen C. Johnson desarrolló YACC (Yet Another Compiler-Compiler) laboratorios Bell, usando un
dialecto portable del lenguaje C. YACC es una herramienta capaz de generar un analizador sintáctico en C a partir de una
serie de reglas de sintaxis que debe cumplir. Dichas reglas se especifican en un lenguaje muy sencillo. YACC se apoya en
la herramienta LEX para el análisis léxico. LEX fue desarrollada por Eric Schmidt. Esta herramienta también fue
desarrollada en C, y también genera un analizador en C. LEX y YACC sirvieron como base a FLEX y BISON, que se
consideran sus herederas. FLEX y BISON son dos productos de la FSF (Free Software Foundation).

Ahora el proceso de compilación está más formalizado; se admite ampliamente que es necesario crear un árbol de
sintaxis abstracta si se quiere realizar un análisis semántico correctamente. Es necesario crear y recorrer de una forma
estandarizada los árboles de sintaxis abstracta.

ANTLR es un software desarrollado en JAVA por varios individuos, aunque la idea inicial y las decisiones principales de
diseño son de Terence Parr. En su proyecto de grado, Terence presentaba una manera eficiente de implementar los
analizadores LL. Los hallazgos presentados en este proyecto fueron los que le llevaron a implementar PCCTS, que puede
considerarse como la “semilla” de ANTLR. PCCTS permite generar analizadores léxicos y sintácticos. Para recorrer los
árboles de sintaxis abstracta, se desarrolló un programa compañero llamado SORCERER. ANTLR ha sufrido varias
reescrituras completas desde su inicio, incluyendo el cambio del lenguaje de programación utilizado (inicialmente fue C)
y varios cambios de nombre. Mientras que FLEX y BISON son herramientas dedicadas a una sola fase del análisis, ANTLR
es capaz de actuar a tres niveles a la vez (cuatro si tenemos en cuenta la generación de código).

El uso de una sola herramienta para todos los niveles tiene varias ventajas. La más importante es la “estandarización”:
con ANTLR basta con comprender el paradigma de análisis una vez para poder implementar todas las fases de análisis.
Con FLEX+BISON es necesario comprender y saber utilizar herramientas completamente diferentes (FLEX está basada en
autómatas finitos deterministas y BISON en un analizador LALR), además de necesitar de otras herramientas para
realizar el análisis semántico.
Práctica Lenguajes de Programación UN




2. ¿Qué es ANTLR?

ANTLR es un generador de analizadores. Mucha gente llama a estas herramientas compiladores de compiladores, dado
que el ayudar a implementar compiladores es su uso más popular. ANTLR es una herramienta que integra la generación
de analizadores léxicos, sintácticos, árboles de sintaxis abstracta y evaluadores de atributos. ANTLR está escrito en Java y
genera: Java, C, C++, C#, Javascript, Python. Todos los detalles se encuentran en su página oficial http://www.antlr.org/.

Su funcionamiento básico es el siguiente:
- Se diseña un analizador léxico y un analizador sintáctico usando una gramática a partir de archivo(s) fuente
(escrito en una especificación propia).
- ANTLR genera el código fuente del analizador léxico y sintáctico correspondientes.

Características:
- ANTLR “ANother Tool for Language Recognition”
- Construcción automática de procesadores de lenguaje
- Genera código fuente en distintos lenguajes
- Permite incorporar acciones semánticas
- Multiplataforma
- Posee un entorno de desarrollo (ANTLWorks) y plugins para distintos IDEs.


3. Instalación

0. Si aún no está instalada, instalar la máquina virtual de JAVA (JVM versión 1.6 o superior)
a. En la consola, verificar que funcionan los comandos: java y javac
1. Descargar http://www.antlr.org/download/antlr-4.2-complete.jar
2. Guardar el archivo en una ubicación conveniente, por ejemplo: “C:\ANTLR”
3. Añadir la ruta al CLASSPATH:
a. Permanentemente: Propiedades del sistema -> Variables de entorno -> Variables del sistema ->
CLASSPATH -> Editar (es necesario reiniciar)
b. Temporalmente, escribiendo en consola:
SET CLASSPATH=.;C:\ANTLR\antlr-4.2-complete.jar;%CLASSPATH%
c. En consola, verificar que funciona:
Práctica Lenguajes de Programación UN
java org.antlr.v4.Tool

4. En la consola, ir al directorio donde vamos a trabajar “C:\ANTLR”
5. Ejecutar:
java -jar antlr-4.2-complete.jar


4. Estructura de un archivo fuente de ANTLR

Los archivos con los que trabaja ANTLR tienen la extensión *.g, y en adelante los llamaremos archivos de especificación
de gramáticas o, directamente, archivos de gramáticas. Éstos contienen la definición de uno o varios analizadores. Cada
uno de estos analizadores se traducirá a código nativo (JAVA, C++ o C#, dependiendo de ciertas opciones) en forma de
clases. Es decir, por cada analizador descrito en el archivo de gramáticas se generará una clase.

Todo archivo de gramática tiene la siguiente estructura:
grammar NombreGramática;

options {
/* opciones generales a todo el archivo */
}

@header {...}

@members {...}

Reglas

Tras grammar indicamos el nombre de la gramática, con ello fijamos el nombre que tendrán las correspondientes clases
del analizador léxico NombreGramática.java y sintáctico NombreGramáticaParser.java (si estamos usando JAVA como
lenguaje de salida).

Options: es la zona de opciones generales. Es opcional. Permite controlar algunos parámetros de ANTLR mediante
“opciones”. Las opciones se representan como asignaciones : nombreOpcion=valor;. Se utilizan mucho en ANTLR. Las
opción más importante de esta zona es la que permite elegir el lenguaje nativo en el que se generarán los analizadores
(JAVA, C++, C#). Su valor por defecto es “JAVA”. Tras las opciones generales del fichero vienen las definiciones de
analizadores. Es muy común que en un mismo fichero se especifiquen varios analizadores. Sin embargo, también es
posible definir cada analizador en un fichero, sobre todo cuando se trata de analizadores extensos.

@header es una zona opcional (puede aparecer o no). Delimitada por las partículas “header {” y “}”. Aquí se incluyen los
elementos en código nativo (JAVA, C++ o C#) que deben preceder a la definición de las diferentes clases de los
analizadores. Esta sección se utiliza para incluir otros ficheros (import e #include), definir el paquete al que pertenecerá
la clase del analizador (package) etc.

Por otra parte, @members permite insertar atributos y métodos definidos por el usuario en esa clase.

La especificación de las reglas se hace con notación gramatical, de la siguiente forma:
ANTECEDENTE : CONSECUENTE;

ANTLR se ha diseñado para incluir las especificaciones léxica y sintáctica tanto juntas como separadas. El caso de tener
ambas especificaciones juntas, se cumple que si el antecedente está escrito en mayúsculas, ANTLR lo interpretará como
una regla léxica. Sin embargo, si el antecedente está escrito en minúsculas, ANTLR lo interpretará como una regla
sintáctica.

Para ANTLR las minúsculas se asocian a los símbolos no terminales y las mayúsculas a los terminales. Cuando se trabaja
con las especificaciones separadas, hay que definir la gramática léxica y la gramática sintáctica. Para la gramática léxica
es necesario introducir en el archivo que contenga dicha especificación lexer gramar NombreArchivo. Esta sentencia
indica a ANTLR que se trata de una especificación léxica. En la especificación sintáctica hay que incluir solamente
grammar Nombre, para indicar que se trata de una especificación sintáctica. Además, es necesario importar la
especificación léxica correspondiente.
Práctica Lenguajes de Programación UN
5. Salida ANTLR

Cuando se ejecutamos ANTLR con el comando: java –jar antlr-4.2-complete.jar NOMBRE_ARCHIVO_PRUEBA.g, se crean
como resultado los archivos: PruebaLexer.java y PruebaParser.java (en el caso que se esté usando JAVA), que
corresponden al código fuente del analizador léxico y sintáctico, respectivamente.

Para poder ejecutar el analizador hay que añadir un método “main” a la clase del analizador. A continuación se muestra
una plantilla para dicho método:

import org.antlr.v4.runtime.*;

public class MiAnalizador {

public static void main(String args[])
{
try{
/*
Atención reemplaza XXXX por el nombre de tu gramática
Este programa funcionaría para una gramática llamada XXXX.g
*/
// Crear el objeto correspondiente al analizador léxico
// Asignar el archivo de entrada al analizador léxico
XXXXLexer analex =
new XXXXLexer(new ANTLRFileStream(args[0]));
// Identificar al analizador léxico como fuente de tokens para
// el sintactico
CommonTokenStream tokens = new CommonTokenStream(analex);
// Crear el objeto correspondiente al analizador sintáctico
XXXXParser anasint = new XXXXParser(tokens);
/* Comenzar el análisis llamando al axioma de la gramática
Atención, sustituye AXIOMA por el nombre del axioma de tu
gramática
*/
anasint.AXIOMA();
}catch (java.io.IOException fnfe){
System.err.println("No se encontró el archivo");
}
}
}

Compilando estos 3 archivos se tiene como resultado el analizador completo que admite un archivo de entrada desde la
línea de comandos, lo procesa y emite los mensajes de error correspondientes (en caso que sea necesario).

6. Reglas (analizadores léxicos y sintácticos)

 Símbolos léxicos: comienzan con mayúscula
 Símbolos auxiliares (no terminales): comienzan con minúscula
 Comentarios:
o // Una línea
o /* varias
líneas */
 Expresiones regulares:
o Literales entre comillas simples p.e. ‘a’
o Rangos: ‘a’..’z’
o Negación: ~x
o Alternativas (o): |
o 0 o más ocurrencias: *
o 1 o más ocurrencias: +
o 0 o 1 ocurrencia: ?

Práctica Lenguajes de Programación UN

 Reglas:
o <símbolo léxico o auxiliar> : <definición1>
| <definición2>
| <definición_i>
;

 Reglas sintácticas en EBNF (Extended Backus-Naur Form): Se permite +, *, ? en las partes derechas de las
reglas.


7. Ejemplo

a. Archivo “Expr.g”:

grammar Expr;

// REGLAS SINTACTICAS

expr : term ( (MAS | MENOS) term)*
{ System.out.println("Análisis terminado.\n");
};

term : factor ( (MULT | DIV) factor)*;

factor : ENTERO;


// TOKENS

MAS : '+';
MENOS : '-';
MULT : '*';
DIV : '/';

// REGLAS LEXICAS

ENTERO :('0'..'9')+;

ESPACIO: ( ' '
| '\t'
| '\r'
| '\n'
)+ -> channel(HIDDEN)
;


b. Generar el código fuente del analizador léxico y sintáctico

>java -jar antlr-4.2-complete.jar Expr.g

c. Archivo MiExpr.java (main)

import org.antlr.v4.runtime.*;
public class MiExpr {
public static void main(String args[]) {
try {
ExprLexer analex = new ExprLexer(new ANTLRFileStream(args[0]));
CommonTokenStream tokens = new CommonTokenStream(analex);
ExprParser anasint = new ExprParser(tokens);
anasint.expr();
} catch (java.io.IOException fnfe) {
System.err.println("No se encontró el archivo");
}
}
}

Práctica Lenguajes de Programación UN
d. Compilar

>javac ExprLexer.java ExprParser.java MiExpr.java

e. Archivo entrada.txt

23+3 -9 *3

f. Probar

>java MiExpr entrada.txt


8. ANTLRWorks

Hacer lo mismo usando y explorando las características del entorno de desarrollo ANTLRWorks.