在Composite结构上使用Interpreter模式

时间:2012-08-12 08:58:05

标签: java design-patterns composite interpreter-pattern

我被要求使用 Composite Recursive Descendent Parser Interpreter 制作表达式评估器。

这是语法

<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 “!”

作业是:

  

该项目的目标,基于Composite,Recursive Builder和   解释器,是获取条件表达式,做一个语法分析   并构建其复合树。从树上开始,你必须这样做   根据外部环境评估条件的结果   (从属性文件中读取)包含内部值   变量

现在,我注意到的第一件事是 Interpreter 使用 Composite 结构,所以扩展 Composite 似乎是个好主意具有 evaluate(:Context)方法的结构。

我已经四处询问,但我被告知这不是执行任务的方式。 好像我已经构建了 Interpreter 树,从 Composite 开始(这对我来说非常不合适,因为我已经有了一棵树可以使用了! )。

所以我使用 Composite + Recursive Builder 构建了我的树,它识别输入并构建树而没有任何问题。

但问题是:如何将 Interpreter 应用于我的结构?

这是我的班级图(某些东西是意大利语但很容易理解)

Composite+Builder class diagram

如果我做得对, Interpreter 为每个语法规则使用一个类,所以我必须创建一个 cond 类,然后是 termb < / em>等等。

但我可以将它们链接到我的复合材料吗?

3 个答案:

答案 0 :(得分:10)

不确定为什么会被告知不要使用相同的树结构。我想我会在我的表达式接口中添加一个evaluate()方法。对于我,这说得通。表达式应该知道如何评估自己。

我会说你当前的表达式接口暴露太多(比如操作数)。作为表达式的客户端,我只需要1)调用它,2)读取结果,我想也许3)打印它。实际上,我更喜欢使用toString()直接打印。

您可能已经注意到但并非所有表达式都采用2个操作数(例如NOT或NEGATE)。这已经与您的界面产生了一种差异。我会将其简化为:

 public interface Expression {
   int evaluate();
 }

然后,您的每个操作和终端都知道如何评估自身(并将自身转换为字符串)。

所以我可以进行如下具体操作:

 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
 }

现在我可以很容易地构建树

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);

我甚至不需要直接访问各个操作数。

答案 1 :(得分:3)

如果我理解你的问题,我会说每个具体的类应该由你的主要复合结构的子类。

如果Expression是你的主要复合词,那么:

表达:术语 表达式:OperandTerm

条件:术语BinOperand表达式 条件:UnaryOperand表达式

术语:Int |       Foat |       ...

。 。

答案 2 :(得分:2)

interpreter为您提供了一种基于终端而非终端对象定义语言表达的方法。解释器本身就是一个复合模式,所以我认为它已经应用了。

也许您不需要为每个终端和终端元素创建一个类,在非终端/终端子句中使用类似(operatorType,expressionType)的属性与您的语法符号不同。

使用你的语法生成的给定和表达式如[A = 0],用解释器的模式类形成的对象树将如下所示(请原谅我的错误质量和UML sintax错误,但我现在没有合适的UML编辑器):

enter image description here

此对象树应由表达式分析器构建。获得此树后,使用Recursive Descendent Parser遍历此树,评估每个树节点。

因此,解析器会对表达式进行评估,解释器会为您提供表示语法表达式的数据结构。

希望得到这个帮助。