
前言
那天,我很无聊,我去了一个编程和学习网站;编程和学习网站最近很热;之前,盖茨(Gates)和扎克伯格(Zuckerberg)等大人物开始宣传,认为每个人都应该学习编程. 我想到这是怎么回事?如果在中国,人们还会生活吗?这个话题不会被拒绝,比方说我去了编程网站. 首先是为您玩一个小游戏,以激发您对编程的兴趣. 游戏是这样的,网页上有一个编辑框,屏幕上有一只小狗,例如,您在编辑框中输入以下句子: down run 10;按Enter键,这时,您将在屏幕上看到小狗的身高下降10格;然后输入步行5,按Enter键,小狗的长度将上升5个正方形. 真的很有趣;但是,对于像我这样不需要这种游戏来激发我学习兴趣的人,我更喜欢的是思考如何实现它以及如何控制输入的句子. 小狗移动. 关于今天总结的解释器模式,所有这些都必须说.
翻译模式
在GOF的“设计模式: 可重用的面向对象软件的基础”中,解释器模式表示: 给定一种语言,定义其语法的表示形式,并定义解释器,该解释器使用该表示形式来解释句子. 语言. 如果特定类型的问题经常发生,则可能值得用简单的语言将每个问题实例表达为一个句子. 这样,您可以构建一个解释器,通过解释这些句子来解决问题.
就像上面提到的游戏一样,我输入了步行5,并且我必须以移动方向+移动模式+移动距离的格式输入指令,并且这种格式的指令是语法,仅根据输入我定义的语法,可以控制屏幕上的小狗移动. 当然,当我输入步行5时,屏幕上的小狗一定看不懂,也不知道我输入了什么,这时我该怎么办?我需要一个工具将输入的内容转换为小狗可以理解的内容,并且该工具是定义中提到的解释器. 解释器解释我输入的命令,然后将解释的命令发送给屏幕上的小狗,在小狗理解后继续前进.
我们在开发中经常使用的正则表达式也代表了这类问题. 有时我们需要匹配电话号码和ID号;我们不必为每个匹配项编写特定的算法,我们可以为每个匹配项定义语法,然后解释语法定义的句子. 好吧.
语法规则和抽象语法树
在上面的解释器模式定义中,提到了一个词: 语法. 在使用代码实现解释器模式之前,有必要学习语法的概念以及如何表达语言的语法规则. 以上面的游戏为例,我可以定义以下五个语法:
复制代码,代码如下:
表达式:: =方向动作距离|复合//表达式
composite :: = expression'and'expression //复合表达式
direction :: ='上'|'下'|'左'|'右'//运动方向
action :: ='move'|'walk'//运动方法
distance :: =整数//移动距离
以上五个语法规则对应五个语言单元. 这些语言单元可以分为两类: 一类是终止符(也称为终止符表达),例如上方的方向,动作和距离. 它是最小的语言单位,不能拆分;另一种类型是非终止符(也称为非终止表达式)c 解释器模式,例如上面的表达式和复合符号,它们都是完整的句子,包含一系列终止符或非终止符.
我们可以根据上面定义的某些语法形成更复杂的句子,并且计算机程序将基于这些句子执行某些操作;并且我们在这里列出的语法无法被计算机直接理解,因此我们需要解释所定义的语法;就像我们编写的C ++代码一样,计算机无法理解它,我们需要对其进行编译. 解释器模式提供了一种模式,可以向计算机解释我们定义的语法,并使计算机根据我们的语法工作.
在语法规则的定义中,某些符号可用于表达不同的含义,例如“ |”对于OR,“ {”和“}”表示组合,“ *”表示0次或多次出现,等等,最常用的符号是“ |”代表“或”关系. 例如,语法规则“ bool Value :: = 0 | 1”表示终止符表达式bool Value的值可以为0或1.
除了使用语法规则定义语言外,在解释器模式下,可以使用称为抽象语法树的图形方法来直观地表示语言的组成. 每个语法树对应一个语言实例. 上面的游戏语法规则可以由以下抽象语法树表示:

在抽象语法树中,复杂的语句可以由终端表达式和非终端表达式组成. 语法规则的每个语言实例都可以表示为抽象语法树,也就是说,每个特定的语句可以为. 它由类似于上图中所示的抽象语法树表示. 在该图中,终端表达式类的实例用作树的叶子节点,非终端表达式类的实例用作非叶子节点. 抽象的语法树描述了如何形成复杂的句子.
UML类图

AbstractExpression: 声明一个抽象解释操作,该接口由抽象语法树中的所有节点共享;
TernimalExpression: 句子中的每个终端都需要一个类的实例,该类可以实现与该终端在语法上相关的解释操作;
NonternimalExpression:
1. 对于语法中的每个规则,都需要一个NonternimalExpression类;
2. 为语法中的每个符号维护一个类型为AbstractExpression的实例变量;
3. 为了对语法中的非终结符实现解释操作,在实现中,通常需要递归调用表示语法符号的那些对象的解释操作;
上下文: 包含解释器之外的一些全局信息;
客户: 构造需要解释操作的语法句子,然后调用解释操作进行解释.
实际口译时,请按照以下顺序进行:
1. 客户端构造一个句子,该句子是NonterminalExpression和TerminalExpression实例的抽象语法树,然后初始化上下文并调用解释操作;
2. 每个非终端表达式节点定义相应子表达式的解释操作. 每个终端表达式的解释操作构成了递归的基础;
3. 每个节点的解释操作都使用操作上下文来存储和访问解释器的状态.
使用场合
在以下情况下可以考虑口译员模式:
1. 需要解释和执行的语言中的句子可以表示为抽象语法树;
2. 某些反复出现的问题可以用一种简单的语言表达;
3. 语言的语法相对简单;
4. 执行效率不是关键问题. [注: 有效的解释器通常不能通过直接解释抽象语法树来实现,但是它们需要转换为其他形式,并且使用解释器模式的执行效率不高. )
代码实现
我们在这里使用代码来实现上述游戏,但不是控制小狗在屏幕上移动,而是将相应的控制指令翻译成中文以表达出来,这就是控制指令翻译的原理小狗的运动. 一样的. 例如,现在有一个命令: down run 10;那么,在解释器模式下获得的结果是: 向下运行10.
复制代码c 解释器模式,代码如下:
#include
#include
使用命名空间标准;
#define MAX_SIZE 256
#define SAFE_DELETE(p)如果(p){删除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“移动”;
const wchar_t * const WALK = L“ walk”;
AbstractNode类

{
公共:
虚拟wchar_t * Interpret()= 0;
};
AndNode类: 公共AbstractNode
{
公共:
AndNode(AbstractNode * left,AbstractNode * right): m_pLeft(left),m_pRight(right){}
wchar_t * Interpret()
{
wchar_t * pResult =新的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);
返回pResult;
}
私人:
AbstractNode * m_pLeft;
AbstractNode * m_pRight;
};
SentenceNode类: 公共AbstractNode
{
公共:
SentenceNode(AbstractNode *方向,AbstractNode *操作,AbstractNode *距离):
m_pDirection(方向),m_pAction(操作),m_pDistance(距离){}
wchar_t * Interpret()
{
wchar_t * pResult =新的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);
返回pResult;
}
私人:
AbstractNode * m_pDirection;
AbstractNode * m_pAction;
AbstractNode * m_pDistance;
};
DirectionNode类: 公共AbstractNode
{
公共:
DirectionNode(wchar_t * direction): m_pDirection(direction){}
wchar_t * Interpret()
{

wchar_t * pResult =新的wchar_t [MAX_SIZE];
memset(pResult,0,MAX_SIZE * sizeof(wchar_t));
如果(!_wcsicmp(m_pDirection,DOWN))
{
wcscat_s(pResult,MAX_SIZE,L“ Down”);
}
否则是否(!_wcsicmp(m_pDirection,UP))
{
wcscat_s(pResult,MAX_SIZE,L“ Up”);
}
否则是否(!_wcsicmp(m_pDirection,LEFT))
{
wcscat_s(pResult,MAX_SIZE,L“ left”);
}
否则((_wcsicmp(m_pDirection,RIGHT))
{
wcscat_s(pResult,MAX_SIZE,L“在右边”);
}
其他
{
wcscat_s(pResult,MAX_SIZE,L“无效指令”);
}
SAFE_DELETE(m_pDirection);
返回pResult;
}
私人:
wchar_t * m_pDirection;
};
ActionNode类: 公共AbstractNode
{
公共:
ActionNode(wchar_t * action): m_pAction(action){}
wchar_t * Interpret()
{
wchar_t * pResult =新的wchar_t [MAX_SIZE];
memset(pResult,0,MAX_SIZE * sizeof(wchar_t));
本文来自电脑杂谈,转载请注明本文网址:
http://www.pc-fly.com/a/jisuanjixue/article-277697-1.html
现在我们的媒体集体失声
常规战是打不赢老美的
2的不会卡