模式适用环境
在以下情况下可以使用解释器模式:
·可以将一个需要解释执行的语言中的句子表示为一个抽象语法树。
·一些重复出现的问题可以用一种简单的语言来进行表达。
·文法较为简单。
·效率不是关键问题。
·一些重复发生的事情包含固定的一系列操作类型,比较适合用解释器模式来实现。
解决问题
·加减乘除四则运算,但是公式每次都不同,比如可配置,有时是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中的ac, //则直接生成对应的变量解析器对象 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() */
语法树构建: