一 模式定义
解释器模式:就是给定一个语言的文法表示,并且定义一个解释器,用来解释语言中的句子。解释器模式描述了怎样在有了一个简单的文法后,使用模式设计解释这些语句。
二模式举例
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
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
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
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
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
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
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
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
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)效率不是软件系统中主要考虑的因素。
五 解释器模式静态类图
相关推荐
解释器模式的核心在于定义一个表示语言元素的类结构,以及这些元素如何相互组合以执行语言的语法规则。在解释器模式中,我们通常会创建抽象语法树(AST,Abstract Syntax Tree),这是一个数据结构,它反映了输入...
解释器是一种计算机程序,它能够读取源代码并直接执行,而无需预先将源代码转换为机器语言(如编译器所做的)。在解释器构造课程中,学生通常会学习如何设计和实现一个简单的语言解释器,这涉及到语法分析、语义分析...
**行为型模式——解释器模式** ...总结来说,解释器模式为我们提供了一种构建小型语言或表达式解析器的方法,它强调的是如何将文法转化为可执行的代码,适用于那些需要频繁解析简单语言或表达式的情景。
根据GoF的经典定义,解释器模式的意图是:“给定一个语言,定义它的文法的一种表示,并定义一种解释器,这个解释器使用该表示来解释语言中的句子。” #### 四、结构与组成 解释器模式主要由以下几个组成部分构成:...
解释器模式是一种行为型设计模式,主要用于处理语言的文法规则、算术规则等问题。它通过定义语言的文法,并根据该文法来解释句子,使得我们可以用统一的方式处理各种语言结构。本文将通过具体的例子——加减运算来...
在这个作业中,学生被要求设计并实现一个CMM(一种教学用的中间语言)解释器。这个作业成果获得了96分的高分,表明了其高质量和原创性。** **解释器是编程语言理论中的核心概念之一,它能够直接执行源代码而无需...
解释器模式定义了一个语言的文法,并提供了它的解释器;迭代器模式提供了一个方法来顺序访问聚合对象的元素,而又不暴露其底层表示;模板方法模式定义了一个操作中的算法骨架,而将一些步骤延迟到子类中;备忘录模式...
除了使用文法规则来定义一个语言,在解释器模式中还可以通过一种称之为抽象语法树(Abstract Syntax Tree, AST)的图形方式来直观地表示语言的构
适配器模式(Adapter Pattern)是软件设计模式中的一种,其主要目的是解决系统中的接口不兼容问题,使得原本由于接口不匹配而无法一起工作的类能够协同工作。在本文中,我们将深入探讨适配器模式的概念、结构、作用...
解释器模式(Interpreter Pattern):给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子. 下面是一个解释器模式的demo: #!/usr/bin/env python # -*- coding:utf-8 -...
这可能包含实现细节,比如使用singleton类、策略模式、内部case语句、参数化方法以及解释器来实现账务处理。这部分内容还可能涉及记账规则的执行、触发方式的比较以及多个账目之间的记账规则。 书籍的其余内容可能...
- **解释器模式**:给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子。 通过对这些设计模式的学习和应用,开发者可以更好地组织代码,使其更具有灵活性、可扩展性...
在实际的编程语言设计中,编译器或解释器的设计通常会包含更复杂的词法分析和语法分析过程,而不仅仅是简单的字符映射。但无论如何,数据结构的应用都是不可或缺的一环。通过线性表、队列和栈等基本数据结构,我们...
首先,我们看到一个名为“starry.rb”的文件,这可能是实现Starry语言解释器的Ruby代码。Ruby是一种动态类型的面向对象编程语言,以其简洁和优雅的语法著称。在这里,它被用来构建Starry语言的解析和执行环境,这为...
- 解释器模式:定义语言的文法,并提供一个解释器来处理这种语言。 - 迭代器模式:提供一种方法顺序访问聚合对象的元素,而又不暴露其底层表示。 - 观察者模式:定义对象之间的一对多依赖关系,当一个对象的状态...
- 解释器模式:给定一种语言,定义其文法的一种表示,并提供一个解释器。 - 迭代器模式:提供一种方法顺序访问聚合对象的元素,而又不暴露其底层表示。 - 中介者模式:用一个中介对象来封装一系列的对象交互,...
Shell解释器是操作系统中的一种重要组件,主要负责解析用户输入的命令并执行相应的操作。在Linux系统中,最常见的Shell是Bash(Bourne-Again SHell),它是Unix-like系统中默认的交互式命令行接口。当用户登录系统后...
递归下降解析是一种简单而直观的方法,适用于上下文无关文法。它通过定义一系列相互递归的函数来模拟文法规则,每个函数对应文法的一个非终结符。这种方法易于理解和实现,但对处理复杂语法可能会遇到困难。 LR分析...