23、解释器模式—编写自己的语法解释器

解释器模式(Interpretor):给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子。

UML图:


|和&表达式的简单解释器代码

package com.thpin.repository.designpattern;

import java.util.HashMap;
import java.util.Map;
import java.util.Stack;
import java.util.regex.Pattern;

public class InterpretorDemo {
    public static void main(String[] args) throws Exception {
        ExpressionContext context = new ExpressionContext("f|f|t&f");
        System.out.println(context.result());
    }
}

/*
 * 解释器抽象类
 */
abstract class AbstractExpression {
    public abstract void interpret(ExpressionContext context);// 解释语法

    public abstract boolean result(ExpressionContext context);// 获取结果
}

/*
 * 表达式上下文 对 ‘|’ 和 ‘&’ 条件表达式解释
 */
class ExpressionContext {
    private String input;// 输入
    private Stack<AbstractExpression> expressions = new Stack<>();// 表达式栈,包括终结表达式和非终结表达式
    private Map<String, Boolean> map = new HashMap<>(); // 终结符字典

    // 校验输入、input初始化、字典初始化
    public ExpressionContext(String input) throws Exception {
        if (!isMatch(input)) {
            throw new Exception("表达式不合法,t或f  和  |或&  相间组合,并以t 或 f 开头结尾");
        }
        this.input = input;
        map.put("t", true);
        map.put("f", false);
    }

    // 校验
    private boolean isMatch(String input) {
        String regex = "([t|f][||&])+[t|f]";
        return Pattern.matches(regex, input);
    }

    // 获取终结符的真实值
    public boolean search(String key) {
        return map.get(key);
    }

    // 获取表达式input的结果
    public boolean result() {
        new TerminalExpression().interpret(this);// 首字符肯定是t 或 f,用终结符解释器,入栈
        removeFirstChar();// 去头(t 或 f)
        while (input.length() > 0) {
            String firstChar = removeFirstChar();// 去头(| 或 &)
            new TerminalExpression().interpret(this);// 此时肯定是t 或 f,用终结符解释器,入栈
            removeFirstChar();// 去头(t 或 f)
            if ("&".equals(firstChar)) {
                new AndExpression().interpret(this);// 取出栈顶两个解释器生成AND解释器再入栈
            }
        }
        while (expressions.size() > 1) {// 这时&的操作已结束,进行|操作
            new OrExpression().interpret(this);// 取出栈顶两个解释器生成OR解释器再入栈
        }
        return expressions.pop().result(this);// 栈底只有一个嵌套结构的解释器,调用其result()获取最终结果
    }

    // input去掉首字符,并返回首字符
    private String removeFirstChar() {
        String firstChar = input.substring(0, 1);
        input = input.substring(1);
        return firstChar;
    }

    // 获取栈
    public Stack<AbstractExpression> getExpressions() {
        return expressions;
    }

    // 获取输入
    public String getInput() {
        return input;
    }
}

/*
 * 终结符解释器,对应表达式 t 、 f
 */
class TerminalExpression extends AbstractExpression {
    private String value;

    // 将自己保存到context的解释器栈栈顶
    public void interpret(ExpressionContext context) {
        this.value = context.getInput().substring(0, 1);
        context.getExpressions().push(this);
    }

    public boolean result(ExpressionContext context) {
        return context.search(value);
    }
}

/*
 * 终结符and解释器, 对应表达式例如 t&f
 */
class AndExpression extends AbstractExpression {
    protected AbstractExpression expression1;
    protected AbstractExpression expression2;

    // 将自己保存到context的解释器栈栈顶
    public void interpret(ExpressionContext context) {
        Stack<AbstractExpression> expressions = context.getExpressions();
        expression1 = context.getExpressions().pop();
        expression2 = context.getExpressions().pop();
        expressions.push(this);
    }

    public boolean result(ExpressionContext context) {
        return expression1.result(context) & expression2.result(context);
    }
}

/*
 * 终结符or解释器,对应表达式例如 t|f
 * 与and结构相同,只是返回结果用 | 做计算
 */
class OrExpression extends AndExpression {
    public boolean result(ExpressionContext context) {
        return expression1.result(context) | expression2.result(context);
    }
}

结果:

false

在ExpressionContext 的 result()方法最后一行

    return expressions.pop().result(this);

这里打断点,可以看到'f|f|t&f'被解释后生成的解释器是这样的结构:


最后解释器栈里只有一个Or解释器,而其属性分别是一个Or和一个Ter,Or又包含一个And和一个Ter,And又包含两个Ter,这正是一个 'f|f|t&f'表达式的计算顺序,只要符合语法规则随意改变表达式,就会产生不同的解释器组合结构,比如‘t&t|t&f’


解释器结构变成了一个Or里面两个And,这正是我们想要的结果。

    如果一种特定问题发生的频率足够高,那么可能就值得将该问题的各个实例表述为一个简单语言中的句子。这样就可以构建一个解释器,该解释器通过解释这些句子来解决该问题。

    当有一个语言需要解释执行,并且你可将该语言中的句子表示为一个抽象语法时,可使用解释器模式。

    解释器模式可以很容易地改变和扩展文法,因为该模式使用类来表示文法规则,你可使用继承来改变或扩展该文法。也比较容易实现文法,因为定义抽象语法树中各个节点的类的实现大体类似,这些类都易于直接编写。

    解释器模式也有不足,解释为文法中的每一条规则至少定义一个类,因此包含许多规则的文法可能难以管理和维护。建议当文法非常复杂时,使用其他的技术如语法分析程序或编译生成器来处理。jvm就是用编译器将.java文件编译成易于解释器理解的.class文件,然后经解释器解释运行。

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值