LR解析器:
这是一种高效的自下而上的语法分析技术,可用于解析大量的上下文无关文法,称为 LR(k) 解析。
L 代表从左到右扫描
R 代表逆向的最右推导
0 代表没有。前瞻的输入符号数
如需更多参考,请访问 https://www.geeksforgeeks.org/lr-parser/
LR解析的优点:
- 它几乎可以识别所有可以为其编写 CFG 的编程语言结构
- 它能够检测语法错误
- 它是一种高效的非回溯移位减少解析方法。
LR解析方法的类型:
- 单反
- CLR
- LALR
CLR 解析器:
CLR 解析器代表规范 LR 解析器。它是一个更强大的 LR 解析器。它利用了前瞻符号。这种方法使用了一个称为 LR(1) 项的大型项集。 LR(0) 项和 LR(1) 项之间的主要区别在于,在 LR(1) 项中,可以在一个状态中携带更多信息,即将排除无用的归约状态。这些额外的信息通过先行符号合并到状态中。一般语法变成 [A->∝.B, a ]
其中 A->∝.B 是产生式,a 是终端或右端标记 $
LR(1) 项=LR(0) 项 + 向前看
如何在生产中添加前瞻?
情况1 –
A->∝.BC, a
假设这是第 0 个产品。现在,因为 ‘ 。 ‘ 在 B 之前,所以我们也必须编写 B 的产生式。
B->.D [1st production]
假设这是 B 的产品。当我们查看以前的产品即第 0 产品时,会给出此产品的超前展望。无论 B 之后是什么,我们都会找到 FIRST(of that value) ,这是第一个生产的前瞻。所以,在第 0 个生产中,在 B 之后,C 在那里。假设 FIRST(C)=d,那么第一次生产变成
B->.D, d
案例 2 –
现在如果第 0 次制作是这样的,
A->∝.B, a
在这里,我们可以看到 B 之后没有任何东西。所以第 0 次生产的超前将是第 1 次生产的超前。 IE-
B->.D, a
案例 3 –
假设产生式 A->a|b
A->a,$ [0th production]
A->b,$ [1st production]
在这里,第一个产生式是先前产生式的一部分,因此前瞻将与其先前产生式相同。
这是前瞻的 2 条规则。
构建CLR解析表的步骤:
- 编写增强语法
- LR(1) 要查找的项目集合
- 在CLR解析表中定义2个函数:goto[终结符列表]和action[非终结符列表]
例子
为给定的上下文无关文法构造一个 CLR 解析表
S-->AA
A-->aA|b
解决方案 :
第 1步 – 查找扩充语法
给定文法的增广文法是:-
S'-->.S ,$ [0th production]
S-->.AA ,$ [1st production]
A-->.aA ,a|b [2nd production]
A-->.b ,a|b [3rd production]
让我们将前瞻规则应用于上述产生式
- 最初的展望总是 $
- 现在,由于 ‘ ,第一个产品诞生了。 ‘ 在第 0 个生产中的 ‘S’ 之前。在 ‘S’ 之后没有任何东西,因此第 0 个生产的超前将是第 1 个生产的超前。即: S–>.AA ,$
- 现在,由于 ‘ ,第二次产生。 ‘ 在第一次制作中的’A’之前。’A’之后是’A’。所以,FIRST(A) 是 a,b
因此,第 2 次产生的前瞻变为 a|b。 - 现在,第三部作品是第二部作品的一部分。所以,展望将是一样的。
第 2步 – 查找 LR(0) 项集合
下图显示了 LR(0) 项目集合。我们将一一了解。
这个文法的终结符是 {a,b}
此文法的非终结符是 {S,A}
规则-
- 如果任何非终端有 ‘ 。 ‘ 在它之前,我们必须编写它的所有产生式并添加 ‘ 。 ‘ 在它的每一个生产之前。
- 从每个状态到下一个状态, ‘ 。 ‘ 移到右边的一个位置。
- 前瞻的所有规则都适用于此。
- 在图中,I0 由增广文法组成。
- 当 ‘ 时,Io 进入 I1。第 0 个产生式的 ‘ 向 S(S’->S.) 的右侧移动。这种状态是接受状态。 S 被编译器看到。由于 I1 是第 0 次产生的一部分,因此前瞻是相同的,即 $
- 当 ‘ 时,Io 进入 I2。 ‘ 1st 产生向右移动 (S->AA)。 A 被编译器看到。由于 I2 是第一个产品的一部分,因此前瞻是相同的,即 $。
- 当 ‘ 时,I0 变为 I3。 ‘ 第二个产品的 ‘ 向右移动 (A->aA) 。 a 被编译器看到。由于 I3 是第二次产生的一部分,因此前瞻是相同的,即 a|b。
- 当 ‘ 时,I0 变为 I4。 ‘ 第三个产生式的右移 (A->b.) 。 b 被编译器看到。由于 I4 是第 3 个产生式的一部分,因此前瞻是相同的,即 a |湾
- 当 ‘ 时,I2 变为 I5。 ‘ 1st 产生向右移动 (S->AA.)。 A 被编译器看到。由于 I5 是第一个产品的一部分,因此前瞻是相同的,即 $.
- 当 ‘ 时,I2 变为 I6。 ‘ 2nd 产生向右移动 (A->aA) 。 A 被编译器看到。由于 I6 是第二次生产的一部分,因此前瞻是相同的,即 $。
- 当 ‘ 时,I2 变为 I7。第三次产生的’向右移动 (A->b.)。 A 被编译器看到。由于 I6 是第 3 次生产的一部分,因此前瞻是相同的,即 $.
- 当 ‘ 时,I3 转到 I3。 ‘ 第二个产品的 ‘ 向右移动 (A->aA) 。 a 被编译器看到。由于 I3 是第二次产生的一部分,因此前瞻是相同的,即 a|b。
- 当 ‘ 时,I3 转到 I8。 ‘ 的第二次产生向右移动 (A->aA.)。 A 被编译器看到。由于 I8 是第二产生式的一部分,因此前瞻是相同的,即 a|b。
- 当 ‘ 时,I6 转到 I9。 ‘ 的第二次产生向右移动 (A->aA.)。 A 被编译器看到。由于 I9 是第二次生产的一部分,因此前瞻是相同的,即 $。
- 当 ‘ 时,I6 转到 I6。 ‘ 第二个产品的 ‘ 向右移动 (A->aA) 。 a 被编译器看到。由于 I6 是第二次生产的一部分,因此前瞻是相同的,即 $。
- 当 ‘ 时,I6 转到 I7。 ‘ 第三个产生式的右移 (A->b.) 。 b 被编译器看到。由于 I6 是第 3 次生产的一部分,因此前瞻是相同的,即 $.
STEP 3-在解析表中定义2个函数:goto[终结符列表]和action[非终结符列表]。下面是CLR解析表
- $ 默认情况下是一个接受状态的非终端。
- 0,1,2,3,4,5,6,7,8,9 表示 I0,I1,I2,I3,I4,I5,I6,I7,I8,I9
- I0 在 I2 中给出 A,因此将 2 添加到 A 列和 0 行。
- I0 给出 I1 中的 S,因此将 1 添加到 S 列和第一行。
- 同样,5写在A列第2行,8写在A列第3行,9写在A列第6行。
- I0 在 I3 中给出 a,因此将 S3(shift 3) 添加到列和 0 行。
- I0 在 I4 中给出 b,因此将 S4(shift 4) 添加到 b 列和 0 行。
- 类似地,S6(shift 6) 添加到 ‘a’ 列和 2,6 行,S7(shift 7) 添加到 b 列和 2,6 行,S3(shift 3) 添加到 ‘a’ 列和 3 row ,S4(shift 4) 添加在 b 列和 3 行上。
- I4 减少为 ‘ 。 ‘ 在最后。 I4 是语法的第 3 产生式。所以在前瞻列中写 r3(reduce 3) 。 I4 的前瞻是 a 和 b,因此在 a 和 b 列中写入 R3。
- I5 减少为 ‘ 。 ‘ 在最后。 I5是语法的第一个产生式。所以在前瞻列中写 r1(reduce 1) 。 I5 的前瞻是 $ 所以在 $ 列中写 R1。
- 同样,在a,b列第8行写R2,在$列第9行写R2。