本文实例讲述了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