[课程设计]LL1 文法分析的实现

  LL1 文法分析的实现

            EmilMatthew ([email protected])       06/07/1 9

[  类别  ]课程设计   

[推荐指数]★★★

[  摘要  ]实现了LL1文法分析的基本功能:消除左递归、构建文法的FirstFollowSelect集、建立分析表并对句子进行分析。

[ 关键词 ]LL1文法, 文法分析

 

                The implementation of LL1 grammar analyzer

[Classify] Curriculum Design  

[  Level ] ★★★

[Abstract] In this article, I realize the basic function of LL1 grammar analyze : eliminate left recursive , construct the grammar’s  first set , follow set and select set, and also construct the analyze table to parse the input sentence.

[Key Words]LL1 grammar, grammar analyze

                                                        

[0引言]

   LL1文法是一种简单易行的,自顶向下的,且较易实现的文法。它的原理在编译原理的书上已有详细叙述,本文着重于介绍其实现过程中的一些细节及思考。

 

[1总体设计思想]

   11文法的表示

   这里采用字符串数组的形式表示文法中的各个项,这样的表示好处在于操作相当直观,缺点是当项目较多时,需要较多的检索时间。

  

   12集合类的设计

   由于初期对集合的操作的复杂认识不足,直接采用其于一维字条符数组的形式来表示first follow集及select集,使得细节处的代码编制较为繁锁,如能采用某类封装好的集合数据类型,如hash等,则可使得内部算法实现较为轻松。

 

   13自动机的实现------GOTO语句的放光

   由于在构建一些有较多情况出现的算法时,用在纸上画出算法对应的自动机是相当方便的。此时,要做的,只是将自动机转化成相应的代码即可。我个人认为,此时是GOTO语句真正有用武之地的一个地方,当自动机的状态多于三个时,用标号结合GOTO语句可以与自动机紧密结合,表达起来相当清晰和简单,如果为了避免用GOTO而改用其它的语句来实现自动机的功能,反而有些得不偿失了。

 

   1.4图算法的应用

   计算first集及follow集时,可以用基于集合扩张的迭代算法,直至没有集合在某次迭代计算中更新即意味着算法结束,过程有些繁锁。不过,用图算法就要轻松多了,不仅意图清晰,而且实现起来也相当容易,最后都会涉及到一个可达性计算,用Floyd算法(O(n^3))可轻松搞定。

  

[2核心算法]

   注:空字符这里用z表示。

2.1消除左递归

   消除左递归时主要经历以下步骤:

a)对文法按推导字母顺序的顺序排列,且将开始符置于数组最前部,这里采用冒泡算法。

b)查看文法是否含有左递归,如果没有,则终止。

c)准备两个字符串数组:tweenStrArrtmpGrammerArrtweenStrArr用以

存放每一个非终止符作为左侧推导项时临时分析结果,tmpGrammerArr则用以存放去除左递归后的文法。

  

接下来即可进行消除左递归的过程,核心算法框架如下:

       For each vn in Grammer

              For each item which started by vn’ (vn’ has been operated)

                     If  has vn->vn’a then

                            Replace all vn’ with vn’->beta

                     Endif

              End for

              If(vn has left recursive)

                     Find new sign vnNew

Change      Vn->VnB|A to

                            Vn->A vnNew

                            vnNew->B vnNew

                            vnNew->z                //这里用z代表空

              Else

                     Copy all vn->beta to tmpGrammerArr

              End If

       End for

 

 

2.2first集,follow集及select

   221计算各非终止符是否可推得空

   这个算法较易,框架如下:

   While has un labeled node

              Changed=0

For all the vn if not labled

If has vn->z*     then

                                   produceZ[vn’s pos]=1

                                   replace all vn in grammer ‘s right side with z

                                   Changed=0

End If

              End for

             

              If(changed==0)

                     Label all the unlabeled vn in produceZ with 0

              End If

       End While

 

   222Frist集的计算

   [a]First集采用基于图的算法:

对于形如A->aB的推导式,则连接A->a一条线;(注意a!=z)

对于形如A->B的推导式,则连A->B一条线,

   对于形如A->BC的推导式,如果B->z,则连A->C一条线。

   再则用Floyd算法计算图的各点间的可达性。

   记录First集中的元素。若A->z,则应将z加入First(A)

 

   223Follow集的计算:

   起始符连’#’一条线。

对于形如P->AB 的推导式,连A->First(B)中的所有元素一条线。

   对于形如P->A的推导式,连A->P一条线。

   对于形如P->Aa的推导式,连A->a一条线。

   对于形如P->ABC的推导式,且B->z,则连A->First(C)中所有元素一条线。

   再则用Floyd算法计算图的各点间的可达性。

   记录Follow集中的元素。

 

   224Select集的计算:

   对于形如A->B的式子,且B->z,则加First(B)-zFollow(A)中互异元素至SelectA)中。

   对于形如A->aB的式子,则有Select(A)=a

   记录Select(A)中的元素。

 

 

2.3符号分析表的构建及预测分析程序

   符号分析表的构建较易,是一个填充二维字符串数组的过程。

   而预测分析程序的主框架如下:

   Push(start sign)to analyse Stack

       While(analyse stack is not empty)

       {

              If top(analyse stack ==curChar)

              {

                     Pop analyse stack.

                     Get new curChar

}

Else

{     

find produce started in analyse table:

       rowIndex: top(analyse stack)’s top

       colIndex: curChar’s pos

       if(not founded)

              error

       eles if ->z

              pop analyse stack

       else

              if ->B1B2

              push B2,B1 to analyse stack.

}

}

 

[3]算法实现结果

试验1

文法规则为:(其中,S表示起始字符)

S

S->aH

H->aMd

H->d

M->Ab

M->z

A->aM

A->e

 

需要分析的句子为:

aaabd#

 

经分析程序得到如下结果:

 

==fisrt group condition==:

group S:a,

group A:a,e,

group H:a,d,

group M:a,e,z,

 

==follow group condition==:

group S:#

group A:b

group H:#

group M:bd

======================

 

===output of group select===:

SaH a,

AaM a,

Ae e,

HaMd a,

Hd d,

MAb a,e,

Mz b,d,

================

===output analyse table.===

  a        b        d        e        z        #       

S aH                                                    

A aM                         e                         

H aMd               d                                  

M Ab       z        z        Ab                        

==========================

===parse setence : aaabd# ===

s   analyseStack   unParseSetence op   

  0 #S            aaabd#        S->aH

  1 #Ha           aaabd#        a matched.

  2 #H            aabd#         H->aMd

  3 #dMa          aabd#         a matched.

  4 #dM           abd#          M->Ab

  5 #dbA          abd#          A->aM

  6 #dbMa         abd#          a matched.

  7 #dbM          bd#           M->z

  8 #db           bd#           b matched.

  9 #d            d#            d matched.

parse successfully.

 

试验2

文法规则为:(E表示起始字符)

E

E->E+T

E->T

T->T*F

T->F

F->i

F->(E)

 

需要分析的句子为:

i*(i+i*i)#

 

则得到的分析表及其分析过程如下:

==output analyse table.==

  (        )        *        +        i        z        #       

E TA                                  TA                        

A          z                 +TA                        z       

B          z        *FB      z                          z       

F (E)                                 i                         

T (E)B                                iB                        

==parse setence : i*(i+i*i)# ==

s   analyseStack   unParseSetence op   

  0 #E            i*(i+i*i)#    E->TA

  1 #AT           i*(i+i*i)#    T->iB

  2 #ABi          i*(i+i*i)#    i matched.

  3 #AB           *(i+i*i)#     B->*FB

  4 #ABF*         *(i+i*i)#     * matched.

  5 #ABF          (i+i*i)#      F->(E)

  6 #AB)E(        (i+i*i)#      ( matched.

  7 #AB)E         i+i*i)#       E->TA

  8 #AB)AT        i+i*i)#       T->iB

  9 #AB)ABi       i+i*i)#       i matched.

 10 #AB)AB        +i*i)#        B->z

 11 #AB)A         +i*i)#        A->+TA

 12 #AB)AT+       +i*i)#        + matched.

 13 #AB)AT        i*i)#         T->iB

 14 #AB)ABi       i*i)#         i matched.

 15 #AB)AB        *i)#          B->*FB

 16 #AB)ABF*      *i)#          * matched.

 17 #AB)ABF       i)#           F->i

 18 #AB)ABi       i)#           i matched.

 19 #AB)AB        )#            B->z

 20 #AB)A         )#            A->z

 21 #AB)          )#            ) matched.

 22 #AB           #             B->z

 23 #A            #             A->z

parse successfully.

 

   以上两个试验从较大呈度上说明了程序运行的正确性及稳定性,当然,对程序本身还有待进行更进一步的严格测试,也欢迎诸位需要此程序的朋友们在抓到BUG时能告知于我,谢谢。

 

[参考文献与网站]

[1] 吕映芝,编译原理,清华大学出版社,2004.

 

[源码下载]

http://emilmatthew.51.net/EmilPapers/0626LL1Grammer/code.rar

 

若直接点击无法下载(或浏览),请将下载(或浏览)的超链接粘接至浏览器地( 推荐MYIEGREENBORWSER)址栏后按回车.若不出意外,此时应能下载.

若下载中出现了问题,请参考:

http://blog.csdn.net/emilmatthew/archive/2006/04/08/655612.aspx

你可能感兴趣的:(框架,算法,table,basic,each,output)