规则引擎设计与实现(下)| 青训营笔记

94 阅读3分钟

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

4. 语法分析

词法分析是一个词接一个词的识别,语法分析是在词法分析的基础上识别节目的语法结构。这个结构是树形结构。这个树被称为抽象语法树(AST)。树的每个节点(子树)都是一个语法单元,这个单元的规则称为“语法”。每个节点也可以有下级节点。

上下文无关语法 Context-Free Grammar

不用考虑上下文,就可以判断语言句子是否正确

...
a = 0;
...
这是一个赋值语句,无论此语句的前后是什么代码,此语句所代表的操作是确定的。即给变量a赋值等于0
复制代码

编程语言为什么不用自然语言,而是用上下文无关的文法呢? 因为

  1. 易于设计编译器。客观上,目前技术还无法实现。如果使用上下文依赖语法,将是真正的人工智能,将是NLP领域的重大突破。
  2. 促进代码开发和维护。如果说开发出来的代码就像高考的中文阅读理解,每个人都有不同的理解,那么,作者真正想表达的是哪一个呢?如果人类不能确定意义,计算机也不能确定意义,最终的结果是执行错误或未执行。
  3. 汇编/机器语言与上下文无关。当CPU执行一条指令时,它会读取并执行该指令。如果CPU需要考虑上下文来确定语句要做什么,那么CPU执行语句的速度将比现在慢数千倍。考虑到上下文的事情,完全可以在用户编程时使用算法来实现。由于机器语言与上下文无关,因此高级语言基本上与上下文无关,并且可能有一些单独的语法被设计为与上下文无关,以方便使用,例如脚本语言的弱类型。它易于使用,但也增加了解析器的复杂性。

上下文无关语法G:终结符集合T + 非终结符集合N + 产生式集合P + 起始符号S

G由T、N、S和P组成,由语法G推导出来的所有句子的集合称为G语言!

终结符: 组成串的基本符号。可以理解为词法分析器产生的token集合。比如 + Id ( )

非终结符: 表示token的的集合的语法变量。比如 stmt varDecl 等等

start:blockStmts ;               //起始
block : '{' blockStmts '}' ;      //语句块
blockStmts : stmt* ;              //语句块中的语句
stmt = varDecl | expStmt | returnStmt | block;   //语句
varDecl : type Id varInitializer? ';' ;         //变量声明
type : Int | Long ;                              //类型
varInitializer : '=' exp ;                       //变量初始化
expStmt : exp ';' ;                              //表达式语句
returnStmt : Return exp ';' ;                    //return语句
exp : add ;                                      //表达式       
add : add '+' mul | mul;                         //加法表达式
mul : mul '*' pri | pri;                         //乘法表达式
pri : IntLiteral | Id | '(' exp ')' ;            //基础表达式 
复制代码

产生式:表示形式,S : AB ,就是说S的含义可以用语法AB进行表达

S : AB
A : aA | ε
B : b | bB
复制代码

展开(expand):将P(A->u )应用到符号串vAw中,得到新串vu **w

折叠(reduce):将P(A->uu )应用到符号串vuu w中,得到新串vAw

推导(derivate):符号串u 应用一系列产生式,变成符号串v ,则u =>v:S => ab | b | bb

巴科斯范式

BNF是描述上下文无关理论的一种具体方法。通过BNF可以实现上下文无关语法的具体化、公式化和科学化,是代码解析的必要条件。

<expr> ::= <expr> + <term>
         | <expr> - <term>
         | <term>

<term> ::= <term> * <factor>
         | <term> / <factor>
         | <factor>

<factor> ::= ( <expr> )
           | Num
复制代码

BNF本质上就是树形分解,分解成一棵抽象语法树

  • 每个产生式就是一个子树,在写编译器时,每个子树对应一个解析函数。

  • 叶子节点叫做 终结符,非叶子节点叫做 非终结符

5. 设计规则引擎

image-20230202152355736

image-20230202152404666

image-20230202152413887

image-20230202152425534

6. 项目参考

github.com/qimengxingy…