• 解释器模式实例分析


    模式适用环境

    在以下情况下可以使用解释器模式:

    ·可以将一个需要解释执行的语言中的句子表示为一个抽象语法树。

    ·一些重复出现的问题可以用一种简单的语言来进行表达。

    ·文法较为简单。

    ·效率不是关键问题。

    ·一些重复发生的事情包含固定的一系列操作类型,比较适合用解释器模式来实现。

    解决问题

    ·加减乘除四则运算,但是公式每次都不同,比如可配置,有时是a + b - c x d,有时是a x b + c - d,等等等等个,公式千变万化,但是都是由加减乘除四个非终结符来连接的,这时我们就可以使用解释器模式。

    ·解释器模式在使用面向对象语言实现的编译器中得到了广泛的应用,如Smalltalk语言的编译器。

    ·目前有一些基于Java抽象语法树的源代码处理工具,如在Eclipse中就提供了Eclipse AST,它是Eclipse JDT的一个重要组成部分,用来表示Java语言的语法结构,用户可以通过扩展其功能,创建自己的文法规则。

    ·可以使用解释器模式,通过C++JavaC#等面向对象语言开发简单的编译器,如数学表达式解析器、正则表达式解析器等,用于增强这些语言的功能,使之增加一些新的文法规则,用于解释一些特定类型的语句。

    解决方案

    ·文法规则定义语言

    文法规则实例:

    expression ::= value | symbol

    symbol ::= expression '+' expression | expression '-' expression

    value ::= an integer //一个整数值

    在文法规则定义中可以使用一些符号来表示不同的含义,如使用|”表示或,使用“{”和“}”表示组合,使用“*”表示出现0次或多次等,其中使用频率最高的符号是表示 或关系的“|” 。

    ·抽象语法数定义语言

    除了使用文法规则来定义一个语言,在解释器模式中还可以通过一种称之为抽象语法树(Abstract Syntax Tree, AST)的图形方式来直观地表示语言的构成,每一棵抽象语法树对应一个语言实例。抽象语法树描述了如何构成一个复杂的句子,通过对抽象语法树的分析,可以识别出语言中的终结符和非终结符类。抽象语法树描述了如何构成一个复杂的句子,通过对抽象语法树的分析,可以识别出语言中的终结符和非终结符类。在解释器模式中,每一种终结符和非终结符都有一个具体类与之对应,正因为使用类来表示每一个语法规则,使得系统具有较好的扩展性和灵活性。

    实例

    实例:数学运算解释器

    现需要构造一个语言解释器,使得系统可以执行整数间的乘、除和求模运算。如用户输入表达式3 * 4 / 2 % 4”,输出结果为2。使用解释器模式实现该功能。

     
     

    解释器模式实例与解析

    实例:数学运算解释器

    //行为型模式:解释器模式
    //场景:四则运算
     
    #include <iostream>
    #include <string>
    #include <map>
    #include <stack>
    #include <typeinfo>
     
    using namespace std;
     
    //*******************************************抽象表达式类***********************************
    class Expression
    {
    public:
        //解析公式和数值,其中var中的key是公式中的参数,value值是具体的数字
        //如a = 100; b = 20; c = 40
        virtual int interpreter(map<string, int>& var) = 0;
        virtual ~Expression(){};
    };
     
     
    //变量解析器(终结符表达式)
    class VarExpression : public Expression
    {
        string key;
    public:
        VarExpression(string key)
        {
            this->key = key;
        }
     
        //从map中取出变量的值
        int interpreter(map<string, int>& var)
        {
            return var[key];
        }
     
        ~VarExpression()
        {
            cout << "~VarExpression()" << endl;
        }
    };
    //**********抽象运算符号解析器***********************
    //抽象运算符号解析器
    class SymbolExpression : public Expression
    {
    protected:
        Expression* left;
        Expression* right;
    public:
        SymbolExpression(Expression* left, Expression* right)
        {
            this -> left = left;
            this -> right = right;
        }
     
        Expression* getLeft()
        {
            return left;
        }
        Expression* getRight()
        {
            return 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);
        }
        ~AddExpression()
        {
            cout << "~AddExpression()" << endl;
        }
    };
     
    //减法解析器
    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);
        }
     
        ~SubExpression()
        {
            cout << "~SubExpression()" << endl;
        }
    };
     
    //*********************************解析器封装类***************************************
    //解析器封装类,这个类是根据迪米特法则进行封装,目的是让Client只与直接朋友打交道,相当于Facade
    class Calculator
    {
    private:
        Expression* expression;
    public:
        //构造函数传参,并解析表达式,构建语法树
        Calculator(string expStr)
        {
            expression = NULL;
     
            //栈,用来暂存中间结果
            stack<Expression*> stkExp;
     
            Expression* left  = NULL;
            Expression* right = NULL;
     
            /*从左到向分析表达式(如:a+b-c),最终的语法树如下:
             *           -
             *         /   
             *       +     c
             *     /   
             *    a     b
            */
            for(unsigned int i = 0; i< expStr.length(); i++)
            {
                switch(expStr[i])
                {
                case '+':  //加法
                    //1.先从栈中取出左操作数
                    left = stkExp.top();
                    stkExp.pop();
     
                    //2.从表达式中取出+号后面的右操作数,并生成终结符解析对象
                    right = new VarExpression(expStr.substr(++i,1));
     
                    //3.将左右操作数相加,并把结果放入栈中
                    stkExp.push(new AddExpression(left, right));
     
                    break;
     
                case '-':
                    //1.先从栈中取出左操作数
                    left = stkExp.top();
                    stkExp.pop();
     
                    //2.从表达式中取出+号后面的右操作数,并生成终结符解析对象
                    right = new VarExpression(expStr.substr(++i,1));
     
                    //3.将左右操作数相减,并把结果放入栈中
                    stkExp.push(new SubExpression(left, right));
     
                    break;
     
                default:
                    //如果是变量(终结符):如a+b+c中的ac,
                    //则直接生成对应的变量解析器对象
                    stkExp.push(new VarExpression(expStr.substr(i,1)));
                }
            }
     
            //栈中保存的就是最终语法树的根结点(本例为SuuExpression对象)
            if(!stkExp.empty())
            {
                expression = stkExp.top();
                stkExp.pop();
            }
        }
     
        void deltree(Expression* expression)
        {
            SymbolExpression* branch = dynamic_cast<SymbolExpression*>(expression);
            //叶子结点
            if (branch == NULL)
            {
                delete expression;
            }
            else  //分支结点
            {
                //左子树
                deltree(branch->getLeft());
     
                //右子树
                deltree(branch->getRight());
     
                //结点
                delete expression;
            }
        }
     
        ~Calculator()
        {
            deltree(expression);
            expression = NULL;
        }
     
        //开始运算
        int run(map<string, int>& var)
        {
            return (expression == NULL) ? 0 : expression->interpreter(var);
        }
    };
    int main()
    {
        string expStr = "a+b-c"; //为简化处理,这里必须是合法的表达式
     
        map<string, int> var;   //相当于Interpreter模式中的Context
        var["a"] = 100;
        var["b"] = 20;
        var["c"] = 40;
     
        Calculator cal(expStr);
     
        cout <<"运算结果为:" << expStr << " = " << cal.run(var) << endl;
        return 0;
    }
    /*
    运算结果为:a+b-c = 80
    ~VarExpression()
    ~VarExpression()
    ~AddExpression()
    ~VarExpression()
    ~SubExpression()
    */
     
     

    语法树构建:

  • 相关阅读:
    关于 UITableView 中 网络获取图片 cell 自适应高度的问题
    iOS开发~CocoaPods使用详细说明
    block的使用
    约数个数
    学习Hibernate的(笔者一共会写四部分)
    八皇后问题
    JAVA(利用jsp+javabean+servlet)实现简易计算器
    学习C++的道路 博主会持续更新的
    高效求解区间约数
    最大化平均值
  • 原文地址:https://www.cnblogs.com/wf1647790534/p/9096818.html
Copyright © 2020-2023  润新知