====== 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]]