一、前言

这是我们23个设计模式中最后一个设计模式了,大家或许也没想到吧,竟然是编译原理上的编译器,这样说可能不对,因为编译器分为几个部分组成呢,比如词法分析器、语法分析器、语义分析器、中间代码优化器以及最终的最终代码生成器。而这个解释器其实就是完成了对语法的解析,将一个个的词组解释成了一个个语法范畴,之后拿来使用而已。

为什么会有这个解释器模式呢,我想这是从编译原理中受到启发的,使用了这样的一个解释器可以在Java语言之上在定义一层语言,这种语言通过Java编写的解释器可以放到Java环境中去执行,这样如果用户的需求发生变化,比如打算做其他事情的时候,只用在自己定义的新的语言上进行修改,对于Java编写的代码不需要进行任何的修改就能在Java环境中运行,这是非常有用的。这就好像,虽然不管怎么编译,最终由中间代码生成最终代码(机器码)是依赖于相应的机器的。但是编译器却能理解高级语言和低级语言,无论高级语言的程序是怎么样编写的编译器的代码是不用修改的而解释器模式就是想做一个建立在Java和我们自定义语言之间的编译器

二、代码

本程序使用自顶向下文法来解析源程序:

首先是文法的定义:

<program> -> program <Command List><Command List> -> <Command>*   end<Command> -> <Repeat Command> | <Primitive Command><Repeat Command> -> repeat <number> <Command List><Primitive Command> -> go | right | left

由此可以生成一颗语法树。

然后使用自顶向下文法生成这样的语法树,自顶向下文法从根节点开始,不断的向下解析,遇到一个语法范畴就尝试着自己的定义去解析,直至解析到相应的程序,这里要注意二义性问题,不能尝试两种解析方式都能对源程序解析成功;在实现的时候将一个语法范畴定义为一个类,然后不断地递归的去解析,直至到了叶子节点,将所有的单词解析完毕。

Node抽象类:

package zyr.dp.interpreter;public abstract class Node {public abstract void parse(Context context) throws ParseException;}

 ProgramNode:起始节点  <program> -> program <Command List>

package zyr.dp.interpreter;public class ProgramNode extends Node {private Node commandListNode;public void parse(Context context) throws ParseException {context.skipToken("program");commandListNode=new CommandListNode();commandListNode.parse(context);}public String toString(){return "[program "+commandListNode+"]";}}

CommandListNode类: <Command List> -> <Command>* end

package zyr.dp.interpreter;import java.util.ArrayList;public class CommandListNode extends Node {private ArrayList list=new ArrayList();public void parse(Context context) throws ParseException {while(true){if(context.getCurrentToken()==null){throw new ParseException("错误!!!"+"当前字符为空");}else if(context.getCurrentToken().equals("end")){context.skipToken("end");break;}else{Node commandNode=new CommandNode();commandNode.parse(context);list.add(commandNode);}}}public String toString(){return list.toString();}}

CommandNode类: <Command> -> <Repeat Command> | <Primitive Command>

package zyr.dp.interpreter;public class CommandNode extends Node {private Node node;public void parse(Context context) throws ParseException {if(context.getCurrentToken().equals("repeat")){node = new RepeatCommandNode();node.parse(context);}else{node = new PrimitiveCommandNode();node.parse(context);}}public String toString(){return node.toString();}}

ReapeatCommandNode类:

package zyr.dp.interpreter;public class RepeatCommandNode extends Node {private int number;private Node commandListNode;public void parse(Context context) throws ParseException {context.skipToken("repeat");number=context.currentNumber();context.nextToken();commandListNode=new CommandListNode();commandListNode.parse(context);}public String toString(){return "[repeat "+number+"  "+commandListNode+"]";}}

 PrimitiveCommandNode类:<Primitive Command> -> go | right | left

package zyr.dp.interpreter;public class PrimitiveCommandNode extends Node {String name;public void parse(Context context) throws ParseException {name=context.getCurrentToken();context.skipToken(name);if(!name.equals("go") && !name.equals("left") && !name.equals("right") ){throw new ParseException("错误!!!非法字符:"+name);}}public String toString(){return name;}
}

 ParseException类:

package zyr.dp.interpreter;public class ParseException extends Exception {private static final long serialVersionUID = 3996163326179443976L;public ParseException(String word){super(word);}}

Context类,承载了词法分析的职责,为上面的语法树提供单词,遍历程序。

package zyr.dp.interpreter;import java.util.StringTokenizer;public class Context {private StringTokenizer tokenizer ;private String currentToken;public Context(String token){tokenizer=new StringTokenizer(token);nextToken();}public String nextToken() {if(tokenizer.hasMoreTokens()){currentToken=tokenizer.nextToken();}else{currentToken=null;}return currentToken;}public String getCurrentToken(){return currentToken;}public void skipToken(String token) throws ParseException{if(!token.equals(currentToken)){throw new ParseException("错误!!!"+"期待"+currentToken+"但是却得到"+token);}nextToken();}public int currentNumber() throws ParseException{int num=0;try{num=Integer.parseInt(currentToken);}catch(NumberFormatException e){throw new ParseException(e.toString());}return num;}}

Main类,读取用户编写的程序并且执行词法分析和语法分析。这里的词法分析就是简单的遍历程序,语法分析采用的自顶向下的语法分析,对于上下文无关文法可以检测到语法错误,并且能生成语法范畴,但是这些语法范畴是我们能看到的,不是及其最终可以拿来去处理的,真正要编写编译系统,最好使用,自下而上的算符优先文法等方式来分析。

package zyr.dp.text;import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;import zyr.dp.interpreter.*;public class Main {public static void main(String[] args) {try {BufferedReader  reader = new BufferedReader(new FileReader("program.txt"));String line=null;while((line=reader.readLine())!=null){System.out.println("源程序为:"+line);System.out.println("自顶向下解析为:");Node node=new ProgramNode();node.parse(new Context(line));System.out.println(node);}} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();} catch (ParseException e) {e.printStackTrace();}}}

运行结果:

源程序:

在这里我专门写错了一个源程序:

program end
program go end
program go right  go right  go right  go right  go right  go right  end
program repeat 4 go right end end
program repeat 4 repeat 3  go right end go right end end
program repeat 4 go right end

可以看到编译器检测到了语法错误,对于语法正确的,也形式化的生成了自己的分析结果,使用[ ]括起来的就是语法范畴了,形成层次递归嵌套结构。

三、总结

    最后的设计模式是解释器模式,在Java这种高级语言之上再次定义一种语言的编译器,然后在不改动这个编译器的条件下,也就是不改变Java代码就能够随意的书写更高级的代码,然后执行。在这种模式之下java程序都不用修改,只用修改上面的文本文件就可以了,非常的方便,适合于结构已经固定,但是可以随意修改功能的场合。

浅谈设计模式<最通俗易懂的讲解>

浅谈Interpreter解释器模式相关推荐

  1. 浅谈示波器X-Y模式 示波器触发模式及使用

    描述 示波器是一种用途十分广泛的电子测量仪器.它能把肉眼看不见的电信号变换成看得见的图像,便于人们研究各种电现象的变化过程.接下来我们就来了解一下示波器的X-Y模式以及示波器触发模式,同时了解一下两种 ...

  2. 建造者模式浅谈 与工厂模式的区别

    感谢您的阅读.如果感觉文章对您有用,麻烦您动动手指点个赞,以资鼓励.谢谢! 转载请注明出处哈 建造者模式浅谈 与工厂模式的区别_茄子_土豆的博客-CSDN博客_建造者模式和工厂模式的区别 创建对象时构 ...

  3. Interpreter解释器模式

    前言: 关于23种设计模式的所有示例代码请参考:https://github.com/Wuchenwcf/MyCode/tree/master/DP 本文所述代码请参考:https://github. ...

  4. Interpreter(解释器模式)行为型

    解释器模式 一.概述 二.结构 三.实例 四.适用场景 五.优缺点 一.概述 描述:当不懂英文的中国人和不懂中文的外国人交流时会存在沟通障碍.这时有种翻译器能将两种语言进行转换各个对方国家语言,然后进 ...

  5. 浅谈Visitor访问者模式

    一.前言 什么叫访问,如果大家学过数据结构,对于这点就很清晰了,遍历就是访问的一般形式,单独读取一个元素进行相应的处理也叫作访问,读取到想要查看的内容+对其进行处理就叫作访问,那么我们平常是怎么访问的 ...

  6. Interpreter - 解释器模式

    定义 给定一个语言, 定于它的文法,并定义一个解释器,这个解释器使用改表示来解释语言中的句子. 类型 行为型模式 案例 像很熟知的正則表達式就是描写叙述字符串模式的一种标准语言,它为每个模式都构造了一 ...

  7. 浅谈知识付费模式的兴起及意义

    近年来, 知识付费风生水起, 2016年被称为知识付费元年, 得到.喜马拉雅F.创客匠人等平台经过一段时间的酝酿, 均在这一年获得快速发展, 在用户数量.产品推出.产品销售等方面取得较大突破, 也引起 ...

  8. 【PS】浅谈PS颜色模式-RGB模式

    在Photoshop的[拾色器]中我们通常看到几种颜色的表达方式,分别为HSB.LAB.RGB.CMYK,另外还有16进制的RGB颜色表示.由于RGB颜色模式经常使用,所以笔者先从RGB开始讲起,过程 ...

  9. 浅谈Facade外观模式

    一. 基本概念 有些人可能炒过股票,但其实大部分人都不太懂,这种没有足够了解证券知识的情况下做股票是很容易亏钱的,刚开始炒股肯定都会想,如果有个懂行的帮帮手就好,其实基金就是个好帮手,支付宝里就有许多 ...

最新文章

  1. Asp.net团队疯了(同时发布WebMatrix, Razor, MVC3和Orchard)
  2. python打完代码怎么运行-Python的代码是如何去进行运行的?
  3. Qt中的QInputDialog
  4. 数据挖掘-聚类分析(Python实现K-Means算法)
  5. Python之web开发(四):python使用django框架搭建网站之主页搭建
  6. oracle 监听 无法连接,解决ORA-12514: TNS: 监听程序当前无法识别连接描述符中请求的服务...
  7. 13-Mybatis 注解开发
  8. 指令集物联网操作系统 iSysCore OS 2021年将推出 3.0 版本!
  9. 关于SVN常用命令之export
  10. JDK下载安装教程及环境变量配置
  11. 【MM32F5270开发板试用】一、移植 TencentOS 到 PLUS-F5270
  12. 中国石油安全问题及解决对策
  13. illustrator cs5 2学习笔记
  14. 基于java的KTV点歌选歌系统
  15. 《最后的教父》小说人物一览表
  16. 实验一.Python安装与开发环境搭建
  17. 总结一下购买阿里云服务器的经验
  18. mysql找不到my.ini文件
  19. 原初.Le.premier.cercle.2009.480X272.PSP.iPhone.MP4
  20. 卷积在信号处理中的意义【转】

热门文章

  1. 论文阅读笔记——Multi-Label Learning with Global and Local Label Correlation(具有全局和局部标签相关性的多标签学习)
  2. NRF24L01P(nrf24l01+)从入门到使用
  3. python计算圆周率近似值_使用python实现计算圆周率π的方法
  4. JavaScript内存溢出
  5. 当面试官问 promise 的时候,他们希望听到什么(二)
  6. 双曲函数 tanh是什么函数
  7. Filament 渲染引擎剖析 之 创建渲染对象 1
  8. libpng warning: iCCP: known incorrect sRGB profile 警告,问题解决
  9. 【已解决】找到无效的 Gradle JDK 配置(invalid Gradle JDK configuration found)
  10. 安卓手机 忘记 锁屏密码