• 编译原理复习——语法分析(自底向上)2


    前面简单介绍了什么是自底向上分析,而且也进行了讨论我们需要创建出一个LR分析表来就和自顶向下分析时我们需要创建的LL(1)分析表一样

    在这里先复习LR(0)分析表这个是最简单的分析表也是其他表的基础

    LR(0) 分析特点
    LR(0) 分析法不需要向前看符号就可以确定是 归约(到哪个符号)还是移入
    LR(0) 分析表的构造思想和方法是其他 LR 分析 表构造基础
    LR 分析的关键是找 可规约成分
    这里有一些琐碎的知识点可以看:
    LR(0) 项目集规范族的构造
    由活前缀的定义,活前缀和句柄之间的关系有三种:
    活前缀中已经包含句柄的全部符号
    此时意味着某一产生式 A→α 的右部符号串α   出现在栈顶 ,相应的分析动作应该是按该产生 式归约
    活前缀中只包含句柄的一部分
    此时意味着形如 A→α1α 2 产生式的右部子串 α1 已经出现在栈顶, 正期待着 从剩余的输入串中能
    移进或归约得α2
    活前缀中不包含句柄的任何符号
    此时意味着 期待 从剩余的输入串中能移进或归约 得到某产生式 A→α的右部α
    LR(0) 项目
    为了刻画在分析过程中文法的一个产生式右部已经有多 大一部分被识别,可在 每个产生式右部某个位置上加一 个圆点 来表示。针对上述三种情况,标有圆点的产生式
    分别为
    A →α ·
    A →α 1 · α 2
    A ·α
    我们把文法 G 中右部添加一个圆点的产生式称为文法 G 的一个 LR(0) 项目
    特别地, A→ε只 有一个项目 A→ ·
    LR(0) 项目进一步分类:
    归约项目 :形如 A→α. 的项目,其中α∈ (V T ∪ V N ) *
    它表示栈顶已形成句柄 α, 下一步动作应该是 归约
    移进项目 :形如 A→α.aβ 的项目。其中,a∈VT ,α,β(VT ∪ V N ) * 它表示期待从输入串中移进一个符号 ,已待形成句柄
    待约项目 :形如 A→α.Bβ 的项目。其中, B∈ V N α,β∈ (V T ∪ V N ) *。它表示期待从输入串中进行归约而 得到 B ,然后进一步得到 A 的全部右部
    接受项目 :形如 S’→α. 的项目。 S’ 是文法开始符, S’ 为左部的规则叧有一个(通过对一般文法拓广 得到的),所以,该归约项目是一个特殊的归约项 目,它表示整个句子已分析完毕,可以接受
    把得到的每一个状态来进行转换可以得到一个NFA最后根据这个NFA我们可以转换成一个DFA当然这种方法比较繁琐而且工作量很大容易出错所以我们在这里不采用这种方法
    通过 闭包函数 和 转换函数 , 直接求出 LR(0) 项目集规范族,再由转换函数建立 状态之间的连接关系得到识别活前缀的 DFA。

    闭包函数:构造项目集 I 的 Closure(I)
    I 的任何项目都属于 Closure ( I )
    若 A→α .Bβ 属于 Closure (I),则对 任何 关于 B 的规则 B→γ , 项目 B→·γ 也属于 Closure (I )
    重复执行上述两步骤,直到 Closure ( I )不再增大为止

    状态转换函数 GO(I,X)
    假定 I 是拓广文法 G′的任一项目集,X 为一 文法符号 ,状态 转换函数 GO(I,X) 的定义如下:
    GO(I,X) = Closure(J)
    其中,J={ A→αX.β│A→α.Xβ∈ I }
    新状态的初始项目即圆点移动后的项目称为核。 即 J 称为 核

    识别文法所有活前缀的DFA
    使用 GO 函数可以将拓广文法 G′的 LR(0)项目集规范族联结成一个识别文法活前缀的DFA。具体步骤如下:
    a) 置项目S′→ ·S 为初态集的核心项目,然后对其求闭包,CLOSURE({S′→·S} )得到初态的项目集
    b) 对初态集或其它所构造的项目集应用转换函数 GO(I ,X)= Closure ( J )
    c) 重复 b) 直到不出现新的项目为止
    d) 状态转换函数 GO(I ,X) 建立项目集之间的关系

    LR(0)分析表

    但是有些时候我们会发现,在构建这个LR(0)分析表的时候我们会产生移进规约冲突。具体可以看一道例题:

    (0) S’→ S
    (1) S→ rD
    (2) D→ D,i
    (3) D→ i

     我们可以发现在标红的位置我们是不知道需要进行移进还是规约的这时候我们发现LR(0)的能力已经不够了。我们需要有一个能力更强大的武器来解决这个问题。

    这里引入SLR(1)文法这里的S指的是simple即简单的。这里提一下例题当中是移进规约冲突但是实际上我们还是有规约规约冲突的

    I ={ X→ α · , 移进项目
          A→   α · , 归约项目
          B→   α ·  归约项目}
    存在移进 - 归约冲突和归约 - 归约冲突,但是只要满足:
    FOLLOW( A ) ∩ FOLLOW ( B ) = Ø
    FOLLOW( A ) ∩{ b } = Ø
    FOLLOW( B ) ∩{ b } = Ø
    当状态 I 面临输入符号 a 时,则动作可以按一下规定决策
    (1) a = b , 则移进 b
    (2) a FOLLOW (A), 则使用 A→   α 归约
    (3) a FOLLOW (B), 则使用 B→ α 归约
    (4) 否则, 报错

    具体操作可以看这个例子所示: 

    I ={ A1→α·a1β1 , 移进项目

          A 2→ α ·a 2 β 2 ,
          …
          A m→ α ·a m β m ,
          B1 →α · , 归约项目
          B2 →α ·
          …
         Bn →α · }
    当状态 I 面临输入符号 a 时,
    (1) a = a i , 则移进 a i
    (2) a FOLLOW(B i ), 则使 B i→ α 归约
    (3) 否则, 报错
    这种解决冲突的方法称为 SLR(1) 方法。若文法的 LR(0) 项目集规范族中所有 项目集的冲突均能如此解决,则称此文法为 SLR(1) 文法
    DFA C={I 0 ,I 1 ,…,I n }, 构造 SLR 分析表
    在构造 LR(0) 分析表的基础上更改
    (1) A→ α·aβ I k GO( I k ,a)= I j , ACTION[ k,a ] =sj
    (2) A→ α· I k , a FOLLOW (A), ACTION[ k,a ]= rj ( 假定产生式 A→ α 是文法 G’ 的第 j 个产生式)
    (3) S’→ I k , ACTION[ k,# ]= acc
    (4) GO(I k ,A)=I j , GOTO[k,A]=j
    (5) 分析表中凡是不能用以上规则填入信息的空白格均置 上“报错标志”
    SLR(1) 分析总结
    求识别文法活前缀的 DFA ,即 LR(0) 项目集规范族 LR(0) 项目集规范族中不存在冲突项目集,则为
    LR(0) 文法,也是 SLR(1) 文法;若存在冲突,则不 LR(0) 文法,但是如果可以用 SLR(1) 方法解决, 则是 SLR(1) 文法,可以构造 SLR(1) 分析表 基于 SLR(1) 分析表,可以对任意输入串进行 SLR(1)
    分析
  • 相关阅读:
    简单快速理解常用的正则表达式
    【已解决】client_loop: send disconnect: Broken pipe|连接CentOS服务器:ssh空闲自动断开
    delphi 在代码中 添加 TO-DO 并且 管理
    如何让企业微信不显示「已读」
    全球人口突破80亿!免费分享全球人口分布数据
    Python高级语法----Python C扩展与性能优化
    还在用 Chrome? Edge 已成为我的主力浏览器
    跳出打工圈!程序员要如何走上创业逆袭路,获得财富自由
    Gzip压缩
    kafka查看消费情况
  • 原文地址:https://blog.csdn.net/m0_53345417/article/details/127673984