第27章解释器模式

一 概念

  • 解释器模式,给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子。
  • 解释器要解决的问题是,如果一种特定类型的问题发生的频率足够高,那么可能就值得将该问题的各个实例表述为一个简单语言中的句子,这样就可以构建一个解释器,该解释器通过解释这些句子来解决该问题。

二 UML图

  • Context 包含解释器之外的一些全局信息,对全局的一些内容进行描述
  • AbstractExpression 抽象表达式,声明一个抽象的解释操作,这个接口为抽象语法树中所有的节点所共享。
  • TerminalExpression 终结符表达式,实现与文法中的终结符相关联的解释操作。
  • NonterminalExpression 非终结符表达式,为文法中的非终结符实现解释操作,对文法中每一条规则R1,R2,。。。Rn都需要一个具体的非终结符表达式类。

三 C++代码实现

#include "pch.h"
#include <iostream>
#include <string>
#include <vector>
#include <sstream>
using namespace std;

template <typename elemType>
elemType stringToNum(const string& str)
{
    istringstream iss(str);
    elemType num;
    iss >> num;
    return num;
}

//包含解释器之外的一些全局信息
class PlayContext
{
public:
    void SetPlayContext(const string text)
    {
        this->str_text = text;
    }
    string GetPlayContext() const
    {
        return this->str_text;
    }
private:
    string str_text;
};
//表达式类 AbstractExpression
//抽象表达式,声明一个抽象的解释操作,这个接口为抽象语法树中所有的节点所共享
class Expression
{
public:
    virtual void Interpret(PlayContext* context)
    {
        string buf;
        string s2;
        if (context->GetPlayContext().size() == 0)
        {
            return;
        }
        else
        {
            vector<string> vec;
            stringstream ss(context->GetPlayContext());
            while (ss >> buf)
            {
                vec.push_back(buf);
            }

            //这里是C++的字符串处理
            string playKey = vec[0];
            double playValue = stringToNum<double>(vec[1]);
            this->Excute(playKey, playValue);

            vec.erase(vec.begin(), vec.begin() + 2);
            vector<string>::iterator it;
            for (it = vec.begin(); it != vec.end(); it++)
            {
                s2 += *it;
                if (it != vec.end() - 1)
                    s2 += " ";
            }
            context->SetPlayContext(s2);
        }
    }
    virtual void Excute(string key, double value) = 0;
};

//音符类
//TerminalExpression 终结符表达式,实现与文法中的终结符相关联的解释操作
class Note : public Expression
{
    void Excute(string key, double value) override
    {
        string note = "";
        switch (key[0])
        {
        case 'C':
            note = "1";
            break;
        case 'D':
            note = "2";
            break;
        case 'E':
            note = "3";
            break;
        case 'F':
            note = "4";
            break;
        case 'G':
            note = "5";
            break;
        case 'A':
            note = "6";
            break;
        case 'B':
            note = "7";
            break;
        default:
            break;
        }
        cout << note << " ";
    }
};

class Scale : public Expression
{
public:
    void Excute(string key, double value) override
    {
        string scale = "";
        switch (static_cast<int>(value))
        {
        case 1:
            scale = "低音";
            break;
        case 2:
            scale = "中音";
            break;
        case 3:
            scale = "高音";
            break;
        default:
            break;
        }
        cout << scale << " ";
    }
};

int main()
{
    PlayContext* context = new PlayContext();
    cout << "上海滩: " << endl;
    context->SetPlayContext("O 2 E 0.5 G 0.5 A 3 E 0.5 G 0.5 D 3 E 0.5 G 0.5 A 0.5 O 3 C 1 O 2 A 0.5 G 1 C 0.5 E 0.5 D 3 ");
    while (context->GetPlayContext().size() > 0)
    {
        Expression* expression = nullptr;
        char c = context->GetPlayContext()[0];

        switch (c)
        {
        case 'O':
            //当首字段是O时,则表达式实例化为音阶
            expression = new Scale();
            break;
        case 'C':
        case 'D':
        case 'E':
        case 'F':
        case 'G':
        case 'A':
        case 'B':
        case 'P':
            //当首字母是CDEFGAB,以及休止符P时,则实例化为音符
            expression = new Note();
            break;
        }
        expression->Interpret(context);
        delete expression;
    }
    system("pause");
}

补充的另外一个例子

  • 一个简单加减法运算器的实例
//一个简单加减法运算器的实例
#include "pch.h"
#include <iostream>
#include <string>
#include <vector>

using namespace std;

//抽象的表达式对象以及Context对象
//用于保存计算的中间结果以及当前执行的操作符
class Context
{
public:
    Context()
        :m_value(0), m_operator('\0')
    {}
    void SetOperator(char type)
    {
        this->m_operator = type;
    }
    char GetOperator() const
    {
        return this->m_operator;
    }
    void SetValue(int number)
    {
        this->m_value = number;
    }
    int GetValue() const
    {
        return this->m_value;
    }
private:
    int m_value;
    char m_operator;
};

//表示所有表达式的抽象接口
class IExpression
{
public:
    virtual void Eval(Context* p) = 0;
};
//拆分表达式的元素
class Operator : public IExpression
{
public:
    Operator(char op)
    {
        this->m_op = op;
    }
    void Eval(Context* pContext) override
    {
        pContext->SetOperator(this->m_op);
    }
private:
    char m_op;
};

//拆分操作数
class Operand : public IExpression
{
public:
    Operand(int number)
    {
        this->m_num = number;
    }
    void Eval(Context* pContext) override
    {
        switch (pContext->GetOperator())
        {
        case '\0':
            pContext->SetValue(this->m_num);
            break;
        case '+':
            pContext->SetValue(this->m_num + pContext->GetValue());
            break;
        case '-':
            pContext->SetValue(pContext->GetValue() - this->m_num);
            break;
        default:
            break;
        }
    }
private:
    int m_num;
};

class Calculator
{
public:
    Calculator()
    {}
    int Calc(string expression)
    {
        Context* pContext = new Context;
        vector<IExpression*> tree;  //语法解析树
        for (int ix = 0; ix < expression.size(); ++ix)
        {
            if (expression[ix] == '+' || expression[ix] == '-')
            {
                tree.push_back(new Operator(expression[ix]));
                cout << "第" << ix << "次压入的符号是" << expression[ix] << endl;
            }
            else
            {
                tree.push_back(new Operand(static_cast<int>(expression[ix] - 48)));
                cout << "第" << ix << "次压入的数字是" << static_cast<int>(expression[ix] - 48) << endl;
            }
        }
        for (vector<IExpression*>::iterator iter = tree.begin(); iter != tree.end(); ++iter)
        {
            (*iter)->Eval(pContext);
        }
        return pContext->GetValue();
    }
};

int main()
{
    Calculator* pc = new Calculator();
    cout << "1+4-2+6+9-5-2-1+1+2= " << pc->Calc("1+4-2+6-9-5-2-1+1+2") << endl;
    system("pause");
    return 0;
}

运行结果

参考资料:
1 https://blog.csdn.net/xiqingnian/article/details/42222369 《大话设计模式C++实现-第27章-解释器模式》
2 https://www.cnblogs.com/hjj-fighting/p/10514935.html 《c++ string 转double》

原文地址:https://www.cnblogs.com/Manual-Linux/p/11162086.html

时间: 2024-08-04 18:44:47

第27章解释器模式的相关文章

大话设计模式C++实现-第27章-解释器模式

一.UML图 二.概念 解释器模式(interpreter):给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子. 三.说明 包含哪些角色? (1)AbstractExpression(抽象表达式):声明一个抽象的解释操作,这个接口为抽象语法树中所有的节点所共享. (2)TerminalExpression(终结符表达式):实现与文法中的终结符相关联的解释操作.实现抽象表达式中所要求的接口,主要是一个interpreter()方法.文法中每一个终结符都

设计模式之第5章-解释器模式(Java实现)

设计模式之第5章-解释器模式(Java实现) “开个商店好麻烦,做个收单的系统,发现类的方法好多.”“真是的,不就是简单的四则运算,这都不会!”你说你会啊.来来来,你把以下的方法用代码写出来: a+b+c+d a+b-c a-b+c a+b a-e ... 这个就是最简单的一些商店的系统,当然了,这里仅仅包含加减,这个时候就需要我-解释器出马了. 解释器模式之自我介绍 在你被给定一个语言,定义它的文法的一种表示,并定义一个一个解释器,用来解释语言中的句子.简单的说就是按照规定语法进行解析的方案,

设计模式之解释器模式--- Pattern Interpreter

模式的定义 类型 行为类 模式的使用场景 优点 缺点 UML类图 角色介绍 模式的通用源码 输出结果 Android源码中的模式实现 杂谈 参考资料 (1).设计模式之禅-第27章 解释器模式 (2)解释器模式 https://github.com/simple-android-framework/android_design_patterns_analysis

第17章 行为型模式—解释器模式

1. 解释器模式(Interpreter Pattern)的定义 (1)定义 给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子. ①文法:即语法规则.在解释器模式中每一个语法都将对应一个解释器对象,用来处理相应的语法规则.它对于扩展.改变文法以及增加新的文法规则都很方便. ②解释器模式描述了如何为简单的语言定义一个文法,如何在该语言中表示一个句子,以及如何解释这些句子. ③在解释器模式中可以通过一种称之为抽象语法树(Abstract Syntax T

设计模式(27)-----解释器模式

解释器模式(interpreter) 定义 给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子. UML类图 角色 抽象表达式(Expression)角色:声明一个所有的具体表达式角色都需要实现的抽象接口.这个接口主要是一个interpret()方法,称做解释操作. 终结符表达式(Terminal Expression)角色:实现了抽象表达式角色所要求的接口,主要是一个interpret()方法:文法中的每一个终结符都有一个具体终结表达式与之相对应.比

&quot;围观&quot;设计模式(27)--行为型之解释器模式(Interpreter Pattern)

解析器是一种按照规定的语法进行解析的例子,在现在的项目中使用较少,定义如下:给定一门语言,定义它的文法的一种表示,并定义一个解释器,该解释器用于解释语言中的句子. 个人理解 解释器模式在项目中很少使用,因为他会引起效率.性能以及维护等问题,准备使用该模式时可以考虑开源框架如:Expression4J.MESP.Jep等.解释器模式一般用来解析比较标准的字符集,比如说SQL语法分析等. 解释器角色 解释器模式主要包含如下几个角色: AbstractExpression: 抽象表达式.声明一个抽象的

第27章 结构型模式大PK

27.1 代理模式 VS 装饰模式 27.1.1 代理模式 (1)场景:客人找运动员代理要求安排运动员参加比赛 (2)说明:代理人有控制权,可以拒绝客人的要求,也可以答应安排,甚至自己下去跑(因为有些运动员本身就作自己的代理) [编程实验]找代理安排运动员比赛 //创建型模式大PK——代理模式和装饰模式 //实例:找代理安排运动员比赛 #include <iostream> #include <ctime> using namespace std; //抽象运动员 class IR

笔记-大话设计模式-27 解释器模式

解释器模式(Interpreter),给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子. 如果一种特定类型的问题发生的频率足够高,那么可能就值得将该问题的各个实例表述为一个简单语言中的句子.这样就可以构建一个解释器,该解释器通过解释这些句子来解决该问题. 而所谓的解释器模式,正则表达式就是它的一种应用,解释器为正则表达式定义了一个文法,如何表示一个特定的正则表达式,以及如何解释这个正则表达式. 通常当有一个语言需要解释执行,并且你可将该语言中的句子表

设计模式之第6章-迭代器模式(Java实现)

设计模式之第6章-迭代器模式(Java实现) “我已经过时了,就不要讲了吧,现在java自带有迭代器,还有什么好讲的呢?”“虽然已经有了,但是具体细节呢?知道实现机理岂不美哉?”“好吧好吧.”(迭代器闷闷不乐的答应下来.作者吃着小笼包,咂咂嘴道:哼,想偷懒,窗户都没有~). 迭代器模式之自我介绍 正如你们所见,我目前已经没落了,基本上没人会单独写一个迭代器,除非是产品性质的研发,我的定义如下:Provide a way to access the elements of an aggregate