C++设计模式:解释器模式(简单的数学表达式解析器)

什么是解释器模式?

解释器模式是一种行为型设计模式,用于为特定的语言定义一个解释器,解释并执行语言中的句子。它主要用于构建一个简单的语法解释器,将特定的业务逻辑转化为可理解的语言表达,并对这些表达式进行求值或解析。


通俗解释

想象一个简单的场景:
你想实现一个计算器,用来解析并计算数学表达式,例如:3 + 5 - 2

  • 表达式中的每个元素(如35+-)是语言的基本符号。
  • 解释器模式会为这些符号定义一个语法规则,然后按照规则逐步解析表达式,并计算结果。

解释器模式就是将这些规则封装到类中,让这些类像搭积木一样组成解析器,最终解释并执行语句。


解释器模式的特点

  1. 递归结构

    • 解释器模式通常以递归的方式解析复杂的表达式,将表达式分解为更小的子表达式。
  2. 语法树

    • 表达式通常可以通过抽象语法树表示,每个节点都是一个表达式或操作符。
  3. 适用领域

    • 适合为特定领域定义简单的语言或语法(如正则表达式、数学解析器等)。

解释器模式的结构

UML 类图
       +------------------------+|    AbstractExpression |  // 抽象表达式+------------------------+|  + interpret(context)  |+------------------------+^           ^|           |+----------------+  +------------------+| TerminalExpr   |  | NonTerminalExpr  |  // 终结符表达式和非终结符表达式+----------------+  +------------------+| + interpret()  |  | + interpret()    |+----------------+  +------------------+

组成部分
  1. AbstractExpression(抽象表达式)

    • 定义了解释器的通用接口,所有表达式都必须实现这个接口。
  2. TerminalExpression(终结符表达式)

    • 代表语法中的基本符号(如数字、变量)。
    • 无需进一步解析。
  3. NonTerminalExpression(非终结符表达式)

    • 代表语法中的操作符(如加法、减法)。
    • 由其他表达式组成,通常包含递归结构。
  4. Context(上下文)

    • 提供解释器所需的全局信息,例如变量的值或其他共享数据。

解释器模式的优缺点

优点
  1. 扩展性强

    • 新的语法规则可以通过添加新的表达式类轻松扩展。
  2. 逻辑清晰

    • 语法规则以类的形式清晰表达,便于维护。
  3. 适合特定领域

    • 非常适合为某些特定领域的语言定义解释器。
缺点
  1. 性能问题

    • 复杂语法可能需要大量的类来表示,增加了系统的复杂性。
  2. 维护困难

    • 如果语法规则复杂,会导致类和对象关系过于繁琐,维护成本较高。

案例:简单的数学表达式解析器

需求描述

实现一个简单的数学解析器,用于计算由加法和减法组成的表达式,例如:
3 + 5 - 2

解析器需要支持以下功能:

  1. 支持整数的加法和减法。
  2. 将表达式拆分为子表达式,并按照语法规则解析。

完整代码实现

以下是解释器模式在数学解析器中的实现,输出为中文,附详细注释。

#include <iostream>
#include <memory>
#include <string>
#include <sstream>
#include <vector>// 抽象表达式类
class Expression {
public:virtual int interpret() const = 0; // 解析并返回结果virtual ~Expression() = default;
};// 终结符表达式类:数字
class NumberExpression : public Expression {
private:int number; // 存储的数字public:explicit NumberExpression(int value) : number(value) {}int interpret() const override {return number; // 返回数字值}
};// 非终结符表达式类:加法
class AddExpression : public Expression {
private:std::shared_ptr<Expression> left;  // 左操作数std::shared_ptr<Expression> right; // 右操作数public:AddExpression(std::shared_ptr<Expression> left, std::shared_ptr<Expression> right): left(left), right(right) {}int interpret() const override {return left->interpret() + right->interpret(); // 返回加法结果}
};// 非终结符表达式类:减法
class SubtractExpression : public Expression {
private:std::shared_ptr<Expression> left;  // 左操作数std::shared_ptr<Expression> right; // 右操作数public:SubtractExpression(std::shared_ptr<Expression> left, std::shared_ptr<Expression> right): left(left), right(right) {}int interpret() const override {return left->interpret() - right->interpret(); // 返回减法结果}
};// 客户端代码:解析输入表达式
std::shared_ptr<Expression> parseExpression(const std::string& input) {std::istringstream iss(input);std::vector<std::shared_ptr<Expression>> expressions;char op;int value;// 读取第一个数字iss >> value;expressions.push_back(std::make_shared<NumberExpression>(value));// 解析后续操作符和数字while (iss >> op >> value) {std::shared_ptr<Expression> right = std::make_shared<NumberExpression>(value);if (op == '+') {expressions.push_back(std::make_shared<AddExpression>(expressions.back(), right));} else if (op == '-') {expressions.push_back(std::make_shared<SubtractExpression>(expressions.back(), right));}// 弹出旧的表达式,保留最新结果表达式expressions.erase(expressions.begin(), expressions.end() - 1);}// 返回最后一个表达式return expressions.back();
}// 主函数
int main() {std::string input;std::cout << "请输入数学表达式(例如:3 + 5 - 2): ";std::getline(std::cin, input);// 解析表达式并计算结果auto expression = parseExpression(input);int result = expression->interpret();std::cout << "表达式的计算结果为: " << result << std::endl;return 0;
}

运行结果

假设输入以下内容:

3 + 5 - 2

输出结果为:

表达式的计算结果为: 6

代码解析

1. 抽象表达式类(Expression
class Expression {
public:virtual int interpret() const = 0;virtual ~Expression() = default;
};
  • 定义了解释器的通用接口。
  • interpret()方法返回当前表达式的值。

2. 终结符表达式类(NumberExpression
class NumberExpression : public Expression {
private:int number;public:explicit NumberExpression(int value) : number(value) {}int interpret() const override {return number;}
};
  • 表示数字。
  • interpret()方法直接返回数字值。

3. 非终结符表达式类(AddExpressionSubtractExpression
  • 加法表达式
int interpret() const override {return left->interpret() + right->interpret();
}
  • 减法表达式
int interpret() const override {return left->interpret() - right->interpret();
}
  • 这两类表达式将左右子表达式的值进行运算,并返回结果。

4. 解析器函数(parseExpression
std::shared_ptr<Expression> parseExpression(const std::string& input) {// 解析表达式并构建语法树...
}
  • 将输入的字符串解析为抽象语法树。
  • 每次读取一个操作符和一个数字,根据操作符创建对应的表达式对象。

解释器模式的应用场景

  1. 数学表达式解析
    • 如计算器、公式解析器。
  2. 脚本语言解释器
    • 如自定义的配置文件解析。
  3. 正则表达式解析
    • 如正则表达式的引擎。

总结

解释器模式的核心优势
  1. 可扩展性强:添加新的语法规则只需新增类,无需修改现有代码。
  2. 逻辑清晰:将语法规则封装为类,便于维护和复用。
注意事项
  1. 性能开销

:对于复杂的语法规则,可能会导致大量的类和对象,增加系统复杂性。
2. 适用领域有限:适合简单的语法,复杂语言的解释器更适合通过生成器工具实现(如ANTLR)。

通过本案例,我们展示了如何使用解释器模式构建一个简单的数学解析器,轻松实现对表达式的解析和计算。解释器模式非常适合用在自定义语言、规则引擎和公式计算等场景中!

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

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

相关文章

【深度学习环境】NVIDIA Driver、Cuda和Pytorch(centos9机器,要用到显示器)

文章目录 一 、Anaconda install二、 NIVIDIA driver install三、 Cuda install四、Pytorch install 一 、Anaconda install Step 1 Go to the official website: https://www.anaconda.com/download Input your email and submit. Step 2 Select your version, and click i…

寻找适合小户型的开源知识库open source knowledge base之路

寻找一个开源的知识库&#xff0c;为了把以前花很多时间收集的信息或是项目/课程资料放到一个容易归类和管理的私有自主系统中&#xff0c;以便更容易查阅&#xff0c;花更少时间收集、对比版本及分享等一系列管理工作&#xff0c;同时确保在需要时可以相对快速找到有用的资料&…

C语言勘破之路-最终篇 —— 预处理(上)

人无完人&#xff0c;持之以恒&#xff0c;方能见真我&#xff01;&#xff01;&#xff01; 共同进步&#xff01;&#xff01; 文章目录 一、预定义符号二、#define定义常量三.、#define定义宏四、带有副作用的宏参数五、宏替换的规则六、宏和函数的对比1.宏的优势2.函数的优…

学习threejs,THREE.RingGeometry 二维平面圆环几何体

&#x1f468;‍⚕️ 主页&#xff1a; gis分享者 &#x1f468;‍⚕️ 感谢各位大佬 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍⚕️ 收录于专栏&#xff1a;threejs gis工程师 文章目录 一、&#x1f340;前言1.1 ☘️THREE.RingGeometry 圆环几…

Win11系统下Oracle11g数据库下载与安装使用教程

文章目录 一、Oracle下载与安装1.1 解压安装包1.2 开始安装Oracle11g1.2.1 用户 1.3 测试数据库是否配置成功1.4 了解一下 Oracle相关服务1.5 了解Oracle体系结构 二、使用工具连接数据库2.1 PL/ SQL 连接本地oracle 三、PL/ SQL远程访问数据库3.1 可能踩坑问题&#xff08;TNS…

数据结构(Java版)第六期:LinkedList与链表(一)

目录 一、链表 1.1. 链表的概念及结构 1.2. 链表的实现 专栏&#xff1a;数据结构(Java版) 个人主页&#xff1a;手握风云 一、链表 1.1. 链表的概念及结构 链表是⼀种物理存储结构上⾮连续存储结构&#xff0c;数据元素的逻辑顺序是通过链表中的引⽤链接次序实现的。与火车…

从零开始C++棋牌游戏开发之第三篇:游戏的界面布局设计

在游戏开发的旅途中&#xff0c;界面布局设计是一个充满创意和挑战的环节。对于棋牌类游戏而言&#xff0c;界面不仅仅是功能的载体&#xff0c;更是玩家与游戏互动的桥梁。一个清晰、直观且美观的界面可以显著提升游戏的用户体验。 在这篇文章中&#xff0c;我们将从功能需求…

计算机基础知识——数据结构与算法(五)(山东省大数据职称考试)

大数据分析应用-初级 第一部分 基础知识 一、大数据法律法规、政策文件、相关标准 二、计算机基础知识 三、信息化基础知识 四、密码学 五、大数据安全 六、数据库系统 七、数据仓库. 第二部分 专业知识 一、大数据技术与应用 二、大数据分析模型 三、数据科学 数据结构与算法…

数据库管理-第275期 Oracle 23ai:画了两张架构图(20241225)

数据库管理275期 2024-12-25 数据库管理-第275期 Oracle 23ai&#xff1a;画了两张架构图&#xff08;20241225&#xff09;1 系统管理分片2 用户定义分片总结 数据库管理-第275期 Oracle 23ai&#xff1a;画了两张架构图&#xff08;20241225&#xff09; 作者&#xff1a;胖…

增强路由器 路由器升级宽带速度

由器中DNS设置 DNS&#xff08;域名系统&#xff09;是什么&#xff1f; DNS将域名和IP地址相互映射的一个分布式数据库&#xff0c;能够使人更方便地访问互联网。DNS使用UDP端口53。 上网前提是&#xff1a;配置 IPv4地址、子网掩码 、网关、DNS 正确才能够上网 DNS填写规…

stm32制作CAN适配器5--WinUsb上位机编写

上次我们要stm32制作了一个基于winusb有canfd适配器&#xff0c;今天我们来制作一个上位机程序来进行报文收发。 上位机还是用以前写好的&#xff0c;只是更改下dll文件。 项目链接器&#xff0c;输入&#xff0c;附加依赖项中增加winusb.lib winusb初始化&#xff1a;#incl…

谷歌浏览器 Chrome 提示:此扩展程序可能很快将不再受支持

问题现象 在Chrome 高版本上的扩展管理页面&#xff08;地址栏输入chrome://extensions/或者从界面进入&#xff09;&#xff1a; &#xff0c; 可以查看到扩展的情况。 问题现象大致如图: 问题原因 出现此问题的根本原因在于&#xff1a;谷歌浏览器本身的扩展机制发生了…

Vue.js组件(6):echarts组件

1 前言 本章主要对常用的echars图表展示进行基本的组件封装。使用该组件前需要在项目中引入echarts。官网&#xff1a;Apache ECharts npm install echarts --save 2 图表组件 2.1 折线图组件 组件属性&#xff1a;chartId&#xff0c;指定图表挂载div的id&#xff0c;注意不…

MySQL用表组织数据

用表组织数据 文章目录 用表组织数据一.四种完整性约束二.数值类型2-1三.数值类型2-2四.字符串.日期类型五.设置1.设置主键2.设置标识列3.设置非空4.设置默认值 六.主外键建立后注意事项 一.四种完整性约束 1.域完整性 列 域完整性约束方法:限制数据类型,检查约束,外键约束,默…

面试经典问题 —— 最大/小前K个数问题(top - K)问题

目录 常见思路更优的解法&#xff08;面试官喜欢的&#xff09; 常见思路 要选出最小的前K个数首先我们会想到排排升序建大堆&#xff0c;排降序建小堆 一个直观的想法是使用&#xff08;小根堆&#xff09;&#xff0c;起始将所有元素放入堆中&#xff0c;然后再从堆中取出k 个…

外包干了27天,技术退步明显。。。。。

时光荏苒&#xff0c;转眼我已是一个拥有近四年功能测试经验的大专生。20年&#xff0c;我满怀激情地通过校招进入湖南某知名软件公司&#xff0c;期待在这里开启我的职业生涯。然而&#xff0c;长时间的舒适环境让我渐渐失去了前进的动力&#xff0c;技术停滞不前&#xff0c;…

从自动驾驶到具身智能漫谈

0. 简介 从作者的眼光来看自动驾驶和具身智能已经是越来越接近了。无论是技术栈以及实现的最终目的。其实都是希望人在环内。这个是古月直播的文字相关的大致梳理。主要会展开聊一聊自动驾驶的变迁以及作为自动驾驶的从业人员要着重关注的一些技术点 1. 自动驾驶的变迁 在自…

Excel粘贴复制不完整的原因以及解决方法

在数据处理和分析的过程中&#xff0c;Excel无疑是不可或缺的工具。然而&#xff0c;在使用Excel进行复制粘贴操作时&#xff0c;有时会遇到粘贴不完整的情况&#xff0c;这可能会让人感到困惑和烦恼。本文将深入探讨Excel粘贴复制不完整的原因、提供解决方案&#xff0c;并给出…

云原生之docker详解

目录 1.云原生概念 1.1 云原生定义 1.2 云原生元素 1.2.1 微服务 1.2.2 DevOps 1.2.3 持续交付 1.2.4 容器化 2. Docker 2.1 Docker概述 2.1.1 Docker 定义 2.1.2 Docker应用场景 2.1.3 Docker的架构 2.2 Docker命令 2.2.1 docker进程相关命令 2.2.2 docker镜像…

数仓开发那些事(8)

程序员圣经 为什么刚刚能运行&#xff0c;现在就不行 为什么刚刚不运行&#xff0c;现在就可以 为什么他的可以跑&#xff0c;我的不能跑 为什么我的可以跑&#xff0c;他的就不行 为什么这台电脑能&#xff0c;那台就不行 为什么这台电脑不行&#xff0c;那台就行 神州员工&a…