LEMON源码分析——项目FOLLOW集求法

来源:互联网 发布:免费刷炫舞装备软件 编辑:程序博客网 时间:2024/05/29 21:36

LEMON源码分析——项目FOLLOW集求法

都知道FOLLOW集是针对非终结符的,而LEMON中的项目FOLLOW是针对项目的,指的是项目产生式左部非终结符FOLLOW

 

知道了项目FOLLOW集,它的求法也自然清楚了。这里把项目分成两类,它们的FOLLOW集来源是不一样的:

A.   号点不在最左的项目,FOLLOW集来源于生产式相同,点号在它前面的项目。

B.    点号在最左的项目,FOLLOW集就是生产式左部非终结符FOLLOW集。

 

非终结符FOLLOW集的计算方法:

1.       对于方法的开始符S,将用于表示输入结束的’$’符放入FOLLOW(S)中;

2.   A->αBβ是一个产生式,则把FIRST(β)/{ε}加至FOLLOW(B)中;

3.   A->αB是一个产生式,或A->αBβ是一个产生式,且β->ε,则把FOLLOW(A)加至FOLLOW(B)中。

 

以状态项目的生成过程介绍项目FOLLOW集的计算。

开始状态中的所有项目都是B类型项目,于是计算开始符FOLLOW集,也就是方法1,对就代码为(FindStates:

 

    for(rp=sp->rule;rp; rp=rp->nextlhs)

    {

        struct config *newcfp;

        rp->lhsStart = 1;

        newcfp = Configlist_addbasis(rp,0);

        SetAdd(newcfp->fws,0);//第一个符号为$

    }

 

对当前状态中的项目进行closure运算,也就是要产生B类的项目,此时运用方法2与方法3计算,对应代码(Configlist_closure函数中):

 

for(newrp=sp->rule;newrp; newrp=newrp->nextlhs)

{

newcfp =Configlist_add(newrp,0);//生成B型项目

for(i=dot+1;i<rp->nrhs;i++)

{

    xsp = rp->rhs[i];

    if( xsp->type==TERMINAL )

    {

         SetAdd(newcfp->fws,xsp->index);//运用方法2

         break;

    }

    else if( xsp->type==MULTITERMINAL )

    {

         ...

    }

    else

    {

         SetUnion(newcfp->fws,xsp->firstset);//运用方法2

         if( xsp->lambda==LEMON_FALSE )break;

    }

}

if(i==rp->nrhs )Plink_add(&cfp->fplp,newcfp);//运用方法3

}

 

运用方法3时,并没有进行真正的FOLLOW拷贝,而只是做了一个记录,在后面一起“结账”。这里也可以看出,config会将自己的FOLLOW集传给自己的fplp域。

求完闭包后,就开始传播了,传播产生A型项目。些时的FOLLOW集,直接由上级往下传就行了。代码位于函数buildshifts中:

 

for(bcfp=cfp;bcfp; bcfp=bcfp->next)

{

if(bcfp->status==COMPLETE )continue;    /* Already used */

if(bcfp->dot>=bcfp->rp->nrhs )continue; /* Can't shift this one */

bsp =bcfp->rp->rhs[bcfp->dot];          /* Get symbol after dot */

if( !same_symbol(bsp,sp) )continue;      /* Must be same as for "cfp"*/

bcfp->status =COMPLETE;                  /* Mark this config as used */

new =Configlist_addbasis(bcfp->rp,bcfp->dot+1);

Plink_add(&new->bplp,bcfp); //A型项目FOLLOW集计算方法

}

 

这里也只是做了个标记,并没有真正传播FOLLOW集。从Plink_add(&new->bplp,bcfp);可以看出bplp暂存着可以将FOLLOW集传播给本项目的项目。

最后将标记转换成实际上的传播。

首先,把bplp转换为fplpFindLinks):

 

for(i=0;i<lemp->nstate;i++)

{

stp =lemp->sorted[i];

for(cfp=stp->cfp;cfp; cfp=cfp->next)//遍历每个状态的所有项目

{

    for(plp=cfp->bplp;plp; plp=plp->next)

    {

         other = plp->cfp;

         Plink_add(&other->fplp,cfp);

    }

}

}

 

再将项目的FOLLOW集,传给它的fplpFindFollowSets):

 

voidFindFollowSets(structlemon *lemp)

{

...

do

{

    progress = 0;

    for(i=0; i<lemp->nstate;i++)//遍历所有状态

    {

         for(cfp=lemp->sorted[i]->cfp;cfp; cfp=cfp->next)//遍历状态内所有项目

         {

              if( cfp->status==COMPLETE )continue;

              for(plp=cfp->fplp;plp; plp=plp->next)

              {

                  change = SetUnion(plp->cfp->fws,cfp->fws);

                  if( change )

                  {

                       plp->cfp->status =INCOMPLETE;

                       progress = 1;

                  }

              }

              cfp->status =COMPLETE;

         }

    }

}

while(progress );

}

 

原创粉丝点击