解释器模式(Interpreter Pattern)

语法规则也是类

1.基本介绍

给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子
在这里插入图片描述

类的一览表
在这里插入图片描述
在这里插入图片描述


2.具体实现

Node抽象类

/**
 * @author Jay
 * @date 2019/7/5 23:00
 * @description 节点类
 */
public abstract class Node {
    /**
     * 解析
     *
     * @param context 上下文
     * @throws ParseException 解析异常
     */
    public abstract void parse(Context context) throws ParseException;
}

ParseException类

/**
 * @author Jay
 * @date 2019/7/5 23:01
 * @description 解析异常类
 */
public class ParseException extends  Exception{
    public ParseException(String msg) {
        super(msg);
    }
}

ProgramNode类

/**
 * @author Jay
 * @date 2019/7/5 23:02
 * @description 程序节点类
 * <program> ::= program <command list>
 */
public class ProgramNode extends Node {
    /**
     * 命令列表节点
     */
    private Node commandListNode;

    @Override
    public void parse(Context context) throws ParseException {
        context.skipToken("program");
        commandListNode = new CommandListNode();
        commandListNode.parse(context);
    }

    @Override
    public String toString() {
        return "[program " + commandListNode + "]";
    }
}

CommandListNode类

/**
 * @author Jay
 * @date 2019/7/5 23:03
 * @description 命令列表节点类
 * <command list> ::= <command>* end
 */
public class CommandListNode extends Node {
    /**
     * 命令列表
     */
    private ArrayList list = new ArrayList();

    @Override
    public void parse(Context context) throws ParseException {
        while (true) {
            if (context.currentToken() == null) {
                throw new ParseException("Missing 'end'");
            } else if (context.currentToken().equals("end")) {
                context.skipToken("end");
                break;
            } else {
                Node commandNode = new CommandNode();
                commandNode.parse(context);
                list.add(commandNode);
            }
        }
    }

    @Override
    public String toString() {
        return list.toString();
    }
}

CommandNode类

/**
 * @author Jay
 * @date 2019/7/5 23:04
 * @description 命令节点类
 * <command> ::= <repeat command> | <primitive command>
 */
public class CommandNode extends Node {
    /**
     * 节点
     */
    private Node node;

    @Override
    public void parse(Context context) throws ParseException {
        if (context.currentToken().equals("repeat")) {
            node = new RepeatCommandNode();
            node.parse(context);
        } else {
            node = new PrimitiveCommandNode();
            node.parse(context);
        }
    }

    @Override
    public String toString() {
        return node.toString();
    }
}

RepeatCommandNode类

/**
 * @author Jay
 * @date 2019/7/5 23:04
 * @description     命令节点类
 */
public class RepeatCommandNode extends Node {
    /**
     * 重复次数
     */
    private int number;
    /**
     * 命令列表节点
     */
    private Node commandListNode;

    @Override
    public void parse(Context context) throws ParseException {
        context.skipToken("repeat");
        number = context.currentNumber();
        context.nextToken();
        commandListNode = new CommandListNode();
        commandListNode.parse(context);
    }

    @Override
    public String toString() {
        return "[repeat " + number + " " + commandListNode + "]";
    }
}

PrimitiveCommandNode类

/**
 * @author Jay
 * @date 2019/7/5 23:05
 * @description 原始命令节点类
 */
public class PrimitiveCommandNode extends Node {
    /**
     * 名字
     */
    private String name;

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

    @Override
    public String toString() {
        return name;
    }
}

Context类

/**
 * @author Jay
 * @date 2019/7/5 23:06
 * @description  上下文类
 */
public class Context {
    /**
     * 分词器
     */
    private StringTokenizer tokenizer;
    /**
     * 当前符号
     */
    private String currentToken;

    public Context(String text) {
        this.tokenizer = new StringTokenizer(text);
        this.nextToken();
    }

    /**
     * 返回下一个符号
     *
     * @return 下一个符号
     */
    public String nextToken() {
        if (tokenizer.hasMoreTokens()) {
            this.currentToken = this.tokenizer.nextToken();
        } else {
            this.currentToken = null;
        }
        return this.currentToken;
    }

    /**
     * 返回当前符号
     *
     * @return 当前符号
     */
    public String currentToken() {
        return this.currentToken;
    }

    /**
     * 跳过指定符号
     *
     * @param token 指定符号
     * @throws ParseException 解析异常
     */
    public void skipToken(String token) throws ParseException {
        if (!token.equals(this.currentToken)) {
            throw new ParseException("Warning: " + token + " is expected, but " + currentToken + " is found.");
        }
        this.nextToken();
    }

    /**
     * 解析数值
     *
     * @return 数值
     * @throws ParseException 解析异常
     */
    public int currentNumber() throws ParseException {
        int number = 0;
        try {
            number = Integer.parseInt(currentToken);
        } catch (NumberFormatException e) {
            throw new ParseException("Warning: " + e);
        }
        return number;
    }
}

测试类

/**
 * @author Jay
 * @date 2019/7/5 23:06
 * @description
 */
public class InterpreterTest {
    /**
     * 测试解释器模式
     */
    @Test
    public void testInterpreter() {
        try {
            BufferedReader reader = new BufferedReader(new FileReader(System.getProperty("user.dir")
                    + "/src/main/java/com/pc/interpreter/example/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();
        }
    }
}
/*
text = "program end"
node = [program []]
text = "program go end"
node = [program [go]]
text = "program go right go right go right go right end"
node = [program [go, right, go, right, go, right, go, right]]
text = "program repeat 4 go right end end"
node = [program [[repeat 4 [go, right]]]]
text = "program repeat 4 repeat 3 go right go left end right end end"
node = [program [[repeat 4 [[repeat 3 [go, right, go, left]], right]]]]

解释器模式中的角色

AbstractExpression(抽象表达式)

AbstractExpression角色定义了语法树节点的共同接口(API)。在案例中,由Node类扮演此角色。在案例中,共同接口(API)的名字是parse,不过在类图中它的名字是interpreter。

TerminalExpression(终结符表达式)

TerminalExpression角色对应BNF中的终结特表达式。在案例中,由PrimitiveCommandNode类扮演此角色。

NonterminalExpression(非终结符表达式)

NonterminalExpression角色对应BNF中的非终结符表达式。在案例中,由ProgramNode类、CommandNode类、RepeatCommandNode类和CommandListNode 类扮演此角色。

Context(文脉、上下文)

Context 角色为解释器进行语法解析提供了必要的信息。在案例中,由Context 类扮演此角色。

Client(请求者)

为了推导语法树, Client 角色会调用TerminalExpression 角色和Nonterm inalExpression 角色。在案例中,由Main 类扮演此角色。


To GitHub

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值