安徽工业大学编译原理实验报告.doc
《安徽工业大学编译原理实验报告.doc》由会员分享,可在线阅读,更多相关《安徽工业大学编译原理实验报告.doc(19页珍藏版)》请在咨信网上搜索。
编译原理实验报告 姓名:叶玉虎 班级:计122班 指导老师:王森玉 实验日期:2015/5/11 实验内容: 1.求出每个非终结符的FIRST集合 2.求出每个产生式右部的FIRST集合 3.求出每个非终结符的Follow集合 实验环境: Visual Studio2010 实验目的: 让同学们掌握FIRST集合和FOLLOW集合的求法 实验代码: #include<stdio.h> #include<string.h> #define MAX 50 char css[MAX][MAX];//保存所有的产生式 int count=0; int cnt=0; struct L{//保存所有的终结符 char ch; int flag;//1:能推出ε,0:不能,初值:-1 int num; char first[MAX]; int s;//first的长度 char follow[MAX]; int l;//follow的长度 }l[MAX]; //对输入的格式进行控制,并校验输入是否符合格式 int handle(char a[]) { int len,i=0,j,k; len=strlen(a); while(a[i]!=10) { if(a[i]=='$') return 2; if((' '==a[i])||(9==a[i])) { i++; continue; } if((a[i]>='A')&&(a[i]<='Z')) { if((a[i+1]!='-')||(a[i+2]!='>')) { printf("产生式格式错误\n"); return -1; } else { j=i; k=0; while((a[j]!=' ')&&(a[j]!=9)&&(a[j]!='$')&&(a[j]!=10)) { if(a[j]=='|') { css[count][k]='\0'; count++; if((a[j+1]==' ')||(a[j]==9)||(a[j]=='$')||(a[j]==10)) { printf("产生式格式错误\n"); return 0; } css[count][0]=a[i]; css[count][1]=a[i+1]; css[count][2]=a[i+2]; k=3; j++; continue; } css[count][k]=a[j]; k++; j++; } css[count][k]='\0'; i=j; count++; } } else { printf("产生式格式错误\n"); return -1; } } return 0; } //从键盘获得输入 int input() { char a[MAX*MAX]; int v; printf("输入产生式,产生式之间以空格回车或Tab键分隔,并以$键结束.\n"); printf("用@表示虚拟符号ε,终结符用大写字母表示,其他字符表示非终结符\n"); while(1) { fgets(a,MAX*MAX,stdin); v=handle(a); if(v==-1) return -1; if(v==2) return 0; } } //求出能推出ε的非终结符 void seekEmpty() { int i,j,k,t; int flag=0,flag2=0; int len,c; char a[MAX][MAX],ch; for(i=0;i<count;i++) { strcpy(a[i],css[i]); } //求出含有的非终结符的个数,并把各终结符保存起来 for(i=0;i<count;i++) { for(j=0;j<cnt;j++) { if(l[j].ch==a[i][0]) { l[j].num++; flag=1; break; } else flag=0; } if((!cnt)||(!flag)) { l[cnt].ch=a[i][0]; l[cnt].flag=-1; l[cnt].num=1; l[cnt].s=0; l[cnt].l=0; cnt++; flag=1; continue; } } c=count; while(c) { for(i=0;i<c;i++) { //如果该终结符推出ε,从a[]中删除所有带有该终结符的产生式 if(a[i][3]=='@') { ch=a[i][0]; for(j=0;j<c;j++) { if(ch==a[j][0]) { if(j!=c-1) { for(k=j;k<c-1;k++) strcpy(a[k],a[k+1]); c--; j--; } else { c--; j--; } } } for(j=0;j<cnt;j++) { if(ch==l[j].ch) { l[j].flag=1; break; } } i--; continue; } len=strlen(a[i]); for(j=3;j<len;j++) { //当该产生式右边含有非终结符时从a[]中删除该条记录 if((a[i][j]<'A')||(a[i][j]>'Z')) { flag2=1; break; } } if(flag2) { for(k=0;k<cnt;k++) { if(a[i][0]==l[k].ch) { l[k].num--; if(l[k].num==0) l[k].flag=0; break; } } if(i!=c-1) for(k=i;k<c-1;k++) { strcpy(a[k],a[k+1]); } c--; i--; flag2=0; continue; } //如果产生式右边为非终结符看看该终结符能不能推出ε for(j=3;j<len;j++) { if((a[i][j]>='A')&&(a[i][j]<='Z')) { for(k=0;k<cnt;k++) { if(a[i][j]==l[k].ch) { if(l[k].flag==0) { flag2=1; break; } else if(l[k].flag==1) { for(t=j;t<len-1;t++) a[i][t]=a[i][t+1]; a[i][len-1]='\0'; j--; len--; break; } break; } } if(flag2) break; } } if(a[i][3]=='\0') { ch=a[i][0]; for(j=0;j<c;j++) { if(ch==a[j][0]) { if(j!=c-1) { for(k=j;k<c-1;k++) strcpy(a[k],a[k+1]); c--; j--; } else { c--; j--; } } } i--; for(k=0;k<cnt;k++) { if(ch==l[k].ch) { l[k].flag=1; break; } } } if(flag2) { for(k=0;k<cnt;k++) { if(a[i][0]==l[k].ch) { l[k].num--; if(l[k].num==0) l[k].flag=0; } } if(i!=c-1) for(k=i;k<c-1;k++) { strcpy(a[k],a[k+1]); } c--; i--; flag2=0; continue; } } } } //求每个非终结符的First集合 void seekFirstVn() { int i,j,k,t,t1,t2,c,item; int len,s,flag=0,flag2=0,fchange; char a[MAX][MAX],ch[MAX]; for(i=0;i<count;i++) { strcpy(a[i],css[i]); } c=count; while(1) { fchange=0; for(i=0;i<c;i++) { //右部为ε,将ε并入到左部的First中 if(a[i][3]=='@') { /*for(j=0;j<cnt;j++) { if(l[j].ch==a[i][0]) { for(k=0;k<l[j].s;k++) if(l[j].first[k]==a[i][3]) { flag=1; break; } if(!flag) { l[j].first[l[j].s]=a[i][3]; l[j].s++; l[j].first[l[j].s]='\0'; fchange=1; break; } flag=0; } }*/ //从当前列表a[]中删除 if(i!=c-1) for(j=i;j<c-1;j++) strcpy(a[j],a[j+1]); c--; i--; continue; } len=strlen(a[i]); //产生式右边符号为终结符时,将该终结符并入到左部的First集合中 for(j=3;j<len;j++) { if((a[i][j]<'A')||(a[i][j]>'Z')) { for(k=0;k<cnt;k++) { if(a[i][0]==l[k].ch) { for(t=0;t<l[k].s;t++) { if(a[i][j]==l[k].first[t]) { flag=1; break; } } if(!flag) { l[k].first[l[k].s]=a[i][j]; l[k].s++; l[k].first[l[k].s]='\0'; fchange=1; } flag=0; break; } } //从a[][]中删除该条产生式 if(i!=c-1) for(k=i;k<c-1;k++) strcpy(a[k],a[k+1]); c--; i--; break; } //产生式右边符号为非终结符时 else if((a[i][j]>='A')&&(a[i][j]<='Z')) { /*将该非终结符的FIRST集合除去ε并入到当前 非终结符的FIRST集合中*/ for(k=0;k<cnt;k++) { if(a[i][j]==l[k].ch) { for(t=0;t<cnt;t++) { if(a[i][0]==l[t].ch) { for(t1=0;t1<l[k].s;t1++) { for(t2=0;t2<l[t].s;t2++) { if(l[k].first[t1]==l[t].first[t2]) { break; } } if((t2==l[t].s)&&(l[k].first[t1])!='@') { fchange=1; l[t].first[l[t].s]=l[k].first[t1]; l[t].s++; l[t].first[l[t].s]='\0'; } } break; } } break; } } if(l[k].flag) continue; else break; } } } if(!fchange) { for(i=0;i<cnt;i++) { if(l[i].flag) { l[i].first[l[i].s]='@'; l[i].s++; l[i].first[l[i].s]='\0'; } printf("FIRST(%c): %s\n",l[i].ch,l[i].first); } printf("\n"); break; } } } //求产生式右部的First集合 void seekFirstRight() { struct Right{ char a[MAX]; char first[MAX]; int s; }r[MAX]; int i,j,k,t; int cnt=0,len,len1,flag=0; for(i=0;i<count;i++) { for(j=0;j<cnt;j++) { if(!strcmp(css[i]+3,r[j].a)) { flag=1; break; } } if(flag) { flag=0; continue; } strcpy(r[j].a,css[i]+3); r[j].s=0; cnt++; } for(i=0;i<cnt;i++) { len=strlen(r[i].a); for(j=0;j<len;j++) { //遇到终结符 if(r[i].a[j]=='@') { r[i].first[r[i].s]='@'; r[i].s++; r[i].first[r[i].s]='\0'; break; } else if((r[i].a[j]<'A')||(r[i].a[j]>'Z')) { r[i].first[r[i].s]=r[i].a[j]; r[i].s++; r[i].first[r[i].s]='\0'; break; } else { for(k=0;k<cnt;k++) { if(r[i].a[j]==l[k].ch) { len1=strlen(l[k].first); for(t=0;t<len1;t++) { if(l[k].first[t]!='@') { r[i].first[r[i].s]=l[k].first[t]; r[i].s++; r[i].first[r[i].s]='\0'; } } break; } } if(l[k].flag) { if(j==len-1) { r[i].first[r[i].s]='@'; r[i].s++; r[i].first[r[i].s]='\0'; } continue; } else break; } } } for(i=0;i<cnt;i++) { printf("FIRST(%s): %s\n",r[i].a,r[i].first); } printf("\n"); } //求每个非终极符的Follow集合 void seekFollow() { int i,j,k,t,t1,t2,t3,c=0; int flag=0,len; int fchange;//判断一次循环是否有改动的地方 char a[MAX][MAX],ch[MAX]; for(i=0;i<count;i++) { len=strlen(css[i]); for(j=3;j<len;j++) { if((css[i][j]>='A')&&(css[i][j]<='Z')) { break; } } if(j!=len) { strcpy(a[c],css[i]); c++; } } l[0].follow[l[0].l]='#'; l[0].l++; l[0].follow[l[0].l]='\0'; while(1) { fchange=0; for(i=0;i<c;i++) { len=strlen(a[i]); for(j=3;j<len;j++) { if((a[i][j]>='A')&&(a[i][j]<='Z')) { //判断该非终结符的前一位是否为非终结符,是的话, //将其First集合去ε后并到其前一位非终结符的Follow集合中 if((a[i][j-1]>='A')&&(a[i][j-1]<='Z')) { for(k=0;k<cnt;k++) { if(a[i][j-1]==l[k].ch) { for(t=0;t<cnt;t++) { if(a[i][j]==l[t].ch) { for(t1=0;t1<l[t].s;t1++) { if(l[t].first[t1]=='@') continue; for(t2=0;t2<l[k].l;t2++) if(l[t].first[t1]==l[k].follow[t2]) break; if(t2==l[k].l) { fchange=1; l[k].follow[l[k].l]=l[t].first[t1]; l[k].l++; l[k].follow[l[k].l]='\0'; } } break; } } break; } } } //如果该非终结符是最后一位, //将该产生式左部非终结符的Follow集合 //加入到当前非终结符的Follow集合中. //然后从当前终结符开始向右判断是否为非终结符,是的话,进行相应处理 //循环直到当前非终结符推不出ε或当前为终结符时退出 if(j==len-1) { t3=j; strcpy(ch,a[i]); while(!flag) { if((ch[t3]>='A')&&(ch[t3]<='Z')) { for(k=0;k<cnt;k++) { if(ch[0]==l[k].ch) { for(t=0;t<cnt;t++) { if(ch[t3]==l[t].ch) { for(t1=0;t1<l[k].l;t1++) { for(t2=0;t2<l[t].l;t2++) if(l[k].follow[t1]==l[t].follow[t2]) break; if(t2!=l[t].l) continue; else { fchange=1; l[t].follow[l[t].l]=l[k].follow[t1]; l[t].l++; l[t].follow[l[t].l]='\0'; } } if(l[t].flag) ch[t3--]='\0'; else { flag=1; t3--; } break; } } break; } } } else break; } flag=0; } } //如果当前位为终结符,判断其前一位是否为非终结符 //是的话,将该终结符并到该非终结符的Follow集合中 else { if((a[i][j-1]>='A')&&(a[i][j-1]<='Z')) { for(k=0;k<cnt;k++) { if(a[i][j-1]==l[k].ch) { for(t=0;t<l[k].l;t++) if(a[i][j]==l[k].follow[t]) break; if(t==l[k].l) { fchange=1; l[k].follow[l[k].l]=a[i][j]; l[k].l++; l[k].follow[l[k].l]='\0'; } } } } } } } if(!fchange) { for(i=0;i<cnt;i++) printf("FOLLOW(%c): %s\n",l[i].ch,l[i].follow); break; } } } int main() { int i; if(input()==-1) return -1; seekEmpty(); seekFirstVn(); seekFirstRight(); seekFollow(); return 0; } 实验演示: 因为不知道怎么用电脑输出’ε’符号,我在代码里用’@’来表示 ‘ε’.以‘$’来结束输入 测试数据1: S->MH|a H->LSo|@ K->dML|@ L->eHf M->K|bLM 测试数据2: S->aH H->aMd|d M->Ab|@ A->aM|e 实验感想: 经过这几次的实验,不仅让我们更加深刻的知道了first集合和follow集合的计算步骤和方法,还很好的培养了我们动手能力。虽然这两个集合用笔算的方法很简单,但是要让计算机来演算就不是那么容易了,这需要设计合理的数据结构和算法才能正确地求出结果。当然在设计算法的时候难免会出现错误,这就需要我们这些程序员们仔细的去调试,发现错误并改正。本以为这次的实验代码不会很长,但是实际写好了却有好几百行,可能是我的算法不够好吧。总的来讲这次的实验没有遇到太大的问题,因为课上老师很认真的给我们讲解了它们的求法,笔推也做了好几次练习,让我们理清了思路。- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 安徽 工业大学 编译 原理 实验 报告
咨信网温馨提示:
1、咨信平台为文档C2C交易模式,即用户上传的文档直接被用户下载,收益归上传人(含作者)所有;本站仅是提供信息存储空间和展示预览,仅对用户上传内容的表现方式做保护处理,对上载内容不做任何修改或编辑。所展示的作品文档包括内容和图片全部来源于网络用户和作者上传投稿,我们不确定上传用户享有完全著作权,根据《信息网络传播权保护条例》,如果侵犯了您的版权、权益或隐私,请联系我们,核实后会尽快下架及时删除,并可随时和客服了解处理情况,尊重保护知识产权我们共同努力。
2、文档的总页数、文档格式和文档大小以系统显示为准(内容中显示的页数不一定正确),网站客服只以系统显示的页数、文件格式、文档大小作为仲裁依据,个别因单元格分列造成显示页码不一将协商解决,平台无法对文档的真实性、完整性、权威性、准确性、专业性及其观点立场做任何保证或承诺,下载前须认真查看,确认无误后再购买,务必慎重购买;若有违法违纪将进行移交司法处理,若涉侵权平台将进行基本处罚并下架。
3、本站所有内容均由用户上传,付费前请自行鉴别,如您付费,意味着您已接受本站规则且自行承担风险,本站不进行额外附加服务,虚拟产品一经售出概不退款(未进行购买下载可退充值款),文档一经付费(服务费)、不意味着购买了该文档的版权,仅供个人/单位学习、研究之用,不得用于商业用途,未经授权,严禁复制、发行、汇编、翻译或者网络传播等,侵权必究。
4、如你看到网页展示的文档有www.zixin.com.cn水印,是因预览和防盗链等技术需要对页面进行转换压缩成图而已,我们并不对上传的文档进行任何编辑或修改,文档下载后都不会有水印标识(原文档上传前个别存留的除外),下载后原文更清晰;试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓;PPT和DOC文档可被视为“模板”,允许上传人保留章节、目录结构的情况下删减部份的内容;PDF文档不管是原文档转换或图片扫描而得,本站不作要求视为允许,下载前自行私信或留言给上传者【Fis****915】。
5、本文档所展示的图片、画像、字体、音乐的版权可能需版权方额外授权,请谨慎使用;网站提供的党政主题相关内容(国旗、国徽、党徽--等)目的在于配合国家政策宣传,仅限个人学习分享使用,禁止用于任何广告和商用目的。
6、文档遇到问题,请及时私信或留言给本站上传会员【Fis****915】,需本站解决可联系【 微信客服】、【 QQ客服】,若有其他问题请点击或扫码反馈【 服务填表】;文档侵犯商业秘密、侵犯著作权、侵犯人身权等,请点击“【 版权申诉】”(推荐),意见反馈和侵权处理邮箱:1219186828@qq.com;也可以拔打客服电话:4008-655-100;投诉/维权电话:4009-655-100。
1、咨信平台为文档C2C交易模式,即用户上传的文档直接被用户下载,收益归上传人(含作者)所有;本站仅是提供信息存储空间和展示预览,仅对用户上传内容的表现方式做保护处理,对上载内容不做任何修改或编辑。所展示的作品文档包括内容和图片全部来源于网络用户和作者上传投稿,我们不确定上传用户享有完全著作权,根据《信息网络传播权保护条例》,如果侵犯了您的版权、权益或隐私,请联系我们,核实后会尽快下架及时删除,并可随时和客服了解处理情况,尊重保护知识产权我们共同努力。
2、文档的总页数、文档格式和文档大小以系统显示为准(内容中显示的页数不一定正确),网站客服只以系统显示的页数、文件格式、文档大小作为仲裁依据,个别因单元格分列造成显示页码不一将协商解决,平台无法对文档的真实性、完整性、权威性、准确性、专业性及其观点立场做任何保证或承诺,下载前须认真查看,确认无误后再购买,务必慎重购买;若有违法违纪将进行移交司法处理,若涉侵权平台将进行基本处罚并下架。
3、本站所有内容均由用户上传,付费前请自行鉴别,如您付费,意味着您已接受本站规则且自行承担风险,本站不进行额外附加服务,虚拟产品一经售出概不退款(未进行购买下载可退充值款),文档一经付费(服务费)、不意味着购买了该文档的版权,仅供个人/单位学习、研究之用,不得用于商业用途,未经授权,严禁复制、发行、汇编、翻译或者网络传播等,侵权必究。
4、如你看到网页展示的文档有www.zixin.com.cn水印,是因预览和防盗链等技术需要对页面进行转换压缩成图而已,我们并不对上传的文档进行任何编辑或修改,文档下载后都不会有水印标识(原文档上传前个别存留的除外),下载后原文更清晰;试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓;PPT和DOC文档可被视为“模板”,允许上传人保留章节、目录结构的情况下删减部份的内容;PDF文档不管是原文档转换或图片扫描而得,本站不作要求视为允许,下载前自行私信或留言给上传者【Fis****915】。
5、本文档所展示的图片、画像、字体、音乐的版权可能需版权方额外授权,请谨慎使用;网站提供的党政主题相关内容(国旗、国徽、党徽--等)目的在于配合国家政策宣传,仅限个人学习分享使用,禁止用于任何广告和商用目的。
6、文档遇到问题,请及时私信或留言给本站上传会员【Fis****915】,需本站解决可联系【 微信客服】、【 QQ客服】,若有其他问题请点击或扫码反馈【 服务填表】;文档侵犯商业秘密、侵犯著作权、侵犯人身权等,请点击“【 版权申诉】”(推荐),意见反馈和侵权处理邮箱:1219186828@qq.com;也可以拔打客服电话:4008-655-100;投诉/维权电话:4009-655-100。
关于本文