• 004-行为型-11-解析器模式(Interpreter)


    一、概述

      提供了评估语言的语法或表达式的方式。这种模式实现了一个表达式接口,该接口解释一个特定的上下文。这种模式被用在 SQL 解析、符号处理引擎等。  

      意图:给定一个语言,定义它的文法表示,并定义一个解释器,这个解释器使用该标识来解释语言中的句子。

      主要解决:对于一些固定文法构建一个解释句子的解释器。

      注意事项:可利用场景比较少,JAVA 中如果碰到可以用 expression4J 代替。

    1.1、适用场景

       1、可以将一个需要解释执行的语言中的句子表示为一个抽象语法树。

      2、一些重复出现的问题可以用一种简单的语言来进行表达。

      3、一个简单语法需要解释的场景。

    1.2、优缺点  

      优点: 1、可扩展性比较好,灵活。 2、增加了新的解释表达式的方式。 3、易于实现简单文法。

      缺点: 1、可利用场景比较少。 2、对于复杂的文法比较难维护。 3、解释器模式会引起类膨胀。 4、解释器模式采用递归调用方法。

    1.3、类图角色及其职责

      

      AbstractExpression: 抽象表达式。声明一个抽象的解释操作,该接口为抽象语法树中所有的节点共享。
      TerminalExpression: 终结符表达式。实现与文法中的终结符相关的解释操作。实现抽象表达式中所要求的方法。文法中每一个终结符都有一个具体的终结表达式与之相对应。
      NonterminalExpression: 非终结符表达式。为文法中的非终结符相关的解释操作。
      Context: 环境类。包含解释器之外的一些全局信息。
      Client: 客户类。
      抽象语法树描述了如何构成一个复杂的句子,通过对抽象语法树的分析,可以识别出语言中的终结符和非终结符类。 在解释器模式中由于每一种终结符表达式、非终结符表达式都会有一个具体的实例与之相对应,所以系统的扩展性比较好。

    1.4、演进过程

      背景:现在我们用解释器模式来实现一个基本的加、减、乘、除和求模运算。例如用户输入表达式“3 * 4 / 2 % 4”,输出结果为2。下图为该实例的UML结构图:

        

      抽象语法树

      

     抽象表达式:Node

    public interface Node {
        int interpret();
    }

    非终结表达式:ValueNode 主要用解释该表达式的值。

    public class ValueNode implements Node {
        private int value;
    
        public ValueNode(int value) {
            this.value = value;
        }
    
        @Override
        public int interpret() {
            return this.value;
        }
    }

    终结表达式抽象类,由于该终结表达式需要解释多个运算符号,同时用来构建抽象语法树:

    public abstract class SymbolNode implements Node {
        protected Node left;
        protected Node right;
    
        public SymbolNode(Node left, Node right) {
            this.left = left;
            this.right = right;
        }
    }
    MulNode
    public class MulNode extends SymbolNode {
        public MulNode(Node left, Node right) {
            super(left, right);
        }
    
        @Override
        public int interpret() {
            return left.interpret() * right.interpret();
        }
    }

    ModNode

    public class ModNode extends SymbolNode {
        public ModNode(Node left, Node right) {
            super(left, right);
        }
    
        @Override
        public int interpret() {
            return super.left.interpret() % super.right.interpret();
        }
    }

    DivNode

    public class DivNode extends SymbolNode {
        public DivNode(Node left, Node right) {
            super(left, right);
        }
    
        @Override
        public int interpret() {
            return super.left.interpret() / super.right.interpret();
        }
    }

    Calculator

    public class Calculator {
        private String statement;
        private Node node;
    
        public void build(String statement) {
            Node left = null, right = null;
            Stack stack = new Stack();
    
            String[] statementArr = statement.split(" ");
    
            for (int i = 0; i < statementArr.length; i++) {
                if (statementArr[i].equalsIgnoreCase("*")) {
                    left = (Node) stack.pop();
                    int val = Integer.parseInt(statementArr[++i]);
                    right = new ValueNode(val);
                    stack.push(new MulNode(left, right));
                } else if (statementArr[i].equalsIgnoreCase("/")) {
                    left = (Node) stack.pop();
                    int val = Integer.parseInt(statementArr[++i]);
                    right = new ValueNode(val);
                    stack.push(new DivNode(left, right));
                } else if (statementArr[i].equalsIgnoreCase("%")) {
                    left = (Node) stack.pop();
                    int val = Integer.parseInt(statementArr[++i]);
                    right = new ValueNode(val);
                    stack.push(new ModNode(left, right));
                } else {
                    stack.push(new ValueNode(Integer.parseInt(statementArr[i])));
                }
            }
            this.node = (Node) stack.pop();
        }
    
        public int compute() {
            return node.interpret();
        }
    }

    测试

        @Test
        public void compute() {
            String statement = "3 * 2 * 4 / 6 % 5";
            Calculator calculator = new Calculator();
            calculator.build(statement);
            int result = calculator.compute();
            System.out.println(statement + " = " + result);
        }

    输出

    3 * 2 * 4 / 6 % 5 = 4

    二、扩展

    java.util.regex.Pattern正则解释器,相当于是一个语法。

    Spring中的解释器

        @Test
        public void compute2() {
    //        java.util.regex.Pattern p=new Pattern();
            ExpressionParser parser = new SpelExpressionParser();
            Expression expression = parser.parseExpression("100 * 2 + 400 * 1 + 66");
            int value = (int) expression.getValue();
            System.out.println(value);
        }

    使用expression4J代替 

  • 相关阅读:
    P3822 [NOI2017]整数
    P4630 [APIO2018] Duathlon 铁人两项
    P3230 [HNOI2013]比赛
    P2570 [ZJOI2010]贪吃的老鼠
    P4576 [CQOI2013]棋盘游戏
    P3256 [JLOI2013]赛车
    P3297 [SDOI2013]逃考
    CF487E Tourists
    设置一个双色球脚本(2)并带颜色输出
    设置一个双色球脚本
  • 原文地址:https://www.cnblogs.com/bjlhx/p/11577245.html
Copyright © 2020-2023  润新知