编译原理实验报告实验题目:词法分析器构造指导教师:杨建,赵会群姓名:班级:学号:实验成绩:实验题目语法分析器构造实验目的和要求借助于词法分析程序提供的分析结果,编写一个算符优先语法分析程序,程序能进行语法结构分析和错误检查并产生相应的归约信息。同时给出出错信息和错误类型,从而加深对语法分析的理解。设计思想与框架1.本实验的优先表可以手工先设计好:算符优先关系表----------------------------------+-*/()i#+-*/(=?)??i??#?=----------------------------------算术表达式-项|算术表达式+项|算术表达式-项项-因子|项*因子|项/因子因子-变量|常数|(算术表达式)2.本实验要求中提出的“产出相应的归约信息”意指在语法分析的过程中,一旦产生归约,在程序上产生并最终输出归约产生式序号。3.出错类型的产生可预先对应优先表中出错栏列表说明其出错类型,并分别编序,当分析中产生错误时以字符串输出相应表中错误信息。核心算法算法采用一个符号栈的数据结构,既用它存放终结符,也用它存放非终结符。设K为符号栈使用深度,其参考算法如下:K:=1S[K]:=#Repeat把下一人输入符读入a中IfS[K]∈VTthenj:=Kelsej:=K-1WhileS[j]adoBeginRepeatQ:=S[j]IfS[j-1]∈VTthenj:=j-1elsej:=j-2UntilS[j]Q把S[j+1]……S[K]归约为某个N记录归约产生式序号K:=j+1S[K]:=NEndofwhileIfS[j]aORS[j]=athenBeginK:=K+1;S[K]:=aEndElseERROR{查表打印出错信息}Untila='#'输出归约产生式序列号;源程序及注释#includeiostream#includecstdio#includeiomanipusingnamespacestd;#defineN100#defineNULL0FILE*fp;//预处理文件指针//定义符号栈的大小与输入字符串的大小以及算术表达式字符串的大小charstack[N],strings[N],oldstrings[N];chara;inttop=-1,k=0,step=1,n=0,No[N],id=1;//二维数组定义字符之间的优先关系(1表示,-1表示,0表示=,-2表示错误)intM[N][N]={{1,1,-1,-1,-1,1,-1,1},{1,1,-1,-1,-1,1,-1,1},{1,1,1,1,-1,1,-1,1},{1,1,1,1,-1,1,-1,1},{-1,-1,-1,-1,-1,0,-1,-2},{1,1,1,1,-2,1,-2,1},{1,1,1,1,-2,1,-2,1},{-1,-1,-1,-1,-1,-2,-1,0}};char*word[6]={N+N,N-N,N*N,N/N,)N(,i};//可归约字符串intprint(intt,intm){cout\nstep++setw(10);coutstacksetw(10);if(m==1)coutsetw(8);elseif(m==0)cout=setw(8);elsecoutsetw(8);coutasetw(10);cout&strings[k]setw(10);if(t){cout归约setw(8);No[n++]=step-1;}elsecout移进setw(8);return0;}voidpush(charch){stack[++top]=ch;}charpop(){chara;a=stack[top--];stack[top+1]='\0';returna;}intch_di(charch){switch(ch){case'+':return1;case'-':return2;case'*':return3;case'/':return4;case'(':return5;case')':return6;case'i':return7;case'#':return8;default:return0;}}intIsVT(charch){if(ch=='N')return0;elsereturn1;}intreadvt(char*a){if(IsVT(strings[k])){(*a)=strings[k];k++;return1;}else{k++;return0;}}intbig(intt,chara){if(M[ch_di(stack[t])-1][ch_di(a)-1]==1)return1;elsereturn0;}intless(intt,chara){if(M[ch_di(stack[t])-1][ch_di(a)-1]==-1)return1;elsereturn0;}intequal(intt,chara){if(M[ch_di(stack[t])-1][ch_di(a)-1]==0)return1;elsereturn0;}voiderror(intt){if(ch_di(stack[t])==6||ch_di(stack[t])==7){printf(\n错误e2:缺少运算符!);}elseif(ch_di(stack[t])==5){printf(\n错误e1:非法左括号!);}elseprintf(\n错误e3:非法右括号!);}voidprior_analysis(){inti,j,m;charq,str,ch[20];push('#');print(0,-1);for(;;){/*u:*/readvt(&a);if(IsVT(stack[top]))j=top;elsej=top-1;do{while(big(j,a)&&strcmp(stack,#N)!=0){do{q=stack[j];if(IsVT(stack[j-1]))j=j-1;elsej=j-2;}while(!less(j,q));i=-1;while((top-j)!=0){ch[++i]=pop();}ch[i+1]='\0';for(m=0;m=5;m++){if(strcmp(word[m],ch)==0)str='N';}push(str);print(1,1);}if(less(j,a)){push(a);print(0,-1);if(stack[top]!='#')//gotou;break;}else{if(equal(j,a)){push(a);print(0,0);if(stack[top]!='#')//gotou;break;}else{error(j);a='#';}}}while(a!='#');if(a=='#')break;}}voidmain(){cout******************************算符优先语法分析程序******************************endl;coutE-E+T|E-T|Tendl;coutT-T*F|T/F|Fendl;coutF-(E)|iendl;coutE表示算术表达式.T表示项.F表示因子.i表示变量或常数.endl;cout优先表endl;cout+-*/()i#endl;cout+endl;cout-endl;cout*endl;cout/endl;cout(=e1endl;cout)e2e2endl;coutie2e2endl;cout#e3=endl;if((fp=fopen(预处理.txt,r))==NULL){cout请先将实验文件夹中的预处理.txt文件复制到实验文件夹中!endl;system(pause);exit(0);}charch=fgetc(fp);charch1;while(ch!='#'){inti=-1,j=0,m=-1;while(ch!='='&&ch!='#'){ch1=ch;ch=fgetc(fp);if((ch1==''||ch1=='')&&ch=='=')ch=fgetc(fp);}if(ch=='#'){cout算符优先语法分析结束!endl;fclose(fp);system(pause);exit(0);}while(ch!=''&&ch!='#'){ch=fgetc(fp);oldstrings[++i]=ch;}oldstrings[i]='\0';if(isalnum(oldstrings[j]))strings[++m]='i';elsestrings[++m]=oldstrings[j];j++;while(oldstrings[j]!='\0'){if(isalnum(oldstrings[j])){if(isalnum(oldstrings[j-1])==0)strings[++m]='i';}elsestrings[++m]=oldstrings[j];j++;}strings[m+1]='#';strings[m+2]='\0';cout算术表达式id为:oldstringsendl;cout转换为输入串:stringsendl;cout步骤号符号栈优先关系当前分析符剩余输入串动作;prior_analysis();n=0;coutendl;cout算术表达式id++的归约产生式步骤号为:;while(No[n]){coutNo[n];n++;}coutendl;while(stack[0]!='\0')pop();while(No[--n]){No[n]='\0';}top=-1;a='\0';k=0;step=1;n=0;}cout算符优先语法分析结束!endl;fclose(fp);system(pause);exit(0);}问题及处理Goto语句修改成for循环的时候,有两种情形能从while循环中跳出,接下来要做的有对应的两条路:一是根据循环条件,当a='#'时循环结束,此时函数prior_analysis应该执行完毕;二是满足循环体中的判断条件stack[top]!='#',跳出while循环,此时接下来要做的是readvt(&a),而不是结束函数。一开始我只考虑到了第二种情况,每次从while中跳出后都去做readvt(&a);,造成程序陷入死循环。后来经过仔细的思考,在while循环结束后加上了判断条件if(a=='#')break;就能在第一种情况时,从while循环出来后,从for循环里出来,结束这个函数,而不是再去做for循环里的内容。实验结果实验心得通过本次实验,我加深对语法分析的理解。刚开始看到题目的时候是对程序无从下手,不知道从何做起,上网查了一些资料,还是觉得看的云里雾里,后来经过仔细研究老师给的例子,真的去弄懂它,发现其实也不是很难的,只要用心去做。通过这些,我懂得了原理,顺着思路对程序做了进一步的分析,从中也学到了很多知识。