📜  CLR 解析器(带有示例)

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

LR解析器:
这是一种高效的自下而上的语法分析技术,可用于解析大量的上下文无关文法,称为 LR(k) 解析。
L 代表从左到右扫描
R 代表逆向的最右推导
0 代表没有。前瞻的输入符号数
如需更多参考,请访问 https://www.geeksforgeeks.org/lr-parser/

LR解析的优点:

  • 它几乎可以识别所有可以为其编写 CFG 的编程语言结构
  • 它能够检测语法错误
  • 它是一种高效的非回溯移位减少解析方法。

LR解析方法的类型:

  1. 单反
  2. CLR
  3. 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解析表的步骤:

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

规则-

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