lr(0)文法分析.doc
编译原理实验报告1实验名称LR(0)文法分析一、实验目的输入任意的压缩了的上下文无关文法。输出相应的LR(0)分析表。二、实验原理对于LR文法,我们可以自动构造相应的LR分析表。为了构造LR分析表,我们需要定义一个重要概念文法的规范句型“活前缀”。这种句柄之后不含任何符号的前缀称为活前缀。在LR分析工作过程中的任何时候,栈里的文法符号(自栈底而上)X1X2XM应该构成活前缀,把输入串的剩余部分配上之后即应成为规范句型(如果整个输入串确实构成一个句子)。因此,只要输入串的已扫描部分保持可归约成一个活前缀,那就意味着所扫描过的部分没有错误。对于一个文法G,我们可以构造一个有限自动机,它能识别G的所有活前缀,然后把这个自动机转变成LR分析表,按照该LR分析表进行LR分析,就能保证在分析的过程中,如果分析的句子是正确的,栈里的文法符号(自栈底而上)始终构成活前缀。假若一个文法G的拓广文法的活前缀识别自动机中的每个状态(项目集)不存在下述情况(1)既含移进项目又含归约项目;(2)含有多个归约项目,则称G是一个LR(0)文法。该自动机的状态集合即为该文法的LR(0)项目集规范族。构造识别文法活前缀DFA有3种方法(1)根据形式定义求出活前缀的正则表达式,然后由此正则表达式构造NFA再确定为DFA;(2)求出文法的所有项目,按一定规则构造识别活前缀的NFA再确定化为DFA;(3)使用闭包函数(CLOSURE)和转向函数GOI,X构造文法G’的LR0的项目集规范族,再由转换函数建立状态之间的连接关系来得到识别活前缀的DFA。符号串的前缀是指该符号串的任意首部,包括空串Ε。例如,对于符号串ABC,其前缀有Ε,A,AB,ABC。如果输入串没有错误的话,一个规范句型的活前缀是该句型的一个前缀,但它不含句柄之后的任何符号。之所以称为活前缀,是因为在该前缀后联接尚未输入的符号串可以构成一个规范句型。活前缀与句柄的关系如下(1)活前缀已含有句柄的全部符号,表明产生式A→Β的右部Β已出现在栈顶。(2)活前缀只含句柄的一部分符号,表明A→Β1Β2的右部子串Β1已出现在栈顶,期待从输入串中看到Β2推出的符号。(3)活前缀不含有句柄的任何符号,此时期望A→Β的右部所推出的符号串。在文法G的每个产生式的右部(候选式)的任何位置上添加一个圆点,所编译原理实验报告2构成的每个产生式称为LR(0)项目。如产生式AXYZ有如下项目AXYZ,AXYZ,AXYZ,AXYZ。为刻划分析过程中的文法的每一个产生式的右部符号已有多大一部分被识别(出现在栈顶),可以用这种标有圆点的产生式来确定。(1)A→Β刻划产生式A→Β的右部Β已出现在栈顶。(2)A→Β1Β2刻划A→Β1Β2的右部子串Β1已出现在栈顶,期待从输入串中看到Β2推出的符号。(3)A→Β刻划没有句柄的任何符号在栈顶,此时期望A→Β的右部所推出的符号串。(4)对于A→Ε的LR0项目只有A→.。设文法G(VT,VN,S,P)是一个上下文无关文法,若存在一个规范推导SAW12W(其中A12P),则称项目A12对活前缀1是RMR有效的,即LR0有效项目。从直观意义上讲,一个LR0项目指明了在分析过程中的某一步我们看到产生式的多大部分被识别,LR0项目中的圆点可看成是分析栈栈顶与输入串的分界线,圆点左边为已进入分析栈的部分,右边是当前输入或继续扫描的符号串。不同的LR0项目,反映了分析栈顶的不同情况。我们根据LR0项目的作用不同,将其分为四类(1)归约项目表现形式A→A这类LR0项目表示句柄A恰好包含在栈中,即当前栈顶的部分内容构成了所期望的句柄,应按A→A进行归约。(2)接受项目表现形式→AS其中是文法惟一的开始符号。这类LR0项目实际是特殊的归约项目,表示分析栈中内容恰好为A,用→A进行归约,则整个分析成功。S(3)移进项目表现形式A→A(BVT)这类LR0项目表示分析栈中是不完全包含句柄的活前缀,为构成恰好有句柄的活前级,需将B移进分析栈。(4)待约项目表现形式A→ΑBΒ(BVN)这类LR0项目表示分析栈中是不完全包含句柄的活前缀,为构成恰好有句柄的活前缀,应把当前输入字符串中的相应内容先归约到B。在给出LR0项目的定义和分类之后,我们从这些LR0项目出发,来构造能识别文法所有前缀的有限自动机。其步骤是首先构造能识别文法所有活前缀的非确定的有限自动机,再将其确定化和最小化,最终得到所需的确定的有限自动机。由文法G的LR0项目构造识别文法G的所有活前缀的非确定有限自动机的方法(1)规定含有文法开始符号的产生式(设→A)的第一个LR0项目S编译原理实验报告3(即→A)为NFA的惟一初态。S(2)令所有LR0项目分别对应NFA的一个状态且LR0项目为归约项目的对应状态为终态。(3)若状态I和状态J出自同一文法G的产生式且两个状态LR0项目的圆点只相差一个位置,即若I为X→X1X2XI1XIXN,J为X→X1X2XIXI1XN,则从状态I引一条标记为XI的弧到状态J。(4)若状态I为待约项目(设X→ΑAΒ),则从状态I引Ε弧到所有A→R的状态。为了使“接受”状态易于识别,我们通常将文法G进行拓广。假定文法G是一个以S为开始符号的文法,我们构造一个,它包含了整个G,但它引进了一个不出现在G中的非终结符,并加进一个新产生式S→S,以→S为开始符号。那么,我们称是G的拓广文法。这样,便会有一个仅含项目→S的状态,这就是惟一的“接受”态。如果I是文法G'的一个项目集,定义和构造I的闭包CLOSUREI如下(1)I的项目都在CLOSUREI中。(2)若A→B属于CLOSUREI,则每一形如B→的项目也属于CLOSUREI。(3)重复(2)直到CLOSUREI不再扩大。定义转换函数如下GO(I,X)CLOSURE(J)其中I为包含某一项目集的状态,X为一文法符号,J{A→X|A→X∈I}。圆点不在产生式右部最左边的项目称为核,惟一的例外是S′→S,因此用GOTO(I,X)状态转换函数得到的J为转向后状态闭包项目集的核。使用闭包函数(CLOSURE)和转换函数GOI,X构造文法G’的LR0的项目集规范族,步骤如下(1)置项目S′→S为初态集的核,然后对核求闭包CLOSURE({S′→S})得到初态的闭包项目集。(2)对初态集或其他所构造的项目集应用转换函数GOI,XCLOSUREJ求出新状态J的闭包项目集。(3)重复(2)直到不出现新的项目集为止。计算LR(0)项目集规范族C{I0,I1,IN}的算法伪代码如下PROCEDUREITEMSETSG’BEGINC{CLOSURE{S’S}}REPEATFORC中每一项目集I和每一文法符号XDOIFGOI,X非空且不属于C编译原理实验报告4THEN把GOI,X放入C中UNTILC不再增大END一个项目集可能包含多种项目,若移进和归约项目同时存在,则称移进归约冲突,若归约和归约项目同时存在,则称归约归约冲突。下面看一个具体的例子我们希望能根据识别文法的活前缀的DFA建立LR分析器,因此,需要研究这个DFA的每个项目集(状态)中的项目的不同作用。我们说项目A→Β1Β2对活前缀ΑΒ1是有效