消除文法的左递归

来源:互联网 发布:pkpm网络计划软件下载 编辑:程序博客网 时间:2024/04/30 23:09
#include<stdio.h>#include<string.h>typedef struct{char right[20];//产生式右部}Right;typedef struct{char left;  //产生式的左部Right r[100];int flag;//标志位,判断该产生式是否存在左递归,0表示无左递归,1表示直接左递归,2表示间接左递归int num;//右部的产生式的个数int ko;//特殊标志位,只判断有无间接左递归}regular;regular re[100];typedef struct{char lz;//非终结符int hh;//标志位,用来标识该条产生式是否已规约过}lfz;lfz l[100]={0,0};//存放左部非终结符int main(){int n; //产生式的个数(不包括/)printf("请输入产生式的个数(以第一个产生式的左部为文法的开始符):\n");scanf("%d",&n);getchar();int i;for(i=0;i<n;i++){scanf("%c",&re[i].left);getchar();getchar();//消掉->re[i].num=1;//右部的产生式的个数int t=0; //表示右部的第几个产生式int tt=0;//表示右部第t个产生式的第几个字符while(1){scanf("%c",&re[i].r[t].right[tt]);if(re[i].r[t].right[tt]=='\n')break;if(re[i].r[t].right[tt]=='/'){re[i].r[t].right[tt]='\0';t++;re[i].num++;tt=-1;}tt++;}re[i].r[t].right[tt]='\0';re[i].flag=0;re[i].ko=0;}//把一个产生式输入进来printf("\n\n");//看是否存在间接左递归for(i=0;i<n;i++){l[i].lz=re[i].left;}int bz1,flgoo;//用来标识右部产生式中是否含有非终结符是其他产生式的左部for(i=0;i<n;i++){int q1,q2,q3;while(1){flgoo=0;for(q2=0;q2<re[i].num;q2++){//对于右部的每个产生式,查看是否有其他产生式的非终结符bz1=0;for(q1=0;q1<n;q1++){if(re[i].r[q2].right[0]==l[q1].lz&&l[q1].hh==0&&re[i].left!=l[q1].lz){bz1=1;break; }}if(q1==n)flgoo++;//若右部产生式含有其他产生式的非终结符,则处理之    if(bz1==1){re[i].ko=1;int len2=strlen(re[i].r[q2].right);int q4;char qq[100]={0};//存放右部产生式除(与左部非终结符一样的首位字符)外for(q4=1;q4<len2;q4++){qq[q4-1]=re[i].r[q2].right[q4];}for(q3=0;q3<re[q1].num;q3++){//将字符串插入到指定位置char yy[100];//用来存放目标端的数据int len1=strlen(re[q1].r[q3].right);strcpy(yy,re[q1].r[q3].right);strncat(yy,qq,len2-1);if(q3==0){strncpy(re[i].r[q2].right,yy,len1+len2-1);}else {strncpy(re[i].r[re[i].num].right,yy,len1+len2-1);        re[i].num++;}}}}if(flgoo==re[i].num){l[i].hh=1;break;}//当flgoo==re[i].num时,说明本条产生式不含有其他产生式的非终结符}}//用来查看不含有左递归的产生式是否多余int q8,a2,a1;for(q8=0;q8<re[0].num;q8++){a1=strlen(re[0].r[q8].right);for(a2=0;a2<a1;a2++){int a3;for(a3=1;a3<n;a3++){if(re[0].r[q8].right[a2]==l[a3].lz){re[a3].flag=5;break;}}}}//消除直接左递归for(i=0;i<n;i++){int p=0;int bz[100]={0};//标志对应的右部产生式第一个字符是否有与左部符号一样,一样为1,否则为0int uu=0;//用来计数右部产生式中有多少个不含有左部符号for(;p<re[i].num;p++){if(re[i].r[p].right[0]==re[i].left){re[i].flag=1;bz[p]=1;if(re[i].ko==1)re[i].flag=2;}else uu++;}if(re[i].flag==1||re[i].flag==2){printf("%c->",re[i].left);for(p=0;p<re[i].num;p++){if(bz[p]==0){printf("%s%c'",re[i].r[p].right,re[i].left);if(uu!=1){printf("/");uu--;}else printf("\n");}}}//输出不含左部符号的右部产生式for(p=0;p<re[i].num;p++){if(bz[p]==1){printf("%c'->",re[i].left);int kk;for(kk=1;kk<strlen(re[i].r[p].right);kk++)printf("%c",re[i].r[p].right[kk]);printf("%c'/ε\n",re[i].left);}}//输出含有左部符号的右部产生式if(re[i].flag==1)printf("这是一个直接左递归!!!\n\n");if(re[i].flag==2)printf("这是一个间接左递归!!!\n\n");//存在左递归的产生式}//输出不存在左递归的产生式int oo=0,uu=0;for(i=0;i<n;i++){if(re[i].flag==0)oo++;}if(oo==n){uu=1;printf("该文法不存在左递归!!!\n");}for(i=0;i<n;i++){if(re[i].flag==5||uu==1){int p1;printf("%c->",re[i].left);for(p1=0;p1<re[i].num-1;p1++){printf("%s/",re[i].r[p1].right);}if(p1==re[i].num-1)printf("%s\n",re[i].r[p1].right);}}return 0;}

原创粉丝点击