个人笔记——消除无用符号·消除空产生式·消除单一产生式·消除左递归

消除无用符号

消除无用符号算法:
对于任意上下文无关文法G=(V,T,P,S),w∈L(G),X∈V,若存在a,b∈(VUT)*使得S经过若干步推出aXb,aXb经过若干步推出w,则称X为有用符号,否则为无用符号。

  1. 首先计算“产生的”符号集N:每个T中的符号都是产生的,若A→a∈P且a中符号都是产生的,则A是产生的。
    伪代码:
for (int i=0;i<V.num;i++)
     for(int j=0;j<v.num;j++)//v表示V的拷贝
        if(p中存在v[j] →a&&a中的每个符号都属于N)
          {将v[j]从v中删除并加到N中,同时跳出内层循环}
  1. 接着计算“可达的”符号集M:开始符号S是可达的,A→a∈P且A是可达的,则a中的符号都是可达的。
    伪代码:
Reach(S){
       if(P中存在S→a)
            {将a中的所有字符加入到M中,
                if(a中存在非终结符B)
                  Reach(B)}
      return }
  1. 最后先消除全部非“产生的”符号,在消除全部非“可达的”符号,剩下的都是有用符号。最后将无用字符和无用产生式都删除
    伪代码:
for(int i=0;i<Q.num;i++){//Q是VUT的集合
     for(int j=0;j<N.num;j++){
         if(Q[i]不在N中)
            将其加入到非“产生的”符号集N1中}} 
//  消除全部非“可达的”符号
for(int i=0;i<N1.num;i++){
   for(int j=0;j<M.num;j++){
      if(N1[i]不在M中)
         将其加入到无用符号集NM中}}
//消除产生式和无用符号,因结构类似只写了一个
for(int i=0;i<P.num;i++){
    if(P[i]个产生式中含有NM符号集的元素)
        将该条产生式删除}}

注意产生集和可达集不能颠倒顺序,否则会消除不干净

消除空产生式

消除ε产生式:称形如A→ε的产生式为ε产生式。
思路:

  1. 由文法推出满足定义(A∈V,且A能在有限步推出ε)的非终结符集合V1。
伪代码:for(int i=0;i<V.num;i++)
           for(int j=0;j<V.num;j++){
              if(左部为V[i]的产生式右部所有符号都在V1中)
                  将V[i]加入V1中,跳出内层循环;
  1. 若产生式B→a0B1…Bkak∈P,其中aj∈(VUT)*,Bi∈V1,那么用ε和Bi本身代替Bi。然后将这些产生式都加入到新的产生式集合中,不满足上述产生式的直接将空产生式扣除后加入到新产生式集合中。若有S→ε,则引入S|→ε|S。S|为新的开始符号。
伪代码:for(int i=0;i<P.num;i++)
          if(存在产生式B→a0B1...Bkak∈P,aj∈(VUT)*,Bi∈V1)
             以Bi或者空代替Bi,并将形成的产生式加入到P|中;
          else if(产生式左部属于V1)
                将ε产生式去除后将其加入P|中;            
          else if(若有S→ε)
           引入S|→ε|S。S|为新的开始符号;}

消除单一产生式

思路:如果存在产生式A→B,则将B作为A的子节点加入图集合X中,若存在B→C,则同样将C作为B的子节点加入到X中。所有的非终结符都进行这样的处理,然后对图集合X进行遍历,所有子节点加入到祖宗节点的链集合中,比如A的子节点有B、C、D,则将B、C、D加入A的链集合中。对于每个非终结符的链集合中若存在非终结符(假设为B),且B→w属于P ,w不属于V,则将A→w加入到P|中。遍历所有的链集合后便完成了单一产生式的消除。

伪代码:
for(int i=0;i<P.num;i++)
  if(存在单一产生式(A→B))
将B作为A的子节点加入到图中;
遍历图找到每个非终结符的链集合;
遍历每个非终结符的链集合:
如果非终结符的链集合不为空(例如B在A的链集合中):
    且B→w属于P,w不属于V;
     将A→w加入到P|中;
如果非终结符的链集合为空则不进行处理。

消除左递归

消除左递归:间接左递归和直接左递归。首先消除间接左递归,转化为直接左递归,在消除所有的直接左递归。

1.消除直接左递归:形如A→Aa。
对于A→Aa|b(b可为空)。因为推导结束后一定有个b在开始位置,故改为:A→bB,B→aB。

2.消除间接左递归:形如:P→Aa,A→Pb。
首先对所有的非终结符进行随机编号排序。
1)若消除过程中出现了直接左递归,就按照直接左递归的方法,来消除。
2)若产生式右部最左的符号是非终结符,且这个非终结符序号大于等于左部非终结符,则暂不处理(后面会处理到)
3)若序号小于左部的非终结符,则用之前求到的式子的右部来替换

伪代码:
所有非终结符按任意顺序排列编号[V1,…,Vn]
按上面的排列顺序,对这些非终结符进行遍历
for(int i = 1; i <= n; ++i) {
  for(int j = 1; j <= n - 1; ++j) {
     遍历产生式,若V[j]序号小于等于产生式右部非终结符按规则3)
     进行替换(序号大于的按规则2)处理) }
  消除i序号的非终结符的直接左递归(如果存在的话)
}
这里需要注意的是,消除左递归后会产生空产生式和无用符号,
所以消除左递归后需要在将空产生式和无用符号处理一遍。
  • 4
    点赞
  • 32
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值