解释器模式实例分析


 

模式适用环境

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

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

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

·文法较为简单。

·效率不是关键问题。

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

解决问题

·加减乘除四则运算,但是公式每次都不同,比如可配置,有时是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中的a\b\c,
                //则直接生成对应的变量解析器对象
                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()
*/

 

 
 

 

语法树构建:


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM