LALR 解析器:
LALR Parser 是前瞻 LR 解析器。它是可以处理大量语法的最强大的解析器。与其他解析表相比,CLR 解析表的大小相当大。 LALR 减少了这个表的大小。LALR 的工作原理类似于 CLR。唯一的区别是,它将 CLR 解析表的相似状态合并为一个状态。
一般语法变成 [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,则第 1 次产生。
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]
在这里,第一个产生式是先前产生式的一部分,因此前瞻将与其先前产生式相同。
构建LALR解析表的步骤:
- 编写增强语法
- LR(1) 要查找的项目集合
- 定义2个函数:LALR解析表中的goto[终端列表]和action[非终端列表]
例子
为给定的上下文无关文法构造 CLR 解析表
S-->AA
A-->aA|b
解决方案:
STEP1-查找增广文法
给定文法的增广文法是:-
S'-->.S ,$ [0th production]
S-->.AA ,$ [1st production]
A-->.aA ,a|b [2nd production]
A-->.b ,a|b [3rd production]
让我们将前瞻规则应用于上述产生式。
- 最初的展望总是 $
- 现在,第 1 个产品因 ‘ . ‘ 在第 0 个生产中的 ‘S’ 之前。在 ‘S’ 之后没有任何东西,因此第 0 个生产的超前将是第 1 个生产的超前。即:S–>.AA ,$
- 现在,第 2 次生产因 ‘ . ‘ 在第一次制作中的 ‘A’ 之前。
在“A”之后是“A”。所以,FIRST(A) 是 a,b。因此,第 2 次产生的超前量变为 a|b。 - 现在,第三部作品是第二部作品的一部分。所以,展望将是一样的。
STEP2 –查找 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。 ‘ 2nd 产生向右移动 (A->aA) 。 a 被编译器看到。因为 I3 是第二个产生式的一部分,所以前瞻是相同的,即 a|b。
- 当 ‘ 时,I0 变为 I4。第三次产生的’向右移动 (A->b.)。 b 被编译器看到。由于 I4 是第 3 次产生的一部分,因此前瞻是相同的,即 a|b。
- 当 ‘ 时,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 次生产的一部分,因此前瞻是相同的,即 $.
第 3 步 –
在解析表中定义2个函数:goto[终端列表]和action[非终端列表]。下面是CLR解析表
一旦我们制作了一个 CLR 解析表,我们就可以轻松地从中制作一个 LALR 解析表。
在step2图中,我们可以看到
- I3 和 I6 相似,除了它们的前瞻。
- I4 和 I7 除了它们的前瞻之外是相似的。
- I8 和 I9 相似,只是它们的前瞻。
在 LALR 解析表构建中,我们合并了这些相似的状态。
- 凡是有 3 或 6 的地方,将其设为 36(组合形式)
- 凡是有 4 或 7 的地方,将其设为 47(组合形式)
- 凡是有 8 或 9 的地方,就做成 89(组合形式)
下面是 LALR 解析表。
现在我们必须删除不需要的行
- 我们可以看到,36 行有两次相同的数据,所以我们删除了 1 行。
- 我们通过组合单个 47 行中的每个值将两个 47 行合并为一个。
- 我们通过组合单个 89 行中的每个值将两个 89 行合并为一个。
最终的 LALR 表如下所示。