📜  LALR 解析器(附示例)

📅  最后修改于: 2021-09-28 10:55:05             🧑  作者: Mango

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解析表的步骤:

  1. 编写增强语法
  2. LR(1) 要查找的项目集合
  3. 定义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}

规则 –

  1. 如果任何非终端有 ‘ 。 ‘ 在它之前,我们必须编写它的所有产生式并添加 ‘ 。 ‘ 在它的每一个生产之前。
  2. 从每个状态到下一个状态, ‘ 。 ‘ 移到右边的一个位置。
  • 在图中,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 表如下所示。