解释器模式

来源:互联网 发布:淘宝网充气浴缸 编辑:程序博客网 时间:2024/05/22 03:51

定义

解释器模式(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的递归调用方式就可以看出来)。

运行结果:



0 0
原创粉丝点击