-
解释器模式:一种行为型设计模式
首先,我想先说明一下,解释器模式是我个人认为最复杂的设计模式,可能因为我目前对编程语言的解析原理不甚了解,对这个模式的理解也很片面。
-
应用场景:
解释器模式的应用场景是对语句进行解析。给定语法规则,先将语句形成语义树,然后通过解释器对语义树进行解释,输出结果。
常用场景如解析xml配置文件。 -
举例:
以解析a+b+c
来举例,将a
,+
,b
,+
,c
五个符号作为独立的对象来解析。
这五个符号根据解析方式不同可分为两类,a b c
为一类,这类对象的解析结果就是这个对象本身的值。而+
的解析要取这个元素左右相邻的两个元素,进行相加,将和作为解析结果返回。
解释前先生成语义树,类似这样:
+
/ \
+ c
/ \
a b
然后从根节点开始,依次对节点进行递归解析。a b c
这类解释器使程序不会无限递归下去,称作终结符解释器(终结递归)。另一类需要递归向下解析的,称作非终结符解释器。
-
实现方式:
解释器基类派生出终结符解释器和非终结符解释器,非终结符解释器根据解释功能派生出具体的解释器类(+
调用左右两数相加,-
调用左右两数相减)。
再有一个解析器,将语句生成语义树。
以下是解释器模式的简单代码实现
#include <iostream>
#include <string>
#include <map>
#include <stack>
#include <typeinfo>
using namespace std;
//解释器抽象类
class Expression
{
public:
//解析公式和数值,其中mapValue中的key是公式中的参数,value值是具体的值
virtual int interpreter(map<string, int>& MapValue) = 0;
virtual ~Expression(){};
};
//变量解析器(终结符)
class VarExpression : public Expression
{
string m_strkey;
public:
VarExpression(string strkey):m_strkey(strkey){}
//从map中取出变量的值
int interpreter(map<string, int>& MapValue)
{
return MapValue[m_strkey];
}
};
//运算符解析器(非终结符)
class SymbolExpression : public Expression
{
protected:
Expression* m_pLeft;
Expression* m_pRight;
public:
SymbolExpression(Expression* pLeft, Expression* pRight):m_pLeft(pLeft), m_pRight(pRight){}
};
//加法解析器
class AddExpression : public SymbolExpression
{
public:
AddExpression(Expression* pLeft, Expression* pRight):SymbolExpression(pLeft,pRight){}
//把左右两个变量相加
int interpreter(map<string, int>& MapValue)
{
return m_pLeft->interpreter(MapValue) + m_pRight ->interpreter(MapValue);
}
};
//减法解析器
class SubExpression : public SymbolExpression
{
public:
SubExpression(Expression* pLeft, Expression* pRight): SymbolExpression(pLeft,pRight)
{
}
//把左右两个变量相减
int interpreter(map<string, int>& MapValue)
{
return m_pLeft->interpreter(MapValue) - m_pRight ->interpreter(MapValue);
}
};
//语义解析器
class Parse
{
private:
Expression* m_pExpression;
public:
//构造函数传参,并解析表达式,构建语法树
Parse(string strExpStr)
{
m_pExpression = NULL;
stack<Expression*> stackExp;
Expression* pLeft = NULL;
Expression* pRight = NULL;
for(unsigned int i = 0; i< strExpStr.length(); ++i)
{
switch(strExpStr[i])
{
case '+': //加法
//1.先从栈中取出左操作数
pLeft = stackExp.top();
stackExp.pop();
//2.从表达式中取出+号后面的右操作数,并生成终结符解析对象
pRight = new VarExpression(strExpStr.substr(++i,1));
//3.将左右操作数相加,并把结果放入栈中
stackExp.push(new AddExpression(pLeft, pRight));
break;
case '-':
//1.先从栈中取出左操作数
pLeft = stackExp.top();
stackExp.pop();
//2.从表达式中取出+号后面的右操作数,并生成终结符解析对象
pRight = new VarExpression(strExpStr.substr(++i,1));
//3.将左右操作数相减,并把结果放入栈中
stackExp.push(new SubExpression(pLeft, pRight));
break;
default:
//如果是变量(终结符),
//则直接生成对应的变量解析器
stackExp.push(new VarExpression(strExpStr.substr(i,1)));
}
}
//栈中保存的就是最终语法树的根结点(本例为SuuExpression对象)
if(!stackExp.empty())
{
m_pExpression = stackExp.top();
stackExp.pop();
}
}
//开始运算
int Calculate(map<string, int>& MapValue)
{
return (!m_pExpression) ? 0 : m_pExpression->interpreter(MapValue);
}
};
主函数中的使用
int main()
{
string strExpression = "a-b+c";
map<string, int> MapValue;
MapValue["a"] = 50;
MapValue["b"] = 40;
MapValue["c"] = 30;
Parse ParseTree(strExpression); //生成语义树
cout << strExpression << " = " << ParseTree.Calculate(MapValue) << endl;
return 0;
}
控制台输出结果
a-b+c = 40
如有错误,欢迎指正
网友评论