一、解释器模式基本介绍
1、基本介绍
(1)在编译原理中,一个算术表达式通过词法分析器形成词法单元,而后这些词法单元再通过语法分析器构建语法分析树,最终形成一颗抽象的语法分析树。这里的词法分析器和语法分析器都可以看做是解释器。
(2)解释器模式(Interpreter Pattern):是指给定一个语言(表达式),定义它的文法的一种表示,并定义一个解释器,使用该解释器来解释语言中的句子(表达式);
(3)应用场景
① 应用可以将一个需要解释执行的语言中的句子表示为一个抽象语法树;
② 一些重复出现的问题可以用一种简单的语言来表达;
③ 一个简单语法需要解释的场景;
(4)这样的例子还有,比如编译器、运算表达式计算、正则表达式、机器人等;
2、原理类图
对原理类图的说明——即(解释器模式的角色及职责)
(1)Context:是环境角色,含有解释器之外的全局信息;
(2)AbstractExpression:抽象表达式,声明一个抽象的解释操作,这个方法为抽象语法树中所有的节点所共享;
(3)TerminalExpression:为终结符表达式,实现与文法中的终结符相关的解释操作;
(4)NonTerminalExpression:为非终结符表达式,为文法中的非终结符实现解释操作;
(5)说明:输入 Context 和 TerminalExpression 信息通过 Client 输入即可;
二、解释器模式实现四则运算
1、应用实例要求
通过解释器模式来实现四则运算,如计算 a+b-c 的值;
2、思路分析和类图
3、代码实现
抽象类表达式:
1 /**
2 * 抽象类表达式,通过 HashMap 键值对,可以获取到变量的值
3 *
4 */
5 public abstract class Expression {
6
7 /**
8 * a + b - c
9 * 解释公式和数值的关系
10 * key 就是公式(表达式) 参数,例如:a,b,c,d
11 * vaule 就是具体的值
12 *
13 * HashMap {a=10, b=20, c=5}
14 * @param var
15 * @return
16 */
17 public abstract int interpreter(HashMap<String, Integer> var);
18 }
终端类(变量)解析器:
1 /**
2 * 变量的解释器
3 */
4 public class VarExpression extends Expression{
5
6 /**
7 * key 就是变量,例如:key=a,key=b,key=c
8 */
9 private String key;
10
11 public VarExpression(String key) {
12 this.key = key;
13 }
14
15
16 /**
17 * var 就是{a=10, b=20}
18 *
19 * interpreter 根据变量名称,返回对应值
20 * @param var
21 * @return
22 */
23 @Override
24 public int interpreter(HashMap<String, Integer> var) {
25 return var.get(key);
26 }
27 }
非终端类(符号)解析器:
1 /**
2 * 抽象运算符号解析器,这里,每个运算符号都只和自己左右两个数字有关系
3 * 但左右两个数字有可能也是一个解析的结果,无论何种类型,都是 Expression 类的实现类
4 */
5 public class SymbolExpression extends Expression{
6
7 protected Expression left;
8 protected Expression right;
9
10 public SymbolExpression(Expression left, Expression right) {
11 this.left = left;
12 this.right = right;
13 }
14
15 /**
16 * 因为 SymbolExpression 是让其子类来实现,
17 * 因此该方法是默认实现
18 * @param var
19 * @return
20 */
21 @Override
22 public int interpreter(HashMap<String, Integer> var) {
23 return 0;
24 }
25 }
加号解析器:
1 /**
2 * 加法解释器
3 */
4 public class AddExpression extends SymbolExpression{
5
6 public AddExpression(Expression left, Expression right) {
7 super(left, right);
8 }
9
10 /**
11 * 处理相加
12 *
13 * var 仍然是{a=10, b=20}
14 *
15 * @param var
16 * @return
17 */
18 @Override
19 public int interpreter(HashMap<String, Integer> var) {
20 //super.left.interpreter(var):返回 left 表达式对应的值 a=10
21 //super.right.interpreter(var):返回 right 表达式对应的值 b=20
22 return super.left.interpreter(var) + super.right.interpreter(var);
23 }
24
25
26 }
减号解析器:
1 public class SubExpression extends SymbolExpression{
2 public SubExpression(Expression left, Expression right) {
3 super(left, right);
4 }
5
6 /**
7 * 相减
8 * 求出 left 和 right 表达式相减后的结果
9 * @param var
10 * @return
11 */
12 @Override
13 public int interpreter(HashMap<String, Integer> var) {
14 return super.left.interpreter(var) - super.right.interpreter(var);
15 }
16 }
计算器:
1 public class Calculator {
2
3 /**
4 * 定义表达式
5 */
6 private Expression expression;
7
8 /**
9 * 构造函数传参,并解析
10 * @param expStr
11 */
12 public Calculator(String expStr) { //expStr = a + b - c
13 //安排运算先后顺序
14 Stack<Expression> stack = new Stack<>();
15 //表达式拆分成字符数组 如:[a, +, b, -, c]
16 char[] charArray = expStr.toCharArray();
17
18 Expression left = null;
19 Expression right = null;
20
21 //遍历字符数组,即遍历 [a, +, b, -, c]
22 //针对不同的情况,做相应处理
23 for (int i = 0; i < charArray.length; i++) {
24 switch (charArray[i]) {
25 case '+':
26 //从 stack 中取出 left,表示 + 号左边表达式 => 'a'
27 left = stack.pop();
28 // right 表示 右边的表达式 => 'b'
29 right = new VarExpression(String.valueOf(charArray[++i]));
30 //然后根据得到 left 和 right 构建 AddExpression 加入栈stack
31 stack.push(new AddExpression(left, right));
32 break;
33
34 case '-':
35 left = stack.pop();
36 right = new VarExpression(String.valueOf(charArray[++i]));
37 stack.push(new SubExpression(left, right));
38 break;
39
40 default:
41 //如果是一个 var,就创建一个 VarExpression,并 push 到 stack
42 stack.push(new VarExpression(String.valueOf(charArray[i])));
43 break;
44 }
45 }
46 //当遍历完整个 charArray 数组后,stack 就得到最后 Expression
47 this.expression = stack.pop();
48 }
49
50 public int run(HashMap<String, Integer> var) {
51 //最后将表达式a+b和 var={a=10,b=20}
52 //然后传递给 expression 的 interpreter 进行解释执行
53 return this.expression.interpreter(var);
54 }
55 }
客户端:
1 public class Client {
2 public static void main(String[] args) throws IOException {
3 String expStr = getExpStr(); //a + b
4
5 HashMap<String, Integer> var = getValue(expStr); //var{a=10.b=20}
6
7 Calculator calculator = new Calculator(expStr);
8 System.out.println("运算结果:" + expStr + "=" + calculator.run(var));
9
10 }
11
12 /**
13 * 获取表达式
14 * @return
15 * @throws IOException
16 */
17 public static String getExpStr() throws IOException {
18 System.out.println("请输入表达式:");
19 return (new BufferedReader(new InputStreamReader(System.in))).readLine();
20 }
21
22 public static HashMap<String, Integer> getValue(String expStr) throws IOException {
23 HashMap<String, Integer> map = new HashMap<>();
24
25 for (char ch : expStr.toCharArray()) {
26 if (ch != '+' && ch != '-') {
27 if (!map.containsKey(String.valueOf(ch))) {
28 System.out.println("请输入" + String.valueOf(ch) + "的值");
29 String in = (new BufferedReader(new InputStreamReader(System.in))).readLine();
30 map.put(String.valueOf(ch), Integer.valueOf(in));
31 }
32 }
33 }
34 return map;
35 }
36 }
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 没有源码,如何修改代码逻辑?
· 一个奇形怪状的面试题:Bean中的CHM要不要加volatile?
· [.NET]调用本地 Deepseek 模型
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· .NET Core 托管堆内存泄露/CPU异常的常见思路
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· DeepSeek R1 简明指南:架构、训练、本地部署及硬件要求
· 没有源码,如何修改代码逻辑?
· NetPad:一个.NET开源、跨平台的C#编辑器
· 面试官:你是如何进行SQL调优的?