Go和Java實現解釋器模式

Go和Java實現解釋器模式

下面通過一個四則運算來說明解釋器模式的使用。

1、解釋器模式

解釋器模式提供了評估語言的語法或表達式的方式,它屬于行為型模式。這種模式實現了一個表達式接口,該接口

解釋一個特定的上下文。這種模式被用在 SQL 解析、符號處理引擎等。

  • 意圖:給定一個語言,定義它的文法表示,并定義一個解釋器,這個解釋器使用該標識來解釋語言中的句子。

  • 主要解決:對于一些固定文法構建一個解釋句子的解釋器。

  • 何時使用:如果一種特定類型的問題發生的頻率足夠高,那么可能就值得將該問題的各個實例表述為一個簡單

    語言中的句子。這樣就可以構建一個解釋器,該解釋器通過解釋這些句子來解決該問題。

  • 如何解決:構建語法樹,定義終結符與非終結符。

  • 關鍵代碼:構建環境類,包含解釋器之外的一些全局信息,一般是 HashMap。

  • 應用實例:編譯器、運算表達式計算。

  • 優點:1、可擴展性比較好,靈活。 2、增加了新的解釋表達式的方式。 3、易于實現簡單文法。

  • 缺點:1、可利用場景比較少。 2、對于復雜的文法比較難維護。 3、解釋器模式會引起類膨脹。 4、解釋器模

    式采用遞歸調用方法。

  • 使用場景:1、可以將一個需要解釋執行的語言中的句子表示為一個抽象語法樹。 2、一些重復出現的問題可

    以用一種簡單的語言來進行表達。 3、一個簡單語法需要解釋的場景。

  • 注意事項:可利用場景比較少,JAVA 中如果碰到可以用 expression4J 代替。

  • 適用性:

    當有一個語言需要解釋執行,并且你可將該語言中的句子表示為一個抽象語法樹時,可使用解釋器模式,而當

    存在當下情況時該模式效果最好:

    該文法簡單對于復雜的文法,文法的層次變得龐大而無法管理。

    效率不是一個關鍵問題最高效的解釋器通常不是通過直接解釋語法分析樹實現的,而是首先將它們轉換成另

    一種形式。

2、Go實現解釋器模式

package interpreter// ========== ArithmeticInterpreter ==========
type ArithmeticInterpreter interface {Interpret() int
}
package interpreter// ========== NumInterpreter ==========
type NumInterpreter struct {Value int
}func NewNumInterpreter(value int) *NumInterpreter {return &NumInterpreter{Value: value}
}func (numInterpreter *NumInterpreter) Interpret() int {return numInterpreter.Value
}
package interpreter// ========== AddInterpreter ==========
type AddInterpreter struct {left  ArithmeticInterpreterright ArithmeticInterpreter
}func NewAddInterpreter(left, right ArithmeticInterpreter) *AddInterpreter {return &AddInterpreter{left: left, right: right}
}func (addInterpreter *AddInterpreter) Interpret() int {return addInterpreter.left.Interpret() + addInterpreter.right.Interpret()
}
package interpreter// ========== SubInterpreter ==========
type SubInterpreter struct {left  ArithmeticInterpreterright ArithmeticInterpreter
}func NewSubInterpreter(left, right ArithmeticInterpreter) *SubInterpreter {return &SubInterpreter{left: left, right: right}
}func (subInterpreter *SubInterpreter) Interpret() int {return subInterpreter.left.Interpret() - subInterpreter.right.Interpret()
}
package interpreter// ========== MultiInterpreter ==========
type MultiInterpreter struct {left  ArithmeticInterpreterright ArithmeticInterpreter
}func NewMultiInterpreter(left, right ArithmeticInterpreter) *MultiInterpreter {return &MultiInterpreter{left: left, right: right}
}func (multiInterpreter *MultiInterpreter) Interpret() int {return multiInterpreter.left.Interpret() * multiInterpreter.right.Interpret()
}
package interpreter// ========== DivInterpreter ==========
type DivInterpreter struct {left  ArithmeticInterpreterright ArithmeticInterpreter
}func NewDivInterpreter(left, right ArithmeticInterpreter) *DivInterpreter {return &DivInterpreter{left: left, right: right}
}func (divInterpreter *DivInterpreter) Interpret() int {return divInterpreter.left.Interpret() / divInterpreter.right.Interpret()
}
package interpreterconst (ADD = "+"SUB = "-"MUL = "*"DIV = "/"
)// =========== OperatorUtil ==========
type OperatorUtil struct{}func (OperatorUtil *OperatorUtil) IsOperator(symbol string) bool {return ("+" == symbol || "-" == symbol || "*" == symbol)
}func (operatorUtil *OperatorUtil) GetInterpreter(left, right ArithmeticInterpreter, symbol string) ArithmeticInterpreter {if ADD == symbol {return NewAddInterpreter(left, right)} else if SUB == symbol {return NewSubInterpreter(left, right)} else if MUL == symbol {return NewMultiInterpreter(left, right)} else if DIV == symbol {return NewDivInterpreter(left, right)}return nil
}
package interpreterimport ("fmt""strconv""strings"
)type Calculator struct{}var (operatorUtil = OperatorUtil{}stack        = make([]ArithmeticInterpreter, 0)
)func (calculator *Calculator) Parse(expression string) {elements := strings.Split(expression, " ")var leftExpr, rightExpr ArithmeticInterpreterfor i := 0; i < len(elements); i++ {operator := elements[i]if operatorUtil.IsOperator(operator) {// 出棧leftExpr = stack[len(stack)-1]stack = stack[:len(stack)-1]i++ele, _ := strconv.Atoi(elements[i])rightExpr = NewNumInterpreter(ele)fmt.Printf("出棧: %d 和 %d \n", leftExpr.Interpret(), rightExpr.Interpret())stack = append(stack, operatorUtil.GetInterpreter(leftExpr, rightExpr, operator))fmt.Println("應用運算符: " + operator)} else {ele, _ := strconv.Atoi(elements[i])numInterpreter := NewNumInterpreter(ele)stack = append(stack, numInterpreter)fmt.Printf("入棧: %d \n", numInterpreter.Interpret())}}}func (calculator *Calculator) Result() int {value := stack[len(stack)-1]stack = stack[:len(stack)-1]return value.Interpret()
}
package mainimport ("fmt". "proj/interpreter"
)func main() {calculator := Calculator{}calculator.Parse("10 + 30")fmt.Println("result:", calculator.Result())calculator.Parse("10 + 30 - 20")fmt.Println("result: ", calculator.Result())calculator.Parse("100 * 2 + 400 - 20 + 66")fmt.Println("result:", calculator.Result())
}
# 程序輸出
入棧: 10 
出棧: 1030   
應用運算符: +
result: 40
入棧: 10 
出棧: 1030 
應用運算符: +
出棧: 4020 
應用運算符: -
result:  20
入棧: 100 
出棧: 1002 
應用運算符: *
出棧: 200400 
應用運算符: +
出棧: 60020 
應用運算符: -
出棧: 58066 
應用運算符: +
result: 40
入棧: 10 
出棧: 1030 
應用運算符: +
出棧: 4020 
應用運算符: -
result:  20
入棧: 100 
出棧: 1002 
應用運算符: *
出棧: 200400 
應用運算符: +
出棧: 60020 
應用運算符: -
出棧: 58066 
應用運算符: +
result: 646

3、Java實現解釋器模式

package com.interpreter;// ========== ArithmeticInterpreter ==========
public interface ArithmeticInterpreter {int interpret();
}
package com.interpreter;// ========== ArithmeticInterpreter ==========
public abstract class Interpreter implements ArithmeticInterpreter{protected ArithmeticInterpreter left;protected ArithmeticInterpreter right;public Interpreter(ArithmeticInterpreter left, ArithmeticInterpreter right) {this.left = left;this.right = right;}
}
package com.interpreter;// ========== NumInterpreter ==========
public class NumInterpreter implements ArithmeticInterpreter {private int value;public NumInterpreter(int value) {this.value = value;}@Overridepublic int interpret() {return this.value;}}
package com.interpreter;// ========== AddInterpreter ==========
public class AddInterpreter extends Interpreter {public AddInterpreter() {super(left, right);}@Overridepublic int interpret() {return this.left.interpret() + this.right.interpret();}
}
package com.interpreter;// ========== MultiInterpreter ==========
public class MultiInterpreter extends Interpreter {public MultiInterpreter(ArithmeticInterpreter left, ArithmeticInterpreter right) {super(left, right);}@Overridepublic int interpret() {return this.left.interpret() * this.right.interpret();}
}
package com.interpreter;// ========== SubInterpreter ==========
public class SubInterpreter  extends Interpreter {public SubInterpreter(ArithmeticInterpreter left, ArithmeticInterpreter right) {super(left, right);}@Overridepublic int interpret() {return this.left.interpret() - this.right.interpret();}
}
package com.interpreter;// ========== DivInterpreter ==========
public class DivInterpreter extends Interpreter {public DivInterpreter(ArithmeticInterpreter left, ArithmeticInterpreter right) {super(left, right);}@Overridepublic int interpret() {return this.left.interpret() / this.right.interpret();}
}
package com.interpreter;// =========== OperatorUtil ==========
public class OperatorUtil {private final static String ADD = "+";private final static String SUB = "-";private final static String MUL = "*";private final static String DIV = "/";public static boolean isOperator(String symbol) {return ("+".equals(symbol) || "-".equals(symbol) || "*".equals(symbol));}public static Interpreter getInterpreter(ArithmeticInterpreter left, ArithmeticInterpreter right, String symbol) {if (ADD.equals(symbol)) {return new AddInterpreter(left, right);} else if (SUB.equals(symbol)) {return new SubInterpreter(left, right);} else if (MUL.equals(symbol)) {return new MultiInterpreter(left, right);} else if (DIV.equals(symbol)) {return new DivInterpreter(left, right);}return null;}
}
package com.interpreter;import java.util.Stack;// ========== Calculator ==========
public class Calculator {private final Stack<ArithmeticInterpreter> stack = new Stack<>();public void parse(String expression) {String[] elements = expression.split(" ");ArithmeticInterpreter leftExpr, rightExpr;for (int i = 0; i < elements.length; i++) {String operator = elements[i];if (OperatorUtil.isOperator(operator)) {leftExpr = this.stack.pop();rightExpr = new NumInterpreter(Integer.parseInt(elements[++i]));System.out.println("出棧: " + leftExpr.interpret() + " 和 " + rightExpr.interpret());this.stack.push(OperatorUtil.getInterpreter(leftExpr, rightExpr, operator));System.out.println("應用運算符: " + operator);} else {NumInterpreter numInterpreter = new NumInterpreter(Integer.parseInt(elements[i]));this.stack.push(numInterpreter);System.out.println("入棧: " + numInterpreter.interpret());}}}public int result() {return this.stack.pop().interpret();}}
package com.interpreter;public class Test {public static void main(String[] args) {Calculator calculator = new Calculator();calculator.parse("10 + 30");System.out.println("result: " + calculator.result());calculator.parse("10 + 30 - 20");System.out.println("result: " + calculator.result());calculator.parse("100 * 2 + 400 - 20 + 66");System.out.println("result: " + calculator.result());}
}
# 程序輸出
入棧: 10
出棧: 1030
應用運算符: +
result: 40
入棧: 10
出棧: 1030
應用運算符: +
出棧: 4020
應用運算符: -
result: 20
入棧: 100
出棧: 1002
應用運算符: *
出棧: 200400
應用運算符: +
出棧: 60020
應用運算符: -
出棧: 58066
應用運算符: +
result: 646

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/38712.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/38712.shtml
英文地址,請注明出處:http://en.pswp.cn/news/38712.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

規劃性和可擴展性,助力企業全面預算管理的推進

對于當今社會經濟市場的不穩定狀況和不斷變化的消費者行為&#xff0c;企業業務也從未像今天這樣不可預測過。面對變化和變革&#xff0c;企業需要具備規劃性的預測能力&#xff0c;才能使得自身在競爭中保持領先地位。那些具備前瞻性的企業都嘗試在現階段通過更好的規劃不斷提…

基于Mysqlrouter+MHA+keepalived實現高可用半同步 MySQL Cluster項目

目錄 項目名稱&#xff1a; 基于Mysqlrouter MHA keepalived實現半同步主從復制MySQL Cluster MySQL Cluster&#xff1a; 項目架構圖&#xff1a; 項目環境&#xff1a; 項目環境安裝包&#xff1a; 項目描述&#xff1a; 項目IP地址規劃&#xff1a; 項目步驟: 一…

windows11下配置vscode中c/c++環境

本文默認已經下載且安裝好vscode&#xff0c;主要是解決環境變量配置以及編譯task、launch文件的問題。 自己嘗試過許多博客&#xff0c;最后還是通過這種方法配置成功了。 Linux(ubuntu 20.04)配置vscode可以直接跳轉到配置task、launch文件&#xff0c;不需要下載mingw與配…

寬度有限搜索BFS搜索數及B3625 迷宮尋路 P1451 求細胞數量 B3626 跳躍機器人

寬度有限搜索BFS搜索 B3625 迷宮尋路 題面 題目描述 機器貓被困在一個矩形迷宮里。 迷宮可以視為一個 nm 矩陣&#xff0c;每個位置要么是空地&#xff0c;要么是墻。機器貓只能從一個空地走到其上、下、左、右的空地。 機器貓初始時位于 (1,1) 的位置&#xff0c;問能否…

localhost:8080 is already in use

報錯原因&#xff1a;本機的8080端口號已經被占用。因為機器的空閑端口號是隨機分配的&#xff0c;而idea默認啟動的端口號是8080,所以是存在這種情況。 對于這個問題&#xff0c;我們只需要重啟idea或者修改項目的啟動端口號即可。 更推薦第二種。對于修改項目啟動端口號&…

Python 程序設計入門(020)—— 循環結構程序設計(1):for 循環

Python 程序設計入門&#xff08;020&#xff09;—— 循環結構程序設計&#xff08;1&#xff09;&#xff1a;for 循環 目錄 Python 程序設計入門&#xff08;020&#xff09;—— 循環結構程序設計&#xff08;1&#xff09;&#xff1a;for 循環一、for 循環的語法二、for …

ZDH-wemock模塊

本次介紹基于版本v5.1.1 目錄 項目源碼 預覽地址 安裝包下載地址 wemock模塊 wemock模塊前端 配置首頁 配置mock wemock服務 下載地址 打包 運行 效果展示 項目源碼 zdh_web: https://github.com/zhaoyachao/zdh_web zdh_mock: https://github.com/zhaoyachao/z…

TCGA數據下載推薦:R語言easyTCGA包

#使用easyTCGA獲取數據 #清空 rm(listls()) gc() # 安裝bioconductor上面的R包 options(BioC_mirror"https://mirrors.tuna.tsinghua.edu.cn/bioconductor") if(!require("BiocManager")) install.packages("BiocManager") if(!require("TC…

怎樣讓音頻速度變慢?請跟隨以下方法進行操作

怎樣讓音頻速度變慢&#xff1f;在會議錄音過程中&#xff0c;經常會遇到主講人語速過快&#xff0c;導致我們無法清晰聽到對方說的內容。如果我們能夠減慢音頻速度&#xff0c;就能更好地記錄對方的講話內容。此外&#xff0c;在聽到快速播放的外語或方言時&#xff0c;我們也…

LA@2@1@線性方程組和簡單矩陣方程有解判定定理

文章目錄 矩陣方程有解判定定理線性方程組有解判定特化:齊次線性方程組有解判定推廣:矩陣方程 A X B AXB AXB有解判定證明推論 矩陣方程有解判定定理 線性方程組有解判定 線性方程組 A x b A\bold{x}\bold{b} Axb有解的充分必要條件是它的系數矩陣A和增廣矩陣 ( A , b ) (A,…

機器人的運動范圍

聲明 該系列文章僅僅展示個人的解題思路和分析過程&#xff0c;并非一定是優質題解&#xff0c;重要的是通過分析和解決問題能讓我們逐漸熟練和成長&#xff0c;從新手到大佬離不開一個磨練的過程&#xff0c;加油&#xff01; 原題鏈接 機器人的運動范圍https://leetcode.c…

高等數學教材重難點題型總結(二)導數與微分

本章重點題目較少&#xff0c;除了*標題頁沒什么特別難的&#xff0c;本帖出于總結性的角度考慮并未囊概全部的*標&#xff0c;最后會出一期*標題的全部內容整理&#xff0c;在攻克重難點的基礎上更上一層樓。 1.根據定義求某點處的導數值 2.通過定義證明導數 3.左右導數的相關…

【數據庫】P4 過濾數據 WHERE

過濾數據 WHERE 簡介WHERE 子句操作符檢測單個值案例范圍值檢查 BETWEEN AND空值檢查 NULL 簡介 數據庫表一般包含大量的數據&#xff0c;很少需要檢索表中的所有行。我們只檢索所需數據需要指定搜索條件(search criteria)&#xff0c;搜索條件也稱為過濾條件(filter conditio…

完全備份、增量備份、差異備份、binlog日志

Top NSD DBA DAY06 案例1&#xff1a;完全備份與恢復案例2&#xff1a;增量備份與恢復案例3&#xff1a;差異備份與恢復案例4&#xff1a;binlog日志 1 案例1&#xff1a;完全備份與恢復 1.1 問題 練習物理備份與恢復練習mysqldump備份與恢復 1.2 方案 在數據庫服務器192…

問AI一個嚴肅的問題

chatgpt的問世再一次掀起了AI的浪潮&#xff0c;其實我一直在想&#xff0c;AI和人類的關系未來會怎樣發展&#xff0c;我們未來會怎樣和AI相處&#xff0c;AI真的會完全取代人類嗎&#xff0c;帶著這個問題&#xff0c;我問了下chatgpt&#xff0c;看一看它是怎么看待這個問題…

Modbus工業RFID設備在自動化生產線中的應用

傳統半自動化生產線在運作的過程&#xff0c;因為技工的熟練程度&#xff0c;專業素養的不同&#xff0c;在制造過程中過多的人為干預&#xff0c;工廠將很難對每條生產線的產能進行標準化管理和優化。如果半自動化生產線系統是通過前道工序的作業結果和檢測結果來決定產品在下…

react實現模擬彈框遮罩的自定義hook

需求描述 點擊按鈕用于檢測鼠標是否命中按鈕 代碼實現 import React from react; import {useState, useEffect, useRef} from react;// 封裝一個hook用來檢測當前點擊事件是否在某個元素之外 function useClickOutSide(ref,cb) {useEffect(()>{const handleClickOutside…

JMeter接口自動化測試實例—JMeter引用javaScript

Jmeter提供了JSR223 PreProcessor前置處理器&#xff0c;通過該工具融合了Java 8 Nashorn 腳本引擎&#xff0c;可以執行js腳本以便對腳本進行前置處理。其中比較典型的應用就是通過執行js腳本對前端數據進行rsa加密&#xff0c;如登錄密碼加密。但在這里我就簡單的應用javaScr…

PyTorch翻譯官網教程-NLP FROM SCRATCH: GENERATING NAMES WITH A CHARACTER-LEVEL RNN

官網鏈接 NLP From Scratch: Generating Names with a Character-Level RNN — PyTorch Tutorials 2.0.1cu117 documentation 使用字符級RNN生成名字 這是我們關于“NLP From Scratch”的三篇教程中的第二篇。在第一個教程中</intermediate/char_rnn_classification_tutor…

ChatGPT爆火,會給教育帶來什么樣的影響或者沖擊?

近來&#xff0c;人工智能聊天機器人ChatGPT連上熱搜&#xff0c;火爆全網。ChatGPT擁有強大的信息整合能力、自然語言處理能力&#xff0c;可謂是“上知天文&#xff0c;下知地理”&#xff0c;而且還能根據要求進行聊天、撰寫文章等。 ChatGPT一經推出&#xff0c;便迅速在社…