《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.pswp.cn/news/208618.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/208618.shtml
英文地址,請注明出處:http://en.pswp.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 實例需求…