定义
解释器模式(InterpreterPattern)给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子。
解释器模式通用类图
AbstractExpression——抽象解释器
具体的解释任务由各个实现类完成,具体的解释器分别由TerminalExpression和NonterminalExpression完成。
TerminalExpression——终结符表达式
实现与文法中的元素相关联的解释操作,通常以一个解释器模式中只有一个终结符表达式,但有多个实例,对应不同的终结符。
NonterminalExpression——非终结符表达式
文法中的每条规则对应于一个非终结表达式,原则上每一个文法规则都需要一个非终结符号表达式。
Context——环境角色
包含解释器之外的一些全局信息
解释器模式的优点
易于改变和扩展文法 因为该模式使用类来表示文法规则,你可使用继承来改变或扩展该文法。已有的表达式可被增量式地改变,而新的表达式可定义为旧表达式的变体。
缺点
复杂的文法难以维护 解释器模式为文法中的每一条规则至少定义了一个类(使用BNF定
义的文法规则需要更多的类)。因此包含许多规则的文法可能难以管理和维护。可应用其他的设计模式来缓解这一问题。但当文法非常复杂时,其他的技术如语法分析程序或编译器生成器更为合适。
举例:
四则运算,简单起见,不含乘除法和括号,即运算不分优先级,只有加减法。
C++源码
#include <iostream>
#include <map>
#include <stack>
using namespace std;
class Expression{ //表达式抽象基类
public:
virtual int interpreter(map<string,int>& var)=0;
virtual ~ Expression(){};
};
class VarExpression:public Expression{ //终结符表达式,这里为数值元素
private:
string key;
public:
VarExpression(string _key):key(_key){}
int interpreter(map<string,int>& var)
{
map<string,int>::iterator it = var.find(this->key);
return it->second;
}
};
class SymbolExpression:public Expression{
protected:
Expression *left;
Expression *right;
public:
SymbolExpression(Expression *_left,Expression *_right)
{
this->left=_left;
this->right=_right;
}
virtual ~ SymbolExpression(){
if(left != NULL)
delete left;
if(right != NULL)
delete 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);
}
};
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);
}
};
class Calculator{
private:
Expression *expression;
public:
Calculator(string expStr){
stack<Expression *> expStack;
Expression *left = NULL;
Expression *right = NULL;
for(size_t i=0;i<expStr.length();i++){
switch(expStr[i])
{
case '+':
left = expStack.top();
expStack.pop();
right = new VarExpression(expStr.substr(++i,1));
expStack.push(new AddExpression(left,right));
break;
case '-':
left = expStack.top();
expStack.pop();
right = new VarExpression(expStr.substr(++i,1));
expStack.push(new SubExpression(left,right));
break;
default:
expStack.push(new VarExpression(expStr.substr(i,1)));
}
}
this->expression = expStack.top();
expStack.pop();
}
int run(map<string,int> &var){
return this->expression->interpreter(var);
}
~Calculator(){
delete expression;
}
};
int main()
{
string expStr;
cout<<"请输入表达式:"<<flush;
cin>>expStr;
map<string,int> var ;
for(size_t i=0;i<expStr.length();i++)
{
if(expStr[i] != '+' && expStr[i] != '-'){
if(var.end() == var.find(expStr.substr(i,1)))
{
cout<<"请输入"<<expStr.substr(i,1)<<"的值"<<flush;
int temp;
cin>>temp;
var.insert(make_pair(expStr.substr(i,1),temp));
}
}
}
Calculator cal(expStr);
cout<<"运算结果为:"<<expStr<<" = "<<cal.run(var);
return 0;
}
对于表达式 a+b-c的语法树分析图:
很明显,这是一棵二叉树,其中,终结符表达式(VarExpression)对象均为树的叶子节点,非终结表达式(SymbolExpression的子类)对象均为树的非叶节点,因为都是二元操作符,所以每个非终结表达式均带两个子树,子树根节点的类型可以为终结符表达式或非终结符表达式。对表达式进行代数运算实际就是后序遍历这棵语法树(由interpreter的递归调用方式就可以看出来)。
运行结果: