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

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):

 

void FindFollowSets(struct lemon *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 );

}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值