第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》