解释器模式
基本介绍
1.解释器模式:指给定一个语言(表达式),定义它的文法的一种表示,并定义一个解释器,使用该解释器来解释语言中的句子(表达式)
2.在编译原理中,一个算术表达式通过词法分析器形成词法单元,而后这些词法单元再通过语法分析器构建语法分析树,最终形成一颗抽象的语法分析树,这里的词法分析器和语法分析器都可以看做是解释器
事项
1.应用场景
(1)将一个需要解释执行的语言中的句子表示为一个抽象语法树
(2)一些重复出现的问题可以用一种简单的语言来表达
(3)一个语言的文法较为简单
(4)对执行效率要求不高
(5)例:编译器、运算表达式计算、正则表达式
2.优点
(1)易于改变和扩展文法:使用类来表示语言的文法规则,通过继承等机制来改变或扩展文法,方便实现一个简单的语言
(2)实现文法较为容易:在抽象语法树中每一个表达式节点类的实现方式都是相似的
(3)增加新的解释表达式较为方便:如果用户需要增加新的解释表达式只需要对应增加一个新的终结符表达式或非终结符表达式类,原有表达式类代码无须修改,符合“开闭原则”
3.缺点
(1)对于复杂文法难以维护:每一条规则至少需要定义一个类,如果一个语言包含太多文法规则,类的个数将会急剧增加,导致系统难以管理和维护
(2)执行效率较低:解释操作使用了大量的循环和递归调用,若解释较为复杂的句子时,其速度很慢,代码的调试过程复杂
角色
1.Context:环境角色,含有解释器之外的全局信息,聚合 AbstractExpression
2.AbstractExpression:抽象表达式,是所有终结符表达式和非终结符表达式的公共父类,声明一个抽象的解释操作,该方法为抽象语法树中所有节点共享
3.TerminalExpression:终结符表达式,实现与文法中终结符相关的解释操作
4.NonTerminalExpression:非终结符表达式,实现与文法中非终结符相关的解释操作,聚合 AbstractExpression
5.Client:客户端,依赖 Context、AbstractExpression,输入 Context、TerminalExpression
代码示例
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.Map;
import java.util.LinkedList;
public class Interpreter {//客户端
public static void main(String[] args) throws IOException {
String parameterExpression = "a+b-c";
System.out.println("参数表达式" + parameterExpression);
Map<String, Integer> map = setValue(parameterExpression);//参数、具体值组成键值对
Calculator calculator = new Calculator(parameterExpression);
System.out.println("运算结果:" + calculator.run(map));
}
//输入具体值
public static String inputValue() throws IOException {
return new BufferedReader(new InputStreamReader(System.in)).readLine();
}
//设置表达式参数的具体值
public static Map<String, Integer> setValue(String expStr) throws IOException {
Map<String, Integer> map = new HashMap<>();
String s;
for (char c : expStr.toCharArray()) {
s = String.valueOf(c);
if (c == '+' || c == '-' || map.containsKey(s)) {
continue;
}
System.out.print("请输入" + s + "的值:");
map.put(s, Integer.valueOf(inputValue()));
}
return map;
}
}
class Calculator {//环境角色
private Expression expression;
//根据环境角色,创建抽象表达式
public Calculator(String expression) {
LinkedList<Expression> list = new LinkedList<>();
char[] charArray = expression.toCharArray();//表达式String转char[]
Expression left;//左方表达式
Expression right;//右方表达式
for (int i = 0; i < charArray.length; i++) {
switch (charArray[i]) {
//根据非终结表达式元素分割参数表达式,将左、右表达式合并创建非终结表达式对象
case '+':
left = list.pollLast();
right = new Value(String.valueOf(charArray[++i]));
list.addLast(new Plus(left, right));
break;
case '-':
left = list.pollLast();
right = new Value(String.valueOf(charArray[++i]));
list.addLast(new Minus(left, right));
break;
default://创建终结表达式对象
list.addLast(new Value(String.valueOf(charArray[i])));
break;
}
}
this.expression = list.pollLast();
}
//对聚合的抽象表达式,进行解释操作
public int run(Map<String, Integer> map) {
return this.expression.interpret(map);
}
}
abstract class Expression {//抽象表达式
public abstract int interpret(Map<String, Integer> value);
}
class Value extends Expression {//终结表达式
private String key;//表达式参数
public Value(String key) {
this.key = key;
}
//获取存入参数对应数值
@Override
public int interpret(Map<String, Integer> value) {
return value.get(this.key);
}
}
class Symbol extends Expression {//抽象非终结符表达式
protected Expression left;
protected Expression right;
public Symbol(Expression left, Expression right) {
this.left = left;
this.right = right;
}
@Override
public int interpret(Map<String, Integer> value) {//默认实现
return 0;
}
}
class Plus extends Symbol {//实现非终结符表达式
public Plus(Expression left, Expression right) {
super(left, right);
}
@Override
public int interpret(Map<String, Integer> value) {
return super.left.interpret(value) + super.right.interpret(value);
}
}
class Minus extends Symbol {//实现非终结符表达式
public Minus(Expression left, Expression right) {
super(left, right);
}
@Override
public int interpret(Map<String, Integer> value) {
return super.left.interpret(value) - super.right.interpret(value);
}
}
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10亿数据,如何做迁移?
· 清华大学推出第四讲使用 DeepSeek + DeepResearch 让科研像聊天一样简单!
· 推荐几款开源且免费的 .NET MAUI 组件库
· 易语言 —— 开山篇
· Trae初体验