设计模式之解释器模式(C++)

news2024/9/21 3:27:42

作者:翟天保Steven
版权声明:著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处

一、解释器模式是什么?

       解释器模式是一种行为型的软件设计模式,定义了一个解释器,来解释给定语言和文法的句子。也可以理解为翻译吧,比如1+1,翻译为一加上一,等于二,这样就做成了一个简单的加法计算器。

       解释器模式的优点:

  1. 良好扩展性。语法的翻译通过类来实现,扩展类可以扩展其解释能力。
  2. 易实现。语法树中每个表达式节点类具备一定相似性,实现起来相对容易。

       解释器模式的缺点:

  1. 执行效率低。解释器中通常有大量循环和递归语句,当被解释句子较复杂时,程序的性能受到较大影响。
  2. 类膨胀。规则较多时,类数量也膨胀。

二、解释器模式

2.1 结构图

       客户端即Main主函数,客户端通过解释器来解析表达式内容,表达式又分为终结型和非终结型。就拿计算器举例,1+1,1就是终结符类型,表达式可以用它结尾;而+就是非终结符类型,出现了+,就意味着它前后还有别的表达式字符,自然不能作终结。

2.2 代码示例

       场景描述:实现简单的加减法计算器。

//Interpreter.h
/****************************************************/
#pragma once
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
#include <stack>

using namespace std;

// 抽象表达式类
class Expression 
{
public:
	// 解释
	virtual int interpret() = 0;

};

// 数字表达式类
class NumberExpression : public Expression 
{
public:
	// 构造函数
	NumberExpression(int num) : number(num) {}

	// 解释
	virtual int interpret() { return number; }

private:
	int number;
};

// 加法表达式类
class AddExpression : public Expression 
{
public:
	// 构造函数
	AddExpression(Expression* left, Expression* right) : left(left), right(right) {}

	// 解释
	virtual int interpret() { return left->interpret() + right->interpret(); }

private:
	Expression* left;
	Expression* right;
};

// 减法表达式类
class SubExpression : public Expression 
{
public:
	// 构造函数
	SubExpression(Expression* left, Expression* right) : left(left), right(right) {}

	// 解释
	virtual int interpret() { return left->interpret() - right->interpret(); }

private:
	Expression* left;
	Expression* right;
};

// 解释器类
class Interpreter 
{
public:
	// 构造函数
	Interpreter(string exp) : expression(exp) {}

	// 解释
	int interpret() {
		stack<Expression*> s;
		// 遍历表达式字符
		for (int i = 0; i < expression.length(); i++) {
			if (isdigit(expression[i])) {
				// 识别数字
				int j = i;
				while (j < expression.length() && isdigit(expression[j])) {
					j++;
				}
				int num = stoi(expression.substr(i, j - i));
				s.push(new NumberExpression(num));
				i = j - 1;
			}
			else if (expression[i] == '+') {
				// 把左数提取出来
				Expression* left = s.top();
				s.pop();
				// 识别右数
				int j = i + 1;
				while (j < expression.length() && isdigit(expression[j])) {
					j++;
				}
				Expression* right = new NumberExpression(stoi(expression.substr(i + 1, j - (i + 1))));
				// 左数+右数的表达式放入栈中
				s.push(new AddExpression(left, right));
				i = j - 1;
			}
			else if (expression[i] == '-') {
				// 把左数提取出来
				Expression* left = s.top();
				s.pop();
				// 识别右数
				int j = i + 1;
				while (j < expression.length() && isdigit(expression[j])) {
					j++;
				}
				Expression* right = new NumberExpression(stoi(expression.substr(i + 1, j - (i + 1))));
				// 左数-右数的表达式放入栈中
				s.push(new SubExpression(left, right));
				i = j - 1;
			}
		}
		return s.top()->interpret();
	}

private:
	string expression;
};
//main.cpp
/****************************************************/
#include <iostream>
#include <string>
#include <unordered_map>
#include "Interpreter.h"

using namespace std;

int main() 
{
	unordered_map<string, int> variables;
	string input;
	while (getline(cin, input)) {
		cout << "input:" << input << endl;
		Interpreter interpreter(input);
		variables[input] = interpreter.interpret();
		cout << "result:" << variables[input] << endl;
	}

	return 0;
}

       程序结果如下。

       上述实现的简易计算器,也是许多大学C/C++课程中的大作业,记得以前用MFC实现了一款计算器,开心了老半天哈哈,梦回大学。感兴趣的同学也可以试试复杂计算器,比如引入了括号还有各类运算符。

三、总结

       我尽可能用较通俗的话语和直观的代码例程,来表述我对解释器模式的理解,或许有考虑不周到的地方,如果你有不同看法欢迎评论区交流!希望我举的例子能帮助你更好地理解解释器模式。

       如果文章帮助到你了,可以点个赞让我知道,我会很快乐~加油!

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

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

相关文章

C语言函数大全-- q 开头的函数

C语言函数大全 本篇介绍C语言函数大全-- q 开头的函数 1. qsort 1.1 函数说明 函数声明函数功能void qsort(void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *));用于将指定数组按指定顺序进行排序 参数&#xff1a; base &#xff1a; 指…

2023年,企业如何做好团队知识管理?

团队知识管理是一个组织管理中非常重要的组成部分。成熟的企业通常会非常注重团队知识管理的实践&#xff0c;以提高团队的协作效率和整体绩效。本文将介绍成熟企业如何做好团队知识管理&#xff0c;以提高企业的竞争力和创新能力。 一、了解团队知识管理的重要性 团队知识管…

【网络进阶】五种IO网络模型(二)

文章目录 1. 多路复用IO2. 异步IO3. 信号驱动IO 1. 多路复用IO I/O多路复用这个术语可能对一些人来说比较陌生&#xff0c;但提到select/epoll&#xff0c;就容易理解了。在某些场景下&#xff0c;这种I/O方式也被称为事件驱动I/O&#xff08;event-driven I/O&#xff09;。我…

[Gitops--5]APISIX

APISIX Apache APISIX是一款开源的高性能,动态云原生网关.Apache APISIX当前已经覆盖了API网关,LB,Ingress,Service,Mesh等多种场景 1. APISIX部署 使用Helm Chart部署Apache APISIX Ingress Controller Apache APISIX Ingress Controller目前和Apache APISIX网关是强关联的…

基于html+css的图展示34

准备项目 项目开发工具 Visual Studio Code 1.44.2 版本: 1.44.2 提交: ff915844119ce9485abfe8aa9076ec76b5300ddd 日期: 2020-04-16T16:36:23.138Z Electron: 7.1.11 Chrome: 78.0.3904.130 Node.js: 12.8.1 V8: 7.8.279.23-electron.0 OS: Windows_NT x64 10.0.19044 项目…

GoodSync 数据自动同步备份工具VS傲梅轻松备份系统数据备份工具 哪款更好?

备份和同步软件的使用越来越广泛&#xff0c;因为在这个数据驱动的时代&#xff0c;数据的备份和恢复非常重要。在这里我想向大家推荐两款备份和同步软件——GoodSync和傲梅轻松备份。 GoodSync是一款备份和同步软件&#xff0c;它可以在多个设备之间同步文件、文件夹、照片、音…

在电脑上剪辑视频用什么软件 如何在电脑上剪辑视频

工作中需要剪辑视频的场景越来越多了&#xff0c;视频剪辑已经成了打工人必备技能之一。但对很多新手小白来说&#xff0c;剪辑视频看起来比较困难&#xff0c;那可能是没有找到合适的软件和方法&#xff0c;下面就为大家介绍在电脑上剪辑视频用什么软件&#xff0c;如何在电脑…

Xcode14 设置Display Name不生效问题

一、前言 早在Xcode13苹果就对Info.plist做了一次大改革&#xff0c;新建的OC项目默认Info.plist文件是“空的”&#xff0c;Swift项目甚至干脆连Info.plist文件都没有了&#xff0c;苹果这样做是为了建立一个新的Info.plist管理方式&#xff0c;把Info.plist物理文件中的配置…

对数据库中存储的程序进行现代化改造,以使用 Amazon Aurora PostgreSQL 联合查询、pg_cron 和 Amazon Lambda

作为数据库迁移和现代化的一部分&#xff0c;您可以继续使用存储的程序和调度作业&#xff0c;将远程实例中的数据整合到集中式数据存储中。 Amazon Schema Conversion Tool&#xff08;Amazon SCT&#xff09;可帮助您将传统的 Oracle 和 SQL Server 函数转换为其等效的开源函…

PDF 预览和下载你是怎么实现的?

前言 在开发过程中要求对 PDF 类型的发票提供 预览 和 下载 功能&#xff0c;**PDF** 类型文件的来源又包括 H5 移动端 和 **PC 端**&#xff0c;而针对这两个不同端的处理会有些许不同&#xff0c;下文会有所提及。 针对 PDF 预览 的文章不在少数&#xff0c;但似乎都没有提…

排查和解决CentOS系统上Nacos服务启动报错“java.net.UnknownHostException: jmenv.tbsite.net“问题

背景 环境是CentOS7操作系统&#xff0c;nacos服务宕掉了&#xff0c;启动服务的时候报错。 Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.boot.web.servlet.FilterRegistrationBean]: Factory method ‘di…

太酷啦,Transformer 的有效上下文长度可扩展至百万级

夕小瑶科技说 原创作者 | 智商掉了一地、iven 用 Recurrent Memory Transformer 架构&#xff1a;可输入长度取决于内存大小 Transformer 因其在自然语言处理领域的成功应用而备受瞩目&#xff0c;同时在计算机视觉领域的研究中&#xff0c;诸多的多模态大模型如 ViT、CLIP、BL…

iperf3使用教程

文章目录 简介1.下载2. 使用测试实例&#xff1a;案例一 TCP通信测试案例二&#xff1a;UDP测试案例三 传输东西进行测试 iperfs3简单使用样例 简介 iPerf3是用于主动测试IP网络上最大可用带宽的工具。它支持时序、缓冲区、协议&#xff08;TCP&#xff0c;UDP&#xff0c;SCT…

软件测试方法——等价类划分法详解

1、等价类划分法的介绍和概念 划分 指互不相交的一组子集&#xff0c;这些子集的并是整个集合。 对测试的意义&#xff1a;完备性和无冗余性。 等价类 等价类是指某个输入域的子集合。在该子集合中&#xff0c;各个输入数据对于揭露程序中的错误都是等效的&#xff0c;具有等…

23.4.25总结

复习了MYSQL数据库的主键和外键的知识&#xff1a; 在设计表时&#xff0c;可以通过外键这个按钮&#xff0c;更改Update rule&#xff08;更新规则&#xff09;和Delete rule&#xff08;删除规则&#xff09;。 外键行为 默认情况下是&#xff1a;NO ACTION、RESTRICT 两…

传统机器学习(七)支持向量机(1)超平面、SVM硬间隔、软间隔模型和损失函数

传统机器学习(七)支持向量机(1) 1 算法概述 1.1 超平面的理解 1.1.1 超平面公式 我们对“平面”概念的理解&#xff0c;一般是定义在三维空间中的&#xff0c;如下&#xff1a; 假设M和M0为平面上的两点&#xff0c;n为该平面的法向量&#xff0c;那么&#xff0c;通过下图…

4.25~~~~~

接着之前PE文件结构的预习 DOS 定位到NT 怎么操作的&#xff1f; 用的是e_lfanew&#xff0c;然后是相对于文件头的偏移量&#xff08;也就是raw表示方法&#xff09; 现在有个问题&#xff0c;为什么e_lfanew 这个变量不直接存储PE头 的绝对地址呢&#xff1f; 比如说&…

python 基础语法学习之变量与运算符

一、注释 注释: 就是对代码的解释&#xff0c;方便阅读&#xff0c;被注释的代码不执行 分类 单行注释 # 1.单行注释 以#号开头 &#xff0c;右边的所有东西都被当做说明文字 &#xff0c;程序不进行编译运行。 print(hello world)多行注释 # 2.多行注释 三个单引号 或…

学习日记(刷题,学java)

先看看题目 给你一个字符串数组 names &#xff0c;和一个由 互不相同 的正整数组成的数组 heights 。两个数组的长度均为 n 。 对于每个下标 i&#xff0c;names[i] 和 heights[i] 表示第 i 个人的名字和身高。 请按身高 降序 顺序返回对应的名字数组 names 。 示例 1&…

Chapter 4 :Constraining I/O Delay(ug903)

4.1 About Constraining I/O Delay 要在设计中准确地建模外部时序上下文&#xff0c;必须为输入和输出端口提供时序信息。由于XilinxVivado集成设计环境&#xff08;IDE&#xff09;只能识别FPGA边界内的时序&#xff0c;因此必须使用以下命令来指定超出这些边界的延迟…