首页 > 编程 > Java > 正文

Java基于解释器模式实现定义一种简单的语言功能示例

2019-11-26 10:01:25
字体:
来源:转载
供稿:网友

本文实例讲述了Java基于解释器模式实现定义一种简单的语言功能。分享给大家供大家参考,具体如下:

一 模式定义

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

二 模式举例

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

五 解释器模式静态类图

更多java相关内容感兴趣的读者可查看本站专题:《Java面向对象程序设计入门与进阶教程》、《Java数据结构与算法教程》、《Java操作DOM节点技巧总结》、《Java文件与目录操作技巧汇总》和《Java缓存操作技巧汇总

希望本文所述对大家java程序设计有所帮助。

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表