22行为型设计模式——解释器模式

一、解释器模式

解释器模式(Interpreter Pattern)是一种行为型设计模式,主要用于解析和解释特定的语言或表达式。它的核心思想是为语言中的每种语法规则定义一个解释器,通过这些解释器将语言的表示形式转换为可执行的操作。解释器模式在实际业务中使用频率相对较低,因为其性能和类膨胀的问题,需求较少。在处理解析和解释特定的语言或类似表达式转换或者算术表达式计算等复杂计算逻辑的场景,这种模式常见。

解释器模式的结构图

  1. 抽象表达式(Abstract Expression)角色:定义解释器的接口,约定解释器的解释操作。

  2. 终结符表达式(Terminal Expression)角色:实现文法中与终结符相关的操作。

  3. 非终结符表达式(Nonterminal Expression)角色:实现文法中与非终结符相关的操作。

  4. 环境(Context)角色:包含解释器需要的数据或是公共的功能。

  5. 客户端(Client):主要任务是将需要分析的句子或表达式转换成抽象语法树,然后调用解释器的解释方法。

解释器模式涉及三个关键的元素

  1. 抽象语法树:在解释器模式中,语言的句子通常表示为抽象语法树(AST)。AST是句子的树形表示,它反映了句子的结构,使得解释器可以按照树的结构来解释句子。

  2. 文法与句子:文法是用于描述语言的语法结构的形式规则。句子是语言的基本单位,由终结符构成,能由“文法”推导出。

  3. 解释器:解释器是使用解释器模式设计的类,它用于解释和执行语言的句子。

二、解释器模式的设计方法

设计代码实现一个简单的算术表达式解释器,能够处理加法和减法操作,并且可以从终端读取表达式进行求值。终端输入表达式格式:[数字][空格][操作符][空格][数字]

interpreter.cpp

#include <iostream>
#include <sstream>
#include <string>
#include <vector>
#include <stack>
#include <cctype>
#include <stdexcept>// 接口
class Expression {
public:virtual ~Expression() {}virtual int interpreter() const = 0;
};// 数值表达式
class NumberExpression : public Expression {
public:NumberExpression(int value) : value_(value) {}int interpreter() const override {return value_;}private:int value_;
};// 加法表达式
class AdditionExpression : public Expression {
public:AdditionExpression(Expression* left, Expression* right) : left_(left), right_(right) {}int interpreter() const override {return left_->interpreter() + right_->interpreter();}~AdditionExpression() {delete left_;delete right_;}private:Expression* left_;Expression* right_;
};// 减法表达式
class SubtractionExpression : public Expression {
public:SubtractionExpression(Expression* left, Expression* right) : left_(left), right_(right) {}int interpreter() const override {return left_->interpreter() - right_->interpreter();	}~SubtractionExpression() {delete left_;delete right_;}
private:Expression* left_;Expression* right_;
};class ExpressionEvaluator {
public:static int evaluate(const std::vector<std::string>& tokens) {std::stack<Expression*> values;std::stack<std::string> operators;for (const auto& token : tokens) {if (isdigit(token[0])) {values.push(new NumberExpression(std::stoi(token)));} else if (token == "+" || token == "-") {while (!operators.empty() && (precedence(operators.top()) >= precedence(token))) {processOPerator(values,operators);}operators.push(token);} else {throw std::runtime_error("Syntax error: 无效的符号 " + token);}}while (!operators.empty()) {processOPerator(values,operators);}if (values.size() != 1) {throw std::runtime_error("Syntax error: 无效的算术表达式");}int  result = values.top()->interpreter();delete values.top();return result;}private:static int precedence(const std::string& operate) {if (operate == "+" || operate == "-") return 1;return 0; }static void processOPerator(std::stack<Expression*>& values, std::stack<std::string>&operators) {if (values.size() <2) {throw std::runtime_error("Syntax error: 操作数不足");}Expression* right = values.top(); values.pop();Expression* left = values.top(); values.pop();std::string operate = operators.top(); operators.pop();Expression* result = nullptr;if (operate == "+") {result = new AdditionExpression(left, right);} else if (operate == "-") {result = new SubtractionExpression(left, right);} else {throw std::runtime_error("Syntax error: 无效的操作符 " + operate);}values.push(result);}
};// 客户端
int main() {std::cout << "\n// 示例用法1 " << std::endl;std::cout << "终端输入 '3 + 4 - 2' " << std::endl;std::vector<std::string> tokens = {"3", "+", "4", "-", "2"};try {int result = ExpressionEvaluator::evaluate(tokens);std::cout << "算术表达式结果: " << result << std::endl;} catch (const std::exception& e) {std::cerr << "Error: " << e.what() << std::endl;}std::cout << "\n// 示例用法2 " << std::endl;std::cout << "终端输入 '10 + 20 - 30 + 40' " << std::endl;tokens = {"10", "+", "20", "-", "30", "+", "40"};try {int result = ExpressionEvaluator::evaluate(tokens);std::cout << "算术表达式结果: " << result << std::endl;} catch (const std::exception& e) {std::cerr << "Error: " << e.what() << std::endl;}tokens.clear();std::string line;std::cout <<  "\n请输入算术表达式 (例如:'3 + 4 - 2'): ";std::getline(std::cin, line);std::istringstream iss(line);std::string token;while (iss >> token) {if (token != "+" && token != "-" && !isdigit(token[0])) {std::cerr << "Error: 无效的符号 " << token << std::endl;return 1;}tokens.push_back(token);}try {int result = ExpressionEvaluator::evaluate(tokens);std::cout << "算术表达式结果: " << result << std::endl;} catch (const std::exception& e) {std::cerr << "Error: " << e.what() << std::endl;return 1;}return 0;
}

代码中使用了中缀表示法(即常见的 3 - 4 + 5 这种形式),并且利用了栈来处理操作符和操作数。需要注意的是数字包括符号之间需要有空格。(空格作为切割符)

运行效果

 

三、解释器模式的应用场景

  1. 编程语言的解释器:解释器模式常用于构建编程语言的解释器。例如,CPython、V8,你也可以设计一个自定义的小型编程语言,通过定义解释器模式中的表达式和语法规则来解析和执行这些语言。

  2. 复杂的计算器:当你需要构建一个可以解析并计算复杂数学表达式的计算器时,解释器模式可以帮助将数学表达式分解为更简单的操作,然后逐步计算结果,例如上面的代码实现中interpreter.cpp。

  3. 规则引擎:在某些应用场景中,需要根据特定的规则或条件执行不同的操作。解释器模式可以用来实现这些规则的解析和执行,例如业务规则引擎。

  4. DSL(领域特定语言):如果你需要为特定领域创建一个定制的语言或语法(例如用于配置或查询),解释器模式可以帮助你解析这种领域特定语言的表达式,并执行相应的操作。

  5. 数据处理和转换:在需要将输入数据转换为特定格式的场景中,解释器模式可以帮助将数据解析成中间表示,然后进行转换和处理。

  6. 脚本语言:当需要实现一个小型脚本语言,或在应用中嵌入一个脚本解释器时,解释器模式提供了一种组织和解释脚本语言的方式。

四、总结

解释器模式允许你可以将复杂的语句表达式转换成对应的执行代码。这种模式通常用于字符串解析或语言解释器中。它将算术或逻辑表达式设计成一个接一个的独立的“组件”,每个组件负责解释其中一个语法符号的含义。这些组件可以单独构建、组合或重用。

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

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

相关文章

双臂机器人协作/合作阻抗建模及其控制实现(Dual-Arm Cooperative)

机器人阻抗控制是一种基于力的控制方法,其核心在于通过调整机器人的阻抗特性(如刚度、阻尼等),使机器人在与环境交互时能够表现出特定的力学行为。以下是对机器人阻抗控制的详细解析: 一、定义与内涵 机器人阻抗控制是指通过调整机器人的阻抗特性(如刚度、阻尼等),使…

【Python机器学习】NLP词频背后的含义——距离和相似度

我们可以使用相似度评分&#xff08;和距离&#xff09;&#xff0c;根据两篇文档的表示向量间的相似度&#xff08;或距离&#xff09;来判断文档间有多相似。 我们可以使用相似度评分&#xff08;和举例&#xff09;来查看LSA主题模型与高维TF-IDF模型之间的一致性。在去掉了…

697.数组的度

697.数组的度 给定一个非空且只包含非负数的整数数组 nums&#xff0c;数组的 度 的定义是指数组里任一元素出现频数的最大值。 你的任务是在 nums 中找到与 nums 拥有相同大小的度的最短连续子数组&#xff0c;返回其长度。 示例 1&#xff1a; 输入&#xff1a;nums [1,2,2…

STM32基于HAL库串口printf使用和接收

我们这里使用HAL库直接用cubemx生成代码配置串口 1.打开cubemx&#xff0c;选择MCU型号 2.我这里使用的是STM32F103C8T6&#xff0c;根据自己的型号选择&#xff0c;这里不限制型号 3.选择时钟源 4.系统设置 5时钟配置 5.选择和配置串口 5.配置中断和中断优先级 6.工程设置…

【时时三省】c语言例题----华为机试题<最长回文子串>

山不在高&#xff0c;有仙则名。水不在深&#xff0c;有龙则灵。 ----CSDN 时时三省 1&#xff0c;题目 HJ85 最长回文子串 描述 给定一个仅包含小写字母的字符串&#xff0c;求它的最长回文子串的长度。 所谓回文串&#xff0c;指左右对称的字符串。 所谓子串&#xff0…

二叉搜索树的最近公共祖先:递归与迭代解法全面解析

在本篇文章中&#xff0c;我们将详细解读力扣第235题“二叉搜索树的最近公共祖先”。通过学习本篇文章&#xff0c;读者将掌握如何在二叉搜索树中找到两个节点的最近公共祖先&#xff0c;并了解相关的复杂度分析和模拟面试问答。每种方法都将配以详细的解释&#xff0c;以便于理…

代码随想录算法训练营第三十一天|56. 合并区间 738.单调递增的数字

56. 合并区间 题目&#xff1a; 以数组 intervals 表示若干个区间的集合&#xff0c;其中单个区间为 intervals[i] [starti, endi] 。请你合并所有重叠的区间&#xff0c;并返回 一个不重叠的区间数组&#xff0c;该数组需恰好覆盖输入中的所有区间 。 示例 1&#xff1a; 输…

MySQL数据库事务的学习(有业务场景案例)

一、事务的基本概念 定义&#xff1a;事务是数据库管理系统执行过程中的一个逻辑单位&#xff0c;由一个或多个SQL语句组成&#xff0c;这些语句作为一个整体一起向系统提交&#xff0c;要么全部执行&#xff0c;要么全部不执行。 二、ACID特性详解 1. 原子性&#xff08;At…

node环境安装、vue-cli搭建过程、element-UI搭建使用过程

vue-cli 官方提供的一个脚手架&#xff0c;用于快速生成一个 vue 的项目模板&#xff1b;预先定义好的目录结构及基础代码&#xff0c;就好比咱们在创建 Maven 项目时可以选择创建一个骨架项目&#xff0c;这个骨架项目就是脚手架&#xff0c;我们的开发更加的快速 前端项目架…

探索Python测试的奥秘:nose库的魔法之旅

文章目录 探索Python测试的奥秘&#xff1a;nose库的魔法之旅1. 背景&#xff1a;为什么要用nose&#xff1f;2. nose是什么&#xff1f;3. 如何安装nose&#xff1f;4. 五个简单的库函数使用方法4.1 nose.tools.assert_true4.2 nose.tools.assert_equal4.3 nose.tools.raises4…

html2canvas、pdf-lib、file-saver将html页面导出成pdf

html2canvas、pdf-lib、file-saver将html页面导出成pdf 项目背景 需要根据用户的账号信息&#xff0c;生成一个pdf报告发给客户&#xff0c;要求报告包含echart饼图、走势图等。 方案 使用html2canvas&#xff0c;将页面转成图片&#xff0c;再通过pdf-lib将图片转成pdf文件…

Visual Studio Code离线汉化

从官网下载Visual Studio Code安装包后&#xff0c; 下载Visual Studio Code&#xff1a;https://code.visualstudio.com/ 若因网络等问题无法在线安装语言包&#xff0c;可以尝试离线安装&#xff1a; 从官网下载语言包&#xff1a; Extensions for Visual Studio family …

Stable Diffusion majicMIX_realistic模型的介绍及使用

一、简介 majicMIX_realistic模型是一种能够渲染出具有神秘或幻想色彩的真实场景的AI模型。这个模型的特点是在现实场景的基础上&#xff0c;通过加入一些魔法与奇幻元素来营造出极具画面效果和吸引力的图像。传统意义的现实场景虽然真实&#xff0c;但通常情况下缺乏奇幻性&a…

【网络世界】网络层

目录 &#x1f308;前言&#x1f308; &#x1f4c1; 网络层 &#x1f4c1; IPV4 &#x1f4c2; 什么是IP地址 &#x1f4c2; 网段划分 &#x1f4c2; 特殊IP &#x1f4c2; 内网和公网 &#x1f4c2; IPV4的危机 &#x1f4c1; IP协议格式 &#x1f4c1; 路由 &#x1f…

极限的性质【上】《用Manim可视化》

通过前面的极限的定义&#xff0c;现在是计算极限的时候了。然而&#xff0c;在此之前&#xff0c;我们需要一些极限的性质&#xff0c;这将使我们的工作变得简单一些。我们先来看看这些。 极限的性质&#xff1a; 1.常数对极限的影响 1.首先&#xff0c;我们假设和存在&…

flutter 类似Android 中RelativeLayout在末尾居中

1&#xff0c;Android RelativeLayout中写法&#xff1a; <RelativeLayoutxmlns:android"http://schemas.android.com/apk/res/android"android:layout_width"match_parent"android:layout_height"match_parent"><Buttonandroid:id&quo…

通过Origin提取图片数据

第一步&#xff1a; Tool --> Digitizer 第二步&#xff1a;点击文件&#xff0c;导入图片 第三步&#xff1a;设置坐标轴位置和数值&#xff08;Edit Aix&#xff09; 滑动鼠标放大图片&#xff0c;将X1移动到0&#xff0c;X2移动到80&#xff0c;Y1移动到97.0&#xff0c…

Kubernetes 上安装 Jenkins

安装 Helm curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash添加 Jenkins Helm 仓库 首先添加 Jenkins Helm 仓库 helm repo add jenkins https://charts.jenkins.io helm repo update安装 Jenkins 使用 Helm 安装 Jenkins 的最新版本&…

Linux下C编程使用动态链接库

为了方便程序功能的后期升级扩展&#xff0c;在程序设计时经常会用到动态库&#xff0c;这样子程序只有到运行阶段才会去加载动态库并且使用库中的函数&#xff0c;那么我们往往只需要更新DLL&#xff08;Windows系统&#xff09;或SO&#xff08;Linux系统&#xff09;文件即可…

tr,cut,diff(数据处理

tr 命令 功能&#xff1a; tr 命令用于转换或删除文件中的字符。 语法&#xff1a; 格式&#xff1a; tr [-cdst][--help][--version][第一字符集][第二字符集] tr [OPTION]…SET1[SET2] 标识符&#xff1a; -d&#xff1a;删除指定的字符。-s&#xff1a;压缩重复的字…