• 设计模式


    解释器模式:给定一门语言,定义其词法规则及语法规则(即:文法表示),并提供一个用于解析与执行该语言的解释器。
    核心:定义文法表示(词法规则和语法规则),并提供一个处理该文法表示的解释器 --- 从而允许用户端自行构造语句执行不同逻辑
    角色:

    • 终结符表达式(value):操作数
    • 非终结符表达式(symbol):操作符
    • 解释器(Calculator): 对用户传入的语句进行正确性校验,并进行词法解析和语法解析得到语法树,最后执行得出语句执行结果
    • 环境上下文(Context):容纳用户输入的语句,或容纳用户输入语句解析后的语法树

    PS: 解释器模式定义了一门语言并提供执行该语言的解释器,相当于一个简化版的编译原理实现

    Calculate(四则运算带括号计算器实现)

    // 抽象表达式,定义所有表达式均有interpret方法,操作数不定长
    public interface IExpression {
        int interpret(IExpression... params);
    }
    
    // 终结符表达式 - 值类型表达式,只返回值。
    public class VarExpression implements IExpression {
        private int value;
    
        public VarExpression(int value) {
            this.value = value;
        }
    
        @Override
        public int interpret(IExpression... params) {
            return value;
        }
    }
    
    // 非终结符表达式 - 运算符表达式抽象父类,定义操作符的优先级
    public abstract class SymbolExpression implements IExpression {
        protected int level;
    
        public SymbolExpression(int level) {
            this.level = level;
        }
    
        public int getLevel() {
            return level;
        }
    }
    
    // 非终结符表达式 - 加号运算表达式
    public class AddExpression extends SymbolExpression {
    
        public AddExpression(int baseLevel) {
            super(baseLevel);
        }
    
        // 传入两个操作数,完成相加操作。
        @Override
        public int interpret(IExpression... params) {
            return params[1].interpret() + params[0].interpret();
        }
    }
    
    // 解释器,完成用户输入语句的解析与执行
    public class Calculate {
        // 使用栈类型容器存储 值 和 操作符
        private Stack<SymbolExpression> symbolStack = new Stack<>();
        private Stack<VarExpression> varExpress = new Stack<>();
    
        // 基本优先级,当存在()时,()内操作符的优先级需大于()外操作符的优先级
        private int baseLever = 0;
    
        public Calculate(String expression){
            this.parse(expression);
        }
    
        private void parse(String expression) {
            expression = expression.replaceAll(" ","");   // 去空格
            char[] express = expression.toCharArray();
            int size = express.length;
    
            StringBuilder temp = new StringBuilder();     // 缓存数值
            for(int i = 0;i < size;i++){
                // 当'('出现时,其之后的非终结符号等级提高,
                // 当')'出现时,其之后的非终结符号等级降低。从而实现(expression)的功能。
                if(express[i] == '('){
                    baseLever = baseLever + 10;
                } else if(express[i] == ')'){
                    baseLever = baseLever - 10;
                } else if(OperatorUtil.isOperator(express[i])){      // 如果是操作符,则将temp中的字符转换为数值存入var栈,同时清空temp
                    // 将之前的数值推入var,并清空var中缓存
                    varExpress.push(new VarExpression(Integer.parseInt(temp.toString())));
                    temp = new StringBuilder();
    
                    // 获取到当前表达式符号
                    SymbolExpression symbolExpress = OperatorUtil.getSymbolExpression(express[i],baseLever);
    
                    // 标记A:当前表达式符号等级不大于栈顶符号,则执行symbol栈顶操作符运算,直到栈顶元素比当前表达式符号优先级小
                    while (!symbolStack.isEmpty() && symbolExpress.getLevel() <= (symbolStack.peek()).getLevel()){
                        SymbolExpression expressA = symbolStack.pop();
                        varExpress.push(new VarExpression(expressA.interpret(varExpress.pop(),varExpress.pop())));
                    }
                    // 该操作符入栈
                    symbolStack.push(symbolExpress);
                }else {
                    // 如果是数字,则加入数字缓存中,知道碰到第一个非数字位时,转换为值存入var
                    temp.append(express[i]);
                }
            }
            // 将最后一个数值存入var
            varExpress.push(new VarExpression(Integer.parseInt(temp.toString())));
    
            // 所有表达式均已解析完成,将栈中符号依次计算(此时,经过标记A的代码,symbol栈中符号等级由栈顶到栈尾递减)
            while (!symbolStack.isEmpty()){
                SymbolExpression expressA = symbolStack.pop();
                varExpress.push(new VarExpression(expressA.interpret(varExpress.pop(),varExpress.pop())));
            }
        }
    
        // 返回结果
        public int value(IExpression... params) {
            return varExpress.pop().interpret();
        }
    }
    

    Spring中集成的SpelExpressionParser

    public class Test {
        public static void main(String[] args) {
            String express = "1+((1+2)*(3-1)+3)/2 + 8";
    
            // 自行实现的计算表达式
            System.out.println(new Calculate(express).getValue());
    
            // Spring封装的表达式
            System.out.println(new SpelExpressionParser().parseExpression(express).getValue());;
        }
    }
    

    编译原理回顾

    编译原理(包括编译器和解释器),用于将源语言程序翻译为目标语言程序

    1. 词法分析: 单词分析,对语句中的单词和符号进行分析和归类(输入源程序,输出单词符号)
    2. 语法分析:句子分析,判断语句是否符合文法规则(输入单词符号,输出语法单位)
    3. 语义分析与中间代码产生:语义检查,判断是否存在冲突的语义(如,public类的类名是否与文件名一致,是否存在方法签名相同的两个方法等),最后生成中间代码
    4. 优化
    5. 目标代码生成
  • 相关阅读:
    Java 回调函数的理解
    Java对象初始化
    Hibernate中get方法和load方法的区别
    Java 如何判断导入表格某列是否有重复数据
    Java学习之Java的单例模式
    Java中怎么设置文件权限
    div居中问题
    JSON
    js
    ajax
  • 原文地址:https://www.cnblogs.com/kiqi/p/14077379.html
Copyright © 2020-2023  润新知