《C++新经典设计模式》之第21章 解释器模式

《C++新经典设计模式》之第21章 解释器模式

        • 解释器模式.cpp

解释器模式.cpp
#include <iostream>
#include <map>
#include <stack>
#include <vector>
#include <cstring>
#include <memory>
#include <set>
#include <sstream>
using namespace std;// 定义一个语言的文法(语法规则),并建立一个解释器解释该语言中的句子
// 4种角色
// AbstractExpression(抽象表达式),声明抽象的解释操作
// TerminalExpression(终结符表达式),实现语言文法中与终结表达式相关的解释操作
// NonterminalExpression(非终结符表达式),实现语言文法中与非终结表达式相关的解释操作
// Context(环境类/上下文类),存储解释器之外的全局信息,变量名与值的映射关系、存储和访问表达式解释器的状态等,作为公共对象的参数传递到表达式的解释操作中namespace ns1
{class Expression // 表达式(节点)父类{public:              // 以下两个成员变量是为程序跟踪调试时观察某些数据方便而引入int m_dbg_num;   // 创建该对象时的一个编号,用于记录本对象是第几个创建的char m_dbg_sign; // 标记本对象的类型,可能是个字符v代表变量(终结符表达式),也可能是个加减号(非终结符表达式)public:Expression(int num, char sign) : m_dbg_num(num), m_dbg_sign(sign) {}virtual ~Expression() {}public:                                                         // 解析语法树中的当前节点virtual int interpret(const map<char, int> &var) const = 0; // 变量名及对应的值};class VarExpression : public Expression // 变量表达式(终结符表达式){char m_key; // 变量名,本范例中诸如a、b、c、d都是变量名public:VarExpression(const char &key, int num, char sign) : Expression(num, sign), m_key(key) {}int interpret(const map<char, int> &var) const override { return var.at(m_key); } // 返回变量名对应的数值};class SymbolExpression : public Expression // 运算符表达式(非终结符表达式)父类{protected: // 左右各有一个操作数shared_ptr<Expression> m_left;shared_ptr<Expression> m_right;public:SymbolExpression(const shared_ptr<Expression> &left, const shared_ptr<Expression> &right, int num, char sign) : m_left(left), m_right(right), Expression(num, sign) {}shared_ptr<Expression> getLeft() const { return m_left; }shared_ptr<Expression> getRight() const { return m_right; }};class AddExpression : public SymbolExpression // 加法运算符表达式(非终结符表达式){public:AddExpression(const shared_ptr<Expression> &left, const shared_ptr<Expression> &right, int num, char sign) : SymbolExpression(left, right, num, sign) {} // 构造函数int interpret(const map<char, int> &var) const override{// 分步骤拆开写,方便理解和观察int value1 = m_left->interpret(var);  // 递归调用左操作数的interpret方法int value2 = m_right->interpret(var); // 递归调用右操作数的interpret方法int result = value1 + value2;return result; // 返回两个变量相加的结果}};class SubExpression : public SymbolExpression // 减法运算符表达式(非终结符表达式){public:SubExpression(const shared_ptr<Expression> &left, const shared_ptr<Expression> &right, int num, char sign) : SymbolExpression(left, right, num, sign) {} // 构造函数int interpret(const map<char, int> &var) const override{int value1 = m_left->interpret(var);int value2 = m_right->interpret(var);int result = value1 - value2;return result; // 返回两个变量相减的结果}};// 分析—创建语法树(表达式树)shared_ptr<Expression> analyse(const string &strExp) // strExp:要计算结果的表达式字符串,比如"a-b+c+d"{stack<shared_ptr<Expression>> expStack; // #include <stack>,这里用到了栈这种顺序容器shared_ptr<Expression> left;shared_ptr<Expression> right;int icount = 1;for (size_t i = 0; i < strExp.size(); ++i) // 循环遍历表达式字符串中的每个字符{switch (strExp[i]){case '+':                                                       // 加法运算符表达式(非终结符表达式)left = expStack.top();                                      // 返回栈顶元素(左操作数)right.reset(new VarExpression(strExp[++i], icount++, 'v')); // v代表是个变量节点// 在栈顶增加元素expStack.push(make_shared<AddExpression>(left, right, icount++, '+')); //'+'代表是个减法运算符节点break;case '-':                  // 减法运算符表达式(非终结符表达式)left = expStack.top(); // 返回栈顶元素right.reset(new VarExpression(strExp[++i], icount++, 'v'));expStack.push(make_shared<SubExpression>(left, right, icount++, '-')); //'-'代表是个减法运算符节点break;default: // 变量表达式(终结符表达式)expStack.push(make_shared<VarExpression>(strExp[i], icount++, 'v'));break;}}shared_ptr<Expression> expression = expStack.top(); // 返回栈顶元素return expression;}
}namespace ns2
{class Expression // 表达式父类{public:virtual ~Expression() {}public: // 解析语法树中的当前节点virtual string interpret() const = 0;};class DirectionExpression : public Expression // 运动方向表达式(终结符表达式){string m_direction; // 运动方向:up、down、left、right分别表示上、下、左、右public:DirectionExpression(const string &direction) : m_direction(direction) {}string interpret() const override{static set<string> directionSet = {"up", "down", "left", "right"};if (directionSet.find(m_direction) != directionSet.end())return m_direction;elsereturn "direction error";}};class ActionExpression : public Expression // 运动方式表达式(终结符表达式){string m_action; // 运动方式:walk、run分别表示行走、奔跑public:ActionExpression(const string &action) : m_action(action) {}string interpret() const override{static set<string> actionSet = {"walk", "run"};if (actionSet.find(m_action) != actionSet.end())return m_action;elsereturn "action error";}};class DistanceExpression : public Expression // 运动距离表达式(终结符表达式){string m_distance; // 运动距离,用字符串表示即可public:DistanceExpression(const string &distance) : m_distance(distance) {}string interpret() const override{return m_distance + "m";}};class SentenceExpression : public Expression // “句子”表达式(非终结符表达式),“运动方向 运动方式 运动距离”构成{shared_ptr<Expression> m_direction; // 运动方向shared_ptr<Expression> m_action;    // 运动方式shared_ptr<Expression> m_distance;  // 运动距离public:SentenceExpression(const shared_ptr<Expression> &direction, const shared_ptr<Expression> &action, const shared_ptr<Expression> &distance): m_direction(direction), m_action(action), m_distance(distance) {}shared_ptr<Expression> getDirection() const { return m_direction; }shared_ptr<Expression> getAction() const { return m_action; }shared_ptr<Expression> getDistance() const { return m_distance; }string interpret() const override{return m_direction->interpret() + " " + m_action->interpret() + " " + m_distance->interpret();}};class AndExpression : public Expression // “和”表达式(非终结符表达式){shared_ptr<Expression> m_left;shared_ptr<Expression> m_right;public:AndExpression(const shared_ptr<Expression> &left, const shared_ptr<Expression> &right) : m_left(left), m_right(right) {}shared_ptr<Expression> getLeft() const { return m_left; }shared_ptr<Expression> getRight() const { return m_right; }string interpret() const override{return m_left->interpret() + " and " + m_right->interpret();}};// 分析—创建语法树(表达式树)shared_ptr<Expression> analyse(const string &strExp) // strExp:要计算结果的表达式字符串,比如"left walk 15 and down run 20"{stack<shared_ptr<Expression>> expStack;shared_ptr<Expression> direction;shared_ptr<Expression> action;shared_ptr<Expression> distance;shared_ptr<Expression> left;shared_ptr<Expression> right;// 机器人运动控制命令之间是用空格来分隔的,所以用空格作为分隔字符来对整个字符串进行拆分vector<string> resultVec;/*char *strc = new char[strlen(strExp.c_str()) + 1];strcpy(strc, strExp.c_str()); // 若本行编译报错提醒使用strcpy_s,则可以在文件头增加代码行:#pragma warning(disable : 4996)char *tmpStr = strtok(strc, " "); // 按空格来切割字符串while (tmpStr != nullptr){resultVec.push_back(string(tmpStr));tmpStr = strtok(NULL, " ");}delete[] strc;*/stringstream iss(strExp);        // 输入流string token;                    // 接收缓冲区while (getline(iss, token, ' ')) // 以' '为分隔符resultVec.push_back(token);for (auto iter = resultVec.begin(); iter != resultVec.end(); ++iter){if ((*iter) == "and") // 和{left = expStack.top(); // 返回栈顶元素(左操作数)++iter;direction.reset(new DirectionExpression(*iter)); // 运动方向++iter;action.reset(new ActionExpression(*iter)); // 运动方式++iter;distance.reset(new DistanceExpression(*iter)); // 运动距离right.reset(new SentenceExpression(direction, action, distance));expStack.push(make_shared<AndExpression>(left, right));}else{direction.reset(new DirectionExpression(*iter)); // 运动方向++iter;action.reset(new ActionExpression(*iter)); // 运动方式++iter;distance.reset(new DistanceExpression(*iter)); // 运动距离expStack.push(make_shared<SentenceExpression>(direction, action, distance));}}shared_ptr<Expression> expression = expStack.top(); // 返回栈顶元素return expression;}
}int main()
{
#if 0using namespace ns1;map<char, int> varmap;// 下面是给字符串表达式中所有参与运算的变量一个对应的数值varmap.insert(make_pair('a', 7)); // 类似于赋值语句a = 7varmap.insert(make_pair('b', 9)); // 类似于赋值语句b = 9varmap.insert(make_pair('c', 3)); // 类似于赋值语句c = 3varmap.insert(make_pair('d', 2)); // 类似于赋值语句d = 2string strExp = "a-b+c+d";                           // 将要求值的字符串表达式shared_ptr<Expression> expression = analyse(strExp); // 调用analyse函数创建语法树int result = expression->interpret(varmap);          // 调用interpret接口求解字符串表达式的结果cout << strExp << " = " << result << endl;           // 输出字符串表达式结果
#endif#if 1using namespace ns2;string strExp = "left walk 15 and down run 20";shared_ptr<Expression> expression = analyse(strExp); // 调用analyse函数创建语法树cout << expression->interpret() << endl;
#endifcout << "Over!\n";return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/208618.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【Vue3从入门到项目实现】RuoYi-Vue3若依框架前端学习——动态路由与菜单栏

菜单栏 若依框架的侧边栏组件通常由菜单项和子菜单组成。 登录后&#xff0c;会获取用户拥有的路由菜单 {"msg": "操作成功","code": 200,"data": [{"name": "System","path": "/system",…

第一百九十六回 通过蓝牙发送数据的细节

文章目录 1. 概念介绍2. 实现方法3. 代码与效果3.1 示例代码3.2 运行效果4. 经验总结我们在上一章回中介绍了"分享三个使用TextField的细节"沉浸式状态样相关的内容,本章回中将介绍SliverList组件.闲话休提,让我们一起Talk Flutter吧。 1. 概念介绍 通过蓝牙设备…

[原创]C++98升级到C++20的复习旅途-个人感觉std::string_literals这个东西实现的不太人性化.

[简介] 常用网名: 猪头三 出生日期: 1981.XX.XX QQ联系: 643439947 个人网站: 80x86汇编小站 https://www.x86asm.org 编程生涯: 2001年~至今[共22年] 职业生涯: 20年 开发语言: C/C、80x86ASM、PHP、Perl、Objective-C、Object Pascal、C#、Python 开发工具: Visual Studio、D…

git操作:使用vscode集成

git操作方式 其实git操作一般有三种方式 分别是终端命令行,开发工具集成,专业的git可视化工具 我前面几章说的都是git的命令行操作,今天这篇文章主要是针对开发工具vscode集成git操作进行演示 说明一下,这里之所以选择vscode,是因为本人用的就是vscode,每个开发工具基本都有…

最新PyTorch机器学习与深度学习实践技术应用

近年来&#xff0c;随着AlphaGo、无人驾驶汽车、医学影像智慧辅助诊疗、ImageNet竞赛等热点事件的发生&#xff0c;人工智能迎来了新一轮的发展浪潮。尤其是深度学习技术&#xff0c;在许多行业都取得了颠覆性的成果。另外&#xff0c;近年来&#xff0c;Pytorch深度学习框架受…

mysql怎么优化查询?

从多个维度优化&#xff0c;这里的优化维度有四个&#xff1a;硬件配置、参数配置、表结构设计和SQL语句及索引。 其中 SQL 语句相关的优化手段是最为重要的。 一、硬件配置 硬件方面的优化可以有 对磁盘进行扩容、将机械硬盘换为SSD&#xff0c;或是把CPU的核数往上提升一些…

IDEA中,Archetype的作用

在IntelliJ IDEA中&#xff0c;Archetype&#xff08;原型&#xff09;是一种用于创建项目的模板&#xff0c;它定义了项目的基本结构和初始文件。Archetype允许您通过预先构建好的项目框架来快速创建项目&#xff0c;从而节省了手动创建项目所需的时间和精力。 使用Archetype…

spark链接hive时踩的坑

使用spark操作hive&#xff0c;使用metastore连接hive&#xff0c;获取hive的数据库时&#xff0c;当我们在spark中创建数据库的时候&#xff0c;创建成功。 同时hive中也可以看到这个数据库&#xff0c;建表插入数据也没有问题&#xff0c;但是当我们去查询数据库中的数据时&a…

IDEA 出现问题:Idea-操作多次commit,如何合并为一个并push解决方案

❤️作者主页&#xff1a;小虚竹 ❤️作者简介&#xff1a;大家好,我是小虚竹。2022年度博客之星评选TOP 10&#x1f3c6;&#xff0c;Java领域优质创作者&#x1f3c6;&#xff0c;CSDN博客专家&#x1f3c6;&#xff0c;华为云享专家&#x1f3c6;&#xff0c;掘金年度人气作…

Python---继承

1、什么是继承 我们接下来来聊聊Python代码中的“继承”&#xff1a;类是用来描述现实世界中同一组事务的共有特性的抽象模型&#xff0c;但是类也有上下级和范围之分&#xff0c;比如&#xff1a;生物 > 动物 > 哺乳动物 > 灵长型动物 > 人类 > 黄种人 从哲学…

prometheus服务发现之consul

文章目录 前言一、Consul 在这里的作用二、原理三、实现过程安装 consul节点信息&#xff08;exporter&#xff09;注册进去consul节点信息&#xff08;exporter&#xff09;从consul解除注册&#xff1a;prometheus配置consul地址 总结 前言 我们平时使用 prometheus 收集监控…

接口的性能优化(从前端、后端、数据库三个角度分析)

接口的性能优化&#xff08;前端、后端、数据库&#xff09; 主要通过三方面进行优化 前端后端数据库 前端优化 接口拆分 不要搞一个大而全的接口&#xff0c;要区分核心与非核心的接口&#xff0c;不然核心接口就会被非核心接口拖累 或者一个接口中大部分返回都很快&…

通过rc.local开机自启执行nohup命令运行Flask,nohup.out中没有Flask请求响应日志

需求 通过修改/etc/rc.d/rc.local&#xff0c;实现开机自启Flask服务&#xff0c;CentOS 7.9。rc.local参考链接1&#xff0c;参考链接2。 问题 在/etc/rc.d/rc.local中添加 /home/python/face_jiance/kaijiziqi.sh 在/home/python/face_jiance/kaijiziqi.sh中写 nohup /…

数据可视化软件的兴起:背后的驱动力

在当今信息时代&#xff0c;数据变得比以往任何时候都更为重要。数据可视化软件的广泛应用成为了一种趋势。那么&#xff0c;为什么越来越多的人选择使用数据可视化软件呢&#xff1f;今天我就以自己的工作经验为基础&#xff0c;进行简单的分析。 数据可视化软件能将枯燥的数…

react-lazyload 的介绍、安装、使用。

目录 基本介绍 安装 使用 基本使用 详细属性 基本介绍 react-lazyload 是一个 React 组件&#xff0c;用于延迟加载&#xff08;懒加载&#xff09;页面上的图片或其他资源。懒加载是一种优化手段&#xff0c;它允许页面在初次加载时只加载可视区域内的内容&#xff0c;…

【Harmony】鸿蒙操作系统架构

目录 导论 第一部分&#xff1a;内核与核心组件 1.1 鸿蒙微内核的设计 1.2 分布式能力的强化 1.3 HarmonyOS的分层架构 1.4 分布式数据管理 第二部分&#xff1a;鸿蒙的核心能力 2.1 华为 ARK Compiler的引入 2.2 分布式图形界面的实现 2.3 统一的设备驱动框架 2.4 轻…

vue3移动端脚手架(纯净,集成丰富)

概述 一个纯净的移动端框架 &#xff0c;用到了 Vue3 vuex Vite3 Vant3 sass eslint stylelint htmlhint husky commitlint axios axios-adapter VConsole 自定义全局 loading &#xff0c;自定义函数式 dialog &#xff08;api模仿微信小程序&#xff09;&#x…

增强现实中的真实人/机/环与虚拟人/机/环

在增强现实中&#xff0c;真实人与虚拟人、真实机器与虚拟机器、真实环境与虚拟环境之间有着密切的关系。增强现实技术通过将真实与虚拟相结合&#xff0c;打破了传统的现实世界与虚拟世界的界限&#xff0c;创造出了一种新的体验方式。真实人、真实机器和真实环境与其对应的虚…

linux进入emergency mode

问题描述 linux系统进入emergency mode模式 解决方法 查看问题原因 journalctl -xb -p3 使用fsck 不一定是sda2&#xff0c;也可能是其他&#xff0c;我的是/dev/sda6&#xff0c;然后接受所有的option&#xff0c;完毕后重启电脑 fsck /dev/sda2接受所有的选项&#xff…

Python与ArcGIS系列(十六)重复节点检测

目录 0 简述1 实例需求2 arcpy开发脚本0 简述 在处理gis线图层和面图层数据时,有时候会遇到这种情况:数据存在重复节点或伪重复节点(两个节点距离极小),往往我们需要对这种数据进行检测标注或进行修改。本篇将介绍如何利用arcpy及arcgis的工具箱实现这个功能。 1 实例需求…