Tengo una DSL relativamente simple que me gustaría manejar de forma más robusta que un montón de instrucciones codificadas manualmente java.util.regex.Pattern
+ lógica de análisis.ANTLR (o alternativa): análisis de desacoplamiento de la evaluación
La herramienta más citada parece ser ANTLR. No estoy familiarizado con esto y estoy dispuesto a intentarlo. Sin embargo, me da un poco de recelo cuando veo los ejemplos (por ejemplo, ANTLR expression evaluator example, o Martin Fowler's HelloAntlr, o this other Q on stackoverflow). La razón de esto es que los archivos de la gramática parecen ser un batiburrillo de definiciones gramaticales intercaladas con fragmentos del lenguaje de implementación (por ejemplo, Java) que son de naturaleza imperativa.
Lo que realmente preferiría es separar la parte de imperativo/evaluación del analizador. ¿Hay alguna manera de usar ANTLR (o alguna otra herramienta) para definir una gramática & producir un conjunto de archivos fuente Java para que se compile en clases que pueda usar para analizar la entrada en una estructura sin actuar sobre esa estructura?
por ejemplo, si quería utilizar evaluación de la expresión con sólo las +
y *
y ()
operadores, y que tenía la entrada
3 * (4 + 7 * 6) * (3 + 7 * (4 + 2))
entonces lo que me gustaría hacer es escribir una gramática para convertir eso a una estructura jerárquica como
Product
Term(3)
Sum
Term(4)
Product
Term(7)
Term(6)
Sum
Term(3)
Product
Term(7)
Sum
Term(4)
Term(2)
donde puedo utilizar clases como
interface Expression<T> {
public T evaluate();
}
class Term implements Expression<Double> {
final private double value;
@Override public Double evaluate() { return value; }
}
class Product implements Expression<Double> {
final private List<Expression<Double>> terms;
@Override public Double evaluate() {
double result = 1;
for (Expression<Double> ex : terms)
result *= ex.evaluate();
return result;
}
}
class Sum implements Expression<Double> {
final private List<Expression<Double>> terms;
@Override public Double evaluate() {
double result = 0;
for (Expression<Double> ex : terms)
result += ex.evaluate();
return result;
}
}
y utilizar antlr para construir la estructura. ¿Hay alguna forma de hacer esto? Realmente preferiría seguir este enfoque, ya que me permite (y otros ingenieros de software) editar y visualizar clases completas de Java sin tener que tener esas clases fragmentadas en piezas extrañas en los archivos de gramática ANTLR.
¿Hay alguna manera de hacerlo?
aclaración: Quiero pasar gran parte de mi esfuerzo posible de dos maneras: la definición de la gramática en sí, y en Java (por ejemplo, mis clases de productos/Suma/Plazo) antlr-independientes. Quiero minimizar la cantidad de tiempo/experiencia que tengo que pasar aprendiendo sintaxis ANTLR, peculiaridades y API. No sé cómo crear y manipular un AST de la gramática ANTLR. Debido a que esta es solo una pequeña parte de un gran proyecto de Java, no soy solo yo, es alguien de mi equipo el que tiene que revisar o mantener mi código.
(No pretendo parecer impertinente: estoy dispuesto a invertir tiempo y energía para utilizar una herramienta, pero solo si la herramienta se convierte en una herramienta útil y no sigue siendo un obstáculo.)
+1. Gracias por publicar el ejemplo paso a paso, eso es más o menos lo que necesitaba. Todos los otros ejemplos que miré tenían acciones imperativas en el archivo .g y no pude entender qué sintaxis era un ANTLR-ismo frente a fragmentos de Java que podían eliminarse. –
p.s. ¿Qué parte (s) de org.antlr.stringtemplate estás usando? ¿son recomendados/necesarios? –
Hmm. Cada uno de los nodos de su árbol * imprime * como una cadena ... pero, ¿qué es el nodo? ¿Cómo sabría si un nodo es un multiplyExp o un additionExp o algo más? Le daré un giro a través del depurador cuando tenga la oportunidad, pero si hay una respuesta corta + obvia, lo agradecería enormemente. –