模式適用環境
在以下情況下可以使用解釋器模式:
·可以將一個需要解釋執行的語言中的句子表示為一個抽象語法樹。
·一些重復出現的問題可以用一種簡單的語言來進行表達。
·文法較為簡單。
·效率不是關鍵問題。
·一些重復發生的事情包含固定的一系列操作類型,比較適合用解釋器模式來實現。
解決問題
·加減乘除四則運算,但是公式每次都不同,比如可配置,有時是a + b - c x d,有時是a x b + c - d,等等等等個,公式千變萬化,但是都是由加減乘除四個非終結符來連接的,這時我們就可以使用解釋器模式。
·解釋器模式在使用面向對象語言實現的編譯器中得到了廣泛的應用,如Smalltalk語言的編譯器。
·目前有一些基於Java抽象語法樹的源代碼處理工具,如在Eclipse中就提供了Eclipse AST,它是Eclipse JDT的一個重要組成部分,用來表示Java語言的語法結構,用戶可以通過擴展其功能,創建自己的文法規則。
·可以使用解釋器模式,通過C++、Java、C#等面向對象語言開發簡單的編譯器,如數學表達式解析器、正則表達式解析器等,用於增強這些語言的功能,使之增加一些新的文法規則,用於解釋一些特定類型的語句。
解決方案
·文法規則定義語言
文法規則實例:
expression ::= value | symbol
symbol ::= expression '+' expression | expression '-' expression
value ::= an integer //一個整數值
在文法規則定義中可以使用一些符號來表示不同的含義,如使用“|”表示或,使用“{”和“}”表示組合,使用“*”表示出現0次或多次等,其中使用頻率最高的符號是表示 或關系的“|” 。
·抽象語法數定義語言
除了使用文法規則來定義一個語言,在解釋器模式中還可以通過一種稱之為抽象語法樹(Abstract Syntax Tree, AST)的圖形方式來直觀地表示語言的構成,每一棵抽象語法樹對應一個語言實例。抽象語法樹描述了如何構成一個復雜的句子,通過對抽象語法樹的分析,可以識別出語言中的終結符和非終結符類。抽象語法樹描述了如何構成一個復雜的句子,通過對抽象語法樹的分析,可以識別出語言中的終結符和非終結符類。在解釋器模式中,每一種終結符和非終結符都有一個具體類與之對應,正因為使用類來表示每一個語法規則,使得系統具有較好的擴展性和靈活性。
實例
實例:數學運算解釋器
現需要構造一個語言解釋器,使得系統可以執行整數間的乘、除和求模運算。如用戶輸入表達式“3 * 4 / 2 % 4”,輸出結果為2。使用解釋器模式實現該功能。
![]()
|
解釋器模式實例與解析
實例:數學運算解釋器
//行為型模式:解釋器模式 //場景:四則運算 #include <iostream> #include <string> #include <map> #include <stack> #include <typeinfo> using namespace std; //*******************************************抽象表達式類*********************************** class Expression { public: //解析公式和數值,其中var中的key是公式中的參數,value值是具體的數字 //如a = 100; b = 20; c = 40 virtual int interpreter(map<string, int>& var) = 0; virtual ~Expression(){}; }; //變量解析器(終結符表達式) class VarExpression : public Expression { string key; public: VarExpression(string key) { this->key = key; } //從map中取出變量的值 int interpreter(map<string, int>& var) { return var[key]; } ~VarExpression() { cout << "~VarExpression()" << endl; } }; //**********抽象運算符號解析器*********************** //抽象運算符號解析器 class SymbolExpression : public Expression { protected: Expression* left; Expression* right; public: SymbolExpression(Expression* left, Expression* right) { this -> left = left; this -> right = right; } Expression* getLeft() { return left; } Expression* getRight() { return right; } }; //加法解析器 class AddExpression : public SymbolExpression { public: AddExpression(Expression* left, Expression* right): SymbolExpression(left,right) { } //把左右兩個表達式運算的結果加起來 int interpreter(map<string, int>& var) { return left->interpreter(var) + right ->interpreter(var); } ~AddExpression() { cout << "~AddExpression()" << endl; } }; //減法解析器 class SubExpression : public SymbolExpression { public: SubExpression(Expression* left, Expression* right): SymbolExpression(left,right) { } //把左右兩個表達式運算的結果相減 int interpreter(map<string, int>& var) { return left->interpreter(var) - right ->interpreter(var); } ~SubExpression() { cout << "~SubExpression()" << endl; } }; //*********************************解析器封裝類*************************************** //解析器封裝類,這個類是根據迪米特法則進行封裝,目的是讓Client只與直接朋友打交道,相當於Facade class Calculator { private: Expression* expression; public: //構造函數傳參,並解析表達式,構建語法樹 Calculator(string expStr) { expression = NULL; //棧,用來暫存中間結果 stack<Expression*> stkExp; Expression* left = NULL; Expression* right = NULL; /*從左到向分析表達式(如:a+b-c),最終的語法樹如下: * - * / \ * + c * / \ * a b */ for(unsigned int i = 0; i< expStr.length(); i++) { switch(expStr[i]) { case '+': //加法 //1.先從棧中取出左操作數 left = stkExp.top(); stkExp.pop(); //2.從表達式中取出+號后面的右操作數,並生成終結符解析對象 right = new VarExpression(expStr.substr(++i,1)); //3.將左右操作數相加,並把結果放入棧中 stkExp.push(new AddExpression(left, right)); break; case '-': //1.先從棧中取出左操作數 left = stkExp.top(); stkExp.pop(); //2.從表達式中取出+號后面的右操作數,並生成終結符解析對象 right = new VarExpression(expStr.substr(++i,1)); //3.將左右操作數相減,並把結果放入棧中 stkExp.push(new SubExpression(left, right)); break; default: //如果是變量(終結符):如a+b+c中的a\b\c, //則直接生成對應的變量解析器對象 stkExp.push(new VarExpression(expStr.substr(i,1))); } } //棧中保存的就是最終語法樹的根結點(本例為SuuExpression對象) if(!stkExp.empty()) { expression = stkExp.top(); stkExp.pop(); } } void deltree(Expression* expression) { SymbolExpression* branch = dynamic_cast<SymbolExpression*>(expression); //葉子結點 if (branch == NULL) { delete expression; } else //分支結點 { //左子樹 deltree(branch->getLeft()); //右子樹 deltree(branch->getRight()); //結點 delete expression; } } ~Calculator() { deltree(expression); expression = NULL; } //開始運算 int run(map<string, int>& var) { return (expression == NULL) ? 0 : expression->interpreter(var); } }; int main() { string expStr = "a+b-c"; //為簡化處理,這里必須是合法的表達式 map<string, int> var; //相當於Interpreter模式中的Context var["a"] = 100; var["b"] = 20; var["c"] = 40; Calculator cal(expStr); cout <<"運算結果為:" << expStr << " = " << cal.run(var) << endl; return 0; } /* 運算結果為:a+b-c = 80 ~VarExpression() ~VarExpression() ~AddExpression() ~VarExpression() ~SubExpression() */
![]()
|
語法樹構建: