====== ANTLR ======
ANTLR (ANother Tool for Language Recognition, otra herramienta para reconocimiento de lenguajes) es la herramienta más utilizada actualmente para construir parsers, interpretes, compiladores y traductores de lenguajes a partir de gramáticas.
* **Ficheros**:
* {{otros:antlr:antlrworks-1.4.tar|ANTLRWorks, una IDE de desarrollo}}.
* {{otros:antlr:dot-net-runtime-3.1.3.zip|Librerías para .NET}}.
* {{otros:antlr:antlr3-completepack.zip|Utilizado para trabajar con él}}.
* {{:otros:antlr:examples.zip|Ejemplos}}
* **Links**
* [[http://www.antlr.org/|Página oficial]].
* [[http://www.antlr.org/wiki/display/ANTLR3/ANTLR+3+Wiki+Home|Wiki]].
* Las páginas (y descargas) para antlr versión 3 pueden fallar porque ya no están en antlr.org sino en antlr3.org.
===== Estructura de un fichero de ANTLR =====
Un fichero para ANTLR tiene la extensión .g, debe definir en su primera línea el tipo de gramática que va a generar (''lexer grammar'', ''parser grammar'' o ''grammar'') y el nombre de esta (que ha de ser el mismo que el nombre del fichero .g). Luego seguirán las opciones y demás secciones las cuales son opcionales, y al final la definición de la gramática...
grammar test;
r : 'call' ID ';' {System.out.println("invoke "+$ID.text);} ;
ID: 'a'..'z'+ ;
WS: (' '|'\n'|'\r')+ {$channel=HIDDEN;} ; // ignore whitespace
Este código se genera en Java (por defecto), cada vez que encuentre un ''call algo;'' será lanzado el ''System.out.println''.
==== Opciones ====
Las opciones nos permiten definir la generación del resultado. Por ejemplo podemos definir el código generado, ANTLR permite generar resultados en gran variedad de lenguajes (C, Java, C#, Python...), para definir el lenguaje utilizaremos la "clave" ''language'':
grammar FQL;
options {
language = Java;
}
==== Sección @header ====
En esta sección agregaremos la cabecera para el archivo de código resultado, esta tendrá la definición del paquete, los imports, los using...
@header {
package bbejeck.antlr.fql;
}
==== Sección @members ====
Código que se añadirá al parser generado (aquí podremos poner nuestras funciones dentro de la clase).
==== Sección @rulecatch ====
Cada regla de un parser es convertida a una llamada a un método dentro de un bloque ''try - catch''. Podemos definir el bloque ''catch'' a partir de esta sección:
@rulecatch{
catch (RecognitionException e){
throw e;
}
}
O en Python:
@rulecatch{
except RecognitionException, e:
print 'ERROR!!!!',
raw_input()
}
==== Sección @init ====
Para inicializar valores dentro de la clase del parser:
@init {
self.line = {}
self.line['parameters'] = {}
}
Luego podremos usarlas así:
logline returns [val]
: globalmessage {val = self.line}
| playerinfo {val = self.line}
;
Las reglas también pueden tener un init:
file returns [List> data]
@init {data = new ArrayList>();}
: (row {data.add($row.list);})+ EOF
;
===== Notas =====
==== Apuntes ====
Para ejecutar antlr3 haremos:
$ java org.antlr.Tool -o ./out/ GameLog.g
=== Signos de gramática ===
| Signos | Significado |
|.| Todo |
|*| Puede existir, no existir o existir varias veces |
|+| Ha de existir al menos una vez |
|?| Opcional |
|~| Negación |
|(x|y|z)| Regla x, y o z |
| EOF | Final de línea |
=== Pequeños apuntes ===
* Se distinguen los identificadores en mayúsculas (reglas de parser que permiten devolver elementos) de minúsculas (tokens léxicos).
* AntlrWorks es el IDE diseñado para montar gramáticas.
* Los tokens 'fragment' no son tokens pero sí que forman parte de otros.
* Existe el método ''getNumberOfSyntaxErrors'' en el objeto parser. Indicará los errores de parsing, pero si se hace un apartado ''@rulecatch'' estos serán ignorados.
* También pueden detectarse los errores en al ejecutarse una regla con ''state.failed''.
Es importante definir antes lo que queremos que coincida:
BEGIN : 'begin' ;
ID : 'a'..'z' + ;
OTHER: . ; // match any other single character
Cuando tengamos varias reglas con las que case lo introducido podremos hacer alias de los tokens (si únicamente fuese uno podríamos hacer ''$PLAYER.text'':
infouser : COMS p1=PLAYER COMS VERB COMS p2=PLAYER COMS WITH COMS GUN COMS (PARENT1 parameter PARENT2)* { print 'oh! > ', $p1.text, $p2.text }
Cuando queremos añadir un atributo:
player returns [ value ]: STRVALUE MAYOR NUMBER MENOR MAYOR STEAMDEF steam=NUMBER MENOR MAYOR (IDENTIFIER)* MENOR {$value = $steam.text};
infouser : COMS p1=player COMS VERB COMS p2=player COMS WITH COMS GUN COMS (PARENT1 parameter PARENT2)* { print 'oh! > ', $p1.value, $p2.value }
Lidiar con un retorno de lista (CSharp):
list returns [ List ValueList ]
@init { $ValueList = new List(); }
: '[]'
| '[' value {$ValueList.Add(value);} (COMMA value {$ValueList.Add(value);})* ']' ;
Lidiar con atributos opcionales:
species returns [int count] : atom DIGITS? { $count = int($DIGITS.text) if $DIGITS else 0 } ;
Podemos retornar varios valores:
foo returns [a, b, c]
: A B C {a=$A.text; b=$B.text; b=$C.text}
;
Podemos inicializar valores dentro de reglas con ''@init'':
calculate_mw returns [float mw]
@init { $mw = 0.0 }
: (species { $mw += $species.species_weight})* EOF ;
Para aprovechar la salida de un parser podremos hacer:
*** Fichero gramática (regla principal '') ****
[...]
calculate_mw returns [float mw]
@init { $mw = 0.0 }
: (species { $mw += $species.species_weight})* EOF ;
[...]
*** Fichero de código *************
[...]
def calculate_mw(formula):
char_stream = antlr3.ANTLRStringStream(formula)
lexer = MWGrammarLexer(char_stream)
tokens = antlr3.CommonTokenStream(lexer)
parser = MWGrammarParser(tokens)
return parser.calculate_mw()
[...]
Para hacer coincidir otros elementos usaremos ''.'':
logline : globalmessage { print 'info' }
| rconcommand { print 'rcon' }
| defvar { print 'var' }
| .* { print 'lodemas' } ;
Un ejemplo para capturar excepciones:
except RecognitionException, e:
print "PARSING ERROR: "+str(e)+" parsing :"+str(self.input)
pprint.pprint(e)
pprint.pprint(self.input)
Atributos de tokens:
* ''text''
==== Documentos ====
* {{otros:antlr:proyecto_fkscript.pdf|Ejemplo con C#}}.
* {{:otros:antlr:antlr_python.pdf|Ejemplo con Python}}
* {{:otros:antlr:antlr-tutorial.pdf|Tutorial}}
==== Ejemplos míos ====
* {{:otros:antlr:gamelog.g.zip|GameLog v0}}
==== Links ====
=== General ===
* [[http://www.antlr3.org/|ANTLR3]]
* [[http://www.antlr.org/wiki/display/ANTLR3/ANTLR+3+Wiki+Home|Wiki ANTLR3]]
* [[http://www.antlr.org/wiki/display/ANTLR3/Five+minute+introduction+to+ANTLR+3|Five minute introduction]]
* [[http://www.antlr.org/wiki/display/ANTLR3/Quick+Starter+on+Parser+Grammars+-+No+Past+Experience+Required|Tutorial]]
* [[http://www.antlr.org/wiki/display/ANTLR3/Expression+evaluator|Ejemplo]]
* [[http://javadude.com/articles/antlr3xtut/|Videotutoriales bastante completos]]
* [[http://www.antlr.org/wiki/display/ANTLR3/Tree+construction|Cómo crear árboles sintácticos]]
=== Python ===
* [[http://www.antlr.org/wiki/display/ANTLR3/Python+runtime|Python runtime]]
* [[http://www.antlr3.org/api/Python/index.html|API Python]]
* [[http://www.antlr.org/wiki/display/ANTLR3/Antlr3PythonTarget|Python code generator]]
* [[http://www.antlr.org/wiki/display/ANTLR3/Example|Example]]
* [[http://www.antlr2.org/doc/python-runtime.html|Tutorial ANTLR2]]