规则引擎:语法分析 | 青训营笔记

208 阅读3分钟

这是我参与「第五届青训营」伴学笔记创作活动的第15天。本篇为第五届字节跳动青训营-寒假专场-后端基础课程的笔记

构建规则引擎的重要一步就是对输入进行语法分析,今天分享常见的语法分析方法。

常见的语法分析方法

  1. LL
  2. LR(1)
  3. SLR(1)
  4. LR(1)
  5. LALR (1):LookAhead(1)LR(0)
    1. 在LR 1 的基础上,我们合并一组ITEM中 item相同,但是后续符号不同的为一个itemitem'
    2. 如果自动机还能正常工作,那么这将是对语法产生更多的限制:从LR(1)到LALR(1)将会引入reduce-reduce 冲突
    3. 从LR(1)构造 LALR (1)自动机?可行,但是还有更加直接的方式(更加高效的)

关系图

几种文法的关系图如下:

Pasted image 20230218234701.png

自底向上分析法

LR 0

为啥这个名字

Left to Right scan

Rightmost derivation

zero Token look ahead

构建LR 自动机(直接从文法构造DFA)

步骤:

  1. 构建增广文法

  2. 将S'-> *S 作为初始状态,构建它的闭包以生成完整的初始状态。

  3. 构建GOTO ——状态集合之间的转换,捕获一个(非终结符或者终结符)

  4. 重复直到没有新的集合产生

LR0 的缺点

reduce-reduce conflict

如果一个状态中,包含二个及以上的LR 0项可规约,这时候基本的LR并无法区分进行哪种规约。

shift-reduce conflict

如果一个状态中,包含可规约和可以shift,这也无法判断。

不是LR 0 的文法

如果一个文法对应自动机内有shift-reduce or reduce-reduce conflict,就不是LR(0)文法。

可行前缀:viable prefix

sequence of symbols on the parsing stack

在解析栈中的一串符号

如果不能在继续通过 shift操作入栈(延长这个symbol串的长度),即进行reduce,stack 和 input 构成的右句型就不是可行前缀。

只要能在栈中,就是右句型的活前缀。

LR (0) 弱爆了

没有利用后文(右侧)的信息,这样是低效的,容易冲突。

LR(0) 的表

y坐标轴:状态集合(items in I)

x坐标轴:终结符 concatenate 非终结符 concatenate 状态遇到前两者的状态

转移方式:

  1. shift (同时需要在 状态和符号交点处表明下一跳转)

  2. reduce using which production

  3. accept

空的Entry:如果进入此状态,那么匹配失败发现 error

SLR(1)

这是对于LR(0)的升级。现在可以Peek next Token,并且在可能发生规约的时候,根据获得的非终结符的FOLLOWSET来确定是否应该/发生哪一个Reduce操作.

SLR(1) 使用LR(0) 的parse table

优点

利用小空间O(1) ,解决了许多冲突。

相比LR(0),其适合的语法更多。

SLR(1) 的弱点也很明显

我们根据FOLLOWSET来判断用哪个跳转,其实是非常粗糙的,可能FOLLOWSET的某些元素不会出现在右句型里面,此时我们按照SLR(1)的规则,反而有可能解决不了冲突(“本来peek 1可以解决的冲突”)。

所以需要有更加强大的工具。