规则引擎的设计与实现| 青训营笔记

126 阅读4分钟

这是我参与「第五届青训营 」伴学笔记创作活动的第 8 天

一、什么是规则引擎

当我们在对复杂的业务进行开发时,程序本身逻辑代码和业务代码互相嵌套、错综复杂,同时维护成本高,可拓展性差。

规则引擎即是:可降低复杂业务逻辑组件复杂性、降低应用程序的维护和可扩展性成本的组件!

如下图:

image.png 规则引擎实际上就是一个推理引擎,用于匹配facts(事实,我们可以理解为输入数据)和rules(规则),以推出结论。

二、编译原理

词法分析

词法分析的第一阶段即扫描器,通常基于有限状态自动机。扫描器能够识别其所能处理的标记中可能包含的所有字符序列(单个这样的字符序列即前面所说的“语素”)。例如“整数”标记可以包含所有数字字符序列。很多情况下,根据第一个非空白字符便可以推导出该标记的类型,于是便可逐个处理之后的字符,直到出现不属于该类型标记字符集中的字符(即最长一致原则)。

词法分析器的工作是低级别的分析:将字符或者字符序列转化成记号。在谈论词法分析时,使用术语“词法记号”(简称记号)、“模式”和“词法单元”表示特定的含义。

在分析时,一是把词法分析器当成语法分析的一部分,另一种是把词法分析器当成编译程序的独立部分。在前一种情况下,词法分析器不断地被语法分析器调用,每调用一次词法分析器将从源程序的字符序列拼出一个单词,并将其Token值返回给语法分析器。后一种情况则不同,词法分析器不是被语法分析器不断地调用,而是一次扫描全部单词完成编译器的独立一遍任务。

抽象语法树

节点

AST是由名为节点Node的数据结构构成的.下图表示为使用各自对应的节点来表示语句,表达式以及变量等.

抽象语法树和节点

所以,生成语法树的核心就是生成节点,下面我们会介绍如何在各个语法规则中生成对应的节点.
AST中用继承自 Node 类的子类来表示单个的节点,继承Node的类很多,层次也很复杂,我们现在只对一级继承的重要的类进行讲解

重要的节点类

Node的location属性

我们只需要了解Node类中,会有一个特定的返回location的方法,location是节点对应的语法在代码中的位置,如果代码中存在错误的话,编译器会将出错的语句或表达式所在的文件和行数表示出来,而这些信息就是以location的形式返回的.

Node表示抽象语法树

Node类中会通过dump方法来以文本的形式表示抽象语法树.dump方法生成的语法树对象.
语法树对象大概有如下属性:

  • 节点的类名
  • 节点对应语法记载的文件名和行号
  • 参数列表

各种类型生成抽象语法树

之后要学习的就是实际地在语法规则文件中添加生成抽象语法树的 action,通过实际例子来理解语法树生成的具体过程,需要分析生成的类型有

  1. 表达式的抽象语法树生成
  2. 语句的抽象语法树生成
  3. 声明的抽象语法树生成

这里涉及到具体的表达式,语句或者声明的设计和具体实现,其中结合了语法分析和语法分析中各个规则的组合使用,以及action的合理编写和对调用时机的控制,非常细节和琐碎,感兴趣的烤鸭具体查看,我们现在只列出类型,不讨论实现.

表达式的抽象语法树生成

本节我们将讲解表达式(expr)的抽象语法树的生成,该章节被细分为

  1. 字面量的抽象语法树
  2. 一元运算的抽象语法树
  3. 二元运算的抽象语法树
  4. 条件表达式的抽象语法树
  5. 赋值表达式的抽象语法树

赋值表达式中提到了运算规则的结合性(associativity),如果x OP y OP z的含义为(x OP y) OP z,则称运算符OP左结合(left
associative),如果含义为 x OP (y OP z),则称运算符 OP右结合(right associative).一般二元运算符都是左结合,只有赋值运算符=右结合的.

随便提一下,还存在既非左结合也非右结合的二元运算符。例如 ==,因此 x==y ==z这样的表达式的语法是错误的.像这样不允许x OP y OP z的运算符称为非结合(non- associative)运算符.