Me gustaría comenzar con ANTLR, pero después de pasar unas horas revisando los ejemplos en el sitio antlr.org , todavía no puedo entender claramente el proceso de gramática en Java.
¿Hay algún ejemplo simple, algo así como una calculadora de cuatro operaciones implementada con ANTLR pasando por la definición del analizador y hasta el código fuente de Java?
Respuestas:
Nota : ¡esta respuesta es para ANTLR3 ! Si está buscando un ejemplo ANTLR4 , estas preguntas y respuestas demuestran cómo crear un analizador de expresiones simple y un evaluador utilizando ANTLR4 .
Primero creas una gramática. A continuación hay una pequeña gramática que puede usar para evaluar las expresiones que se crean utilizando los 4 operadores matemáticos básicos: +, -, * y /. También puede agrupar expresiones usando paréntesis.
Tenga en cuenta que esta gramática es muy básica: no maneja operadores unarios (el menos en: -1 + 9) o decimales como .99 (sin un número inicial), por nombrar solo dos deficiencias. Este es solo un ejemplo en el que puede trabajar usted mismo.
Aquí está el contenido del archivo de gramática Exp.g :
(Las reglas del analizador comienzan con una letra minúscula y las reglas del lexer comienzan con una letra mayúscula)
Después de crear la gramática, querrás generar un analizador y un lexer a partir de ella. Descargue el jar ANTLR y guárdelo en el mismo directorio que su archivo de gramática.
Ejecute el siguiente comando en su shell / símbolo del sistema:
No debería producir ningún mensaje de error, y los archivos ExpLexer.java , ExpParser.java y Exp.tokens ahora deberían generarse.
Para ver si todo funciona correctamente, cree esta clase de prueba:
y compilarlo:
y luego ejecutarlo:
Si todo va bien, no se imprime nada en la consola. Esto significa que el analizador no encontró ningún error. Cuando se cambia
"12*(5-6)"
en"12*(5-6"
y luego volver a compilar y ejecutarlo, no debe ser impresa la siguiente:Bien, ahora queremos agregar un poco de código Java a la gramática para que el analizador realmente haga algo útil. La adición de código se puede hacer colocando
{
y}
dentro de su gramática con algún código Java simple dentro de él.Pero primero: todas las reglas del analizador en el archivo de gramática deben devolver un valor doble primitivo. Puede hacerlo agregando
returns [double value]
después de cada regla:que necesita poca explicación: se espera que cada regla devuelva un valor doble. Ahora, para "interactuar" con el valor de retorno
double value
(que NO está dentro de un bloque de código Java simple{...}
) desde el interior de un bloque de código, deberá agregar un signo de dólar delante devalue
:Aquí está la gramática pero ahora con el código Java agregado:
y como nuestra
eval
regla ahora devuelve un doble, cambie su ANTLRDemo.java por esto:Nuevamente (re) genere un nuevo lexer y analizador de su gramática (1), compile todas las clases (2) y ejecute ANTLRDemo (3):
¡y ahora verá el resultado de la expresión
12*(5-6)
impresa en su consola!De nuevo: esta es una explicación muy breve. Te animo a navegar por el wiki de ANTLR y leer algunos tutoriales y / o jugar un poco con lo que acabo de publicar.
¡Buena suerte!
EDITAR:
Esta publicación muestra cómo extender el ejemplo anterior para que
Map<String, Double>
se pueda proporcionar un archivo que contenga variables en la expresión proporcionada.Para que este código funcione con una versión actual de Antlr (junio de 2014), necesitaba hacer algunos cambios.
ANTLRStringStream
necesitaba serANTLRInputStream
, el valor devuelto necesitaba cambiar deparser.eval()
aparser.eval().value
, y necesitaba eliminar laWS
cláusula al final, porque los valores de atributo como$channel
ya no pueden aparecer en acciones lexer.fuente
parser.eval()
ocurren las implementaciones de ? ¡Eso no está claro AQUÍ ni en el Wiki ANTLR3!eval
es una regla de analizador que devuelve adouble
. Entonces, hay uneval()
método al que puede llamar en una instancia de unExpParser
, tal como lo demostré en elANTLRDemo.main(...)
. Después de generar un lexer / parser, simplemente abra el archivoExpParser.java
y verá que hay uneval()
método que devuelve adouble
.El mega tutorial ANTLR de Gabriele Tomassetti es muy útil
Tiene ejemplos de gramática, ejemplos de visitantes en diferentes lenguajes (Java, JavaScript, C # y Python) y muchas otras cosas. Muy recomendable.
EDITAR: otros artículos útiles de Gabriele Tomassetti sobre ANTLR
fuente
Para Antlr 4, el proceso de generación de código java es el siguiente:
Actualice su nombre de jar en classpath en consecuencia.
fuente
En https://github.com/BITPlan/com.bitplan.antlr encontrará una biblioteca ANTLR de Java con algunas clases auxiliares útiles y algunos ejemplos completos. Está listo para usarse con maven y si te gusta eclipse y maven.
https://github.com/BITPlan/com.bitplan.antlr/blob/master/src/main/antlr4/com/bitplan/exp/Exp.g4
es un lenguaje de expresión simple que puede multiplicar y agregar operaciones. https://github.com/BITPlan/com.bitplan.antlr/blob/master/src/test/java/com/bitplan/antlr/TestExpParser.java tiene las pruebas unitarias correspondientes.
https://github.com/BITPlan/com.bitplan.antlr/blob/master/src/main/antlr4/com/bitplan/iri/IRIParser.g4 es un analizador IRI que se ha dividido en tres partes:
https://github.com/BITPlan/com.bitplan.antlr/blob/master/src/test/java/com/bitplan/antlr/TestIRIParser.java tiene las pruebas unitarias para ello.
Personalmente, esta es la parte más difícil de entender. Ver http://wiki.bitplan.com/index.php/ANTLR_maven_plugin
https://github.com/BITPlan/com.bitplan.antlr/tree/master/src/main/antlr4/com/bitplan/expr
contiene tres ejemplos más que se han creado para un problema de rendimiento de ANTLR4 en una versión anterior. Mientras tanto, este problema se ha solucionado como muestra el caso de prueba https://github.com/BITPlan/com.bitplan.antlr/blob/master/src/test/java/com/bitplan/antlr/TestIssue994.java
fuente
la versión 4.7.1 era ligeramente diferente: para importar:
para el segmento principal - tenga en cuenta los CharStreams:
fuente