消除文法左递归的算法

存储文法的数据结构

 1 typedef struct P{
 2     char key;           // 产生式左部
 3     char * value [16];  // 产生式右部
 4     int count;          // 几组规则
 5 }P;
 6 typedef struct G{
 7     char * vn ;     // 非终结符集合
 8     char * vt ;     // 终结符集合
 9     P   p[16];      // 产生式
10     char start;     // 开始符号
11     int pcount ;
12 }G;

文法G由多条产生式组成,出现在产生式左部的非终结符,会指向一个P文法数组,每一个数组元素对应一个程式的右部,这样的结构显然是对文法进行了压缩的

算法过程

1、 扫描文法,先将间接做递归转换成直接左递归

2、 借助如下公式,消除直接左递归

对形如这样的程式

A->Aα1|Aα2|Aα3| Aαn|..|ρ1|ρ2|….| ρn

转换成如下形式

A->ρ1A'|ρ2A'|ρ3A'

A'->α1A'|α2A'|....|ε

输入

1 3
2 2 S Qc|c
3 2 Q Rb|b
4 2 R Sa|a

完整算法

  1 #include <stdio.h>
  2 #include <malloc.h>
  3 #include <string.h>
  4 
  5 typedef struct P{
  6     char key;           // 产生式左部
  7     char * value [16];  // 产生式右部
  8     int count;          // 几组规则
  9 }P;
 10 typedef struct G{
 11     char * vn ;     // 非终结符集合
 12     char * vt ;     // 终结符集合
 13     P   p[16];      // 产生式
 14     char start;     // 开始符号
 15     int pcount ;
 16 }G;
 17 
 18 int main(){
 19     int i,n;
 20     freopen("xczdg.in","r",stdin);
 21     printf("Plese input P count :");
 22     scanf("%d",&n);
 23     printf("\n");
 24     G g;
 25     g.pcount = n;
 26     //g.p = (P *)malloc(sizeof(P)*n);
 27     for(i=0;i<n;i++){
 28         scanf("%d%*c",&g.p[i].count);
 29         g.p[i].key = getchar();
 30         getchar();
 31         char ch,str[255];
 32         int sp = 0,c=0;
 33         while((ch = getchar()) != '\n'){
 34             if('|' == ch){
 35                 str[sp]='\0';
 36                 g.p[i].value[c] = (char *) malloc(sizeof(char)*255);
 37                 strcpy(g.p[i].value[c],str);
 38                 sp = 0;
 39                 c++;
 40             }
 41             else{
 42                     str[sp] = ch;
 43                     sp++;
 44             }
 45         }
 46         str[sp]='\0';
 47         g.p[i].value[c] = (char *) malloc(sizeof(char)*255);
 48         strcpy(g.p[i].value[c],str);
 49 
 50         printf("%c=>%s|%s\n",g.p[i].key,g.p[i].value[0],g.p[i].value[1]);
 51     }
 52 
 53     for(i=0;i<n;i++){
 54         int j = 0;
 55         for(;j<i;j++){
 56             // 将间接左递归转换成直接左递归
 57             // 扫描Ai的开始符号,一定要是非终结符
 58             int k;
 59             for(k=0;k<g.p[i].count;k++){
 60                 char i_start = g.p[i].value[k][0];
 61                 //printf("%c\n",start);
 62                 if(i_start==g.p[j].key){
 63                     // 满足 Ai->Ajr
 64                     char tmp[255];
 65                     char fiel[255];
 66                     strcpy(fiel,&g.p[i].value[k][1]);
 67 
 68                     strcpy(tmp,g.p[j].value[0]);
 69                     strcpy(g.p[i].value[k],strcat(tmp,fiel));
 70                     printf("%d %s\n",k,g.p[i].value[k]);
 71                     int m;
 72                     for(m=1;m<g.p[j].count;m++){
 73                         strcpy(tmp,g.p[j].value[m]);
 74                         g.p[i].value[g.p[i].count] = (char *) malloc(sizeof(char)*255);
 75                         strcpy(g.p[i].value[g.p[i].count],strcat(tmp,fiel));
 76                         printf("%d %s\n",g.p[i].count,g.p[i].value[g.p[i].count]);
 77                         g.p[i].count++;
 78 
 79                     }
 80                 }
 81 
 82             }
 83         }
 84         // 消除直接左递归
 85         // 扫描Pi.key 为产生式右部的所有产生式
 86         for(j=0;j<g.p[i].count;j++){
 87             char * pivj = g.p[i].value[j];
 88             if(g.p[i].key == pivj[0]){
 89                 // 存在直接左递归
 90                 int m;
 91                 for(m=0;m<g.p[i].count;m++){
 92                     if(m!=j){
 93                         // A->ρ1A'|ρ2A'|ρ3A'    ρρσσαα
 94                         char aci[2] = {g.p[i].key-32,'\0'};
 95                         strcat(g.p[i].value[m],aci);         // 这里A'直接已A的ASCII码值减32表示
 96                     }else{
 97                         // A'->α1A'|α2A'|....|ε
 98                         g.p[g.pcount].key = g.p[i].key-32;
 99                         g.p[g.pcount].value[0] = (char *) malloc(sizeof(char)*255);
100                         strcpy(g.p[g.pcount].value[0],&pivj[1]);
101                         char aci[2] = {g.p[g.pcount].key,'\0'};
102                         strcat(g.p[g.pcount].value[0],aci);
103                         g.p[g.pcount].value[1] = (char *) malloc(sizeof(char)*255);
104                         strcpy(g.p[g.pcount].value[1],"kong");
105                         g.p[g.pcount].count = 2;
106                         g.p[i].value[j] = NULL;
107                         g.pcount++;
108                     }
109                 }
110                 break;
111             }
112         }
113 
114     }
115 
116     printf("\n-----------------------\n");
117     // 打印文法
118     for(i=0;i<g.pcount;i++){
119         if(g.p[i].key){
120             if(g.p[i].key) printf("%c=>",g.p[i].key);
121             int j;
122             for(j=0;j<g.p[i].count;j++){
123                 if(g.p[i].value[j]) printf("%s ",g.p[i].value[j]);
124             }
125             printf("\n");
126         }
127     }
128     free(g.p);
129     return 0;
130 }

运行结果

(这里用2代替R',用kong代表空字符)

消除文法左递归的算法

 

 

 

上一篇:SQL SERVER TRANSACTION 事物


下一篇:数据结构KMP算法配图详解(超详细)