LR 类分析方法总结

LR 类分析方法相关定义

LR(k) 分析方法是 1965 年由 D. Knuth 提出来的一种自底向上的语法分析文法。这里的 L 表示从左向右扫描输入串,R 表示构造一个最右推导的逆过程,k 表示在决定语法分析动作时需要向前看的符号个数。由于 LR(k) 分析方法对文法的限制很少,因而大多数能用上下文无关文法描述的程序设计语言都可用 LR 分析法进行有效的分析。LR(k) 分析方法适用范围较广、分析速度很快,并且能够准确及时地发现语法错误,因此,LR 分析法是当前最一般的语法分析方法(这里我书上是这样写的,但是我听老师好像说过因为移入归约冲突等不好解决就用的少了)。LR 分析法主要有 LR(0)、SLR(1)、LR(1)、LALR(1) 方法。

下面是其中的一些术语以及定义:

  • 规范句型: 用最右推导导出的句型,也称右句型。
  • 规范前缀: 若有规范句型 αβ, 且 β 是终极符串或空串, 则称 α 为规范前缀。
  • 规范活前缀:若某一规范句型的规范前缀 α 不含句柄或含一个句柄并且具有形式 α=α′π( π 是句柄),则称规范前缀 α 为规范活前缀(简称活前缀)。
  • 可归前缀:若活前缀 α 是含句柄的规范前缀,且句柄在 α 的最右端,即有 α=α′π,且 π 是句柄,则称活前缀 α 为可归前缀(归约规范活前缀、归约活前缀和可归活前缀都是指这个)

注:可归前缀中,『句柄在 α 的最右端』这里说的『最右端』是因为规范句型是指最右推导导出的句型,因此每次都选择最右边的非终极符进行替换。如果最右边出现了句柄,则可以将句柄归约。(这里存疑,看本节例题就可以很容易从符号栈中看出是从最右端开始的,因为例题中符号栈栈底在左边)

LR 类分析法的基本思想和工作过程

img

LR 方法的主要思想是,从输入流依此把符号移入符号栈,直至栈顶出现一个句柄;之后对句柄进行归约,直至栈顶不出现句柄;重复上述过程,直至最终归约为一个开始符,且输入流为空。

一个 LR 分析器由以下几个部分组成:

  1. 输入流(Input):一个有待分析的输入符号串
  2. 分析栈:其中包括文法符号栈和相应的状态栈
  3. 分析表:其中包括 Action 表和 GoTo 表。
  4. 驱动程序:对于不同的 LR 分析方法其驱动程序都是相同的。

LR 分析表

LR 分析表是提取可归前缀状态机 LRSM 中的信息形成的矩阵形式的表。包括 Action 表和 GoTo 表两部分:

  • Action 矩阵:行代表状态,列代表输入符(包括输入结束符 #,值得注意的是输入符都是终极符),而矩阵元素则表示相应的分析动作:移入 Shift / 归约 Reduce / 成功 Accept / 失败 Error

  • GoTo 矩阵:行代表状态,列则代表非终极符,而矩阵元素则表示归约后的转向状态。

  • Action(s, a) 规定了当状态 s 面对输入符号 a 时采用什么动作,用『动作矩阵』存储

  • Goto(s, x) 规定了状态 s 面对符号 x 时下一个状态是什么,用『转向矩阵』存储。

LR 驱动程序

不妨假设状态栈、符号栈和输入流的开始格局为:(#S1, #, a1a2…an#),各部分以逗号分隔。

  • 移入:若当前格局为(#S1S2…Sn, #X1X2…Xn, aiai+1…an#),且 Action(Sn, ai)=Sj,ai∈VT,则 ai 入符号栈,第 j 个状态 Sj 入状态栈。即移入后的格局变为:(#S1S2…Sn Sj, #X1X2…Xn ai, ai+1…an#)
  • 归约:若当前格局为(#S1S2…Sn, #X1X2…Xn, aiai+1…an#),且 Action(ISn, a)=Rj,a∈VT∪{#},则按照第 j 个产生式进行归约,符号栈和状态栈相应元素退栈,归约后的文法符号入栈。假设第 j 个产生式为 A→α,k=|α| (α=Xn-k+1…Xn),则归约后的格局变为:(#S1S2…Sn-kS, #X1X2…Xn-kA, aiai+1…an#),其中 S=GoTo(Sn-k, A)。
  • 成功:若状态栈的栈顶状态为 Si,输入流当前值为 #,且 Action(Si, #)=Accept,则分析成功。
  • 失败:若状态栈的栈顶状态为 Si,输入流当前值为 a,且 Action(Si, a)=Error 或空,则转向出错处理程序。

例: 设文法 G(S) : \
[1] S → aAdBc \
[2] A → Aaa\
[3] A → a\
[4] B → Bbb\
[5] B → b

则对句子 aaaacbbbd 有如下规范推导:

S ⇒ aAdBc[1] \
⇒ aAdBbb[4]c[1] \
⇒ aAdb[5]bb[4]c[1] \
⇒ aAaa[2]db[5]bb[4]c[1] \
⇒ aa[3]aa[2]db[5]bb[4]c[1]

其归约过程为:

aa[3]aa[2]db[5]bb[4]c[1] \
⇒ aAaa[2]db[5]bb[4]c[1] \
⇒ aAdb[5]bb[4]c[1] \
⇒ aAdBbb[4]c[1] \
⇒ aAdBc[1] \
⇒ S

LR 分析法的关键问题

  • 如何判断分析栈内容是否为可归前缀
  • 能唯一的确定可归前缀中的句柄

可归前缀的判断

我们有如下『派生定理』

  1. 开始符产生式的右部是可归前缀。
  2. 如果 α1Aα2 是可归前缀,且 A→β 是产生式,则 α1β 也是可归前缀。

第一个就是 Z->α1|α2|...αn 则 α1,…αn 都为可归前缀,这个结论对不对稍微分析一下就可以知道。

比如说一开始符号栈里是 α1,输入流是一个#,相当于 β=空,所以 α1 首先是一个规范前缀,然后他也是必然为一个句柄,也就是可归前缀了。所以第一点就是开始符的右部都是可归前缀。以它为基础可以推出其他的可归前缀。

第二个结论怎么得出来的呢,思想是 α1Aα2 是可归前缀,这里的右端肯定有句柄,大概有几种可能

  • 要么 A 不在句柄里,而在 α2 里,假如 A 不在里面的话,α2 有一颗子树,又有 A→β,α1 里面一定没有句柄存在,否则 α1Aα2 是可归前缀就不可满足。这样的话,α1β 一定是含有句柄,并且在最右边。
  • 要么 A 在句柄里,假如 A 在句柄里,一定是一层节点,然后 A→β 是下一层的,所以依然成立。

例子:设有文法 G[S]:

[1] S → aAc
[2] A → Abb
[3] A → b

其中可归前缀为:aAc,aAbb,ab

确定句柄

因为本文是先画可归前缀状态机的,然后进行 Action 矩阵等的填写。而可归前缀状态机本身就可以提供出可归前缀的判断信息(待补充如何判断)

LR(0) 分析法

LR(0) 分析法基本概念

LR(0) 项目

LR(0)项目(简称项目)是带一个圆点 『•』 的产生式。每个项目都标志分析时的某一状态。

即:若 A→α 是产生式,则称 A→α•β 为 LR(0) 项目(简称项目)

项目的含义:对产生式 A 进行分析的某个状态:圆点的左部表示分析过程已经识别过的部分,圆点右部表示期待的后缀部分。简单来说就表示分析到哪了。

  • 形如 A→ α• 的项目称为 归约型项目 (点在最后)
  • 形如 A→ α•β 的项目称为 移入型项目

这里有个特殊情况是:•ε 这一个是看作归约项的。

归约型项目按照自动机来说,实际上是自动机的一个终止状态,也就自动机可以接受的一个 可归前缀

例:起始符 S → aAc 对应四个 LR(0) 项目:

  1. S → •aAc 表明我们希望接下来在输入中看到一个从 aAc 推导得到的串。这时符号栈为空。
  2. S → a•Ac 表明刚在输入中看到了一个 a,我们希望接下来看到一个能从 Ac 推导得到的串。这时符号栈中包含活前缀 a。
  3. S → aA•c 表明刚在输入中看到了一个可以由 aA 推导得到的串。这时符号栈中包含活前缀 aA。
  4. S → aAc• 表明我们已经看到了产生式全体 aAc,已经是时候把 aAc 归约为 S 了。符号栈中为可归前缀,右部为句柄。

项目集的闭包

项目集就是项目的集合的简称。

假设 IS 是 LR(0) 项目集,则称下面 CLOSURE(IS) 为 IS 的闭包集:

CLOSURE(IS) = IS∪{ A→•π | Y→β•Aη∈CLOSURE(IS),A→π是产生式 }

项目集的闭包 CLOSURE(IS) 的含义:表示项目集 IS 中每一个 Y→β•Aη 项目的圆点右部非终极符 A,可以应用的所有可能产生式。

值得注意的是,这是一个动态的过程。也就是说,A 可以应用的产生式作为项目后,还要继续判断这些新产生的项目。

例 1:G[S]:

  • [1] S → aAc (S 可以应用的产生式)
  • [2] A → dbb (A 可以应用的产生式)
  • [3] A → b (A 可以应用的产生式)

令项目集 IS={S → a•Ac[1]},则

CLOSURE(IS) ={S→a•Ac[1],A→•dbb[2],A→•b[3] }

例 2:G[S]:

  • S → E
  • E → E+T | T
  • T → T*F | F
  • F → (E) | id

令项目集 IS={S→•E}

CLOSURE(IS):

  • S → •E
  • E → •E+T
  • E → •T
  • T → •T*F
  • T → •F
  • F → •(E)
  • F → •id

项目集的投影

假设 IS 是 LR(0) 项目集,则称下面定义的 IS(X) 为 IS 关于 X 的投影集:

IS (X) = {A→αX•β | A→α•Xβ∈IS, X∈(V T∪V N)}

项目集 IS 关于 X 的投影集的含义:项目集中每个项目 A→α•Xβ 所描述的状态,处理完一个符号 X 后所对应的后继项目。

这里说句人话就是 IS 中的一个项目接收一个符号(终极符或非终极符)到达的下一个项目。

比如 S → •aAB 这个项目可以接收 a 会到 S → a•AB 这个项目。不能接收 A 所以到空状态。

这样对项目集里的所有项目尝试接收所有终极符和非终极符后能到的下一个项目就是该项目关于那个满足条件的符号的投影集。

例:G[S]:

  • [1] S → aAB
  • [2] A → dbb
  • [3] A → b
  • [4] B → e

令项目集 IS={S → a•AB[1],A → •dbb[2] ,A →•b[3] },则:

  • IS(A)={S → aA•B[1]}
  • IS(S)={ }
  • IS(d)={A →d•bb [2] }
  • IS(b)={A →b•[3] }
  • IS(a)={ }
  • IS©={ }

项目集的转换函数(GO 函数)

若 IS 是一个 LR(0) 项目集,X∈(VT∪VN),函数 GO(IS, X) 定义为

GO(IS, X)=CLOSURE(IS (X))

其中 IS(X) 为 LR(0) 项目集 IS 关于 X 的投影。

例:G[S]:

  • [1] S → aAc
  • [2] A → dbb
  • [3] A → b

令项目集 IS={S → •aAc [1]},则:

GO(IS, a )
= CLOSURE(IS(a))
= CLOSURE({S→a•Ac[1]})
= {S → a•Ac[1],A → •dbb[2],A → •b[3]}

构造 LR(0) 可归前缀状态机 LRSM

这里的 LRSM 应该是 线性正则式状态机,即 linear regex state machine,这个名词我并没有 Google 到,貌似是我们学校老师起得名字。

不过可能也是 LR state machine,反正我也不太知道。

为了使“成功”状态易于识别,通常 LR 文法要求文法的开始符 唯一 且不

  • 10
    点赞
  • 52
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值