编译原理第四章—语法分析(自上而下分析)

  对于一个文法,当给你一串终结符号时,怎样知道它是不是该文法的一个句子呢?在自上而下的语法分析里,就是要判断能否从文法的开始符号推导出这个输入串。语法分析这一部分在编译过程中承前启后,是核心部分。

  自上而下分析就是对输入串通过试探,反复使用不同产生式谋求匹配输入串,为的是从文法开始符号(根节点)出发,自上而下的为输入串建立一棵语法树,即为输入串寻找一个最左推导。

    在这种推导过程中,因为反复的试探,不对就回去重来,存在很多缺点:一是文法的左递归性,会使分析陷入无限循环。二是回溯,会导致白走很多错路。三是虚假匹配,像X**Y,比如把第一个*匹配了,但发现还有第二个*,其实是不能匹配的,就无法识别X**Y是一个句子。第四,如果出错也难以知道确切位置。

     当然,我们要讨论的重点是解决了一些上述问题的LL(1)分析方法。

    一、 左递归的消除

     P是非终结符,这就是左递归的形式。

    

    按这个方法扩展一下,假定P关于的全部产生式是P->Pα1|Pα2|...|Pαm|β1|β2|β3

    这里的α、β不一定是终结符,只是式子的代称,每个α都不等于空字,每个β都不以P开头。那么消除P的直接左递归性就是改写为:

   

     这个方法只能消除直接左递归,如果是间接左递归,要先变成直接左递归。

    如 S->Qc|c

        Q->Rb|b

        R->Sa|a

    含有隐含左递归,把R代入到Q的有关候选之后,我们把Q的规则变为Q->Sab|ab|b

    再把Q代入S,得S->Sabc|abc|bc|c这样就可以按直接左递归处理了。

二、消除回溯

    为了消除回溯就必须保证匹配不再是试探,假如非终结符A->α1|α1|...|αn,它面临的输入符号为a,这里A不再是让某个αi去试探匹配,而是根据所面临的输入符号的不同准确制定一个αi去匹配,若匹配到最后没能识别整个字串,则该字串一定不是该文法中的句子。αi的工作成败完全代表了A。

      在不得回溯的前提下,文法不能有左递归。

     令G是一个不含左递归的文法,对G的所有非终结符的每个候选α定义它的终结首符集FIRST(α)为

    

    特别地,如果α 最终能推出ε,则ε∈FIRST(α),也就是说FIRST(α)是α的所有可能推导的开头终结符或可能的空字。
    如果非终结符A的任意两个候选式αi和αj的开始符号集不相交,则A可以根据所面临的第一个输入符号a,准确地指派一个候选式α去执行任务,α是那个FIRST集含a的候选式,即  a ∈FIRST(α)
    那么怎样才能使它们两两不相交呢?可以提取公共左因子,办法是:
假设A的产生式为
  A→δβ1|δβ2|…|δβn|γ1| γ2|…|γm 其中每个γ不以δ开头
那么把这些产生式改写为:
  A→δA’ |γ1| γ2|…|γm
  A’→β1|β2|…|βn
   工作做到这里还有一个问题:如果非终结符A面临符号1a,且a不属于A的任意候选首符集怎么办?我们可以这样,如果A的某个候选首符集包含空字,让它和A自动匹配,其条件是a是允许在文法的某个句型中跟在A后面的终结符。怎么表示这个条件呢?这里我们引入FOLLOW集:
     假定S是文法G的开始符号,对于G的任何非终结符A:
 

   特别是如果,则#∈FOLLOW(A),即FOLLOW(A)是所有句型中出现在紧接A之后的终结符或“#”。

   上面的条件就可以表示成a∈FOLLOW(A)


三,LL(1)文法

     到这里,我们已经能判断LL(1)文法了。
    (1)文法不含左递归
    (2)对于文法中每一个非终结符A的各个产生式的候选式的FIRST集两两不相交。即,若
   A→α1|α2|…|αn
   则 FIRST(αi)∩FIRST(αj)=Φ (i≠j)
    (3)对于文法中的每个非终结符A,若它的某个候选首符集包含ε,则
   FIRST(A)∩FOLLOW(A)=Φ
    如果一个文法G满足以上条件,则称该文法G为LL(1)文法
 
  对于LL(1)文法,假设要用非终结符A进行匹配,面临输入符号为a,A的所有产生式为
   A→α1|α2|…|αn
 (1)若a ∈ FIRST(αi) ,则指派αi去匹配
 (2)若a不属于任何一个候选首符集,则:
  ①若ε属于某个 FIRST(αi)且a∈FOLLOW(A),则让A与ε自动匹配;
  ②否则,a的出现是一种语法错误


四,预测分析程序

   用上面的思想,我们已经有了预测分析程序。
  预测分析程序需要一张预测分析表和一个栈。

预测分析表

  其中预测分析表指导分析过程中候选式的选取。它是一个M[A,a]形式的矩阵,A是非终结符,a是终结符或‘#’,矩阵元素M[A,a]中存放着一条关于A的产生式,指出当A面临输入符号a时所应采用的候选,也可能存放着一个出错标志(如空白格),指出A根本不应该面临输入符号a。对如下文法:
   

    有如下预测分析表:


  这个预测分析表是怎么构造出来的呢?
  首先构造与文法有关的集合FIRST和FOLLOW

构造FIRST集

 首先对每一个文法符号X属于VT∪VN构造FIRST(X),办法是连续使用以下规则,直到每个FIRST不再增大。
1,若X终结符,则FIRST(X)={X}
2,若X为非终结符,且有X->a …的产生式,则把a加入到FIRST(X)中;
3,若X->Y…是一个产生式,且Y为非终结符,则把FIRST (Y)-ε加入到FIRST(X)中;
 若X->Y1Y2Y3….YK,是产生式, Y1Y2Y3….Yi-1是非终结符,而且ε属于 FIRST (Yj)(1<=j<=i-1),则把FIRST (Yj)-ε加入到FIRST(X)中;如果ε属于所有的FIRST (Yj),则ε加入到FIRST(X)中

对于上述文法,可以构造出每个非终结符的FIRST集:
从F开始,因为F->(E)|i,由规则2,可得FIRST(F)={(,i},这里注意要关注到F的每条产生式
由T'->*FT'|ε ,由规则2,可得FIRST(T')={*,ε },这里注意对于T'->*FT',已经有*了,就不用管F了
由T->FT',由规则3,可得FIRST(T)=FIRST(F)-{ε }={(,i},这里注意考虑了F就不用考虑T'了
由E'->+TE'|ε ,由规则2,可得FIRST(E')={+,ε}
由E->TE',由规则3,得FIRST(E)= FIRST(T)-{ε}={(,i}


构造FOLLOW集

下面对每个非终结符A构造FLLOW(A),连续使用下面的规则,直到每个FOLLOW不再增大:

1, 对于文法的开始符,置#于FOLLOW(S)中,

2,若A->αBβ, 则把FIRST (β)-ε加入到FOLLOW(B)中,
3,若A->αB 是一个产生式,或 A->αBβ是一个产生式,而β-> ε,则把FOLLOW(A)加入到FOLLOW(B)中

  对上述文法:

 从E开始,由规则1,得FOLLOW(E)={#},又F->(E)|i,由规则2,FOLLOW(E)={#, )}

 对于E‘,由规则3和E->TE',得应将FOWLLOW(E)加入FOLLOW(E')中,FOLLOW(E’)={#, )}

 对于T,有E'->+TE'|ε,由规则2,应将FIRST(E')-{ε}加到FOLLOW(T)中,FOLLOW(T)={+},又由规则3和E'->+TE',由于FIRST(E')包含 ε,应把FOLLOW(E')加入到FOLLOW(T)中,FOLLOW(T)={+, ), #}

  对于T',由T->FT'和规则3,应把FOLLOW(T)包含到FOLLOW(T'),FOLLOW(T’)= FOLLOW(T)= {+,),#}  
 对于F,由T'->*FT'|ε和规则3,应把FOLLOW(T')包含到FOLLOW(F),同时由规则2,应把FIRST(T')-{ε}包含到FOLLOW(F),FOLLOW(F)={*, + , ), #}
 


 对上述文法,还要知道FIRST集合不光是对单个非终结符,对符号串也能构造FIRST集,规则是:对符号串α=X1X2...Xn,首先置FIRST(α)=FIRST(X1)\{ε };

若对任何1<=j<=i-1,ε ∈FIRST(Xj),则把FIRST(Xi)\{ε }加入到FIRST(α);

特别是,若所有的FIRST(Xj)均含有ε,1<=j<=n,则把,ε 也加至FIRST(α);
显然,若α=ε则FIRST(α)={ε}

对上述文法,我们总结一下成果

文法      E→TE’     
      E’→+TE’|ε 
      T→FT’   
      T’→*FT’|ε    
      F→(E)|i

FIRST(F)={ (,i }
FIRST(T’)={*,ε}
FIRST(T)={ (,i}
FIRST(E’)={+,ε}
FIRST(E)= {(,i}

FOLLOW(E)={#, )}
FOLLOW(E’)={#, )}
FOLLOW(T)={+, ), #}
  FOLLOW(T’)=  {+,),#} 
FOLLOW(F)={*, + , ), #}

下面我们求符号串的FIRST集:


FIRST(TE’)=FIRST(T)-{ε}={(,i}

  FIRST(+TE’)={+}

   FIRST(FT’)= FIRST(F)-{ε}={(,i}


 FIRST(*FT’)={*} 

FIRST((E))={(}  

FIRST(ε)={ε}

 FIRST(i)={i}

  到此,就可以构造预测分析表了,规则如下:对文法G的每个产生式A->α:对每个终结符a,如果a属于FIRST(α),则把该产生式写入到M[A,a];
若ε属于FIRST(α),则对任何b属于FOLLOW(A), 把该产生式加入到M[A,b]


对 E→TE’,因为FIRST(TE’)={(,i} ,则把该式写进M[E,i]和M[E,(]


对 E’→+TE’|ε ,因为FIRST(+TE’)={+} ,FIRST(ε)={ε} ,FOLLOW(E’)={#, )}则把E’→+TE’写进M[E',+];把E'->ε 写进M[E',)]和M[E',#]

对T→FT’,因为FIRST(FT’)={(,i} ,则把T→FT’写进M[T,(]和M[T,i]

对T’→*FT’|ε    ,因为FIRST(*FT’)={*}  ,FIRST(ε)={ε} ,FOLLOW(T’)=  {+,),#}  则把T’→*FT’写进M[T',*],;把T'->ε 写进M[T',+],M[T',)]和M[T',#]

 对 F→(E)|i,因为FIRST((E))={(}  ,FIRST(i)={i},则把F->(E)写进M[F,(],把F->i写进M[F,i]

这样就构造了如上的预测分析表。


用于存放文法符号,栈底有一个‘#’,输入串之后也有一个'#'

预测分析程序任何时候都是按栈顶符号X和当前的输入符号a行事的。

分析程序按以下步骤:

(1)若X=a=#,分析成功,停止。E匹配输入串成功.
(2)若X=a≠#,把X推出栈,再读入下一个符号。

(3)若X∈Vn,查分析表M。
    a) M[X,a]=   X→UVW  则将X弹出栈,按WVU顺序进栈
     注:U在栈顶 (最左推导)
   b) M[X, a] = error   转出错处理
   c) M[X, a] = X-〉ε     ---a为X的后继符号
       则将X弹出栈 (不读下一符号) 继续分析。



对于上述文法,输入串为i+i*i#,分析步骤为:

步骤   符号栈          读入符号       剩余符号串         使用规则

1.          #E                    i              +i*i#   


2.          #E’T               i              +i*i#                 E->TE’

3.          #E’T’F          i              +i*i#                 T->FT’

4.          #E’T‘ i          i              +i*i#                 F-> i
5.          #E’T’            +                i*i#          (出栈,读下一个符号)
6.           #E’                +              i*i#                  T->ε
7.         #E’T+              +              i*i#                E->+TE’

8.          #E’T                 i               *i#           

9.         #E’T’F             i               *i #                  T->FT’

10.       #E’T’ i             i                *i#                   F-> i

10.       #E’T’ i             i              *  i#                   F-> i

11.       #E’T’               *                i#        

12.     #E’T’F*              *                i#  
13.    #E’T’F  i             #
14.    #E’T’ i    i           #                                     F-> i
15.      #E’T’               #      
16.      #E’                    #                                      T’->ε
17.      #                         #                                      E’->ε

根据上述原理,有以下课后题:






  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值