C++设计模式之解释器模式(2)
在抽象语法树种,可以通过终结符表达式和非终结符表达式组成复杂的语句,每个文法规则的语言实例都可以表示为一个抽象语法树,就是说每一条具体的语句都可以用类似上图所示的抽象语法树来表示,在图中终结符表达式类的实例作为树的叶子节点,而非终结符表达式类的实例作为非叶子节点。抽象语法树描述了如何构成一个复杂的句子。
UML类图
AbstractExpression:声明一个抽象的解释操作,这个接口被抽象语法树中所有的节点所共享;
TernimalExpression:一个句子中的每个终结符需要该类的一个实例,它实现与文法中的终结符相关联的解释操作;
NonternimalExpression:
1.对于文法中的每一条规则都需要一个NonternimalExpression类;
2.为文法中的的每个符号都维护一个AbstractExpression类型的实例变量;
3.为文法中的非终结符实现解释操作,在实现时,一般要递归地调用表示文法符号的那些对象的解释操作;
Context:包含解释器之外的一些全局信息;
Client:构建一个需要进行解释操作的文法句子,然后调用解释操作进行解释。
实际进行解释时,按照以下时序进行的:
1.Client构建一个句子,它是NonterminalExpression和TerminalExpression的实例的一个抽象语法树,然后初始化上下文并调用解释操作;
2.每一非终结符表达式节点定义相应子表达式的解释操作。而各终结符表达式的解释操作构成了递归的基础;
3.每一节点的解释操作用作用上下文来存储和访问解释器的状态。
使用场合
在以下情况下可以考虑使用解释器模式:
1.可以将一个需要解释执行的语言中的句子表示为一个抽象语法树;
2.一些重复出现的问题可以用一种简单的语言来进行表达;
3.一个语言的文法较为简单;
4.执行效率不是关键问题。【注:高效的解释器通常不是通过直接解释抽象语法树来实现的,而是需要将它们转换成其他形式,使用解释器模式的执行效率并不高。】
代码实现
我们这里用代码来实现上面的游戏,只不过不是控制小狗在屏幕上移动了,而是将对应的控制指令翻译成汉语进行表示,这和翻译成控制小狗移动的指令的原理是一样的。比如现在有指令:down run 10;那么,经过解释器模式得到的结果为:向下跑动10。
#include <iostream>
#include <vector>
using namespace std;
#define MAX_SIZE 256
#define SAFE_DELETE(p) if (p) { delete p; p = NULL; }
const wchar_t *const DOWN = L"down";
const wchar_t *const UP = L"up";
const wchar_t *const LEFT = L"left";
const wchar_t *const RIGHT = L"right";
const wchar_t *const MOVE = L"move";
const wchar_t *const WALK = L"walk";
class AbstractNode
{
public:
virtual wchar_t *Interpret() = 0;
};
class AndNode : public AbstractNode
{
public:
AndNode(AbstractNode *left, AbstractNode *right) : m_pLeft(left), m_pRight(right){}
wchar_t *Interpret()
{
wchar_t *pResult = new wchar_t[MAX_SIZE];
memset(pResult, 0, MAX_SIZE * sizeof(wchar_t));
wchar_t *pLeft = m_pLeft->Interpret();
wchar_t *pRight = m_pRight->Interpret();
wcscat_s(pResult, MAX_SIZE, pLeft);
wcscat_s(pResult, MAX_SIZE, pRight);
SAFE_DELETE(pLeft);
SAFE_DELETE(m_pRight);
return pResult;
}
private:
AbstractNode *m_pLeft;
AbstractNode *m_pRight;
};
class SentenceNode : public AbstractNode
{
public:
SentenceNode(AbstractNode *direction, AbstractNode *action, AbstractNode *distance) :
m_pDirection(direction), m_pAction(action), m_pDistance(distance){}
wchar_t *Interpret()
{
wchar_t *pResult = new wchar_t[MAX_SIZE];
memset(pResult, 0, MAX_SIZE * sizeof(wchar_t));
wchar_t *pDirection = m_pDirection->Interpret();
wchar_t *pAction = m_pAction->Interpret();
wchar_t *pDistance = m_pDistance->Interpret();
wcscat_s(pResult, MAX_SIZE, pDirection);
wcscat_s(pResult, MAX_SIZE, pAction);
wcscat_s(pResult, MAX_SIZE, pDistance);
SAFE_DELETE(pDirection);
SAFE_DELETE(pAction);
SAFE_DELETE(pDistance);
return pResult;
}
private:
AbstractNode *m_pDirection;
AbstractNode *m_pAction;
AbstractNode *m_pDistance;
};
class DirectionNode : public AbstractNode
{
public:
DirectionNode(wchar_t *direction) : m_pDirection(direction){}
wchar_t *Interpret()
{
wchar_t *pResult = new wchar_t[MAX_SIZE];
memset(pResult, 0, MAX_SIZE * sizeof(wchar_t));
if (!_wcsicmp(m_pDirection, DOWN))
{
wcscat_s(pResult, MAX_SIZE, L"向下");
}
else if (!_wcsicmp(m_pDirection, UP))
{
wcscat_s(pResult, MAX_SIZE, L"向上");
}
else if (!_wcsicmp(m_pDirection, LEFT))
{
wcscat_s(pResult, MAX_SIZE, L"向左");
}
else if (!_wcsicmp(m_pDirection, RIGHT))
{
wcscat_s(pResult, MAX_SIZE, L"向右");
}
else
{
wcscat_s(pResult, MAX_SIZE, L"无效指令");
}
SAFE_DELETE(m_pDirection);
return pResult;
}
private:
wchar_t *m_pDirection;
};
class ActionNode : public AbstractNode
{
public:
ActionNode(wchar_t *action) : m_pAction(action){}
wchar_t *Interpret()
{
wchar_t *pResult = new wchar_t[MAX_SIZE];
memset(pResult, 0, MAX_SIZE * sizeof(wchar_t));
if (!_wcsicmp(m_pAction, MOVE))
{
wcscat_s(pResult, MAX_SIZE, L"移动");
}
else if (!_wcsicmp(m_pAction, WALK))
{
wcscat_s(pResult, MAX_SIZE, L"走动");
}
else
{
wcscat_s(pResult, MAX_SIZE, L"无效指令");
}
SAFE_DELETE(m_pAction);
return pResult;
}
private:
wchar_t *m_pAction;
};
class DistanceNode : public AbstractNode
{
public:
DistanceNode(wchar_t *distance) : m_pDistance(distance){}
wchar_t *Interpret()
{
wchar_t *pResult = new wchar_t[MAX_SIZE];
memset(pResult, 0, MAX_SIZE * sizeof(wchar_t));
wcscat_s(pResult, MAX_SIZE, m_pDistance);
SAFE_DELETE(m_pDistance);
return pResult;
}
private:
wchar_t *m_pDistance;
};
class InstructionHandler
{
public:
InstructionHandler(wchar_t *instruction) : m_pInstruction(instruction), m_pTree(NULL){}
void Handle();
void Output();
private:
void SplitInstruction(wchar_t **&instruction, int &size);
wchar_t *m_pInstruction;
AbstractNode *m_pTree;
};
void InstructionHandler::Handle()
{
AbstractNode *pLeft = NULL;
AbstractNode *pRight = NULL;
AbstractNode *pDirection = NULL;
AbstractNode *pAction = NULL;
AbstractNode *pDistance = NULL;
vector<AbstractNode *> node; // Store the instruction expression
// Split the instruction by " "
wchar_t **InstructionArray = NULL;
int size;
SplitInstruction(InstructionArray, size);
for (int i = 0; i < size; ++i)
{
if (!_wcsicmp(InstructionArray[i], L"and")) // The instruction is composited by two expressions
{
wchar_t *pDirectionStr = InstructionArray[++i];
pDirection = new DirectionNode(pDirectionStr);
wchar_t *pActionStr = InstructionArray[++i];
pAction = new ActionNode(pActionStr);
wchar_t *pDistanceStr = InstructionArray[++i];
pDistance = new DistanceNode(pDistanceStr);
pRight = new SentenceNode(pDirection, pAction, pDistance);
node.push_back(new AndNode(pLeft, pRight));
}
else
{
wchar_t *pDirectionStr = InstructionArray[i];
pDirection = new DirectionNode(pDirectionStr);
wchar_t *pActionStr = InstructionArray[++i];
pAction = new ActionNode(pActionStr);
wchar_t *pDistanceStr = InstructionArray[++i];
pDistance = new DistanceNode(pDistanceStr);
pLeft = new SentenceNode(pDirection, pAction, pDistance);
node.push_back(pLeft);
}
}
m_pTree = node[node.size() - 1];
}
void InstructionHandler::Output()
{
wchar_t *pResult = m_pTree->Interpret();
setlocale(LC_ALL,"");
wprintf_s(L"%s\n", pResult);
SAFE_DELETE(pResult);
}
void InstructionHandler::SplitInstruction(wchar_t **&instruction, int &size)
{
instruction = new wchar_t*[10];
memset(instruction, 0, 10 * sizeof( wchar_t*));
for (int i = 0; i < 10; ++i)
{
instruction[i] = new wchar_t[10];
memset(instruction[i], 0, 10 * sizeof(wchar_t));
}
size = 0;
int n = 0;
while (*m_pInstruction != L'\0')
{
if (*m_pInstruction == L' ')
{
size++;
m_pInstruction++;
n = 0;
continue;
}
instruction[size][n++] = *m_pInstruction++;
}
size++;
}
int main()
{
wchar_t *pInstructionStr = L"up move 5 and down walk 10";
InstructionHandler *pInstructionHandler = new InstructionHandler(pInstructionStr);
pInstructionHandler->Handle();
pInstructionHandler->Output();
SAFE_DELETE(pInstructionHandler);
}
- 上一篇:C++中的RTTI机制详解
- 下一篇:C++短路求值(逻辑与、逻辑或)实例