2012-08-12 87 views
10

我一直在問要使用複合遞歸下降解析器解釋表達式評估使用解釋器模式。在複合結構

這裏的語法

<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 「!」 

分配是:

項目的基礎上,綜合,遞歸Builder和 解釋的目的,是爲了獲得一個條件表達式,做一個語法分析 並構建它的組合樹。從樹上開始,你就必須 評估條件的結果,基於外部背景 (從屬性文件讀取),它包含內部 變量

的價值現在,第一我注意到的是,解釋使用複合結構,所以它似乎是一個好主意,用致以複合結構評估(:上下文)方法。

我問過周圍,但我被告知這不是做任務的方式。 好像我已經建立了譯員樹,從複合樹(這對我來說是非常不可思議的,因爲我已經有一棵樹可以使用!)。

所以我已經建立了使用複合 + 遞歸構建我的樹,它識別輸入,並將其打造的樹沒有任何形式的問題。

但問題是:我如何將解釋器應用於我的結構?

這裏是我的類圖(什麼是意大利人,但它是完全可以理解的)

Composite+Builder class diagram

如果我這樣做是正確,解釋使用每個語法規則一類,所以我必須做a cond class,then a termb等等。

但我是否將它們鏈接到我的合成?

回答

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

而且我也不需要單獨的操作數的直接訪問。

+0

這基本上是我從一開始就想到的,但也許我應該停止相信那些在不知道他們在說什麼的情況下提供建議的人! – StepTNT 2012-08-21 11:03:11

3

如果我正確理解你的問題,我會說每一個具體的類應該由你的主要複合結構的子類。

如果表達的是你的主要組合則:

表達:期限 表達:OperandTerm

條件:期限BinOperand表達 條件:UnaryOperand表達

期限:國際| Foat | ...

。 。 。

2

interpreter爲您提供了一種基於終端而不是終端對象定義語言表達式的方法。解釋器本身就是一個複合模式,所以我認爲它已經被應用。

也許您不需要爲每個非終端和終端元素創建一個類,在非終端/終端類中使用像(operatorType,expressionType)這樣的屬性與您的語法符號不同。

給定和表達式用[A = 0]的語法生成,與解釋器的模式類形成的對象樹看起來像這樣(請原諒質量差和UML sintax錯誤,但我現在沒有合適的UML編輯):

enter image description here

該目的樹應該由表達式分析器來構造。一旦擁有這棵樹,使用Recursive Descendent Parser來遍歷這棵樹來評估每個樹節點。

因此,表達式的評估由解析器完成,解釋器爲您提供一個數據結構來表示您的語法表達式。

希望得到這個幫助。