美文网首页设计模式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