当前位置:网站首页>16 解释器模式
16 解释器模式
2022-06-22 08:21:00 【留点头发。】
原文转载:https://blog.csdn.net/sinat_21107433/article/details/102864850
看过《大明王朝1566》吗?这是Jungle所看过的历史剧当中最最喜欢和推崇的一部剧。看过这部剧的小伙伴们都知道,嘉靖皇帝说话从来不会明明白白说出来,而是喜欢绕着说,或者说暗语,若不细细揣测,根本不知道嘉靖说的真实含义是什么。比如他跟陈洪说“行到水穷处,坐看云起时”,陈洪就意会到皇上是让他除草;太子喜获儿子,嘉靖给了枣和栗……要是Jungle生活在那时候,脑壳真得变大啊,整天揣测皇帝的意图都够了。要是有个解释器就好了,能够把皇帝的话解释为明明白白的语言!

1.解释器模式概述
解释器模式用于描述一个简单的语言解释器,主要应用于使用面向对象语言开发的解释器的设计。当需要开发一个新的语言是,可以使用解释器模式。
解释器模式:
给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子。
解释器模式需要解决的是,如果一种特定类型的问题发生的频率足够高,那么可能就值得将该问题的各个实例表述为一个简单语言中的句子。这样就可以构件一个解释器,该解释器通过解释这些句子,来解决该问题。解释器模式描述了如何为简单的语言定义一个文法,如何在该语言中表示一个句子,以及如何解释这些句子。

2.解释器模式结构
解释器模式的结构由抽象表达式、终结符表达式、非终结符表达式和环境类组成:
- AbstractExpression(抽象表达式):声明了抽象的解释操作interpret(),是所有终结符表达式和非终结符表达式的基类;
- TerminalExpression(终结符表达式):终结符是文法规则的组成元素中最基本的语言单位,不能再分解。终结符表达式实现了与文法规则中终结符相关的解释操作,句子中的每一个终结符都是该类的一个实例。
- NonterminalExpression(非终结符表达式):实现了文法规则中非终结符的解释操作,因为非终结符表达式同样可以包含终结符表达式,所以终结符表达式可以是非终结符表达式的成员。
- Context(环境类):即上下文类,用于存储解释器之外的一些全局信息,通常临时存储需要解释的语句。

解释器模式的UML图如上所示。抽象表达式声明了抽象接口interpret(),终结符表达式和非终结符表达式式具体实现了该接口。其中,终结符表达式的interpret()接口实现了具体的解释操作,而非终结符表达式中可能包含终结符表达式或者非终结符表达式,所以非终结符表达式的interpret()接口中可能是递归调用每一个组成部分的interpret()方法。
3.解释器模式代码实例
本节Jungle使用解释器模式实现下面一个小功能:
设计一个简单的解释器,使得系统可以解释0和1的或运算和与运算(不考虑或运算和与运算的优先级,即从左往右依次运算),语句表达式和输出结果的几个实例如下表:
表达式及输出结果部分实例表 表达式 输出结果 表达式 输出结果 1 and 1 1 0 or 0 0 1 or 1 1 1 and 1 or 0 1 1 or 0 1 0 or 1 and 0 0 1 and 0 0 0 or 1 and 1 or 1 1 0 and 0 0 1 or 0 and 1 and 0 or 0 0
结合前面叙述的解释器模式的结构和本例,可以划分出以下角色:
- 终结符表达式角色——值节点(ValueNode):0、1,因为它们是表达式的基本组成元素,不可再细分
- 终结符表达式角色——运算符节点(OperatorNode):运算符号“and”和“or” ,同样也是表达式的基本组成元素
- 非终结符表达式角色——句子节点(SentenceNode):类似于“1 and 1”这样的表达式或者更长的组合表达式
- 上下文类角色——处理者(Handler):保存输入的表达式和输出的结果
由此,本例的UML实例图如下:

3.1.抽象表达式
// 抽象表达式类class AbstractNode{public:AbstractNode(){}// 声明抽象接口virtual char interpret() = 0;};
3.2.终结符表达式角色——值节点
// 终结符表达式:ValueNodeclass ValueNode :public AbstractNode{public :ValueNode(){}ValueNode(int iValue){this->value = iValue;}// 实现解释操作char interpret(){return value;}private:int value;};
3.3.终结符表达式角色——运算符节点
// 终结符表达式:OperationNodeclass OperatorNode :public AbstractNode{public:OperatorNode(){}OperatorNode(string iOp){this->op = iOp;}// 实现解释操作char interpret(){if (op == "and"){return '&';}else if (op == "or"){return '|';}return 0;}private:string op;};
3.4.非终结符表达式角色——句子节点
每一个句子节点由“左值节点+运算符节点+右值节点”组成。
// 非终结符表达式:SentenceNodeclass SentenceNode :public AbstractNode{public:SentenceNode(){}SentenceNode(AbstractNode *iLeftNode,AbstractNode *iRightNode, AbstractNode* iOperatorNode){this->leftNode = iLeftNode;this->rightNode = iRightNode;this->operatorNode = iOperatorNode;}char interpret(){if (operatorNode->interpret() == '&'){return leftNode->interpret()&rightNode->interpret();}else{return leftNode->interpret()|rightNode->interpret();}return 0;}private:AbstractNode *leftNode;AbstractNode *rightNode;AbstractNode *operatorNode;};
3.5.上下文角色——处理者
处理者将处理输入的表达式,并解释出表达式最终的结果。
// 处理者class Handler{public:Handler(){}void setInput(string iInput){this->input = iInput;}void handle(){AbstractNode *left = NULL;AbstractNode *right = NULL;AbstractNode *op = NULL;AbstractNode *sentence = NULL;string iInput = this->input;vector<string>inputList;char* inputCh = const_cast<char*>(iInput.c_str());char *token = strtok(inputCh, " ");while (token != NULL){inputList.push_back(token);token = strtok(NULL, " ");}for (int i = 0; i < inputList.size() - 2; i += 2){left = new ValueNode(*(inputList[i].c_str()));op = new OperatorNode(inputList[i + 1]);right = new ValueNode(*(inputList[i+2].c_str()));sentence = new SentenceNode(left, right, op);inputList[i + 2] = string(1, sentence->interpret());}string tmpRes = inputList[inputList.size() - 1];if (tmpRes == "1"){result = 1;}else if (tmpRes == "0"){result = 0;}else{result = -1;}this->output();}void output(){printf("%s = %d\n", input.c_str(), result);}private:string input;char result;};
3.6.客户端代码示例和结果
#include <iostream>#include "InterpreterPattern.h"int main(){Handler *handler = new Handler();string input_1 = "1 and 1";string input_2 = "1 and 0";string input_3 = "0 and 1";string input_4 = "0 and 0";string input_5 = "0 or 0";string input_6 = "0 or 1";string input_7 = "1 or 0";string input_8 = "1 or 1";string input_9 = "1 and 0 or 1";string input_10 = "0 or 0 and 1";string input_11 = "1 or 1 and 1 and 0";string input_12 = "0 and 1 and 1 and 1";string input_13 = "0 and 1 and 1 and 1 or 1 or 0 and 1";handler->setInput(input_1); handler->handle();handler->setInput(input_2); handler->handle();handler->setInput(input_3); handler->handle();handler->setInput(input_4); handler->handle();handler->setInput(input_5); handler->handle();handler->setInput(input_6); handler->handle();handler->setInput(input_7); handler->handle();handler->setInput(input_8); handler->handle();handler->setInput(input_9); handler->handle();handler->setInput(input_10); handler->handle();handler->setInput(input_11); handler->handle();handler->setInput(input_12); handler->handle();handler->setInput(input_13); handler->handle();printf("\n\n");system("pause");return 0;}
运行结果如下:

4.总结
优点:
- 易于改变和扩展文法,在解释器中使用类表示语言的文法规则,可以通过继承等机制类改变或扩展文法;
- 每一条文法规则都可以表示为一个类,因此可以方便地实现一个简单的语言;
- 如果要增加新的解释表达式,只需增加一个新的终结符表达式或非终结符表达式类,无需修改原有代码,符合开闭原则。
缺点:
- 对于复杂文法难以维护。在解释器模式中每一条规则至少需要定义一个类,因此如果一个语言包含太多文法规则,类的个数将会大量增加,导致系统难以管理和维护;
- 执行效率低,因为解释器模式中有大量循环和递归调用。
适用环境:
- 一些重复出现的问题可以用一种简单的语言进行表达;
- 一个语言的文法较为简单;
- 不考虑执行效率的问题时可以使用解释器模式。
边栏推荐
- 并发三大特性1-可见性
- Matrix operation
- Calculation of water charge
- steam教育文化传承的必要性
- Mysq index optimization and how to avoid deadlock
- Powerful database design tool PowerDesigner
- Mysql5.7 master-slave mode reference
- Weekly recommended short video: what is the "computing world"?
- Define the data source of hikaricp connection pool for bee
- Calculation days ()
猜你喜欢

QT custom composite control (class promotion function)

The solution to the problem of the first screen picture loading flicker

并发线程池底层原理详解与源码分析

PostgreSQL source code (56) extensible type analysis expandedobject/expandedrecord

Analyzing the role of cognitive theory in maker teacher training

第八章 Web项目测试(此章完结)

Web Knowledge 2 (request+response)

Mt4/mql4 getting started to proficient in foreign exchange EA automatic trading tutorial - special identification of the K line on the chart

矩阵分解

Mt4/mql4 getting started to mastering EA tutorial lesson 4 - common functions of MQL language (IV) - common functions of K-line value
随机推荐
安装 MySQL 服务时提示 InstallRemove of the Service Denied
Alibaba cloud ~ simply send SMS
[Oracle database] mammy tutorial Day12 character function
A simple - timed task component (quartz) -demo
第八章 Web项目测试(此章完结)
Synchronized
多点闹钟实例
Five skills to be an outstanding cloud architect
Mt4-mql4 language EA automatic transaction programming introduction to proficiency
Android kotlin Camera2预览功能实现
QT error prompt 1:invalid use of incomplete type '***‘
Third party services (file and picture storage)
Flask博客实战 - 实现全站导航菜单及首页数据展示
Coding complexity C (n)
Using KDJ metrics on MT4
Chapter VIII web project testing (the end of this chapter)
Golang 开发 常用的第三方库 没有最全只有更全
Easyui数据表实现增删改
Idea reports an error "insufficient memory"
Mt4/mql4 getting started to be proficient in EA tutorial lesson 6 - common functions of MQL language (VI) - common order function