这是我参与「第五届青训营 」伴学笔记创作活动的第 5 天
目录
- 认识规则引擎
- 编译原理基本概念
- 设计一个规则引擎
- 规则引擎的实现
1. 认识规则引擎
什么是规则引擎
规则引擎由推理引擎发展而来,是一种嵌入在应用程序中的组件,实现了将业务决策从应用程序代码中分离出来,并使用预定义的语义模块编写业务决策。接受数据输入,解释业务规则,并根据规则做出业务决策。
简单来说规则引擎就是自定义的一套组件,接收输入,并执行决策,最终输出。
2.编译原理基本概念
词法分析(Lexical Analysis)
词法分析就是把源代码字符串转换为词法单元(Token)的这个过程,即对一个字符串输入,进行分词处理。
price > 500 && (isNewUser || userLevel > 5)
将这个语句分词后为
price>500&&(isNewUser||userLevel>5)
如何识别Token?有限状态机(Finite-State Automation) 有限自动机就是一个状态机,根据输入并进行有限的转换,确定一个最终的状态。
语法分析(Syntax Analysis)
语法分析就是在词法分析的基础上,识别表达式的语法结构的过程
简单来说,就是确定语法的优先级(比如+ * 运算的优先级),以此构建一颗语法树,便于后面递归处理。
比如上面的 && 和 || 的优先级
抽象语法树(Abstract Syntax Tree)
上下文无关语法 Context-Free Grammar:即语句不需要考虑上下文,就可以判断正确性和执行,比如汇编语句的执行,我们可以使用巴科斯范式(BNF)来表达。
- BNF范式是一种用递归的思想来表述计算机语言符号集的定义规范
- ::=表示定义
- “ ”双引号里的内容表示字符
- <>尖括号里的内容表示必选内容
- | 竖线两边的是可选内容,相当于or
exp : add ;
add : add '+' mul | mul ;
mul : mul '*' pri | pri ;
pri : string | bool | number | identifer ;
借用知乎大佬的解释:
也就是一直通过递归将表达式分解,直到最终状态被确定。(即递归下降算法)
递归下降算法
递归下降算法通过自顶向下构造语法树,利用递归不断对Token进行语法展开(下降)
类型检查
当两个数进行运算时,我们会考虑其是否为同一种类型,这在构造语法树的过程中我们其实就有在判断该结点的左右子树的节点值类型是否相同,或者可以互相转换。
int a = 3 + "345" // errro
int b = 3 + 4 // success
3.设计一个规则引擎
设计目标
设计一个规则引擎,支持特定的词法、运算符、数据类型和优先级。并且支持以上预定义语法的规则表达式的编译和执行
- 词法(合法token):如字符串,布尔值true/false, 整数,浮点数等
- 运算符:+ - * / ++ -- >= < && || ! () 等(以及确定优先级)
设计词法分析的状态机
可以看到包含以上所有状态的状态机还是比较复杂的,需要考虑的东西很多。
优先级的表达
type precedence struct {
validSymbols []Symbol //当前优先级支持的运算符类型
nextPrecedence *precedence //更高优先级
planner planner //当前优先级的处理函数
}
语法树结构
- 一元运算符: 左子树空,右子树为右操作数
- 二元运算符:左子树为左操作数,右子树为右操作数
- 括号: 左子树为空,右子树为内部表达式的AST(抽象语法树)
语法树的执行:我们使用后序遍历(左右根)来执行
4.规则引擎的实现
编译原理这块没学,感觉还是挺不好写的,先鸽着,以后回来补(逃)