编译原理Ch5

第五章 自下而上的语法分析

一、自下而上分析的基本问题

1.自下而上分析方法的关键

找出当前句型的可归约串,然后根据产生式判别将它归约成什么样的非终结符

2.规范规约基本概念

(1)短语

G为文法,S为开始符号,假定αβδ是G的一个句型,如果
$$
S\overset*{\Rightarrow}αβδ且A\overset+{\Rightarrow}β
$$
则称β是句型αβδ相对于非终结符A的短语。
使用语法树来表示:
针对某一非终结符,以该终结符为根的,高度大于等于2的子树的,所有叶子结点,组成了该终结符的短语。

(2)直接短语

若$ A {\Rightarrow} β $,则β是非终结符A的直接短语。
使用语法树来表示:
针对某一非终结符,以其为根节点的,高度等于2的树的叶子结点,是该非终结符的直接短语。

(3)句柄

最左直接短语。
使用语法树来表示:
一棵语法树的最左边的高度为2的子树的叶子节点。

(4)规范规约

从句子到开始符号的归约序列,如果每一步都是把句柄替换为相应产生式的左部符号而得到的,则称为规范归约。规范归约是最右推导(规范推导)的逆过程。
语法树

3.自下而上的分析过程

考虑文法

$G(E):E→E+T|T$
$T→T*F | F$
$F→i| (E)$
$并假定输入串为(i+i)*i,考察自下而上的分析过程$

答案:
分析过程答案

二、LR分析法

1.LR分析表工作过程

(1)初始化

状态栈:$S_0$
符号栈:#
输入串:$a_1a_2a_3…a_n$

(2)一般情况下

状态栈:$S_0S_1…S_m$
符号栈:#$X_1X_2…X_m$
输入串:$a_ia_{i+1}…a_n$#

(3)$ACTION[S_m,a_i]=S_x$移入动作

表示当前状态栈顶是状态$m$,输入串头为$a_i$,此时让$x$入状态栈,让$a_i$入符号栈,变为:
状态栈:$S_0S_1…S_mx$
符号栈:#$X_1X_2…X_ma_i$
输入串:$a_{i+1}…a_n$#

(4)$ACTION[S_m,a_i]=R_x$归约动作

表示当前状态栈顶是状态$m$,输入串头为$a_i$,此时,状态栈和符号栈顶k个元素出栈,并用产生式$x(A→X_{m-(k-1)}…X_m)$对符号栈出栈元素进行规约。(k表示被规约了k个字母)变为:
状态栈:$S_0S_1…S_{m-k}$
符号栈:#$X_1X_2…X_{m-k}A$
输入串:$a_ia_{i+1}…a_n$#
并且此时,若
$$
GOTO[S_{m-k},A]=y,
$$
则跳转到状态y,y入状态栈顶,格局变为:
状态栈:$S_0S_1…S_{m-k}y$
符号栈:#$X_1X_2…X_{m-k}A$
输入串:$a_ia_{i+1}…a_n$#

(5)$ACTION[S_m,a_i]=acc$

分析成功

(6)$ACTION[S_m,a_i]=空白$

出现语法错误

2.LR分析算法

  • 输入:串w和LR语法分析表,该表描述了文法G的ACTION函数和GOTO函数
  • 输出:如果w在L(G)中,则输出w的自底向上语法分析过程中的规约步骤;否则给出一个错误提示。
  • 方法:初始时,语法分析器栈中的内容为初始状态$S_0$,输入缓冲区中的内容为w#。然后,语法分析器执行下面的程序:
    LR分析算法

3.LR分析器的逻辑结构

LR分析器的逻辑结构

三、LR(0)分析

1.LR(0)项目

  • 把右部某位置有圆点的产生式称为相应文法的一个LR(0)项目,简称项目。
    $$
    A→a_1·a_2
    $$
    例如,

$S→·bBB(1)$
$S→b·BB(2)$
$S→bB·B(3)$
$S→bBB·(4)$

  • 项目描述了句柄识别的状态
  • 产生式1是移进项目,·后跟着终结符
  • 产生式2/3是待约项目,·后跟着非终结符
  • 产生式4是规约项目,·后为空

2.增广文法

  • 如果G是一个以S为开始符号的文法,则G的增广文法是在G中加上新开始符号S’和产生式S’→S而得到的文法
  • 目的是使得文法的开始符号仅出现在一个产生式的左边,从而使得分析器只有有一个接受状态

3.项目闭包closure(I)

  • I是一个LR(0)项目,表示为$I→I_0…I_i·I_{i+1}…I_n,closure(I)$表示为:
    • $I$本身
    • 若形如$K→α·Aβ$的项目属于$I$,且$A→µ$是文法的一个产生式,任何形如$A→·µ$的项目也应加到$closure(I)$中
    • 重复上述过程,直到$closure(I)$不变
  • 此时,$closure(I)$中的所有项目互相称为等价项目,$closure(I)$集合视为一个状态。

4.构建LR(0)自动机

构建LR(0)自动机

5.构造LR(0)分析表

  • 行标为状态编号
  • ACTION表列标为终结符+#,GOTO函数列标为规约时使用过的非终结符
  • ACTION表中,若LR(0)自动机中的项目为移进项目,则ACTION=sn,n为下一个状态的编号
  • ACTION表中,若LR(0)自动机中的项目为规约项目,则ACTION=rn,n为使用产生式规约的编号
  • GOTO表中,若LR(0)自动机中的项目为待约项目,则GOTO=n,n为下一个状态的编号
  • 例:
    构造LR(0)分析表

6.LR(0)分析过程的冲突

(1)移进/规约冲突

移进/规约冲突

  • $I_2$的第一条表示,无论后边是什么字符,都要采取规约动作,但$I_2$的第二条表示,如果下一个读入字符是*,则采取移进操作。
  • 此时,自动机不知道到底是用移进还是规约动作。
  • 同理$I_9$也有同样的问题。
    移进/规约冲突的LR(0)分析表
  • 如果LR(0)分析表中没有语法分析动作冲突,那么给定的文法就称为LR(0)文法
  • 不是所有CFG【上下文无关文法】都能用LR(0)方法进行分析,也就是说,CFG不总是LR(0)文法

(2)规约/规约冲突

规约/规约冲突

  • 对于某一个状态,接受某个终极符后既可执行规约动作1,也可执行规约动作2,如图中的B和T,同时图中也有移进规约冲突。

7.SLR分析

(1)思想

  • 可以解决一些冲突。移进/规约冲突例中,若下一个输入符号是*,即使我们选择规约出E,但*并不在E的FOLLOW集中,而在T的FOLLOW集中,因此我们要选择移进动作。
    SLR化解冲突后的分析表

(2)算法

SLR算法

  • 理解:下一个输入符号是a,先查看所有移进项目,圆点后边如果有a,则选择移进a,如果a在规约项目左部的FOLLOW集中,则选择规约。

(3)与LR(0)对比

  • LR(0)在分析时向前看0个符号,也就是不向前看,在分析表中,若遇到ACTION=r,则一行全都是规约动作;SLR分析时向前查看一个符号,当输入符号不在FOLLOW集中,才采取规约动作。
    SLR分析

(4)SLR分析遇到的冲突

SLR分析法的冲突

  • 此例中,等号在R的FOLLOW集中,发生了冲突。

四、LR(1)分析法

1.LR(1)项目

  • 将一般形式为$[A→αβ,a]$的项称为$LR(1)$项,其中$A→αβ$是一个产生式
  • a是一个终结符(包括#),他的含义是,在当前状态下,A后面要求紧跟的终结符,称为该项的展望符(lookahead)
  • 也就是说,只有在A后面是a时,才使用这个项目。
  • LR(1)中的1指二元组第二个项。
  • 在形如$[A→α·β,a]$且$ β≠ \varepsilon $的项中,展望符a没有任何作用。
  • 但是一个形如$[A→α,a]$的项在只有在下一个输入符号是a时才可以按照A→α进行规约。
    • 这样的a的集合总是FOLLOW(A)的子集,而且它通常是一个真子集。

2.LR(1)等价项目

  • 对于待约项目$[A→α·Bβ,a]$,若$B→γ$,则等价项目是$[B→·γ,b]$
  • $b∈FIRST(βa)$

3.构建LR(1)自动机

LR(1)自动机例子

  • 如果除展望符外,两个LR(1)项目集是相同的,则称这两个LR(1)项目集是同心的,如$I_8$和$I_10$、$I_4$和$I_11$

4.LR(1)项目集闭包计算算法

  • 对于I中的每一项$[A→α·β,a]$
  • 对于增广文法中的每一个产生式$[B→·γ,b]$
  • 对于$FIRST[βa]$中的每一个符号b
  • 将$[B→·γ,b]$加到集合I中
  • 直到集合I没有变化为止

5.LR(1)分析表的构造算法

LR(1)分析表的构造算法

五、LALR分析法

1.为何被提出?

  • LR(1)分析法占用的空间多,因为状态多,有很多同心项:
    合并同心项前
    合并同心项后

2.可能出现的问题

(1)可能会产生归约/规约冲突

LALR冲突

  • 不会产生移进规约冲突

    因为同心项目中,“心”是相同的,即每一项的产生式部分相同,合并的是展望符,而展望符只在归约时起作用,在移进时不起作用。
    因此,只要合并前无移进/归约冲突,合并后就没有。

(2)推迟错误的发现

  • 会晚发现错误,不会放过错误

3.LALR(1)特点

  • 形式上与LR(1)相同
  • 大小上与LR(0)/SLR相当
  • 分析能力介于SLR和LR(1)之间
    $$
    SLR<LALR(1)<LR(1)
    $$
  • 合并后的展望符的集合依旧是FOLLOW集的子集

编译原理Ch5
https://sdueryrg.github.io/2024/10/29/编译原理Ch5/
作者
yrg
发布于
2024年10月29日
许可协议