自底向上的语法分析

Posted by BY KiloMeter on June 26, 2019

自底向上分析过程是自顶向下分析过程的逆过程,这里的分析过程也是用到了栈,同样也有一个指针指向输入语句,依次将非终结符推入栈,然后判断栈顶的多个元素是否符合某个产生式的右部,如果符合,则将这几个栈顶元素弹出,将产生式的左部入栈,直到指针指向末尾,如果指针指向末尾时,栈顶元素仅有开始符号,那么代表匹配成功,否则匹配失败。这种方法叫做移入-规约法

该算法存在的问题是,如果栈顶多个元素与多个产生式的右部匹配上,此时就不知道该使用哪条产生式。

LR分析法

自底向上识别的关键问题在于识别出句柄。

这里解释下句柄,短语和直接短语

短语:由语法树中某一棵子树的全部叶子节点组成的终结符序列

直接短语:定义和短语一样,区别就是选取的某一棵子树,该子树不允许有非叶子节点

句柄:最左直接短语就是句柄

LR分析法中最重要的就是得到LR分析表

构造LR分析表有LR(0)分析、SLR分析、LR(1)分析和LALR分析

LR(0)分析法

右部某位置标有圆点的产生式称为该文法的一个LR(0)项目(简称为项目)

LR分析器的总体结构

和之前的LL(1)文法的预测分析法相比,一样使用到了栈,但是这里使用了两个栈,一个是符号栈,一个是状态栈,分析表也分成了两部分,一部分是动作表,一部分是转移表。两个表的构建过程可以看下面。这里说下如何判断过程。

刚开始时,状态栈仅有一个元素0,符号栈仅有一个$符号。依次读取每个缓冲区字符,每当读取到一个字符时,先根据分析表,查找出状态栈的栈顶元素和当前读取到的字符在分析表中的位置是什么,如果是Sn,则代表是移入操作,将该字符移入到符号栈,并把状态n移入到符号栈。如果是Rn,则代表使用第n条产生式进行规约,将产生式右部的元素弹出,并将规约后产生式的左部移入到符号栈,注意,在规约的时候,符号栈在弹出元素的同时,状态栈也得弹出相应数量的元素。在规约之后,符号栈的元素个数会比状态栈的元素个数多1,这种时候,下一步要根据符号栈和状态栈的栈顶元素,查找分析表,找到转移表部分中对应的值,并把对应位置的状态移入到状态表中,之后继续回到最起始的步骤,继续对下一个字符和状态栈的栈顶元素进行分析,继续移入和规约操作。

直到遇到分析表中的acc状态且字符串读到了末尾,这种情况代表分析成功,其他情况均代表分析失败。

增广文法

如果G 是一个以S为开始符号的文法,则G的增广文法 G’ 就是在G中加上新开始符号S’ 和产生式S’ → S而得到的文法

引入这个新的开始产生式的目的是使得文法开始符号仅出现在一个产生式的左边,从而使得分析器只有一个接受状态

构造LR分析表过程如下

但是LR(0)分析存在着一个问题,就是有移进规约冲突,如下图所示

在I2状态时,遇到*符号时,既可以进行规约,也可以进行移进。如何解决LR(0)的移进规约冲突?下面的SLR分析法就可以解决该问题

SLR分析法

SLR分析法的思想就是结合非终结符的follow集进行判断

从上面这个例子可以看到,当遇到*符号时,如果采取了规约操作,把T规约成了E,从E的follow集中可以看到,E的follow集中并没有*,因此根据这个条件,可以得出,在I2时,如果遇到*符号,应该采取移入操作。

因此可以得到SLR分析法的基本思想

但是SLR分析法也存在着不足,即使是根据follow集,也会出现无法处理的情况,如下

在I2中,当遇到=时,第一条式子表示执行移入操作,第二条式子表示进行规约,这个时候判断下follow(R),由于follow(R)中也包含了=,因此无法进行判断是否是要执行移入还是规约。

LR(1)分析法

为什么SLR分析法会出现冲突呢?原因是在于,SLR分析法只是简单地考察下一个输入符号b是否在规约项目的follow集中,但是b存在于follow集中只是规约的必要条件,而不是充分条件,就是说如果要进行规约操作,那么b一定存在于规约项目的follow集中,但是b存在于follow集中,并不一定能进行规约。

在特定的位置中,非终结符A的后继符集合只是follow(A)的子集

上面这个例子中,左边的R,其后继符号只能是=,而在右边的R,其后继符号只能是$,利用SLR分析法,笼统地使用follow集进行判断,扩大了可以规约的范围。

因此LR(1)分析法的一般形式如下:

[A—>α·β,a],其中A—>α·β是一个产生式,和前面LR(0)和SLR一样,多了后面一个a,a是一个终结符(在LR(1)分析法中,$是一个特殊的终结符),a表示在当前状态下,A后面必须紧跟的终结符,称为该项的展望符

LALR(1)分析法

和上面SLR分析法相比,LR(1)分析法多了4个项目。

从上面的构造结果可以看到,用LR(1)分析法的项目多了不少,能否把部分项目进行合并呢?

这里先说下一个概念:同心项目集指的是,如果除展望符外,两个LR(1)项目集是相同的,则称这两个LR(1)项目是同心的。

如果两个同心项目集的合并结果没有冲突,那么就能够把两个同心项目集进行合并,什么意思呢?看上面这个例子,其中I${10}$和I${8}$,I${4}$和I${11}$,I${5}$和I${12}$,I${7}$和I${13}$,就可以进行合并,但并不是同心项目集都是可以合并的,看下面这个例子

这个例子中,I${6}$和I${9}$,虽然是同心项目集,但是如果合并之后,遇到d时,既可以选A—>c这条产生式进行规约,也能选择B—>c进行规约,同理遇到e也是这种情况,出现了规约规约冲突。这种情况下就不能进行合并。

LARL(1)分析法也有缺点,就是合并之后,会推迟了错误的发现。