100% encontró este documento útil (3 votos)
802 vistas23 páginas

Tutorial ANTLR

Este documento presenta una introducción al uso de ANTLR v4 para la generación de analizadores. Explica brevemente los antecedentes de herramientas como YACC y LEX, y define ANTLR como un generador de analizadores que puede crear analizadores léxicos, sintácticos y semánticos. Luego describe la estructura de árboles sintácticos generados por ANTLR v4 y los mecanismos de listeners y visitors para recorrer dichos árboles y ejecutar acciones semánticas.
Derechos de autor
© © All Rights Reserved
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como PDF, TXT o lee en línea desde Scribd
100% encontró este documento útil (3 votos)
802 vistas23 páginas

Tutorial ANTLR

Este documento presenta una introducción al uso de ANTLR v4 para la generación de analizadores. Explica brevemente los antecedentes de herramientas como YACC y LEX, y define ANTLR como un generador de analizadores que puede crear analizadores léxicos, sintácticos y semánticos. Luego describe la estructura de árboles sintácticos generados por ANTLR v4 y los mecanismos de listeners y visitors para recorrer dichos árboles y ejecutar acciones semánticas.
Derechos de autor
© © All Rights Reserved
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como PDF, TXT o lee en línea desde Scribd
Está en la página 1/ 23

Tutorial ANTLR v4

Felipe Restrepo Calle


Profesor Asistente
ltima actualizacin: 13/03/2016
[email protected]

Contenido
Tutorial ANTLR v4 .....................................................................................................................1
1. Antecedentes.....................................................................................................................2
2. Qu es ANTLR? .............................................................................................................3
3. rboles sintcticos en ANTLR v4....................................................................................4
4. Aplicaciones en el mundo actual ......................................................................................7
5. Instalacin .........................................................................................................................7
6. Estructura de un archivo fuente de ANTLR (especificacin de la gramtica) .................9
7. Reglas (analizadores lxicos y sintcticos) ....................................................................10
8. Salida ANTLR v4 ...........................................................................................................11
9. Probar el analizador generado ........................................................................................11
10. Ejemplos .......................................................................................................................16
11. Recursos adicionales (recomendados) ..........................................................................23
12. Referencias ...................................................................................................................23

Carrera 30 No. 45-03, FACULTAD DE INGENIERA, Edificio 453 Oficina 101,


Telefax: Conmutador: (57-1) 316 5000 Ext. 14011 Fax: 14014.
Correo electrnico: [email protected] / Bogot, Colombia, Sur Amrica

1. Antecedentes
Ya sea para ensamblador, un lenguaje intermedio, o un lenguaje de programacin de alto nivel, al escribir un compilador
a mano debemos realizar muchas tareas de forma repetitiva. Todo este proceso se pude automatizar enormemente
utilizando herramientas de software.
Debido a la necesidad de automatizacin aparecieron, desde los aos 70, las primeras herramientas de ayuda a la
construccin de procesadores de lenguajes. Lo que hacen estas herramientas es generar cdigo en un lenguaje de
programacin (C, C++, JAVA, etc.) para ahorrar al programador la parte repetitiva de la programacin de compiladores,
pudiendo ste dedicarse al diseo del lenguaje y de las aplicaciones de procesamiento de lenguaje.
Varias universidades construyeron herramientas de este tipo, pero fueron YACC y LEX las que ms 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 sintctico 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 anlisis lxico. LEX fue desarrollada por Eric Schmidt. Esta herramienta tambin fue desarrollada
en C, y tambin 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 que el proceso de compilacin est ms formalizado; se admite ampliamente que es necesario crear un rbol de
sintaxis abstracta si se quiere realizar un anlisis semntico correctamente. Es necesario crear y recorrer de una forma
estandarizada los rboles de sintaxis abstracta.
ANTLR es un software desarrollado en JAVA por varios desarrolladores, aunque la idea inicial y las decisiones principales
de diseo son de Terence Parr. En su proyecto de grado, Terence presentaba una manera eficiente de implementar los
analizadores sintcticos 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 lxicos y sintcticos. Para
recorrer los rboles de sintaxis abstracta, se desarroll un programa llamado SORCERER. ANTLR ha sufrido varias
reescrituras completas desde su inicio, incluyendo el cambio del lenguaje de programacin utilizado (inicialmente fue C) y
varios cambios de nombre. Mientras que FLEX y BISON son herramientas dedicadas a una sola fase del anlisis (anlisis
lxico y sintctico, respectivamente), ANTLR es capaz de actuar a tres niveles a la vez: anlisis lxico, sintctico y
semntico (cuatro si tenemos en cuenta la generacin de cdigo).
El uso de una sola herramienta para todos los niveles tiene varias ventajas. La ms importante es la estandarizacin:
con ANTLR basta con comprender el paradigma de anlisis una vez para poder implementar todas las fases de anlisis.
Con FLEX+BISON es necesario comprender y saber utilizar herramientas completamente diferentes. FLEX est basada en
autmatas finitos deterministas y BISON en un analizador LALR(1).

Carrera 30 No. 45-03, FACULTAD DE INGENIERA, Edificio 453 Oficina 101,


Telefax: Conmutador: (57-1) 316 5000 Ext. 14011 Fax: 14014.
Correo electrnico: [email protected] / Bogot, Colombia, Sur Amrica

2. Qu es ANTLR?
ANTLR (ANother Tool for Language Recognition) es un generador de analizadores. Mucha gente llama a estas
herramientas compiladores de compiladores, dado que el ayudar a implementar compiladores es su uso ms popular.
ANTLR es una herramienta que integra la generacin de analizadores lxicos, sintcticos, rboles de sintaxis abstracta y
evaluadores de atributos. ANTLR est escrito en Java y genera: Java, C#, Javascript, Python2, Python3 (prximamente
C++). Todos los detalles se encuentran en su pgina oficial: http://www.antlr.org/
Su funcionamiento bsico es el siguiente:
Se disea un analizador lxico y un analizador sintctico usando una gramtica descrita en un archivo de
especificacin (escrito con la sintaxis propia de ANTLR).
ANTLR genera el cdigo fuente del analizador lxico y sintctico correspondientes.

Caractersticas:

ANTLR ANother Tool for Language Recognition


Construccin automtica de procesadores de lenguaje
Genera el cdigo fuente de analizadores en distintos lenguajes que pueden no slo realizar el anlisis, sino
tambin construir rboles de derivacin de forma automtica. Tambin pueden generar tree walkers que son
estructuras que se usan para visitar los nodos de los rboles sintcticos y ejecutar cdigo especfico de la
aplicacin cuando se visita alguno de los nodos del rbol.
Permite incorporar acciones semnticas independientes de las gramticas.
Multiplataforma
Posee un entorno de desarrollo (ANTLWorks) y plug-ins para distintos IDEs.

Carrera 30 No. 45-03, FACULTAD DE INGENIERA, Edificio 453 Oficina 101,


Telefax: Conmutador: (57-1) 316 5000 Ext. 14011 Fax: 14014.
Correo electrnico: [email protected] / Bogot, Colombia, Sur Amrica

Importante: ANTLR v4 genera analizadores LL(*) Adaptativos ALL(*). Gracias a esto, ANTLR v4 se ha llamado a ANTLR v4
como la versin Honey Badger en honor a ese curioso animal. It takes whatever grammar you give it; it doesnt give a
damn!
Ver video: The Crazy Nastyass Honey Badger - http://www.youtube.com/watch?v=4r7wHMg5Yjg

3. rboles sintcticos en ANTLR v4


A continuacin se presenta un ejemplo de un rbol sintctico generado por ANTLR v4 (con los nombres de las clases):

Carrera 30 No. 45-03, FACULTAD DE INGENIERA, Edificio 453 Oficina 101,


Telefax: Conmutador: (57-1) 316 5000 Ext. 14011 Fax: 14014.
Correo electrnico: [email protected] / Bogot, Colombia, Sur Amrica

Observe que las hojas del rbol corresponden a nodos terminales y los dems nodos corresponden a alguna regla de
produccin de la gramtica. Estos ltimos objetos se conocen en ANTLR v4 como contextos (context) porque almacenan
todo lo que sabemos del reconocimiento de una frase por una regla particular de la gramtica. Cada contexto conoce su
token inicial y final para la frase y proporciona acceso a todos los elementos de esa frase. Por ejemplo, AssignContext
(Assign: ID TK_EQUAL expr) proporciona los mtodos: ID() y expr() para acceder al nodo identificador y el subrbol de la
expresin.
Con esta estructura de datos podramos implementar a mano nuestros algoritmos para recorrer el rbol sintctico en
profundidad y programar las acciones requeridas durante el anlisis, las cuales sern ejecutadas a medida que se vayan
visitando los nodos del rbol. Sin embargo, para evitar tener que escribir estos mtodos cada vez que implementemos un
procesador de lenguaje, ANTLR proporciona sus propios mecanismos para hacer esto por nosotros, mediante dos
patrones de diseo: Listeners y Visitors.

Parse-tree Listeners
Por defecto, ANTLR genera una interfaz para un parse-tree listener que responde a los eventos desencadenados por el
objeto que recorre el rbol sintctico (walker). Los Listeners son como los objetos manejadores de documentos SAX
(Simple API for XML) para los analizadores de XML. Estos reciben una notificacin de eventos como startDocument() y
endDocument() y ejecutan las acciones correspondiente. Los mtodos de un Listener son simplemente callbacks que
responden a eventos que ocurren al recorrer el rbol sintctico. Pueden ser comparados con los mtodos que
implementamos para responder a un evento de click en un botn de una aplicacin con interfaz grfica (GUI).
Para recorrer el rbol y por ende desencadenar las llamadas a los mtodos del Listener, ANTLR proporciona la clase
ParseTreeWalker. Para implementar una aplicacin, necesitamos desarrollar una implementacin de ParseTreeListener
que contenga el cdigo especfico de la aplicacin. ANTLR genera automticamente una subclase de ParseTreeListener
para cada gramtica especfica con los mtodos enter y exit para cada regla. Cuando el walker llega al nodo para la regla
Assign, se dispara el evento enterAssign(), el cual recibe como parmetro toda la informacin almacenada en ese
contexto (AssignContext). Asimismo, despus de que el walker ha visitado todos los hijos del nodo assign, se dispara el
evento exitAssign().

Carrera 30 No. 45-03, FACULTAD DE INGENIERA, Edificio 453 Oficina 101,


Telefax: Conmutador: (57-1) 316 5000 Ext. 14011 Fax: 14014.
Correo electrnico: [email protected] / Bogot, Colombia, Sur Amrica

A continuacin se presenta toda la secuencia de mtodos desencadenados por el walker para la sentencia de ejemplo
(sp=100;):

Lo mejor de este mecanismo de Listeners es que todo funciona automticamente. No tenemos que implementar el
walker, y nuestros mtodos de los Listeners no tienen que visitar explcitamente a sus hijos. ANTLR proporciona esto.

Parse-tree Visitors
Sin embargo, en algunas situaciones queremos controlar el recorrido del rbol, llamando a los mtodos para visitar a los
hijos de algn nodo de forma explcita. En este caso debemos usar la opcin de ANTLR visitor en la lnea de
comandos. Esta opcin hace que ANTLR genere una interface de Visitor a partir de una gramtica, la cual contiene un
mtodo visit() por cada una de las reglas. A continuacin se puede ver el patrn de diseo visitor operando en nuestro
rbol sintctico:

Para dar inicio al recorrido del rbol, nuestra aplicacin crear una implementacin del visitor y llamar al mtodo visit()
de la raz del rbol (regla inicial de la gramtica).

Carrera 30 No. 45-03, FACULTAD DE INGENIERA, Edificio 453 Oficina 101,


Telefax: Conmutador: (57-1) 316 5000 Ext. 14011 Fax: 14014.
Correo electrnico: [email protected] / Bogot, Colombia, Sur Amrica

ParseTree tree = ... ; // tree is result of parsing


MyVisitor v = new MyVisitor();
v.visit(tree);

Al hacer esto, ANTLR al ver la regla inicial de la gramtica, llamar al mtodo visitStat(). A partir de aqu, la
implementacin de visitStat(), llamar al mtodo visit() de los nodos hijos para continuar el recorrido del rbol. Tambin
se pueden llamar los mtodos explcitamente de la forma visitAssign().

4. Aplicaciones en el mundo actual

Las bsquedas en Twitter usan ANTLR para parsear las consultas (ms de 2 millones de consultas al da).
Oracle utiliza ANTLR dentro del IDE SQL Developer y sus herramientas de migracin.
El IDE NetBeans analiza C++ con ANTLR.
Los lenguajes de Apache Hive, Apache Pig, y en general, los sistemas de bodegas de datos de Hadoop, todos
utilizan ANTLR.
Lex Machina1 utiliza ANTLR para la extraccin de informacin de textos legales.
El lenguaje HQL en el Hibernate object-relational mapping framework est construido con ANTLR.
Entorno de endurecimiento automtico de cdigo fuente SHE.
Muchos ms.

5. Instalacin
0.

1.
2.
3.

Si an no est instalada, instalar la mquina virtual de JAVA (JVM versin 1.6 o superior)
a. En la consola, verificar que funcionan los comandos: java y javac. Si no, incluir en la variable de
entorno PATH, el directorio donde estn dichos programas.
Descargar la versin ms reciente de ANTLR (Complete ANTLR 4.5.X Java binaries jar) desde
http://www.antlr.org/download.html
Guardar el archivo en una ubicacin conveniente, por ejemplo: C:\apps\ANTLR (sin espacios en blanco)
Aadir la ruta al CLASSPATH:
Windows:
a. Permanentemente:
Propiedades del sistema -> Variables de entorno -> Variables del sistema
->
CLASSPATH
->
Editar:
adicionar
.;C:\apps\ANTLR\antlr-4.5.2complete.jar (es necesario reiniciar la consola)

IMPORTANTE: No olvidar el . al principio de la cadena anterior. Sirve para configurar el


directorio actual dentro del CLASSPATH.

Carrera 30 No. 45-03, FACULTAD DE INGENIERA, Edificio 453 Oficina 101,


Telefax: Conmutador: (57-1) 316 5000 Ext. 14011 Fax: 14014.
Correo electrnico: [email protected] / Bogot, Colombia, Sur Amrica

b.

Temporalmente, escribiendo en consola:


SET CLASSPATH=.;C:\apps\ANTLR\antlr-4.5.2-complete.jar;%CLASSPATH%

Unix:
a. Ejecutar el siguiente comando desde consola o adicionarlo al script de inicio del shell (.bash_profile):
$ export CLASSPATH=".:/usr/local/lib/antlr-4.5.2-complete.jar:$CLASSPATH"

4.

En consola, verificar que funciona:


java org.antlr.v4.Tool
Deber aparecer lo siguiente:
ANTLR Parser Generator Version 4.5.2
-o ___
specify output directory where all output is generated
-lib ___
specify location of grammars, tokens files
-atn
generate rule augmented transition network diagrams
-encoding ___
specify grammar file encoding; e.g., euc-jp
-message-format ___ specify output style for messages in antlr, gnu, vs2005
-long-messages
show exception details when available for errors and warnings
-listener
generate parse tree listener (default)
-no-listener
don't generate parse tree listener
-visitor
generate parse tree visitor
-no-visitor
don't generate parse tree visitor (default)
-package ___
specify a package/namespace for the generated code
-depend
generate file dependencies
-D<option>=value
set/override a grammar-level option
-Werror
treat warnings as errors
-XdbgST
launch StringTemplate visualizer on generated code
-XdbgSTWait
wait for STViz to close before continuing
-Xforce-atn
use the ATN simulator for all predictions
-Xlog
dump lots of logging info to antlr-timestamp.log

Si no funciona correctamente, verifique la instalacin antes de continuar. Vuelva al paso 0.


5.

En la consola, ir al directorio donde vamos a trabajar. Por ejemplo: C:\workspace


a. Ejecutar y verificar que funciona nuevamente:
java -jar C:\apps\ANTLR\antlr-4.5.2-complete.jar
Debe aparecer lo mismo que en la prueba anterior.

Carrera 30 No. 45-03, FACULTAD DE INGENIERA, Edificio 453 Oficina 101,


Telefax: Conmutador: (57-1) 316 5000 Ext. 14011 Fax: 14014.
Correo electrnico: [email protected] / Bogot, Colombia, Sur Amrica

6. Estructura de un archivo fuente de ANTLR (especificacin de la gramtica)


Los archivos con los que trabaja ANTLR tienen la extensin *.g4 (*.g para versiones anteriores), y en adelante los
llamaremos archivos de especificacin de gramticas o, directamente, archivos de gramticas. Contienen la definicin de
uno o varios analizadores. Cada uno de estos analizadores se traducir a cdigo de alto nivel (Java, Python o C#,
dependiendo de ciertas opciones) en forma de clases. Es decir, por cada analizador descrito en el archivo de gramticas se
generar una clase.
Todo archivo de gramtica tiene la siguiente estructura:
grammar NombreGramatica;
options {
/* opciones generales a todo el archivo */
}
@header {...}
@members {...}
Reglas
Tras grammar indicamos el nombre de la gramtica, con ello fijamos el nombre que tendrn las correspondientes clases
del analizador lxico NombreGramaticaLexer.java y sintctico NombreGramaticaParser.java (si estamos usando Java
como lenguaje de salida). Ms adelante se detalla mejor cada uno de los archivos de salida que genera ANTLR.
Options: es la zona de opciones generales. Es opcional. Permite controlar algunos parmetros de ANTLR mediante
opciones. Las opciones se representan como asignaciones: nombreOpcion=valor;. Se utilizan mucho en ANTLR. Las
opcin ms importante de esta zona es la que permite elegir el lenguaje nativo en el que se generarn los analizadores
(Java, Python, C#). Su valor por defecto es JAVA. Tras las opciones generales del archivo vienen las definiciones de
analizadores. Es posible que en un mismo archivo se especifiquen varios analizadores. Sin embargo, tambin es posible
definir cada analizador en un archivo aparte, sobre todo cuando se trata de analizadores extensos.
@header es una zona opcional. Delimitada por header { y }. Aqu se incluyen los elementos en cdigo nativo (Java,
Python o C#) que deben preceder a la definicin de las diferentes clases de los analizadores. Esta seccin se utiliza para
incluir otros archivos (import, etc.), definir el paquete al que pertenecer la clase del analizador (package), etc.
Por otra parte, @members permite insertar atributos y mtodos definidos por el usuario en esa clase.

Carrera 30 No. 45-03, FACULTAD DE INGENIERA, Edificio 453 Oficina 101,


Telefax: Conmutador: (57-1) 316 5000 Ext. 14011 Fax: 14014.
Correo electrnico: [email protected] / Bogot, Colombia, Sur Amrica

La especificacin de las reglas se hace con notacin gramatical, de la siguiente forma:


ANTECEDENTE: CONSECUENTE;
Importante: ANTLR se ha diseado para incluir las especificaciones lxica y sintctica tanto juntas como separadas. El
caso de tener ambas especificaciones juntas, se cumple que si el antecedente est escrito en maysculas, ANTLR lo
interpretar como una regla lxica. Sin embargo, si el antecedente est escrito en minsculas, ANTLR lo interpretar
como una regla sintctica.
Para ANTLR las minsculas se asocian a los smbolos no terminales y las maysculas a los terminales. Cuando se trabaja
con las especificaciones separadas, hay que definir la especificacin lxica y la gramtica sintctica. Para la especificacin
lxica es necesario introducir al principio del archivo que contenga dicha especificacin: lexer gramar NombreArchivo.
Esta sentencia indica a ANTLR que se trata de una especificacin lxica. En la especificacin sintctica hay que incluir
solamente: grammar Nombre, para indicar que se trata de una especificacin sintctica. Adems, es necesario importar la
especificacin lxica correspondiente.

7. Reglas (analizadores lxicos y sintcticos)

Smbolos lxicos: comienzan con mayscula


Smbolos auxiliares (no terminales): comienzan con minscula
Comentarios:
o // Una lnea
o /* varias
lneas */
Expresiones regulares:
o Literales entre comillas simples p.e. a
o Rangos: a..z
o Negacin: ~x
o Alternativas (o): |
o 0 o ms ocurrencias: *
o 1 o ms ocurrencias: +
o 0 o 1 ocurrencia: ?
Reglas:
o

<smbolo lxico o auxiliar> : <definicin1>


| <definicin2>
| <definicin_i>
;

Reglas sintcticas en EBNF (Extended Backus-Naur Form): Se permite +, *, ? en las partes derechas de las reglas.
Carrera 30 No. 45-03, FACULTAD DE INGENIERA, Edificio 453 Oficina 101,
Telefax: Conmutador: (57-1) 316 5000 Ext. 14011 Fax: 14014.
Correo electrnico: [email protected] / Bogot, Colombia, Sur Amrica

8. Salida ANTLR v4
Cuando ejecutamos ANTLR con el comando:
java org.antlr.v4.Tool PRUEBA.g4

Se crean como resultado los siguientes archivos (en el caso que se est usando JAVA):

cdigo fuente del analizador lxico


cdigo fuente del analizador sintctico
tokens para el analizador sintctico
tokens para el analizador lxico
Interface que describe los eventos que podemos llamar al recorrer el rbol
sintctico que genera ANTLR automticamente
PRUEBABaseListener.java Clase con un conjunto de implementaciones vacas. Basta con sobreescribir
los mtodos que nos interesan.
PRUEBALexer.java
PRUEBAParser.java
PRUEBA.tokens
PRUEBALexer.tokens
PRUEBAListener.java

9. Probar el analizador generado


Para realizar la prueba de un analizador generado con ANTLR v4 usaremos el siguiente ejemplo simple:
Archivo: Hello\Hello.g4
grammar Hello; // Define a grammar called Hello
r : 'hello' ID ; // match keyword hello followed by an identifier
ID : [a-z]+ ; // match lower-case identifiers
WS : [ \t\r\n]+ -> skip ; // skip spaces, tabs, newlines, \r (Windows)

A partir de la especificacin de la gramtica Hello.g4 generamos el analizador:


>java org.antlr.v4.Tool Hello.g4

Lo cual genera los siguientes archivos:


HelloLexer.java
Hello.tokens
HelloListener.java

HelloParser.java
HelloLexer.tokens
HelloBaseListener.java

Aunque los archivos que genera ANTLR v4 contienen todo lo necesario para ejecutar nuestro analizador, an no contamos
con un programa main que inicie el proceso de procesamiento del lenguaje dada una cadena/archivo de entrada.

Carrera 30 No. 45-03, FACULTAD DE INGENIERA, Edificio 453 Oficina 101,


Telefax: Conmutador: (57-1) 316 5000 Ext. 14011 Fax: 14014.
Correo electrnico: [email protected] / Bogot, Colombia, Sur Amrica

Para probar los analizadores generados por ANTLR v4 primero que todo debemos compilar los fuentes generados (java):
>javac *.java
Esto nos genera los archivos *.class correspondientes y a partir de aqu tenemos 2 opciones: utilizar la herramienta de
prueba que proporciona ANTLR llamada TestRig; o desarrollar un programa main para integrar todo.

Opcin 1: TestRig
Es una herramienta flexible de prueba que ofrece ANTLR. De acuerdo a las opciones utilizadas puede mostrar informacin
til acerca del proceso de anlisis. Se puede ejecutar as:
>java org.antlr.v4.gui.TestRig Hello r opcin
Donde:
Hello: es el nombre de la gramtica a probar
r: es el smbolo inicial (la primer regla) de la gramtica
opcin: entre otras, puede ser:
o

tokens: si queremos que imprima los tokens que reconoce durante el anlisis de una cadena de
entrada. Ejemplo:
>java org.antlr.v4.gui.TestRig Hello r tokens

hello unal
EOF

# input for the recognizer that you type


# type ctrl-D on Unix or Ctrl+Z on Windows

A lo cual retorna:
[@0,0:4='hello',<1>,1:0]
[@1,6:9='unal',<2>,1:6]
[@2,12:11='<EOF>',<-1>,2:0]
Cada lnea de la salida representa la informacin conocida acerca de un token. Por ejemplo,
[@1,6:9='unal',<2>,1:6] indica que el token es el segundo (indexado desde 0 - @1), va
desde el carcter ubicado en la posicin 6 de la lnea hasta la 9 (inclusive y empezando en 0),
corresponde al lexema unal, tiene el token tipo 2 (ID), y est en la lnea 1 (contando desde 1) y en la
posicin 6 (empezando desde 0 y contando las tabulaciones como un solo carcter).

Carrera 30 No. 45-03, FACULTAD DE INGENIERA, Edificio 453 Oficina 101,


Telefax: Conmutador: (57-1) 316 5000 Ext. 14011 Fax: 14014.
Correo electrnico: [email protected] / Bogot, Colombia, Sur Amrica

tree: imprime el rbol de derivacin al estilo LISP, en forma textual. As:


>java org.antlr.v4.gui.TestRig Hello r tree

hello unal
EOF
A lo cual retorna:
(r hello unal)
o

gui: permite ver el rbol de derivacin grficamente. La forma ms fcil de verlo. Ejemplo:
>java org.antlr.v4.gui.TestRig Hello r gui

hello unal
EOF
A lo cual retorna:

Carrera 30 No. 45-03, FACULTAD DE INGENIERA, Edificio 453 Oficina 101,


Telefax: Conmutador: (57-1) 316 5000 Ext. 14011 Fax: 14014.
Correo electrnico: [email protected] / Bogot, Colombia, Sur Amrica

Opcin 2: main
La segunda opcin, y la que utilizaremos despus de haber hecho las pruebas bsicas con TestRig, es realizar la
implementacin del mtodo main del analizador. A continuacin se muestra una plantilla para dicho mtodo. Reemplazar
NOMBRE_GRAMATICA y reglaInicialGramatica por los identificadores correspondientes:
// import de librerias de runtime de ANTLR
import org.antlr.v4.runtime.*;
import org.antlr.v4.runtime.tree.*;
import java.io.File;
public class Test {
public static void main(String[] args) throws Exception {
try{
// crear un analizador lxico que se alimenta a partir de la entrada (archivo o consola)
NOMBRE_GRAMATICALexer lexer;
if (args.length>0)
lexer = new NOMBRE_GRAMATICALexer(new ANTLRFileStream(args[0]));
else
lexer = new NOMBRE_GRAMATICALexer(new ANTLRInputStream(System.in));
// Identificar al analizador lxico como fuente de tokens para el sintactico
CommonTokenStream tokens = new CommonTokenStream(lexer);
// Crear el analizador sintctico que se alimenta a partir del buffer de tokens
NOMBRE_GRAMATICAParser parser = new NOMBRE_GRAMATICAParser(tokens);
ParseTree tree = parser.reglaInicialGramatica(); // comienza el anlisis en la regla inicial
System.out.println(tree.toStringTree(parser)); // imprime el rbol de derivacin en forma textual
} catch (Exception e){
System.err.println("Error (Test): " + e);
}
}
}

Compilando una vez ms todos los archivo *.java, obtenemos el ejecutable de la clase Test (nuestro analizador). Se tiene
como resultado el analizador completo que admite un archivo de entrada desde la lnea de comandos, lo procesa y emite
los mensajes de error correspondientes (en caso que sea necesario).
Por ejemplo, para el caso de Hello.g4, el archivo Test.java contiene el main como se muestra a continuacin:
// import de librerias de runtime de ANTLR
import org.antlr.v4.runtime.*;
import org.antlr.v4.runtime.tree.*;
import java.io.File;
public class Test {
public static void main(String[] args) throws Exception {
try{
//File f = new File(args[0]);
// crear un analizador lxico que se alimenta apartir de la entrada (archivo o consola)
HelloLexer lexer;
if (args.length>0)
lexer = new HelloLexer(new ANTLRFileStream(args[0]));
else
lexer = new HelloLexer(new ANTLRInputStream(System.in));
// Identificar al analizador lxico como fuente de tokens para el sintactico
CommonTokenStream tokens = new CommonTokenStream(lexer);
// Crear objeto del analizador sintctico que se alimenta apartir del buffer de tokens
HelloParser parser = new HelloParser(tokens);
ParseTree tree = parser.r(); // begin parsing at init rule

Carrera 30 No. 45-03, FACULTAD DE INGENIERA, Edificio 453 Oficina 101,


Telefax: Conmutador: (57-1) 316 5000 Ext. 14011 Fax: 14014.
Correo electrnico: [email protected] / Bogot, Colombia, Sur Amrica

System.out.println(tree.toStringTree(parser)); // print LISP-style tree


} catch (Exception e){
System.err.println("Error (Test): " + e);
}
}
}

A continuacin se genera el cdigo del analizador con ANTLR:


>java org.antlr.v4.Tool Hello.g4

Se compila todo (incluyendo Test.java):


>javac *.java

Suponiendo que Test.java est en el mismo directorio con los archivos generador por ANTLR

Se prueba:
>java Test input.in

Donde input.in es el archivo de prueba. En este caso contiene la cadena hello unal

La salida generada es:

(r hello unal)

Carrera 30 No. 45-03, FACULTAD DE INGENIERA, Edificio 453 Oficina 101,


Telefax: Conmutador: (57-1) 316 5000 Ext. 14011 Fax: 14014.
Correo electrnico: [email protected] / Bogot, Colombia, Sur Amrica

10. Ejemplos
Ejemplo 1: Reconocedor de expresiones aritmticas - Expr (sin Listeners ni Visitors)
1.

Especificacin de la gramtica:
Archivo: Expr.g
grammar Expr;
// REGLAS SINTACTICAS
expr
: term ( (MAS | MENOS) term)*
{ System.out.println("Anlisis terminado.");
};
term

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

factor

: ENTERO;

// TOKENS
MAS
:
MENOS
:
MULT
:
DIV
:

'+';
'-';
'*';
'/';

// REGLAS LEXICAS
ENTERO : ('0'..'9')+;
ESPACIO : ( ' '
| '\t'
| '\r'
| '\n'
)+ -> channel(HIDDEN)
;

2.

Generar el cdigo fuente del analizador lxico y sintctico:


>java org.antlr.v4.Tool Expr.g

3.

Programa main:
Archivo: MiExpr.java
// import de librerias de runtime de ANTLR
import org.antlr.v4.runtime.*;
import org.antlr.v4.runtime.tree.*;

Carrera 30 No. 45-03, FACULTAD DE INGENIERA, Edificio 453 Oficina 101,


Telefax: Conmutador: (57-1) 316 5000 Ext. 14011 Fax: 14014.
Correo electrnico: [email protected] / Bogot, Colombia, Sur Amrica

import java.io.File;
public class MiExpr {
public static void main(String[] args) throws Exception {
try{
// crear un analizador lxico que se alimenta a partir de la entrada (archivo o consola)
ExprLexer lexer;
if (args.length>0)
lexer = new ExprLexer(new ANTLRFileStream(args[0]));
else
lexer = new ExprLexer(new ANTLRInputStream(System.in));
// Identificar al analizador lxico como fuente de tokens para el sintactico
CommonTokenStream tokens = new CommonTokenStream(lexer);
// Crear el analizador sintctico que se alimenta a partir del buffer de tokens
ExprParser parser = new ExprParser(tokens);
ParseTree tree = parser.expr(); // comienza el anlisis en la regla inicial
System.out.println(tree.toStringTree(parser)); // imprime el rbol en forma textual
} catch (Exception e){
System.err.println("Error (Test): " + e);
}
}
}

4.

Compilar todo
>javac ExprLexer.java ExprParser.java MiExpr.java

5.

Editar archivo de entrada para probar


Archivo: entrada.txt
23+3 -9 *3

6.

Probar funcionamiento:
>java MiExpr entrada.txt
Anlisis terminado.
(expr (term (factor 23)) + (term (factor 3)) - (term (factor 9) * (factor 3)))

Carrera 30 No. 45-03, FACULTAD DE INGENIERA, Edificio 453 Oficina 101,


Telefax: Conmutador: (57-1) 316 5000 Ext. 14011 Fax: 14014.
Correo electrnico: [email protected] / Bogot, Colombia, Sur Amrica

Ejemplo 2: Reconocedor de nmeros enteros encerrados entre llaves - ArrayInt


Vamos a construir una gramtica para desarrollar un reconocedor de conjuntos de nmeros enteros separados por comas
y encerrados entre llaves (posiblemente anidados), como por ejemplo: {1, 2, 3} y {1, {2, 3}, 4}. Esto podra ser til para
reconocer expresiones de inicializacin de arreglos en Java, por ejemplo. Cuando hayamos desarrollado el reconocedor,
implementaremos un traductor de este tipo de cadenas basado en Listeners.

Especificacin de la gramtica:
Archivo: ArrayInit.g4
/** Grammars always start with a grammar header. This grammar is called
* ArrayInit and must match the filename: ArrayInit.g4
*/
grammar ArrayInit;
/** A rule called init that matches comma-separated values between {...}. */
init : '{' value (',' value)* '}' ; // must match at least one value
/** A value can be either a nested array/struct or a simple integer (INT) */
value : init
| INT
;
// parser rules start with lowercase letters, lexer rules with uppercase
INT : [0-9]+ ; // Define token INT as one or more digits
WS : [ \t\r\n]+ -> skip ; // Define whitespace rule, toss it out
;

Generar el cdigo fuente usando ANTLR:


>java org.antlr.v4.Tool ArrayInit.g4

Carrera 30 No. 45-03, FACULTAD DE INGENIERA, Edificio 453 Oficina 101,


Telefax: Conmutador: (57-1) 316 5000 Ext. 14011 Fax: 14014.
Correo electrnico: [email protected] / Bogot, Colombia, Sur Amrica

Compilar todo
>javac *.java

Probar el reconocedor generado usando TestRig:


Tokens
>java org.antlr.v4.runtime.misc.TestRig ArrayInit init -tokens
{99, 3, 491}
^Z
[@0,0:0='{',<1>,1:0]
[@1,1:2='99',<4>,1:1]
[@2,3:3=',',<2>,1:3]
[@3,5:5='3',<4>,1:5]
[@4,6:6=',',<2>,1:6]
[@5,8:10='491',<4>,1:8]
[@6,11:11='}',<3>,1:11]
[@7,14:13='<EOF>',<-1>,2:0]

Tree
>java org.antlr.v4.runtime.misc.TestRig ArrayInit init -tree
{99, 3, 491}
^Z
(init { (value 99) , (value 3) , (value 491) })

Gui (ntese que no importan los espacios en blanco en la cadena a reconocer)


>java org.antlr.v4.runtime.misc.TestRig ArrayInit init -gui
{1, {2,
3
},4}
^Z

Carrera 30 No. 45-03, FACULTAD DE INGENIERA, Edificio 453 Oficina 101,


Telefax: Conmutador: (57-1) 316 5000 Ext. 14011 Fax: 14014.
Correo electrnico: [email protected] / Bogot, Colombia, Sur Amrica

Integrando el reconocedor generado con un programa en Java (main):


Archivo: Test.java
// import de librerias de runtime de ANTLR
import org.antlr.v4.runtime.*;
import org.antlr.v4.runtime.tree.*;
import java.io.File;
public class Test {
public static void main(String[] args) throws Exception {
try{
// crear un analizador lxico que se alimenta a partir de la entrada (archivo o consola)
ArrayInitLexer lexer;
if (args.length>0)
lexer = new ArrayInitLexer(new ANTLRFileStream(args[0]));
else
lexer = new ArrayInitLexer(new ANTLRInputStream(System.in));
// Identificar al analizador lxico como fuente de tokens para el sintactico
CommonTokenStream tokens = new CommonTokenStream(lexer);
// Crear el analizador sintctico que se alimenta a partir del buffer de tokens
ArrayInitParser parser = new ArrayInitParser(tokens);
ParseTree tree = parser.init(); // comienza el anlisis en la regla inicial
System.out.println(tree.toStringTree(parser)); // imprime el rbol en forma textual
} catch (Exception e){
System.err.println("Error (Test): " + e);
}
}
}

Compilamos nuevamente para generar el archivo .class de Test:


>javac ArrayInit*.java Test.java

Probamos el funcionamiento desde consola:

Cadena sin errores sintcticos:


>java Test
{1, {2, 3}, 4}
^Z
(init { (value 1) , (value (init { (value 2) , (value 3) })) , (value 4) })

Cadena con errores sintcticos:


>java Test
{1, 2,
^Z
line 2:0 missing '}' at '<EOF>'
(init { (value 1) , (value 2) <missing '}'>)

Carrera 30 No. 45-03, FACULTAD DE INGENIERA, Edificio 453 Oficina 101,


Telefax: Conmutador: (57-1) 316 5000 Ext. 14011 Fax: 14014.
Correo electrnico: [email protected] / Bogot, Colombia, Sur Amrica

Desarrollar un traductor para este tipo de cadenas (usando Listeners): vamos a traducir los elementos de
inicializacin de un arreglo en Java como {99, 3, 451} (los cuales ya reconocemos) a una cadena de constantes
Unicode como: \u0063\u0003\u01c3, donde cada uno de estos corresponde a la notacin hexadecimal del valor
original (por ejemplo: 99d = 63h).
Anlisis previo:
Ejemplo de traduccin:

De aqu podemos identificar las reglas de traduccin necesarias:


Traducir { a .
Traducir } a .
Traducir los nmeros enteros a una cadena de 4 dgitos con su representacin hexadecimal, precedida de \u.
Implementacin de los mtodos del traductor (en el Listener)
Para lograr el objetivo, lo nico que tendremos que hacer es implementar algunos mtodos en una subclase de
ArrayInitBaseListener. La estrategia bsica consiste en que cada mtodo del Listener imprima una pequea parte de
la traduccin correspondiente a la cadena de entrada cuando sea llamado por el objeto (walker) que recorre el rbol
sintctico.
A continuacin se presenta la implementacin del Listener de acuerdo a nuestras reglas de traduccin.
Archivo: ShortToUnicodeString.java
/** Convert short array inits like {1,2,3} to "\u0001\u0002\u0003" */
public class ShortToUnicodeString extends ArrayInitBaseListener {
@Override
/** Translate { to " */
public void enterInit(ArrayInitParser.InitContext ctx) {
System.out.print('"');
}
@Override
/** Translate } to " */
public void exitInit(ArrayInitParser.InitContext ctx) {
System.out.print('"');
}
@Override
/** Translate integers to 4-digit hexadecimal strings prefixed with \\u */
public void enterValue(ArrayInitParser.ValueContext ctx) {
// Assumes no nested array initializers
int value = Integer.valueOf(ctx.INT().getText());
System.out.printf("\\u%04x", value);
}
}

Carrera 30 No. 45-03, FACULTAD DE INGENIERA, Edificio 453 Oficina 101,


Telefax: Conmutador: (57-1) 316 5000 Ext. 14011 Fax: 14014.
Correo electrnico: [email protected] / Bogot, Colombia, Sur Amrica

No es necesario sobreescribir todos los mtodos enter/exit, slo los que vamos a usar. La nica expresin poco
familiar en este ejemplo es ctx.INT(), la cual le solicita al objeto del contexto el token del nmero entero INT
(capturado por la regla value). A continuacin se presenta la implementacin del Listener de acuerdo a nuestras
reglas de traduccin.
Crear la aplicacin (traductor)
Slo nos falta crear la aplicacin como tal, basndonos en la clase Test mostrada previamente.
Archivo: Translate.java
// import ANTLR's runtime libraries
import org.antlr.v4.runtime.*;
import org.antlr.v4.runtime.tree.*;
public class Translate {
public static void main(String[] args) throws Exception {
// create a CharStream that reads from standard input
ANTLRInputStream input = new ANTLRInputStream(System.in);
// create a lexer that feeds off of input CharStream
ArrayInitLexer lexer = new ArrayInitLexer(input);
// create a buffer of tokens pulled from the lexer
CommonTokenStream tokens = new CommonTokenStream(lexer);
// create a parser that feeds off the tokens buffer
ArrayInitParser parser = new ArrayInitParser(tokens);
ParseTree tree = parser.init(); // begin parsing at init rule

// Create a generic parse tree walker that can trigger callbacks


ParseTreeWalker walker = new ParseTreeWalker();
// Walk the tree created during the parse, trigger callbacks
walker.walk(new ShortToUnicodeString(), tree);
System.out.println(); // print a \n after translation

En este caso creamos un objeto walker de la clase ParseTreeWalker. Llamamos su mtodo walk(), el cual recorre el
rbol sintctico retornado por el parser. A medida que se va recorriendo el rbol, se van desencadenando los
llamados a los mtodos de nuestro Listener (ShortToUnicodeString).
Finalmente, compilamos y probamos el traductor
>javac ArrayInit*.java Translate.java
>java Translate
{99, 3, 451}
^Z
"\u0063\u0003\u01c3"

Carrera 30 No. 45-03, FACULTAD DE INGENIERA, Edificio 453 Oficina 101,


Telefax: Conmutador: (57-1) 316 5000 Ext. 14011 Fax: 14014.
Correo electrnico: [email protected] / Bogot, Colombia, Sur Amrica

11. Recursos adicionales (recomendados)

Revisar (y utilizar) las herramientas disponibles en: http://www.antlr.org/tools.html


ANTLRWorks
Plugins para: NetBeans, Eclipse, Intellij.

Ver la clase de Terence Parr (creador de ANTLR) en la Universidad de San Francisco, donde presenta ANTLR v4 explica Listeners y Visitors y los analizadores ALL(*). En este enlace: https://vimeo.com/59285751

12. Referencias
[1]

Parr Terence. The Definitive ANTLR 4 Reference. The pragmatic bookshelf. 2012.

Carrera 30 No. 45-03, FACULTAD DE INGENIERA, Edificio 453 Oficina 101,


Telefax: Conmutador: (57-1) 316 5000 Ext. 14011 Fax: 14014.
Correo electrnico: [email protected] / Bogot, Colombia, Sur Amrica

También podría gustarte