解释器模式

定义

解释器模式(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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值