¡Esta es una revisión vieja del documento!
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.
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.
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;
}
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;
}
Código que se añadirá al parser generado (aquí podremos poner nuestras funciones dentro de la clase).
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;
}
}
Para ejecutar antlr3 haremos:
$ java org.antlr.Tool -o ./out/ GameLog.g
| 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 |
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<string> ValueList ]
@init { $ValueList = new List<string>(); }
: '[]'
| '[' 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' } ;
Atributos de tokens:
text