编译原理期末论文一、概述算符文法:即它的任一产生式的右部都不含两个相继的非终结符的文法。
如果G是一个不含空字符的算法文法,那么只要它的任一对终结符都只满足>,=,<的关系的一种,则称G是一个算符优先文法。
算符文法分类:对于一个算符优先文法,只要能构造出它的算符优先表,就可以利用算符优先分析方法,分析一个句子是否符合这个文法的定义。
那么定义FirstVT(P)={a|P(+=>)a···或P(+=>)Qa···,a属于终结字符集,而Q属于非终结字符集},其中···表示所有字符集LastVT(P)={a|P(+=>)···a或P(+=>)···aQ,a属于终结字符集,而Q 属于非终结字符集}由以下两条规则来构造FirstVT集:(1) 若有产生式P=>a···、或P=>Qa···,则a属于FirstVT(P);(2) 若有a属于FirstVT(Q),且有产生式P=>Q···,则a属于FirstVT(P);类似的有构造LastVT集的规则:(1) 若有产生式P=>···a或P=>···aQ,则a属于LastVT集。
(2) 若a属于LastVT(Q),且有产生式P=>···Q,则a属于LastVT集。
构造FirstVT集的算法:BeginFor 每个非终结符P和终结符a Do F[P,a]=FALSE;For 每个形如P=>a...或P=>Qa...的产生式 (1)DO insert(P,a)While Stack 非空 DoBegin把Stack 的顶项,记为(Q,a),上托出去;For每条形如P=>Q...的产生式DO . (2)Insert(P,a)End of while;END构造LastVT集的算法:将上述算法的对应的(1),(2)分别修改为For 每个形如P-〉…a或P-〉…aQ的产生式,For每条形如P-〉…Q的产生式便可得。
假定G是一个不含空字符产生式的算符文法。
对于任何一对终结符a,b,(1)a=b,当且仅当G中含有形如P->…ab…或P->…aQb…的产生式;(2)a<b, 当且仅当G中含有形如P->…aR…的产生式,而R-〉b…或R->Qb…;(3)a>b, 当且仅当G中含有形如P->…Rb…的产生式,而R->…a或R->…aQ;这样再结合上次的FirststVT和LastVT集的概念便可以由文法自动构造出算符优先表。
再定义一个素短语的概念:它至少含有一个终结符,并且,除它自身之外不再含任何更小的素短语,所谓最左素短语就是处于句型最左边的素短语。
而一个算符优先文法G的任何句型的最左素短语是满足以下条件的最左子串NaNb…NcNdN(N是非终结符,a,b,c,d是终结符)a<b b=…=c c>d这样形成一个驼峰结构,当找到这样一个子串的时候,它们优先级相等的一段就可以归约为一个非终结符,否则报错。
因此算符优先文法分析就是找到这样的字串并归约,最终所有终结符都被成功归约为##时表明这个句子符合所定义的文法要求。
构造优先表的算法:For每条产生式P-〉X1X2…Xn DOFor i=1;to n-1 DoBeginIf xi和xi+1 均为终结符then 置xi=xi+1If i<=n-2 且xi 和xi+2都为终结符但Xi+1为非终结 then 置xi=xi+1If xi为终结符而xi+1为非终结符 thenFor FirstVt(xi+1)中的每个a DO置xi<a;If xi为非终结符而xi+1为终结符 thenFor LastVt(xi)中的每个a DO置a>xi;END二、改进算法这是课本上基本的算符优先分析法,目前教材中讲述的算符优先分析算法没有考虑到在语法分析中出现错误时如何及时报告错误并尽快从错误中恢复过来,因此现有教材中的算符优先分析算法并不完整。
下面我来介绍一下改进后的算法,加入错误诊断恢复机制后,可使算符优先分析算法在语法分析中出现错误时,能及时报告错误并尽快从错误中恢复过来,使分析继续下去,改进后的算法更加完整准确。
1 算符优先法的构造算符优先法包含三个要素:算符优先表、栈和分析程序。
下面以简化的表达式文法为例介绍算符优先法的构造过程。
简化的表达式文法G[E]如下:E→E+T|TT→T*F|FF→i|(E)可证明文法G[E]为算符优先文法。
构造文法G[E]的算符优先表如表1。
算符优先法的分析程序是通用的,其算法如图1k:=1;s[k]:=’#’; /*数组s[]为栈,k 为栈指针*/REPEAT把下一输入符号读入a;IF s[k]∈VT THEN j:=k ELSE j:=k-1; /*取栈顶运算符*/WHILE s[j]>a DO /*若栈顶运算符s[j]的优先级高于读入运算符的优先级,则说明栈中有句柄,找到句柄进行归约*/BEGINREPEATQ:=s[j];IF s[j-1]∈VT THEN j:=j-1 ELSE j:=j-2UNTIL s[j]<Q把s[j-1]…s[k]归约为N; /*s[j-1]…s[k]为句柄*/k:=j+1;s[k]:=NEND;IF s[j]<a OR s[j]=a THEN /*若栈顶运算符s[j]优先级低于或等于读入运算符a 的优先级,则a 入栈*/BEGIN k:=k+1;s[k]:=a END.UNTIL a=’#’图1 算符优先分析程序表1 的算符优先表,图1 的算符优先分析程序和栈共同构成了文法G[E]的算符优先分析器。
2 算符优先析法的错误诊断恢复机制的构造使用算符优先法进行语法分析时,出现下面两种情况,则发生错误:(1) 若栈顶算符与当前输入符号间不存在优先关系;(2) 若找到某一句柄,但不存在任一产生式,其右部与此句柄形式吻合。
2.1 第一种出错情况下错误诊断恢复机制的构造在第一种出错情况下,即栈顶算符与当前输入符号间不存在优先关系时,可采用改变、插入或删除符号的方法来纠正错误。
例如a 和b 是栈顶的两个相继出现的算符(b为栈顶),c 和d 为当前输入串中前面两个符号,且b 和c之间不存在优先关系,此时出现错误,分析无法继续。
一种解决方法是若 a 的优先级低于或等于c,则可将b 从栈顶删除,此时a 变为栈顶算符,a 与c 之间有优先关系,可继续分析;另一种解决方法是找出某个算符e,使得b≤e≤c,把e 插入输入串中c 的前面,继续分析。
若找不到单个符号e,则可插入一串符号,使得b≤e1≤e2≤…≤en≤c。
按照这一原则可构造出现第一种情况的错误时的出错处理子程序。
文法G[E]的算符优先表表 1 中的空白表项即为算符之间无优先关系的情况,分析这些情况并按照上述原则可构造文法G[E]的算符优先分析器纠正第一种情况错误时的出错处理子程序如下:e1:/*表1 中的终结符号对((,#)无优先关系,当栈顶算符为(,当前输入符号为#,说明表达式中有(,但无)便结束了,此时调用此子程序*/ 将(从栈顶删除,继续分析。
给出诊断信息;“缺少)。
”e2:/*表 1 中的终结符号对(),(),(),i),(i,(),(i,i)无优先关系,当栈顶算符为)或i,当前输入符号为i 或(时出错,)或i 不能直接跟i 或(,它们之间应有运算符,此时调用此程序*/在输入串当前符号前插入+,继续分析。
给出诊断信息:“缺少运算符。
”e3:/*表1 中的终结符号对(#,))无优先关系,当栈顶算符为#,当前输入符号为)时,说明表达式中有),但)前无与其配对的(,此时出错,调用此程序*/从输入串中删除当前符号),继续分析。
给出诊断信息:“缺少(。
”e4:/*表1 中的终结符号对(#,#)优先级相等,若栈顶为#,当前输入符号为#,这时可能会出现两种情况:(1)若栈顶有非终结符E,则说明表达式分析正常结束,不出错。
(2)若栈顶为空,此时出错,则调用此程序。
*/在输入串当前符号前插入i,继续分析。
给出诊断信息;“缺少表达式。
”将e1、e2、e3、e4 加入表1 的出错位置,表示出错时调用相应的出错处理子程序。
改写后的表1 变为表2。
用算符优先法进行语法分析时,算符优先分析程序须不断查算符优先表,来比较栈顶算符与读入算符之间的优先级,当发现栈顶算符与读入算符之间无优先关系时就出错,调用相应的错误处理子程序使分析继续下去。
2.2 第二种情况下错误诊断恢复机制的构造算符优先法的第二种出错情况指算符优先法在分析过程中,找到某一句柄时要进行归约,但不存在任一产生式,其右部与该句柄形式吻合。
所谓形式吻合是指句柄与某一产生式右部非终结符位置一致,终结符位置一致,名称一致,此时可将该句柄归约为一非终结符N。
用算符优先法进行分析时,栈中已处理部分与输入串中剩余的未处理部分构成一个句型,假设栈中为#a1N1a2N2…anNn,输入串为an+1…ak#,则当前句型为#a1N1a2N2…anNnan+1…ak#,句柄指当前句型的最左素短语,它的特点是句柄中算符的优先级相等,句柄中算符的优先级高于句柄外相邻算符的优先级。
若a1<a2,a2=a3=…=an,an>an+1, 则当前句型的句柄为N1a2N2…anNn,该句柄应与某产生式右部形式吻合才可归约。
若句柄与任一产生式右部都不形式吻合则出错,这种情况下的出错处理子程序应能完成两项功能:诊断错误和从错误中恢复过来。
下面以文法G[E]的算符优先分析器为例介绍针对第二种出错情况的出错处理子程序的设计。
e5:/*句柄中含+时,若该句柄正确,则它应与产生式E→E+T 右部形式吻合,即+两边各出现一个非终结符,否则出错,调用此程序*/将句柄归约为非终结符N,继续分析。
给出诊断信息:“缺表达式。
”e6:/*句柄中含*时,若该句柄正确,则它应与产生式T→T*F 右部形式吻合,即*两边各出现一个非终结符,否则出错,调用此程序*/将句柄归约为非终结符N,继续分析。
给出诊断信息:“缺表达式。
”e7:/*句柄中含i 时,若该句柄正确,则它应与产生式F→i 右部形式吻合,即i 左边或右边不能出现非终结符,否则出错,调用此程序*/将句柄归约为非终结符N,继续分析。
给出诊断信息:“表达式间无运算符连接。