`
cakin24
  • 浏览: 1336038 次
  • 性别: Icon_minigender_1
  • 来自: 西安
社区版块
存档分类
最新评论

解释器模式——定义一种简单的语言

阅读更多

一 模式定义

解释器模式:就是给定一个语言的文法表示,并且定义一个解释器,用来解释语言中的句子。解释器模式描述了怎样在有了一个简单的文法后,使用模式设计解释这些语句。

 

二模式举例

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)效率不是软件系统中主要考虑的因素。

 

五 解释器模式静态类图



 

 

  • 大小: 31.9 KB
  • 大小: 31.2 KB
  • 大小: 41.3 KB
1
1
分享到:
评论

相关推荐

    zkk950815#design-pattern-java-1#自定义语言的实现——解释器模式(二)1

    除了使用文法规则来定义一个语言,在解释器模式中还可以通过一种称之为抽象语法树(Abstract Syntax Tree, AST)的图形方式来直观地表示语言的构

    Python设计模式之解释器模式原理与用法实例分析

    解释器模式(Interpreter Pattern):给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子. 下面是一个解释器模式的demo: #!/usr/bin/env python # -*- coding:utf-8 -...

    java设计模式

    27.2 解释器模式的定义 27.3 解释器模式的应用 27.3.1 解释器模式的优点 27.3.2 解释器模式的缺点 27.3.3 解释器模式使用的场景 27.3.4 解释器模式的注意事项 27.4 最佳实践 第28章 享元模式 28.1 内存溢出,...

    C#23种设计模式_示例源代码及PDF

    解释器模式: 给定一个语言后,解释器模式可以定义出其文法的一种表示,并同时提供一 解释器模式 个解释器。 客户端可以使用这个解释器来解释这个语言中的句子。 解释器模式将描述怎样 在 有了一个简单的文法后, ...

    C#全能速查宝典

    1.1.9 迭代器——相同类型的值的有序序列的一段代码 10 1.1.10 泛型——处理算法和数据结构 11 1.1.11 分部类——将一个类分成几部分 12 1.1.12 is操作符——检查变量是否为指定的类型 14 1.1.13 lock关键字——锁定...

    simplang:低级语言学习环境——IFPI简单语言

    Simplang 是一种模拟机器语言的在线伪代码执行环境。 在编辑器中输入代码 查看内存的变化并在旁边注册 :sparkles: 魔法 :sparkles: 语言说明文档 在开始之前,我们需要定义一些关于 simlang 模拟执行环境的注意...

    3D游戏卷2:动画与高级实时渲染技术——2

    9.1 引言——一种拟人的游戏界面 9.2 将语言表述转变为动画——示例 9.2.1 IMPROV(纽约大学媒体研究实验室) 9.2.2 PAR体系结构(宾夕法尼亚大学人体建模和仿真中心) 9.2.3 具体化的对话界面代理(MIT媒体实验室) 9.2.4...

    3D游戏卷2:动画与高级实时渲染技术——1

    9.1 引言——一种拟人的游戏界面 9.2 将语言表述转变为动画——示例 9.2.1 IMPROV(纽约大学媒体研究实验室) 9.2.2 PAR体系结构(宾夕法尼亚大学人体建模和仿真中心) 9.2.3 具体化的对话界面代理(MIT媒体实验室) 9.2.4...

    java拦截器

    在Webwork的中文文档的解释为——拦截器是动态拦截Action调用的对象。它提供了一种机制可以使开发者可以定义在一个action执行的前后执行的代码,也可以在一个action执行前阻止其执行。同时也是提供了一种可以提取...

    理解拦截器用于在某个方法或字段被访

    它提供了一种机制可以使开发者可以定义在一个action执行的前后执行的代码,也可以在一个action执行前阻止其执行。同时也是提供了一种可以提取action中可重用的部分的方式。 谈到拦截器,还有一个词大家应该知道——...

    asp.net知识库

    .NET20 一种简单的窗口控件UI状态控制方法 翻译MSDN文章 —— 泛型FAQ:最佳实践 Visual C# 3.0 新特性概览 C# 2.0会给我们带来什么 泛型技巧系列:如何提供类型参数之间的转换 C#2.0 - Object Pool 简单实现 ...

    Python语言程序设计源代码.zip

    学习本章,要了解Python作为一种计算机程序设计脚本语言,结合了解释性、编译性和互动性的特点;了解在Linux和Windows中安装Python的方法;了解IDLE、PyCharm和Jupyter三种常用Python程序编辑环境。工欲善其事,必先...

    CuteFTP9简易汉化版

    这些选项告诉链接一种上传软件如何解释,如何导航和链接,以及如何处理产生的目标。 各种主机文件夹Listings-View文件夹列表,包括UNIX,NT,vm,MVS,AS / 400,OS / 2英镑连接:企业,范·戴克SSH,和更多。简单文件夹清单...

    C#微软培训资料

    1.1 Microsoft.NET——一场新的革命.4 1.2 .NET 与 C#.6 1.3 C#语言的特点.8 1.4 小 结 .11 第二章 运行环境 全面了解.NET.12 2.1 .NET 结构.12 2.2 公用语言运行时环境与公用语言规范.13 2.3 开 发 ...

    antlrworks-1.5.1.jar

    Antlr是一种语言识别的工具,可以用来构造领域语言。 使用antlr需要我们提前定义好识别字符流的词法规则和用于解释Token流的语法分析规则。然后,antlr会根据我们提供的语法文件自动生成相应的词法/语法分析器。...

    Homework_2011:一个实现自定义机器语言的玩具虚拟机和一个到 x86_64 的提前翻译器

    这实际上只是一个解释器平台——也就是说,一个类似于 LLVM 的模块化虚拟机(虽然简单得多)。 它通过使用多个读取器插件读取一个或多个输入文件来运行,这些插件将源代码转换为字节码,链接生成的字节码图像并在...

    c#学习笔记.txt

    在C#刚刚推出的时候,大多数的程序员都不免吼上两句——不是因为高兴,而是因为又多了一种语言。他们觉得现在的语言太多了,没有必要再多出一种来添乱子。但是当他们看完C#的文档后又开始高兴起来,因为C#是如此简单...

    antlr4权威指南

     本书的读者对象本书尤其适用于对数据读取器、语言解释器和翻译器感兴趣的开发者。虽然本书主要利用ANTLR来完成这些工作,你仍然可以学到很多有关词法分析器和语法分析器的知识。初学者和专家都需要本书来高效地...

    Tinyxml 源代码(VC6 & VS2005)

    TinyXML支持UTF-8,所以可以处理任何语言的XML文件,而且TinyXML也支持“legacy模式”——一种在支持UTF-8之前使用的编码方式,可能最好的解释是“扩展的ascii”。 正常情况下,TinyXML会检测出正确的编码并使用它...

Global site tag (gtag.js) - Google Analytics