zoukankan      html  css  js  c++  java
  • 编译原理之语法分析-自下而上分析(三)

        在上一篇博客中我们已经讲过如何构造LR(0)分析表,SLR构造分析表的前五个步骤是与LR(0)一样的,因此这里就不再对前五个步骤讲解。

        前五个步骤一样的原因:一个文法如果是SLR文法,则它一定是LR(0)文法,因此我们在判断它是不是SLR文法之前要先判断是不是LR(0)文法

        https://www.cnblogs.com/scm2019/p/12899757.html (前五个步骤可参考上一篇博客)

        (一)SLR分析法

          SLR分析法作用:SLR基于LR(0),通过一个前看符号,来决定是否执行归约动作或执行哪个归约动作。

          SLR分析法优点:1、有可能减少需要归约的情况   2、能够去除某些移进-归约冲突

          SLR分析法缺点:仍然有冲突出现的可能。

          

          SLR(1)解决冲突的办法

          首先看一下比较标准的解释:

          

          举个例子理解上图,假如这里有一个项目集,如下图。

         

           很明显这是一个s-r冲突,所以它不属于LR(0)文法,但是根据SLR(1)的解决方法,我们可以先求出产生式左侧终结符的Follow集。

           假如Follow(R) = { +, - } ,Follow(T) = { !,* }

           这时根据R和T的Follow集和移进项目圆点后的非终结符有以下三种情况

           1、当输入符号为 = 时,这时我们就把第一个产生式进行移进操作。

           2、当输入符号属于Follow(R)时(+ 或者 -),就将R->L·进行归约。

           3、当输入符号属于Follow(T)时(! 或者 *),就将T->T·进行归约。

           以上为成功消除冲突的情况

           假如Follow(R) = { =, * } ,Follow(T) = { +,* }

           1、移进项目圆点后的终结符(=)属于Follow(R),因此报错,即还是存在移进-归约冲突。因为我们还是不知道当输入符号为=时,要对S->L·=R进行移进,还是对R->L·进行归约。

           2、此外,Follow(R) ∩ Follow(T) = { * },报错,即还是存在归约-归约冲突。因为我们还是不知道当输入符号为*时,要对R->L·进行归约,还是对T->L·进行归约。

           以上为消除冲突失败的情况

           总结:如果想消除项目中的集冲突,必须满足以下两种情况(重要事情说三遍)

              总结:如果想消除项目中的集冲突,必须满足以下两种情况(重要事情说三遍)

           总结:如果想消除项目中的集冲突,必须满足以下两种情况(重要事情说三遍)

           1、移进项目圆点后的终结符(严格来说是圆点后的First集),不属于归约项目的Follow集。

           2、所有归约项目的Follow集两两相交必须为空。

        (二)构造SLR分析表

          ,判断文法是否属于SLR文法,如果是给出SLR分析表

          1、列出文法的规范项目集

           

           2、构造识别活前缀的NFA

            

          3、识别或前缀的DFA

             

          

           4、根据DFA判断LR(0)

            显然,在I1中面对符号E我们无法判断要进行归约还是移进,及存在S-R冲突。

            同样,在I2中面对终结符id,也存在着S-R冲突。

            因此该文法不是LR(0)文法

          5、算出Follow集,然后判断能否使用SLR的方法消除冲突,如果可以则是SLR文法        

            在I1中, Follow(S)={#} 不包含终结符+,因此I1中的S-R冲突可以消解。

            在I2中,Follow(E)={ #, ),+ },不包含终结符( ,因此I2的S-R冲突可以消解。

            综上所述,冲突能够被消除,该文法属于SLR(1)文法。

          6、画出SLR(1)分析表

               文法编号为:      

            1 : S->E

            2 : E -> id

            3 : E -> id(E)

            4 : E -> E+ id

            

             构造SLR(1)方法技巧

             其实LR(0)和SLR(1)分析表雷同,SLR(1)分析表只是比LR(0)分析表少几个归约项。

             假如该文法是一个LR(0)文法,那么跟上图不一样的是3、6、7所在的行应该填满,即3所在行全填r2,6所在行全填r4,7所在行全填r3。其余的和上图一模一样。

             但是为什么SLR(1)比LR(0)分析表少几个呢?

             其实我们找到r2对应的归约产生式为E->id,而发现Follow(E)={ (,+,# },即Follow(E)中不存在id 和 ( ,因此就不需要将id 和 ( 所在列也填上r2,否则使我们发现错误不及时,造成效率低额问题。

             同理r3和r4对应归约产生式为 E -> id(E) 和  E -> E+ id,同样Follow(E)={ (,+,# }。因此id 和 ( 不需要填r3 和 r4。

          如果还没明白我们再举一个例子,有如下文法

          

           该文法LR(0)分析表为

          

          该文法SLR(1)分析表为

           

           r1对应的归约产生式为S->BB·,r2和r3对应的归约产生式为B->aB· 和 B->b·

           在状态5所在的行,LR(0)分析表全部填写了r1,但是Follow(S)= { # },并没有a和b,所以在SLR(1)分析表中,只需要在状态5的#所在列填写r1。

           同理,我们先计算r2和r3产生式的Follow集,Follow(B)= { a,b,# },三个都有,因此在SLR(1)分析表中和LR(0)分析表中对应状态行都应该填写上。

           总结,LR(0)和SLR(0)分析表结构一样,唯一不同的就是归约项目所在的状态行,LR(0)不需要判断直接全部填写Rn,而在SLR(1)分析表中需要先判断Follow集,然后根据Follow集中已有的终结符去填SLR(1)表

             下边分别给出构造LR(0)和SLR(1)分析表比较系统的描述,可根据上述例子去理解一下:

           

            

           以上均为个人学习总结,如有错误或异议欢迎提出(自下而上分析法未完待续......)。

  • 相关阅读:
    LeetCode 230. 二叉搜索树中第K小的元素(Kth Smallest Element in a BST)
    LeetCode 216. 组合总和 III(Combination Sum III)
    LeetCode 179. 最大数(Largest Number)
    LeetCode 199. 二叉树的右视图(Binary Tree Right Side View)
    LeetCode 114. 二叉树展开为链表(Flatten Binary Tree to Linked List)
    LeetCode 106. 从中序与后序遍历序列构造二叉树(Construct Binary Tree from Inorder and Postorder Traversal)
    指针变量、普通变量、内存和地址的全面对比
    MiZ702学习笔记8——让MiZ702变身PC的方法
    你可能不知道的,定义,声明,初始化
    原创zynq文章整理(MiZ702教程+例程)
  • 原文地址:https://www.cnblogs.com/scm2019/p/12904320.html
Copyright © 2011-2022 走看看