zoukankan      html  css  js  c++  java
  • 第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('')
    	{}
    	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 '':
    			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》

  • 相关阅读:
    构造函数、原型、实例化对象
    JS闭包的理解
    JQuery知识点
    面向对象
    学习使用Vuex
    Runtime详解
    ffmpeg各结构体之间关联 ---- AVPacket
    AVFrame
    block的底层原理
    performSelector
  • 原文地址:https://www.cnblogs.com/Manual-Linux/p/11162086.html
Copyright © 2011-2022 走看看