本文實例講述了java基于解釋器模式實現定義一種簡單的語言功能。分享給大家供大家參考,具體如下:
一 模式定義
解釋器模式:就是給定一個語言的文法表示,并且定義一個解釋器,用來解釋語言中的句子。解釋器模式描述了怎樣在有了一個簡單的文法后,使用模式設計解釋這些語句。
二 模式舉例
1 模式分析
我們自己設計一種語言來說明這一模式
(1)該語言區分大小寫
(2)該語言以program開頭,end結尾
(3)println表示打印一行并換行
(4)使用for…from…to…end表示循環
示例語言內容如下:
program println start... for i from 90 to 100 println i end println end...end
該句表示的意思是:首先打印“start…”換行,然后循環打印“90”換行、“91”換行、……“100”換行,最后打印“end…”換行。
2 該語言解釋樹結構
3 該語言解釋器活動圖
4 代碼示例
4.1 創建上下文環境——context
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
|
package com.demo.interpreter.context; import java.util.hashmap; import java.util.iterator; import java.util.map; import java.util.stringtokenizer; /** * 上下文環境 * * @author * */ public class context { // 待解析的文本內容 private final stringtokenizer stringtokenizer; // 當前命令 private string currenttoken; // 用來存儲動態變化信息內容 private final map<string, object> map = new hashmap<string, object>(); /** * 構造方法設置解析內容 * * @param text */ public context(string text) { // 使用空格分隔待解析文本內容 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 ; } /** * 獲得當前命令內容 * * @return */ public string getcurrenttoken() { return this .currenttoken; } /** * 獲得節點的內容 * * @return */ public string gettokencontent(string text) { string str = text; if (str != null ) { // 替換map中的動態變化內容后返回 iterator<string> // 替換map中的動態變化內容后返回 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 表達式接口——iexpressions
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
package com.demo.interpreter.express; import com.demo.interpreter.context.context; /** * * 表達式接口 * * @author * */ public interface iexpressions { /** * 解析 * * @param context */ public void parse(context context); /** * 執行方法 * * @param context */ public void interpret(); } |
4.3 主表達式——programexpression
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
|
package com.demo.interpreter.express; import com.demo.interpreter.context.context; /** * program 表達式 * * @author * */ public class programexpression implements iexpressions { // 上下文環境 private final context context; // 當前命令 private final static string command = "program" ; // 存儲下一個表達式引用 private iexpressions expressions; /** * 構造方法將待解析的內容傳入 * * @param text */ public programexpression(string text) { this .context = new context(text); this .parse( this .context); } @override public void parse(context context) { // 獲取第一個命令節點 this .context.next(); } /** * 實現解釋方法 */ @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表達式開始解析 this .expressions.interpret(); } } } |
4.4 列表表達式——listexpression
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
|
package com.demo.interpreter.express; import java.util.arraylist; import java.util.iterator; import com.demo.interpreter.context.context; /** * 列表表達式 * * @author * */ public class listexpression implements iexpressions { private context context; private final arraylist<iexpressions> list = new arraylist<iexpressions>(); /** * 構造方法將待解析的context傳入 * * @param context */ public void parse(context context) { this .context = context; // 在listexpression解析表達式中,循環解釋語句中的每一個單詞,直到終結符表達式或者異常情況退出 while ( true ) { if ( this .context.getcurrenttoken() == null ) { // 獲取當前節點如果為 null 則表示缺少end表達式 system.out.println( "error: the experssion missing 'end'! " ); break ; } else if ( this .context.equalswithcommand( "end" )) { this .context.next(); // 解析正常結束 break ; } else { // 建立command 表達式 iexpressions expressions = new commandexperssion( this .context); // 添加到列表中 list.add(expressions); } } } /** * 實現解釋方法 */ @override public void interpret() { // 循環list列表中每一個表達式 解釋執行 iterator<iexpressions> iterator = list.iterator(); while (iterator.hasnext()) { (iterator.next()).interpret(); } } } |
4.5 命令表達式——commandexperssion
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
|
package com.demo.interpreter.express; import com.demo.interpreter.context.context; /** * 命令表達式 * * @author * */ public class commandexperssion implements iexpressions { private final context context; private iexpressions expressions; /** * 構造方法將待解析的context傳入 * * @param context */ public commandexperssion(context context) { this .context = context; this .parse( this .context); } public void parse(context context) { // 判斷當前命令類別 在此只對for和最原始命令進行區分 if ( this .context.equalswithcommand( "for" )) { // 創建for表達式進行解析 expressions = new forexpression( this .context); } else { // 創建原始命令表達式進行內容解析 expressions = new primitiveexpression( this .context); } } /** * 解析內容 */ @override public void interpret() { // 解析內容 this .expressions.interpret(); } } |
4.6 循環表達式——forexpression
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
|
package com.demo.interpreter.express; import com.demo.interpreter.context.context; /** * for表達式 * * @author * */ public class forexpression implements iexpressions { private final context context; // 存儲當前索引key值 private string variable; // 存儲循環起始位置 private int start_index; // 存儲循環結束位置 private int end_index; private iexpressions expressions; /** * 構造方法將待解析的context傳入 * * @param context */ public forexpression(context context) { this .context = context; this .parse( this .context); } /** * 解析表達式 */ @override public void parse(context context) { // 首先獲取當前節點 this .context.next(); while ( true ) { // 判斷節點 if ( this .context.equalswithcommand( "from" )) { // 設置開始索引內容 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 ; } // 獲取下一個節點 this .context.next(); } else if ( this .context.equalswithcommand( "to" )) { // 設置結束索引內容 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 { // 設置當前索引變量內容 if ( this .variable == null ) { this .variable = this .context.getcurrenttoken(); } // 獲取下一個節點 this .context.next(); } } // 建立列表表達式 this .expressions = new listexpression(); this .expressions.parse( this .context); } /** * 實現解釋方法 */ @override public void interpret() { // 建立命令表達式 for ( int x = this .start_index; x <= this .end_index; x++) { // 設置變量內容 this .context.put( "" + this .variable, x); // 執行解釋方法 this .expressions.interpret(); } // 移除使用的臨時變量內容 this .context.clear( "" + this .variable); } } |
4.7 基礎表達式——primitiveexpression
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
|
package com.demo.interpreter.express; import com.demo.interpreter.context.context; /** * 最基礎的表達式 * * @author * */ public class primitiveexpression implements iexpressions { private context context; // 節點名稱 private string tokenname; // 文本內容 private string text; /** * 構造方法將待解析的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(); } } /** * 實現解釋方法 */ @override public void interpret() { // 首先獲取當前節點內容 if ( "println" .equals(tokenname)) { // 獲得內容信息 // 打印內容 system.out.println( this .context.gettokencontent( this .text)); } } } |
4.8 讓語言解釋器開始工作——client
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
package com.demo.interpreter; import com.demo.interpreter.express.iexpressions; import com.demo.interpreter.express.programexpression; /** * 主應用程序 * * @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); // 創建program表達式 iexpressions expressions = new programexpression(str); // 解釋執行 expressions.interpret(); } } |
5 運行結果
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...
三 設計原則
1 “開-閉”原則
2 封閉變化原則
四 使用場合
(1)一種特定類型的問題發生的頻率足夠高,并且業務規則頻繁變化,不斷重復出現類似情況。
(2)業務規則不是過于復雜煩瑣,比較容易抽象出語法規則。
(3)效率不是軟件系統中主要考慮的因素。
五 解釋器模式靜態類圖
希望本文所述對大家java程序設計有所幫助。
原文鏈接:https://blog.csdn.net/chengqiuming/article/details/70139382