您好,登錄后才能下訂單哦!
怎么在Java中利用解釋器模式實(shí)現(xiàn)定義一種語言?相信很多沒有經(jīng)驗(yàn)的人對(duì)此束手無策,為此本文總結(jié)了問題出現(xiàn)的原因和解決方法,通過這篇文章希望你能解決這個(gè)問題。
一 模式定義
解釋器模式:就是給定一個(gè)語言的文法表示,并且定義一個(gè)解釋器,用來解釋語言中的句子。解釋器模式描述了怎樣在有了一個(gè)簡(jiǎn)單的文法后,使用模式設(shè)計(jì)解釋這些語句。
二 模式舉例
1 模式分析
我們自己設(shè)計(jì)一種語言來說明這一模式
(1)該語言區(qū)分大小寫
(2)該語言以PROGRAM開頭,END結(jié)尾
(3)PRINTLN表示打印一行并換行
(4)使用FOR…FROM…TO…END表示循環(huán)
示例語言內(nèi)容如下:
PROGRAM PRINTLN start... FOR i FROM 90 TO 100 PRINTLN i END PRINTLN end...END
該句表示的意思是:首先打印“start…”換行,然后循環(huán)打印“90”換行、“91”換行、……“100”換行,最后打印“end…”換行。
2 該語言解釋樹結(jié)構(gòu)
3 該語言解釋器活動(dòng)圖
4 代碼示例
4.1 創(chuàng)建上下文環(huán)境——Context
package com.demo.interpreter.context; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.StringTokenizer; /** * 上下文環(huán)境 * * @author * */ public class Context { // 待解析的文本內(nèi)容 private final StringTokenizer stringTokenizer; // 當(dāng)前命令 private String currentToken; // 用來存儲(chǔ)動(dòng)態(tài)變化信息內(nèi)容 private final Map<String, Object> map = new HashMap<String, Object>(); /** * 構(gòu)造方法設(shè)置解析內(nèi)容 * * @param text */ public Context(String text) { // 使用空格分隔待解析文本內(nèi)容 this.stringTokenizer = new StringTokenizer(text); } /** * 解析文本 */ public String next() { if (this.stringTokenizer.hasMoreTokens()) { currentToken = this.stringTokenizer.nextToken(); } else { currentToken = null; } return currentToken; } /** * 判斷命令是否正確 * * @param command * @return */ public boolean equalsWithCommand(String command) { if (command == null || !command.equals(this.currentToken)) { return false; } return true; } /** * 獲得當(dāng)前命令內(nèi)容 * * @return */ public String getCurrentToken() { return this.currentToken; } /** * 獲得節(jié)點(diǎn)的內(nèi)容 * * @return */ public String getTokenContent(String text) { String str = text; if (str != null) { // 替換map中的動(dòng)態(tài)變化內(nèi)容后返回 Iterator<String> // 替換map中的動(dòng)態(tài)變化內(nèi)容后返回 Iterator<String> iterator = this.map.keySet().iterator(); while (iterator.hasNext()) { String key = iterator.next(); Object obj = map.get(key); str = str.replaceAll(key, obj.toString()); } } return str; } public void put(String key, Object value) { this.map.put(key, value); } public void clear(String key) { this.map.remove(key); } }
4.2 表達(dá)式接口——IExpressions
package com.demo.interpreter.express; import com.demo.interpreter.context.Context; /** * * 表達(dá)式接口 * * @author * */ public interface IExpressions { /** * 解析 * * @param context */ public void parse(Context context); /** * 執(zhí)行方法 * * @param context */ public void interpret(); }
4.3 主表達(dá)式——ProgramExpression
package com.demo.interpreter.express; import com.demo.interpreter.context.Context; /** * program 表達(dá)式 * * @author * */ public class ProgramExpression implements IExpressions { // 上下文環(huán)境 private final Context context; // 當(dāng)前命令 private final static String COMMAND = "PROGRAM"; // 存儲(chǔ)下一個(gè)表達(dá)式引用 private IExpressions expressions; /** * 構(gòu)造方法將待解析的內(nèi)容傳入 * * @param text */ public ProgramExpression(String text) { this.context = new Context(text); this.parse(this.context); } @Override public void parse(Context context) { // 獲取第一個(gè)命令節(jié)點(diǎn) this.context.next(); } /** * 實(shí)現(xiàn)解釋方法 */ @Override public void interpret() { // 判斷是否是以PROGRAM 開始 if (!this.context.equalsWithCommand(COMMAND)) { System.out.println("The '" + COMMAND + "' is Excepted For Start!"); } else { // 是以PROGRAM 開始 this.context.next(); this.expressions = new ListExpression(); this.expressions.parse(this.context); // ListExpression表達(dá)式開始解析 this.expressions.interpret(); } } }
4.4 列表表達(dá)式——ListExpression
package com.demo.interpreter.express; import java.util.ArrayList; import java.util.Iterator; import com.demo.interpreter.context.Context; /** * 列表表達(dá)式 * * @author * */ public class ListExpression implements IExpressions { private Context context; private final ArrayList<IExpressions> list = new ArrayList<IExpressions>(); /** * 構(gòu)造方法將待解析的context傳入 * * @param context */ public void parse(Context context) { this.context = context; // 在ListExpression解析表達(dá)式中,循環(huán)解釋語句中的每一個(gè)單詞,直到終結(jié)符表達(dá)式或者異常情況退出 while (true) { if (this.context.getCurrentToken() == null) { // 獲取當(dāng)前節(jié)點(diǎn)如果為 null 則表示缺少END表達(dá)式 System.out.println("Error: The Experssion Missing 'END'! "); break; } else if (this.context.equalsWithCommand("END")) { this.context.next(); // 解析正常結(jié)束 break; } else { // 建立Command 表達(dá)式 IExpressions expressions = new CommandExperssion(this.context); // 添加到列表中 list.add(expressions); } } } /** * 實(shí)現(xiàn)解釋方法 */ @Override public void interpret() { // 循環(huán)list列表中每一個(gè)表達(dá)式 解釋執(zhí)行 Iterator<IExpressions> iterator = list.iterator(); while (iterator.hasNext()) { (iterator.next()).interpret(); } } }
4.5 命令表達(dá)式——CommandExperssion
package com.demo.interpreter.express; import com.demo.interpreter.context.Context; /** * 命令表達(dá)式 * * @author * */ public class CommandExperssion implements IExpressions { private final Context context; private IExpressions expressions; /** * 構(gòu)造方法將待解析的context傳入 * * @param context */ public CommandExperssion(Context context) { this.context = context; this.parse(this.context); } public void parse(Context context) { // 判斷當(dāng)前命令類別 在此只對(duì)For和最原始命令進(jìn)行區(qū)分 if (this.context.equalsWithCommand("FOR")) { // 創(chuàng)建For表達(dá)式進(jìn)行解析 expressions = new ForExpression(this.context); } else { // 創(chuàng)建原始命令表達(dá)式進(jìn)行內(nèi)容解析 expressions = new PrimitiveExpression(this.context); } } /** * 解析內(nèi)容 */ @Override public void interpret() { // 解析內(nèi)容 this.expressions.interpret(); } }
4.6 循環(huán)表達(dá)式——ForExpression
package com.demo.interpreter.express; import com.demo.interpreter.context.Context; /** * For表達(dá)式 * * @author * */ public class ForExpression implements IExpressions { private final Context context; // 存儲(chǔ)當(dāng)前索引key值 private String variable; // 存儲(chǔ)循環(huán)起始位置 private int start_index; // 存儲(chǔ)循環(huán)結(jié)束位置 private int end_index; private IExpressions expressions; /** * 構(gòu)造方法將待解析的context傳入 * * @param context */ public ForExpression(Context context) { this.context = context; this.parse(this.context); } /** * 解析表達(dá)式 */ @Override public void parse(Context context) { // 首先獲取當(dāng)前節(jié)點(diǎn) this.context.next(); while (true) { // 判斷節(jié)點(diǎn) if (this.context.equalsWithCommand("FROM")) { // 設(shè)置開始索引內(nèi)容 String nextStr = this.context.next(); try { this.start_index = Integer.parseInt(nextStr); } catch (Exception e) { System.out .println("Error: After 'FROM' Expression Exist Error!Please Check the Format Of Expression is Correct!"); break; } // 獲取下一個(gè)節(jié)點(diǎn) this.context.next(); } else if (this.context.equalsWithCommand("TO")) { // 設(shè)置結(jié)束索引內(nèi)容 String nextStr = this.context.next(); try { this.end_index = Integer.parseInt(nextStr); } catch (Exception e) { System.out .println("Error: After 'TO' Expression Exist Error!Please Check the Format Of Expression is Correct!"); } this.context.next(); break; } else { // 設(shè)置當(dāng)前索引變量?jī)?nèi)容 if (this.variable == null) { this.variable = this.context.getCurrentToken(); } // 獲取下一個(gè)節(jié)點(diǎn) this.context.next(); } } // 建立列表表達(dá)式 this.expressions = new ListExpression(); this.expressions.parse(this.context); } /** * 實(shí)現(xiàn)解釋方法 */ @Override public void interpret() { // 建立命令表達(dá)式 for (int x = this.start_index; x <= this.end_index; x++) { // 設(shè)置變量?jī)?nèi)容 this.context.put("" + this.variable, x); // 執(zhí)行解釋方法 this.expressions.interpret(); } // 移除使用的臨時(shí)變量?jī)?nèi)容 this.context.clear("" + this.variable); } }
4.7 基礎(chǔ)表達(dá)式——PrimitiveExpression
package com.demo.interpreter.express; import com.demo.interpreter.context.Context; /** * 最基礎(chǔ)的表達(dá)式 * * @author * */ public class PrimitiveExpression implements IExpressions { private Context context; // 節(jié)點(diǎn)名稱 private String tokenName; // 文本內(nèi)容 private String text; /** * 構(gòu)造方法將待解析的context傳入 * * @param context */ public PrimitiveExpression(Context context) { this.parse(context); } @Override public void parse(Context context) { this.context = context; this.tokenName = this.context.getCurrentToken(); this.context.next(); if ("PRINTLN".equals(this.tokenName)) { this.text = this.context.getCurrentToken(); this.context.next(); } } /** * 實(shí)現(xiàn)解釋方法 */ @Override public void interpret() { // 首先獲取當(dāng)前節(jié)點(diǎn)內(nèi)容 if ("PRINTLN".equals(tokenName)) { // 獲得內(nèi)容信息 // 打印內(nèi)容 System.out.println(this.context.getTokenContent(this.text)); } } }
4.8 讓語言解釋器開始工作——Client
package com.demo.interpreter; import com.demo.interpreter.express.IExpressions; import com.demo.interpreter.express.ProgramExpression; /** * 主應(yīng)用程序 * * @author * */ public class Client { /** * @param args */ public static void main(String[] args) { // myida語言語句 String str = "PROGRAM PRINTLN start... FOR i FROM 90 TO 100 PRINTLN i END PRINTLN end... END"; System.out.println("str:" + str); // 創(chuàng)建PROGRAM表達(dá)式 IExpressions expressions = new ProgramExpression(str); // 解釋執(zhí)行 expressions.interpret(); } }
5 運(yùn)行結(jié)果
str:PROGRAM PRINTLN start... FOR i FROM 90 TO 100 PRINTLN i END PRINTLN end... END
start...
90
91
92
93
94
95
96
97
98
99
100
end...
三 設(shè)計(jì)原則
1 “開-閉”原則
2 封閉變化原則
四 使用場(chǎng)合
(1)一種特定類型的問題發(fā)生的頻率足夠高,并且業(yè)務(wù)規(guī)則頻繁變化,不斷重復(fù)出現(xiàn)類似情況。
(2)業(yè)務(wù)規(guī)則不是過于復(fù)雜煩瑣,比較容易抽象出語法規(guī)則。
(3)效率不是軟件系統(tǒng)中主要考慮的因素。
五 解釋器模式靜態(tài)類圖
看完上述內(nèi)容,你們掌握怎么在Java中利用解釋器模式實(shí)現(xiàn)定義一種語言的方法了嗎?如果還想學(xué)到更多技能或想了解更多相關(guān)內(nèi)容,歡迎關(guān)注億速云行業(yè)資訊頻道,感謝各位的閱讀!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。