佛山科学技术学院 实 验 报 告 课程名称 编译原理 实验项目 递归下降分析法 专业班级 1x计算机科学与技术1 姓 名 许xx 学 号 201xxxxxx 指导教师 吴臣 成 绩 日 期 2017-11-13
实验三:递归下降分析法 一、实验目的: 根据某一文法编制调试递归下降分析程序,以便对任意输入的符号串进行分析。本次实验的目的主要是加深对递归下降分析法的理解。 二、实验预习提示 1、递归下降分析法的功能 词法分析器的功能是利用函数之间的递归调用模拟语法树自上而下的构造过程。 2、递归下降分析法的前提 改造文法:消除二义性、消除左递归、提取左因子,判断是否为LL(1)文法, 3、递归下降分析法实验设计思想及算法 为G的每个非终结符号U构造一个递归过程,不妨命名为U。 U的产生式的右边指出这个过程的代码结构: (1)若是终结符号,则和向前看符号对照, 若匹配则向前进一个符号;否则出错。 (2)若是非终结符号,则调用与此非终结符对应的过程。当A的右部有多个产生式时,可用选择结构实现。 具体为: (1)对于每个非终结符号U->u1|u2|…|un处理的方法如下: U( ) { ch=当前符号; if(ch可能是u1字的开头)处理u1的程序部分; else if(ch可能是u2字的开头)处理u2的程序部分; … else error() } (2)对于每个右部u1->x1x2…xn的处理架构如下: 处理x1的程序; 处理x2的程序; … 处理xn的程序; (3)如果右部为空,则不处理。 (4)对于右部中的每个符号xi ①如果xi为终结符号: if(xi= = 当前的符号) { NextChar(); return; } else 出错处理 ②如果xi为非终结符号,直接调用相应的过程xi()
说明: NextChar为前进一个字符函数。 四、实验过程和指导: (一)准备: 1.阅读课本有关章节, 2.考虑好设计方案; 3.设计出模块结构、测试数据,初步编制好程序。 (二)上课上机: 将源代码拷贝到机上调试,发现错误,再修改完善。第二次上机调试通过。 (三)程序要求: 程序输入/输出示例: 对下列文法,用递归下降分析法对任意输入的符号串进行分析: (1)E->TG (2)G->+TG|—TG (3)G->ε (4)T->FS (5)S->*FS|/FS (6)S->ε (7)F->(E) (8)F->i 输出的格式如下: (1)递归下降分析程序,编制人:姓名,学号,班级 (2)输入一以#结束的符号串(包括+—*/()i#):在此位置输入符号串例如:i+i*i# (3)输出结果:i+i*i#为合法符号串
备注:输入一符号串如i+i*#,要求输出为“非法的符号串”。 引用也要改变)。 注意:1.表达式中允许使用运算符(+-*/)、分割符(括号)、字符I,结束符#; 2.如果遇到错误的表达式,应输出错误提示信息(该信息越详细越好); 3.对学有余力的同学,可以详细的输出推导的过程,即详细列出每一步使用的产生式。
(四)程序思路: 0.定义部分:定义常量、变量、数据结构。 1.初始化:从文件将输入符号串输入到字符缓冲区中。 2.利用递归下降分析法分析,对每个非终结符编写函数,在主函数中调用文法开始符号的函数。 (五)练习该实验的目的和思路: 程序开始变得复杂起来,需要利用到程序设计语言的知识和大量编程技巧,递归下降分析法是一种较实用的分析法,通过这个练习可大大提高软件开发能力。通过练习,掌握函数间相互调用的方法。 (六)为了能设计好程序,注意以下事情: 1.模块设计:将程序分成合理的多个模块(函数),每个模块做具体的同一事情。 2.写出(画出)设计方案:模块关系简图、流程图、全局变量、函数接口等。 3.编程时注意编程风格:空行的使用、注释的使用、缩进的使用等。 程序流程图: 图1:主函数main()流程图 图2:E函数的流程图 图三:T函数的流程图
图4:G函数()流程图
图5:F函数
图6:S函数()流程图
1、功能描述 这个程序是一个递归下降分析程序,能够判定输入的一个字符串是否属于给定的文法,如果不是,则会给出一定的出错信息,并且列出每一步使用的产生式。 2、全局变量及其定义 Char a[50];//--------------存储输入的字符串- Char ch; //---------------暂时存储输入的字符串 Char d[200];//-------------记录当前栈中的产生式 Int n1; //--------------输入字符串的长度 Char token; //-------------当前待分析的字符 3、模块设计 Int E();//------------------E过程,对应产生式E->TG Int T();//------------------T过程,对应产生式T->FS Int G();//-----------------G过程,对应产生式G->+TG|-TG|e Int S();//-----------------S过程,对应产生式S->*FS|/FS|e Int F();//-----------------F过程,对应产生式F->(E)|i Void output();//-------输出已分析字符串和当前字符 Void input1();//--------输出剩余字符
截图:
完整代码:
对老师发下来的代码进行了相应的增加就可以了(由于老师的代码无法进行相应的减法和除法,所以需要进行相应的修改就可以了) #include #include #include #include
char a[50] ,b[50],d[200],e[10]; //a[50]用来存储字符串的 char ch; int n1,i1=0,flag=1,n=5;
int E(); int E1(); int T(); int G(); int S(); int F(); void input(); void input1(); void output();
void main() /*递归分析*/ { int f,p,j=0; char x; d[0]='E'; d[1]='='; d[2]='>'; d[3]='T'; d[4]='G'; d[5]='#'; printf("请输入字符串(长度<50,以#号结束)\n"); do{ scanf("%c",&ch); a[j]=ch; j++; }while(ch!='#'); n1=j; //j会比字符串大1. ch=b[0]=a[0]; printf("文法\t分析串\t\t分析字符\t剩余串\n"); f=E1(); if (f==0) return; if (ch=='#') { printf("accept\n"); p=0; x=d[p]; while(x!='#') { printf("%c",x); p=p+1; x=d[p]; /*输出推导式*/ } } else { printf("error\n"); printf("回车返回\n"); getchar(); getchar(); } printf("\n"); printf("回车返回\n"); getchar(); getchar(); }
int E1() { int f,t; printf("E-->TG\t"); flag=1; input(); input1(); f=T(); if (f==0) return(0); t=G(); if (t==0) return(0); else return(1); }
int E() { int f,t; printf("E-->TG\t"); e[0]='E';e[1]='=';e[2]='>';e[3]='T';e[4]='G';e[5]='#'; output(); flag=1; input(); input1(); f=T(); if (f==0) return(0); t=G(); if (t==0) return(0); else return(1); }
int T() { int f,t; printf("T-->FS\t"); e[0]='T';e[1]='=';e[2]='>';e[3]='F';e[4]='S';e[5]='#'; output(); flag=1; input(); input1(); f=F(); if (f==0) return(0); t=S(); if (t==0) return(0); else return(1); }
int G() { int f; if(ch=='+') { b[i1]=ch; printf("G-->+TG\t"); e[0]='G';e[1]='=';e[2]='>';e[3]='+';e[4]='T';e[5]='G';e[6]='#'; //注意这些地方需要进行修改 output(); flag=0; input();input1(); ch=a[++i1]; f=T(); if (f==0) return(0); G(); return(1); } if(ch=='-') { b[i1]=ch; printf("G-->-TG\t"); e[0]='G';e[1]='=';e[2]='>';e[3]='-';e[4]='T';e[5]='G';e[6]='#'; //还有这里记得要记得修改 output(); flag=0; input();input1(); ch=a[++i1]; f=T(); if (f==0) return(0); G(); return(1); }
printf("G-->^\t"); e[0]='G';e[1]='=';e[2]='>';e[3]='^';e[4]='#'; //记得这里也需要修改 output(); flag=1; input();input1(); return(1); }
int S() { int f,t; if(ch=='*') { b[i1]=ch;printf("S-->*FS\t"); e[0]='S';e[1]='=';e[2]='>';e[3]='*';e[4]='F';e[5]='S';e[6]='#'; //这里也需要 output(); flag=0; input();input1(); ch=a[++i1]; f=F(); if (f==0) return(0); t=S(); if (t==0) return(0); else return(1); } if(ch=='/') { b[i1]=ch;printf("S-->/FS\t"); e[0]='S';e[1]='=';e[2]='>';e[3]='/';e[4]='F';e[5]='S';e[6]='#'; //还有这里 output(); flag=0; input();input1(); ch=a[++i1]; f=F(); if (f==0) return(0); t=S(); if (t==0) return(0); else return(1); }
printf("S-->^\t"); e[0]='S';e[1]='=';e[2]='>';e[3]='^';e[4]='#'; //还有这里 output(); flag=1; a[i1]=ch; input();input1(); return(1); }
int F() { int f; if(ch=='(') { b[i1]=ch;printf("F-->(E)\t"); e[0]='F';e[1]='=';e[2]='>';e[3]='(';e[4]='E';e[5]=')';e[6]='#'; output(); flag=0; input();input1(); ch=a[++i1]; f=E(); if (f==0) return(0); if(ch==')') { b[i1]=ch;printf("F-->(E)\t"); flag=0;input();input1(); ch=a[++i1]; } else { printf("error\n"); return(0); } }
else if(ch=='i') { b[i1]=ch;printf("F-->i\t"); e[0]='F';e[1]='=';e[2]='>';e[3]='i';e[4]='#'; output(); flag=0;input();input1(); ch=a[++i1]; } else {printf("error\n");return(0);} return(1); }
void input() { int j=0; for (;j<=i1-flag;j++) printf("%c",b[j]); /*输出分析串*/ printf("\t\t"); printf("%c\t\t",ch); /*输出分析字符*/ }
void input1() { int j; for (j=i1+1-flag;j printf("%c",a[j]); /*输出剩余字符*/ printf("\n"); } void output(){ /*推导式计算*/ int m,k,j,q; int i=0; m=0;k=0;q=0; i=n; d[n]='=';d[n+1]='>';d[n+2]='#';n=n+2;i=n; i=i-2; while(d[i]!='>'&&i!=0) i=i-1; i=i+1; while(d[i]!=e[0]) i=i+1; q=i; m=q;k=q; while(d[m]!='>') m=m-1; m=m+1; while(m!=q) { d[n]=d[m];m=m+1;n=n+1; } d[n]='#'; for(j=3;e[j]!='#';j++){ d[n]=e[j]; n=n+1; } k=k+1; while(d[k]!='=') { d[n]=d[k];n=n+1;k=k+1; } d[n]='#'; } 五、上交: 1.程序源代码(上交软盘); 2.已经测试通过的测试数据3组; 3.实验报告: 实验名称 实验目的和要求 (一)实验内容 (1)功能描述:该程序具有什么功能? 这个程序是一个递归下降分析程序,能够判定输入的一个字符串是否属于给定的文法。如果不是,则会给出一定的出错信息,并且列出每一步使用的产生式 (2)程序结构描述:函数调用格式、参数含义、返回值描述、函数功能;函数之间的调用关系图。 (3)程序总体执行流程图 (二)实验过程记录:出错次数、出错严重程度、解决办法摘要。 使用十次,出错八次。占比百分之80. (三)实验总结:你在编程过程中花时多少?多少时间在纸上设计?多少时间上机输入和调试?多少时间在思考问题?遇到了哪些难题?你是怎么克服的?你对你的程序的评价?你的收获有哪些? 通过这次实习。不仅使我对递归下降分析过程进一步了解,并且对C语言进行温习。在实验之前,我花了四个小时进行书中的理论进行模拟与分析,递归下降分析就是对每个非终结符按其产生结构老构造相应语法分析子程序,其中终结符产生匹配命令,而非终结符则产生过程调用命令。因为文法递归相应子程序也递归,所以称这种方法为递归子程序下降法或递归下降法。然后还花了三个小时在程序的调错上,总会出现很多出其不意的意外,不过同时也提高了自己的程序的调错能力和调错技巧 如有转载,请注明出处。请勿完全抄袭! |