2012-08-12 13 views
10

Me han pedido hacer un evaluador de expresiones usando Compuesto , recursiva Descendiente Analizador y intérprete.Utilizando los patrones de intérpretes bajo una estructura compuesta

Aquí está la gramática:

<cond> → <termb> [OR <termb>]* 
<termb>→<factb>[AND <factb>]* 
<factb>→<expr> RELOP <expr> | NOT <factb> | OPAR <cond> CPAR 
<expr> → [PLUS | MINUS] <term> [(PLUS <term>) | (MINUS <term>)]* 
<term> → <termp> [(MULT <termp>) | (DIV <termp>) | (REM <termp>)]* 
<termp> → <fact> [POWER <fact>]* 
<fact> → ID | NUM | OPAR1 <expr> CPAR1 
----TERMINALS---- 
ID → ("A" | ... | "Z" | "a" | ...| "z") [("A"| ... | "Z" | "a" | ...| "z" | "0" | ... | "9")]* 
NUM → ("0" | ... | "9") [("0" | ... | "9")]* 
OPAR → "(" 
CPAR → ")" 
OPAR1 → "[" 
CPAR1 → "]" 
RELOP → EQ | NEQ | GT | GE | LT | LE 
EQ → "= =" 
NEQ → "!=" 
GT → ">" 
GE → ">=" 
LT → "<" 
LE → "<=" 
POWER → "^" 
DIV → "/" 
REM → "%" 
MULT → "*" 
MINUS → "−" 
PLUS → "+" 
AND → “and” or “&&” 
OR → “or” or “||” 
NOT → “not” or “!” 

La asignación es:

El objetivo del proyecto, basado en compuesto, recursiva Builder y intérprete, es conseguir una expresión condicional, hacer un análisis de sintaxis y construir su árbol compuesto. A partir del árbol, tienes que evaluar el resultado de la condición, en base a un contexto externo (leer desde un archivo de propiedades) que contiene el valor de las variables internas

Ahora, la primera cosa que he notado es que intérprete utiliza una estructura compuesta , por lo que parecía una buena idea para extender mi compuesto con una estructura evaluar (: Contexto) método.

He preguntado por ahí, pero me han dicho que esta no es la forma de hacer la tarea. Parece que tengo construir el intérprete árbol, comenzando desde Composite uno (que es bastante absurdo para mí, ya que ya tengo un árbol para trabajar!).

Así que he construido mi árbol usando Compuesto + recursiva Constructor, reconoce la entrada y construir el árbol sin ningún tipo de problema.

Pero la pregunta es: ¿cómo puedo aplicar Intérprete a mi estructura?

Aquí es mi diagrama de clases (algo que es italiano pero es bastante comprensible)

Composite+Builder class diagram

Si lo tengo derecho, intérprete utiliza una clase para cada regla gramatical, por lo que tengo que hacer un cond clase, luego un termb y así sucesivamente.

Pero, ¿los puedo vincular con mi compuesto?

Respuesta

10

No estoy seguro de por qué le dijeron que no use la misma estructura de árbol. Creo que agregaría un método de evaluación() a mi interfaz de expresión. Tiene sentido para mí. Una expresión debe saber cómo evaluarse a sí misma.

Yo diría que su interfaz de expresión actual expone demasiado (como operandos). Como cliente de expresión, solo debería necesitar 1) invocarlo y 2) leer el resultado y supongo que quizás 3) imprimirlo. En realidad, preferiría usar toString() sobre la impresión directa.

Probablemente ya lo haya notado pero no todas las expresiones toman 2 operandos (como NOT o NEGATE). Esto ya crea una especie de discrepancia con su interfaz. Me simplificarlo a:

public interface Expression { 
    int evaluate(); 
} 

A continuación, cada una de sus operaciones y terminales sabe cómo evaluar en sí (y convertir a sí una cadena).

así que podría haber operaciones concretas como:

public class Terminal implements Expression { 
    private final int value; 

    public Terminal(int value) { this.value = value; } 

    public int evaluate() { return value; } 

    public String toString() { return String.valueOf(value); } 
} 

public class Add implements Expression { 
    private final Expression left; 
    private final Expression right; 

    public Add(Expression left, Expression right) { 
    this.left = left; 
    this.right = right; 
    } 

    public String toString() { 
    return left.toString() + " + " + right.toString(); 
    } 

    // leave the rest for you 
} 

Ahora puedo construir el árbol con bastante facilidad

Expression expr = new Add(new Terminal(1), new Subtract(new Terminal(2), new Terminal(3))); 

int result = expr.evaluate(); 
System.out.print(expr.toString() + " = " + result); 

Y yo ni siquiera necesita acceso directo a los operandos individuales.

+0

Eso es básicamente lo que pensé desde el principio, pero ¡quizás debería dejar de confiar en las personas que brindan consejos sin saber de qué están hablando! – StepTNT

3

Si entiendo correctamente su problema, yo diría que cada clase concreta debe hacerse por una subclase de su estructura compuesta principal.

si la expresión que está compuesto principal a continuación:

Expresión: Plazo Expresión: OperandTerm

Estado: Plazo BinOperand Expresión Estado: Expresión UnaryOperand

Plazo: Int | Foat | ...

. . .

2

El interpreter le proporciona una forma de definir una expresión de su idioma basada en objetos terminales y no terminales. Un intérprete es un patrón compuesto en sí mismo, así que creo que ya está aplicado.

Quizás no necesite crear una clase por elemento terminal y terminal, use atributos como (operatorType, expressionType) en clases NonTerminal/Terminal para diferir de sus símbolos gramaticales.

Dada y expresión generada con su gramática como [A = 0], el árbol de objetos formado con clases de patrones de intérpretes se verá así (perdonen la mala calidad y los errores sintaxis UML pero ahora no tengo un UML adecuado editor):

enter image description here

Este árbol de objetos deben construirse mediante un analizador de expresión. Una vez que tenga este árbol, use el analizador de descendientes recursivo para recorrer este árbol evaluando cada nodo de árbol.

Así que la evaluación de la expresión es hecha por el analizador, y el intérprete le proporciona una estructura de datos para representar sus expresiones gramaticales.

Espero que esta ayuda.

Cuestiones relacionadas