栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

设计模式(二十三)----解释器模式

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

设计模式(二十三)----解释器模式

目录

1.Interpreter模式

1.1 作用

1.2 示例迷你语言

1.2.1 迷你语言的命令

1.2.2 迷你语言的语法

1.2.3 迷你语言的语法树

1.3 示例程序

1.3.1 示例程序类图

1.3.2 Node抽象类

1.3.3 Node各层具体类

1.3.4 Context类

1.3.5 ParseWarningException异常类

1.3.6 Main类

1.4 Interpreter模式中的角色

1.5 其他特点


1.Interpreter模式

1.1 作用

   在Interpreter模式中,程序要解决的问题会被用非常简单的“迷你语言”表述出来,即用“迷你语言”编写的“迷你程序”把具体的问题表述出来,迷你程序是无法单独工作的,还需要用Java语言编写一个负责“翻译”的程序,这段翻译程序称为解释器。这样的话,当需要解决的问题发生变化时,不需要修改Java语言程序,只需要修改迷你语言程序即可应对,提高了Java程序的复用性。

1.2 示例迷你语言

1.2.1 迷你语言的命令
  • go:前进1米

  • right:右转

  • left:左转

  • repeat:重复

1.2.2 迷你语言的语法
 ::= program 
 ::= * end
 ::=  | 
 ::= repeat  
 ::= go | right | left

1.2.3 迷你语言的语法树

   迷你程序program repeat 4 go right end end的语法树:

 

1.3 示例程序

   示例程序就是实现了一个迷你程序的语法解析器。将迷你程序推导成结构(语法树)的处理,就是语法解析。语法解析时的处理单位为标记token。

1.3.1 示例程序类图

 

1.3.2 Node抽象类
//语法树中各个部分(节点)中的最顶层的类
public abstract class Node {
    //进行语法解析处理
    public abstract void parse(Context context) throws ParseWarningException;
}

1.3.3 Node各层具体类
// ::= program 
public class ProgramNode extends Node{
    private Node commandListNode;//保存对应的节点

    @Override
    public void parse(Context context) throws ParseWarningException {
        context.skipToken("program");//跳过program这个标记
        commandListNode = new CommandListNode();
        commandListNode.parse(context);//继续向下解析
    }

    public String toString() {
        return "[program " + commandListNode + "]";
    }
}
// ::= * end
public class CommandListNode extends Node {
    private List list = new ArrayList<>();

    @Override
    public void parse(Context context) throws ParseWarningException {
        while (true) {
            if (context.currentToken() == null) {
                throw new ParseWarningException("Missing 'end'");
            } else if (context.currentToken().equals("end")) {//当前标记为end
                context.skipToken("end");
                break;//结束
            } else {//继续向下解析
                Node commandNode = new CommandNode();
                commandNode.parse(context);
                list.add(commandNode);
            }
        }
    }

    public String toString() {
        return list.toString();
    }
}
// ::=  | 
public class CommandNode extends Node {
    private Node node;
    @Override
    public void parse(Context context) throws ParseWarningException {
        //解析是哪种命令
        if (context.currentToken().equals("repeat")) {//循环命令
            node = new RepeatCommandNode();
            node.parse(context);
        } else {//基本命令
            node = new PrimitiveCommandNode();
            node.parse(context);
        }
    }

    public String toString() {
        return node.toString();
    }
}
// ::= repeat  
public class RepeatCommandNode extends Node {
    private int number;
    private Node commandListNode;

    @Override
    public void parse(Context context) throws ParseWarningException {
        context.skipToken("repeat");
        number = context.currentNumber();//获取循环次数
        context.nextToken();
        commandListNode = new CommandListNode();
        commandListNode.parse(context);
    }

    public String toString() {
        return "[repeat " + number + " " + commandListNode + "]";
    }
}
// ::= go | right | left
public class PrimitiveCommandNode extends Node {
    private String name;

    @Override
    public void parse(Context context) throws ParseWarningException {
        name = context.currentToken();
        context.skipToken(name);
        if (!name.equals("go") && !name.equals("right") && !name.equals("left")) {
            throw new ParseWarningException(name + " is undefined.");
        }
    }

    public String toString() {
        return name;
    }
}

1.3.4 Context类
//提供语法解析所必需的方法
public class Context {
    private StringTokenizer tokenizer;
    private String currentToken;
    public Context(String text) {
        tokenizer = new StringTokenizer(text);
        nextToken();
    }

    public String nextToken() {
        if (tokenizer.hasMoreTokens()) {
            currentToken = tokenizer.nextToken();
        } else {
            currentToken = null;
        }
        return currentToken;
    }

    public String currentToken() {
        return currentToken;
    }

    public void skipToken(String token) throws ParseWarningException {
        if (!token.equals(currentToken)) {
            throw new ParseWarningException("Warning:" + token + "is expected, but " + currentToken + " is found.");
        }
        nextToken();
    }

    public int currentNumber() throws ParseWarningException {
        int number = 0;
        try {
            number = Integer.parseInt(currentToken);
        } catch (NumberFormatException e) {
            throw new ParseWarningException("Warning: " + e);
        }
        return number;
    }
}

1.3.5 ParseWarningException异常类
public class ParseWarningException extends Exception {
    public ParseWarningException(String msg) {
        super(msg);
    }
}

1.3.6 Main类
public class Main {
    public static void main(String[] args) {
        try {
            BufferedReader reader = new BufferedReader(new FileReader("program.txt"));
            String text;
            while ((text = reader.readLine()) != null) {
                System.out.println("text = "" + text + """);
                Node node = new ProgramNode();
                node.parse(new Context(text));
                System.out.println("node = " + node);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

   文件program.txt如下:

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

   输出为:

1.4 Interpreter模式中的角色
  • AbstractExpression(抽象表达式):该角色定义了语法树节点的共同接口API。上述的Node抽象类,共同接口API是parse()方法。
  • TerminalExpression(终结符表达式):该角色对应BNF中的终结符表达式。上述的PrimitiveCommandNode类。
  • NonterminalExpression(非终结符表达式):该角色对应BNF中的非终结符表达式。上述的ProgramNode、CommandListNode类、CommandNode类、RepeatCommandNode类。
  • Context(文脉、上下文):该角色为解释器进行语法解析提供必要的信息。上述的Context类。
  • Client(请求者):为了推导语法树,该角色会调用TerminalExpression角色和NonterminalExpression角色。上述的Main类。
  • Interpreter模式的类图:

1.5 其他特点
  • 有哪些种类的迷你语言:
    • 正则表达式。
    • 检索表达式:表示单词组合的Little Language模式。
    • 批处理语言:即将基本命令组合在一起,并按顺序执行或是循环执行的语言。示例程序的迷你语言即批处理语言。
  • 在制作解释器时,必须时刻注意“进入这个方法时已经读至哪个标记?出了这个方法应该读至哪个标记?”

根据图解设计模式书籍进行整理

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/924828.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号