美文网首页设计模式C++设计模式设计模式 BY C++
C++ 设计模式 —— 15.解释器模式

C++ 设计模式 —— 15.解释器模式

作者: JeremyYv | 来源:发表于2019-12-28 00:52 被阅读0次
  • 解释器模式:一种行为型设计模式

首先,我想先说明一下,解释器模式是我个人认为最复杂的设计模式,可能因为我目前对编程语言的解析原理不甚了解,对这个模式的理解也很片面。

  • 应用场景:
    解释器模式的应用场景是对语句进行解析。给定语法规则,先将语句形成语义树,然后通过解释器对语义树进行解释,输出结果。
    常用场景如解析xml配置文件
  • 举例:
    以解析a+b+c来举例,将a+b+c五个符号作为独立的对象来解析。
    这五个符号根据解析方式不同可分为两类,a b c为一类,这类对象的解析结果就是这个对象本身的值。而+的解析要取这个元素左右相邻的两个元素,进行相加,将和作为解析结果返回。
    解释前先生成语义树,类似这样:
      +
    /   \
   +     c
  /   \
 a     b

然后从根节点开始,依次对节点进行递归解析。a b c这类解释器使程序不会无限递归下去,称作终结符解释器(终结递归)。另一类需要递归向下解析的,称作非终结符解释器

  • 实现方式:
    解释器基类派生出终结符解释器非终结符解释器,非终结符解释器根据解释功能派生出具体的解释器类+调用左右两数相加,-调用左右两数相减)。
    再有一个解析器,将语句生成语义树。

以下是解释器模式的简单代码实现
#include <iostream>
#include <string>
#include <map>
#include <stack>
#include <typeinfo>

using namespace std;

//解释器抽象类
class Expression
{
public:
    //解析公式和数值,其中mapValue中的key是公式中的参数,value值是具体的值
    virtual int interpreter(map<string, int>& MapValue) = 0;
    virtual ~Expression(){};
};


//变量解析器(终结符)
class VarExpression : public Expression
{
    string m_strkey;
public:
    VarExpression(string strkey):m_strkey(strkey){}

    //从map中取出变量的值
    int interpreter(map<string, int>& MapValue)
    {
        return MapValue[m_strkey];
    }
};

//运算符解析器(非终结符)
class SymbolExpression : public Expression
{
protected:
    Expression* m_pLeft;
    Expression* m_pRight;
public:
    SymbolExpression(Expression* pLeft, Expression* pRight):m_pLeft(pLeft), m_pRight(pRight){}
};

//加法解析器
class AddExpression : public SymbolExpression
{
public:
    AddExpression(Expression* pLeft, Expression* pRight):SymbolExpression(pLeft,pRight){}

    //把左右两个变量相加
    int interpreter(map<string, int>& MapValue)
    {
        return m_pLeft->interpreter(MapValue) + m_pRight ->interpreter(MapValue);
    }
};

//减法解析器
class SubExpression : public SymbolExpression
{
public:
    SubExpression(Expression* pLeft, Expression* pRight): SymbolExpression(pLeft,pRight)
    {
    }

    //把左右两个变量相减
    int interpreter(map<string, int>& MapValue)
    {
        return m_pLeft->interpreter(MapValue) - m_pRight ->interpreter(MapValue);
    }
};

//语义解析器
class Parse
{
private:
    Expression* m_pExpression;
public:
    //构造函数传参,并解析表达式,构建语法树
    Parse(string strExpStr)
    {
        m_pExpression = NULL;
        stack<Expression*> stackExp;

        Expression* pLeft  = NULL;
        Expression* pRight = NULL;

        for(unsigned int i = 0; i< strExpStr.length(); ++i)
        {
            switch(strExpStr[i])
            {
            case '+':  //加法
                //1.先从栈中取出左操作数
                pLeft = stackExp.top();
                stackExp.pop();

                //2.从表达式中取出+号后面的右操作数,并生成终结符解析对象
                pRight = new VarExpression(strExpStr.substr(++i,1));

                //3.将左右操作数相加,并把结果放入栈中
                stackExp.push(new AddExpression(pLeft, pRight));

                break;

            case '-':
                //1.先从栈中取出左操作数
                pLeft = stackExp.top();
                stackExp.pop();

                //2.从表达式中取出+号后面的右操作数,并生成终结符解析对象
                pRight = new VarExpression(strExpStr.substr(++i,1));

                //3.将左右操作数相减,并把结果放入栈中
                stackExp.push(new SubExpression(pLeft, pRight));

                break;

            default:
                //如果是变量(终结符),
                //则直接生成对应的变量解析器
                stackExp.push(new VarExpression(strExpStr.substr(i,1)));
            }
        }

        //栈中保存的就是最终语法树的根结点(本例为SuuExpression对象)
        if(!stackExp.empty())
        {
            m_pExpression = stackExp.top();
            stackExp.pop();
        }
    }

    //开始运算
    int Calculate(map<string, int>& MapValue)
    {
        return (!m_pExpression) ? 0 : m_pExpression->interpreter(MapValue);
    }
};

主函数中的使用
int main()
{
    string strExpression = "a-b+c";

    map<string, int> MapValue;
    MapValue["a"] = 50;
    MapValue["b"] = 40;
    MapValue["c"] = 30;

    Parse ParseTree(strExpression); //生成语义树

    cout << strExpression << " = " << ParseTree.Calculate(MapValue) << endl;

    return 0;
}
控制台输出结果
a-b+c = 40

如有错误,欢迎指正

相关文章

网友评论

    本文标题:C++ 设计模式 —— 15.解释器模式

    本文链接:https://www.haomeiwen.com/subject/iwujoctx.html