Removed_合肥工业大学编译原理实验 LL(1)分析法
编译原理实验LL1分析法
编译原理程序设计实验报告——表达式语法分析器的设计实现班级:计算机1306班姓名:王利达学号:20133959 实验目标:使用LL(1)分析法构造表达式语法分析器程序,判别算术表达式,给出判别结果。
实验内容:一、概要设计1.算术表达式文法:E→ T | Eω0TT→ F | Tω1FF→ i | ( E )其中ω0:+ -ω1:* /i:数字或常数文法变换:E → T MM →ω0 T M |εT → F | NN →ω1 F N |εF → i | ( E )其中ω0:+ -ω1:* /i:数字或常数2.LL(1)分析表表1.LL(1)分析表i + - * / ( ) #E MT,p MT,pM MT,n MT,n ε,p ε,pT NF,p NF,pN NF,n NF,n ε,p ε,pF ε,n )E,n) ε,n# OK二、数据结构1.输入表达式定义char型数组expstr为存放输入表达式的数组,char expstr[100];2.分析栈定义一个栈来进行LL(1)分析。
栈中有bottom、top、stacksize 等元素,用于程序调用栈和对栈操作。
typedef struct //定义语法的栈{SElemType *bottom;//底SElemType *top;//顶int stacksize;}SqStack;(包括:概要设计、数据结构、流程图、关键函数等有选择填写)源程序代码:(加入注释)#include<iostream>#include<stdio.h>#include<cstdlib>using namespace std;#define STACKSIZE 30 //栈大小#define STACKINCREMENT 10 //栈增量#define OK 1#define Error 0#define OVERFLOW -1typedef char SElemType;typedef int Status;int i=0;int count1=0;int count2=0; //计数终结符的个数char expstr[100];typedef struct //定义语法的栈{SElemType *bottom;//底SElemType *top;//顶int stacksize;}SqStack;Status InitStack(SqStack &S) //初始化栈{S.bottom=(SElemType*)malloc(STACKSIZE*sizeof(SElemType));if(!S.bottom)exit(OVERFLOW);S.top=S.bottom;S.stacksize=STACKSIZE;return OK;}Status PUSH(SqStack &S,SElemType e){if(S.top-S.bottom>=S.stacksize){S.bottom=(SElemType*)realloc(S.bottom,(S.stacksize+STACKINCREMENT)*sizeof(SElemType ));if(!S.bottom)exit(OVERFLOW);S.top=S.bottom+S.stacksize;S.stacksize+=STACKINCREMENT;}*(S.top)=e;(S.top)++;return OK;}Status POP(SqStack &S,SElemType &e){if(S.top==S.bottom)return Error;S.top--;e=*(S.top);return OK;}void wrong()//调用此函数,表示出错{cout<<"Wrong!"<<endl;getchar();exit(0);}bool ch_judge(char s[],int n) //字符是否合法{if((s[n]=='(')||(s[n]==')')||(s[n]>='0'&&s[n]<='9')||(s[n]>='a'&&s[n]<='z')||(s[n]=='+')||(s[n]=='-')||(s[ n]=='*')||(s[n]=='/')||(s[n]=='#'))return 1;elsereturn 0;}bool ter_judge(char c) //终结符集合与非终结符集合{if((c=='(')||(c==')')||(c>='0'&&c<='9')||(c>='a'&&c<='z')||(c=='+')||(c=='-')||(c=='*')||(c=='/')) return 1; //终结符返回1else //if(c=='E'||c=='E1'||c=='T'||c=='T1'||c=='F')return 0; //非终结符或#,返回0}bool num_letter(char s[],int i) //判断当前字符是数字还是字母{if((s[i]>='0'&&s[i]<='9')||(s[i]>='a'&&s[i]<='z')){i++;while((s[i]>='0'&&s[i]<='9')||(s[i]>='a'&&s[i]<='z')){i++;count1++;}while(count1!=0){i--;count1--;}i--;return 1; //是字母或数字返回1}elsereturn 0; //不是字母或数字返回0}void LL1(SqStack &S,char s[],int i)//LL1文法分析函数{SElemType e;PUSH(S,'#');PUSH(S,'E');while(s[i]!='#'){if(ch_judge(s,i)){POP(S,e);if(!(ter_judge(e))) //是非终结符{if(e=='#'&&s[i]=='#')break; //表达式正确else if(e=='#'&&s[i]!='#')wrong();else if(e!='#') //分析表匹配{switch(e){case 'E':if(num_letter(s,i)||s[i]=='('){e='M'; // E' MPUSH(S,e);e='T';PUSH(S,e);break;}elsewrong();case 'M':if(s[i]=='+'||s[i]=='-'){e='M';PUSH(S,e);e='T';PUSH(S,e);e=s[i];PUSH(S,e);break;}else if(s[i]==')'||s[i]=='#'){break;}elsewrong();case 'T':if(num_letter(s,i)||s[i]=='('){e='N'; //T' NPUSH(S,e);e='F';PUSH(S,e);break;}elsewrong();case 'N':if(s[i]=='+'||s[i]=='-'||s[i]==')'||s[i]=='#'){break;}else if(s[i]=='*'||s[i]=='/'){e='N';PUSH(S,e);e='F';PUSH(S,e);e=s[i];PUSH(S,e);break;}elsewrong();case 'F':if(num_letter(s,i)){while((s[i]>='0'&&s[i]<='9')||(s[i]>='a'&&s[i]<='z')) //将连续的终结符压栈{e=s[i];PUSH(S,e);i++;count2++; //给连续终结符计数}i--; //使s[i]为连续终结符即一个整数的最后一字break;}else if(s[i]=='('){e=')';PUSH(S,e);e='E';PUSH(S,e);e='(';PUSH(S,e);break;}elsewrong();default:wrong();}}}else{if((s[i]>='0'&&s[i]<='9')||(s[i]>='a'&&s[i]<='z'))//如果是数字或字母则依次计数{while(ter_judge(e)){if(e==s[i]){i--;POP(S,e);}elsewrong();}while(count2!=0){i++;count2--;}PUSH(S,e);i++;}else //如果是+-*/则直接比较{if(e==s[i])i++;elsewrong();}}}elsewrong();}}int main(){SqStack S;InitStack(S);cout<<"LL(1)\nPlease enter the expression and end with the \"#\":"<<endl;cin>>expstr;LL1(S,expstr,i);cout<<"Right! "<<endl;getchar();return 0;}程序运行结果:(截屏)图1.正确的算术表达式(((a+b)*(c/B)))的判断图2.错误的算术表达式a/b++的判断思考问题回答:(如果有)LL(1)分析法和递归下降子程序法在语法分析中同属于自顶向下分析法,LL(1)分析法相对于递归下降子程序法的优势是:LL(1)分析法消除了文法的左递归性,而且克服了回溯,使程序运行的效率大大提升。
编译原理实验报告材料LL(1)分析报告法84481
课程编译原理实验名称实验二 LL(1)分析法实验目的1.掌握LL(1)分析法的基本原理;2.掌握LL(1)分析表的构造方法;3.掌握LL(1)驱动程序的构造方法。
一.实验内容及要求根据某一文法编制调试LL(1)分析程序,以便对任意输入的符号串进行分析。
本次实验的目的主要是加深对预测分析LL(1)分析法的理解。
对下列文法,用LL(1)分析法对任意输入的符号串进行分析:(1)E->TG(2)G->+TG(3)G->ε(4)T->FS(5)S->*FS(6)S->ε(7)F->(E)(8)F->i程序输入一以#结束的符号串(包括+*()i#),如:i+i*i#。
输出过程如下:步骤分析栈剩余输入串所用产生式1 E i+i*i# E->TG... ... ... ...二.实验过程及结果代码如下:#include<iostream>#include "edge.h"using namespace std;edge::edge(){cin>>left>>right;rlen=right.length();if(NODE.find(left)>NODE.length())NODE+=left;}string edge::getlf(){return left;}string edge::getrg(){return right;}string edge::getfirst(){return first;}string edge::getfollow(){return follow;}string edge::getselect(){return select;}string edge::getro(){string str;str+=right[0];return str;}int edge::getrlen(){return right.length();}void edge::newfirst(string w){int i;for(i=0;i<w.length();i++)if(first.find(w[i])>first.length())first+=w[i];}void edge::newfollow(string w){int i;for(i=0;i<w.length();i++)if(follow.find(w[i])>follow.length()&&w[i]!='@')follow+=w[i];}void edge::newselect(string w){int i;for(i=0;i<w.length();i++)if(select.find(w[i])>select.length()&&w[i]!='@') select+=w[i];}void edge::delfirst(){int i=first.find('@');first.erase(i,1);}int SUM;string NODE,ENODE;//计算firstvoid first(edge ni,edge *n,int x){int i,j;for(j=0;j<SUM;j++){if(ni.getlf()==n[j].getlf()){if(NODE.find(n[j].getro())<NODE.length()){for(i=0;i<SUM;i++)if(n[i].getlf()==n[j].getro())first(n[i],n,x);}elsen[x].newfirst(n[j].getro());}}}//计算followvoid follow(edge ni,edge *n,int x){int i,j,k,s;string str;for(i=0;i<ni.getrlen();i++){s=NODE.find(ni.getrg()[i]);if(s<NODE.length()&&s>-1) //是非终结符if(i<ni.getrlen()-1) //不在最右for(j=0;j<SUM;j++)if(n[j].getlf().find(ni.getrg()[i])==0){if(NODE.find(ni.getrg()[i+1])<NODE.length()){for(k=0;k<SUM;k++)if(n[k].getlf().find(ni.getrg()[i+1])==0){n[j].newfollow(n[k].getfirst());if(n[k].getfirst().find("@")<n[k].getfirst().length())n[j].newfollow(ni.getfollow());}}else{str.erase();str+=ni.getrg()[i+1];n[j].newfollow(str);}}}}//计算selectvoid select(edge &ni,edge *n){int i,j;if(ENODE.find(ni.getro())<ENODE.length()){ni.newselect(ni.getro());if(ni.getro()=="@")ni.newselect(ni.getfollow());}elsefor(i=0;i<ni.getrlen();i++){for(j=0;j<SUM;j++)if(ni.getrg()[i]==n[j].getlf()[0]){ni.newselect(n[j].getfirst());if(n[j].getfirst().find('@')>n[j].getfirst().length())return;}}}//输出集合void out(string p){int i;if(p.length()==0)return;cout<<"{";for(i=0;i<p.length()-1;i++){cout<<p[i]<<",";}cout<<p[i]<<"}";}//连续输出符号void outfu(int a,string c){int i;for(i=0;i<a;i++)cout<<c;}//输出预测分析表void outgraph(edge *n,string (*yc)[50]){int i,j,k;bool flag;for(i=0;i<ENODE.length();i++){if(ENODE[i]!='@'){outfu(10," ");cout<<ENODE[i];}}outfu(10," ");cout<<"#"<<endl;int x;for(i=0;i<NODE.length();i++){outfu(4," ");cout<<NODE[i];outfu(5," ");for(k=0;k<ENODE.length();k++){flag=1;for(j=0;j<SUM;j++){if(NODE[i]==n[j].getlf()[0]){x=n[j].getselect().find(ENODE[k]);if(x<n[j].getselect().length()&&x>-1){cout<<"->"<<n[j].getrg();yc[i][k]=n[j].getrg();outfu(9-n[j].getrlen()," ");flag=0;}x=n[j].getselect().find('#');if(k==ENODE.length()-1&&x<n[j].getselect().length()&&x>-1){cout<<"->"<<n[j].getrg();yc[i][j]=n[j].getrg();}}}if(flag&&ENODE[k]!='@')outfu(11," ");}cout<<endl;}}//分析符号串int pipei(string &chuan,string &fenxi,string (*yc)[50],int &b) {char ch,a;int x,i,j,k;b++;cout<<endl<<" "<<b;if(b>9)outfu(8," ");elseoutfu(9," ");cout<<fenxi;outfu(26-chuan.length()-fenxi.length()," "); cout<<chuan;outfu(10," ");a=chuan[0];ch=fenxi[fenxi.length()-1];x=ENODE.find(ch);if(x<ENODE.length()&&x>-1){if(ch==a){fenxi.erase(fenxi.length()-1,1);chuan.erase(0,1);cout<<"'"<<a<<"'匹配";if(pipei(chuan,fenxi,yc,b))return 1;elsereturn 0;}elsereturn 0;}else{if(ch=='#'){if(ch==a){cout<<"分析成功"<<endl;return 1;}elsereturn 0;}elseif(ch=='@'){fenxi.erase(fenxi.length()-1,1);if(pipei(chuan,fenxi,yc,b))return 1;elsereturn 0;}else{i=NODE.find(ch);if(a=='#'){x=ENODE.find('@');if(x<ENODE.length()&&x>-1)j=ENODE.length()-1;elsej=ENODE.length();}elsej=ENODE.find(a);if(yc[i][j].length()){cout<<NODE[i]<<"->"<<yc[i][j];fenxi.erase(fenxi.length()-1,1);for(k=yc[i][j].length()-1;k>-1;k--)if(yc[i][j][k]!='@')fenxi+=yc[i][j][k];if(pipei(chuan,fenxi,yc,b))return 1;elsereturn 0;}elsereturn 0;}}}void main(){edge *n;string str,(*yc)[50];int i,j,k;bool flag=0;cout<<"请输入上下文无关文法的总规则数:"<<endl;cin>>SUM;cout<<"请输入具体规则(格式:左部右部,@为空):"<<endl;n=new edge[SUM];for(i=0;i<SUM;i++)for(j=0;j<n[i].getrlen();j++){str=n[i].getrg();if(NODE.find(str[j])>NODE.length()&&ENODE.find(str[j])>ENODE.length()) ENODE+=str[j];}//计算first集合for(i=0;i<SUM;i++){first(n[i],n,i);}//outfu(10,"~*~");cout<<endl;for(i=0;i<SUM;i++)if(n[i].getfirst().find("@")<n[i].getfirst().length()){if(NODE.find(n[i].getro())<NODE.length()){for(k=1;k<n[i].getrlen();k++){if(NODE.find(n[i].getrg()[k])<NODE.length()){for(j=0;j<SUM;j++){if(n[i].getrg()[k]==n[j].getlf()[0]){n[i].newfirst(n[j].getfirst());break;}}if(n[j].getfirst().find("@")>n[j].getfirst().length()){n[i].delfirst();break;}}}}}//计算follow集合for(k=0;k<SUM;k++){for(i=0;i<SUM;i++){if(n[i].getlf()==n[0].getlf())n[i].newfollow("#");follow(n[i],n,i);}for(i=0;i<SUM;i++){for(j=0;j<SUM;j++)if(n[j].getrg().find(n[i].getlf())==n[j].getrlen()-1)n[i].newfollow(n[j].getfollow());}}//计算select集合for(i=0;i<SUM;i++){select(n[i],n);}for(i=0;i<NODE.length();i++){str.erase();for(j=0;j<SUM;j++)if(n[j].getlf()[0]==NODE[i]){if(!str.length())str=n[j].getselect();else{for(k=0;k<n[j].getselect().length();k++)if(str.find(n[j].getselect()[k])<str.length()){flag=1;break;}}}}//输出cout<<endl<<"非终结符";outfu(SUM," ");cout<<"First";outfu(SUM," ");cout<<"Follow"<<endl;outfu(5+SUM,"-*-");cout<<endl;for(i=0;i<NODE.length();i++){for(j=0;j<SUM;j++)if(NODE[i]==n[j].getlf()[0]){outfu(3," ");cout<<NODE[i];outfu(SUM+4," ");out(n[j].getfirst());outfu(SUM+4-2*n[j].getfirst().length()," ");out(n[j].getfollow());cout<<endl;break;}}outfu(5+SUM,"-*-");cout<<endl<<"判定结论: ";if(flag){cout<<"该文法不是LL(1)文法!"<<endl;return;}else{cout<<"该文法是LL(1)文法!"<<endl;}//输出预测分析表cout<<endl<<"预测分析表如下:"<<endl;yc=new string[NODE.length()][50];outgraph(n,yc);string chuan,fenxi,fchuan;cout<<endl<<"请输入符号串:";cin>>chuan;fchuan=chuan;fenxi="#";fenxi+=NODE[0];i=0;cout<<endl<<"预测分析过程如下:"<<endl;cout<<"步骤";outfu(7," ");cout<<"分析栈";outfu(10," ");cout<<"剩余输入串";outfu(8," ");cout<<"推导所用产生式或匹配";if(pipei(chuan,fenxi,yc,i))cout<<endl<<"输入串"<<fchuan<<"是该文法的句子!"<<endl;elsecout<<endl<<"输入串"<<fchuan<<"不是该文法的句子!"<<endl;}截屏如下:三.实验中的问题及心得这次实验让我更加熟悉了LL(1)的工作流程以及LL(1)分析表的构造方法。
编译原理实验报告LL(1)分析法
编译原理实验报告LL(1)分析法课程编译原理实验名称实验二 LL(1)分析法实验目的1.掌握LL(1)分析法的基本原理;2.掌握LL(1)分析表的构造方法;3.掌握LL(1)驱动程序的构造方法。
一.实验内容及要求根据某一文法编制调试LL(1)分析程序,以便对任意输入的符号串进行分析。
本次实验的目的主要是加深对预测分析LL(1)分析法的理解。
对下列文法,用LL(1)分析法对任意输入的符号串进行分析:(1)E->TG(2)G->+TG(3)G->ε(4)T->FS(5)S->*FS(6)S->ε(7)F->(E)(8)F->i程序输入一以#结束的符号串(包括+*()i#),如:i+i*i#。
输出过程如下:步骤分析栈剩余输入串所用产生式1 E i+i*i# E->TG... ... ... ...二.实验过程及结果代码如下:#include#include "edge.h"using namespace std;edge::edge(){cin>>left>>right;rlen=right.length();if(NODE.find(left)>NODE.length()) NODE+=left;}string edge::getlf(){return left;}string edge::getrg(){return right;}string edge::getfirst(){return first;}string edge::getfollow(){return follow;}string edge::getselect(){return select;}string edge::getro(){string str;str+=right[0];return str;}int edge::getrlen(){return right.length();}void edge::newfirst(string w){int i;for(i=0;iif(first.find(w[i])>first.length())first+=w[i];}void edge::newfollow(string w){int i;for(i=0;iif(follow.find(w[i])>follow.length()&&w[i]!='@')follow+=w[i];}void edge::newselect(string w){int i;for(i=0;iif(select.find(w[i])>select.length()&&w[i]!='@') select+=w[i];}void edge::delfirst(){int i=first.find('@');first.erase(i,1);}int SUM;string NODE,ENODE;//计算firstvoid first(edge ni,edge *n,int x){int i,j;for(j=0;j{if(ni.getlf()==n[j].getlf()){if(NODE.find(n[j].getro()){for(i=0;iif(n[i].getlf()==n[j].getro())first(n[i],n,x);}elsen[x].newfirst(n[j].getro());}}}//计算followvoid follow(edge ni,edge *n,int x){int i,j,k,s;string str;for(i=0;i{s=NODE.find(ni.getrg()[i]);if(s-1) //是非终结符if(ifor(j=0;jif(n[j].getlf().find(ni.getrg()[i])==0) {if(NODE.find(ni.getrg()[i+1]){for(k=0;kif(n[k].getlf().find(ni.getrg()[i+1])==0) {n[j].newfollow(n[k].getfirst());if(n[k].getfirst().find("@")n[j].newfollow(ni.getfollow());}}else{str.erase();str+=ni.getrg()[i+1];n[j].newfollow(str);}}}}//计算selectvoid select(edge &ni,edge *n){int i,j;if(ENODE.find(ni.getro()){ni.newselect(ni.getro());if(ni.getro()=="@")ni.newselect(ni.getfollow());}elsefor(i=0;i{for(j=0;jif(ni.getrg()[i]==n[j].getlf()[0]){ni.newselect(n[j].getfirst());if(n[j].getfirst().find('@')>n[j].getfirst().length()) return;}}}//输出集合void out(string p){int i;if(p.length()==0)return;coutfor(i=0;i{cout}cout}//连续输出符号void outfu(int a,string c){int i;for(i=0;icout}//输出预测分析表void outgraph(edge *n,string (*yc)[50]) {int i,j,k;bool flag;for(i=0;i{if(ENODE[i]!='@'){outfu(10," ");cout}}outfu(10," ");coutint x;for(i=0;i{outfu(4," ");coutoutfu(5," ");for(k=0;k{flag=1;for(j=0;j{if(NODE[i]==n[j].getlf()[0]){x=n[j].getselect().find(ENODE[k]); if(x-1){cout"yc[i][k]=n[j].getrg();outfu(9-n[j].getrlen()," ");flag=0;}x=n[j].getselect().find('#');if(k==ENODE.length()-1&&x-1) {cout"yc[i][j]=n[j].getrg();}}}if(flag&&ENODE[k]!='@')outfu(11," ");}cout}}//分析符号串int pipei(string &chuan,string &fenxi,string (*yc)[50],int &b){char ch,a;int x,i,j,k; b++; cout9) outfu(8," "); else outfu(9," "); cout-1) { if(ch==a) { fenxi.erase(fenxi.length()-1,1); chuan.erase(0,1); coutfenxi.erase(fenxi.length()-1,1); if(pipei(chuan,fenxi,yc,b)) return 1;elsereturn 0;}else{i=NODE.find(ch);if(a=='#'){x=ENODE.find('@');if(x-1) j=ENODE.length()-1; elsej=ENODE.length();}elsej=ENODE.find(a);if(yc[i][j].length()){cout"-1;k--) if(yc[i][j][k]!='@')fenxi+=yc[i][j][k];if(pipei(chuan,fenxi,yc,b)) return 1; elsereturn 0;}elsereturn 0;}}}void main(){edge *n;string str,(*yc)[50];int i,j,k;bool flag=0;cin>>SUM; coutNODE.length()&&ENODE.find(str[j])>ENODE.length())ENODE+=str[j]; } //计算first集合 for(i=0;in[j].getfirst().length()){ n[i].delfirst(); break; } } } } }for(k=0;koutfu(SUM," "); cout>chuan; fchuan=chuan; fenxi="#"; fenxi+=NODE[0]; i=0; coutoutfu(7," ");coutoutfu(10," ");coutoutfu(8," ");coutif(pipei(chuan,fenxi,yc,i))coutelsecout}截屏如下:三.实验中的问题及心得这次实验让我更加熟悉了LL(1)的工作流程以及LL(1)分析表的构造方法。
编译原理实验报告分析法
工业大学实验报告课程编译原理实验名称实验二LL(1)分析法实验目的1.掌握LL(1)分析法的基本原理;2.掌握LL(1)分析表的构造法;3.掌握LL(1)驱动程序的构造法。
一.实验容及要求根据某一文法编制调试LL(1)分析程序,以便对任意输入的符号串进行分析。
本次实验的目的主要是加深对预测分析LL(1)分析法的理解。
对下列文法,用LL(1)分析法对任意输入的符号串进行分析:(1)E->TG(2)G->+TG(3)G->ε(4)T->FS(5)S->*FS(6)S->ε(7)F->(E)(8)F->i程序输入一以#结束的符号串(包括+*()i#),如:i+i*i#。
输出过程如下:步骤分析栈剩余输入串所用产生式1 E i+i*i# E->TG... ... ... ...二.实验过程及结果代码如下:#include<iostream>#include "edge.h"using namespace std;edge::edge(){cin>>left>>right;rlen=right.length();if(NODE.find(left)>NODE.length())NODE+=left;}string edge::getlf(){return left;}string edge::getrg(){return right;}string edge::getfirst(){return first;}string edge::getfollow(){return follow;}string edge::getselect(){return select;}string edge::getro(){string str;str+=right[0];return str;}int edge::getrlen(){return right.length();}void edge::newfirst(string w){int i;for(i=0;i<w.length();i++)if(first.find(w[i])>first.length())first+=w[i];void edge::newfollow(string w){int i;for(i=0;i<w.length();i++)if(follow.find(w[i])>follow.length()&&w[i]!='@')follow+=w[i];}void edge::newselect(string w){int i;for(i=0;i<w.length();i++)if(select.find(w[i])>select.length()&&w[i]!='@')select+=w[i];}void edge::delfirst(){int i=first.find('@');first.erase(i,1);}int SUM;string NODE,ENODE;//计算firstvoid first(edge ni,edge *n,int x){int i,j;for(j=0;j<SUM;j++){if(ni.getlf()==n[j].getlf()){if(NODE.find(n[j].getro())<NODE.length()){for(i=0;i<SUM;i++)if(n[i].getlf()==n[j].getro())first(n[i],n,x);}elsen[x].newfirst(n[j].getro());}}//计算followvoid follow(edge ni,edge *n,int x){int i,j,k,s;string str;for(i=0;i<ni.getrlen();i++){s=NODE.find(ni.getrg()[i]);if(s<NODE.length()&&s>-1) //是非终结符if(i<ni.getrlen()-1) //不在最右for(j=0;j<SUM;j++)if(n[j].getlf().find(ni.getrg()[i])==0){if(NODE.find(ni.getrg()[i+1])<NODE.length()){for(k=0;k<SUM;k++)if(n[k].getlf().find(ni.getrg()[i+1])==0){n[j].newfollow(n[k].getfirst());if(n[k].getfirst().find("@")<n[k].getfirst().length())n[j].newfollow(ni.getfollow());}}else{str.erase();str+=ni.getrg()[i+1];n[j].newfollow(str);}}}}//计算selectvoid select(edge &ni,edge *n){int i,j;if(ENODE.find(ni.getro())<ENODE.length()){ni.newselect(ni.getro());if(ni.getro()=="@")ni.newselect(ni.getfollow());}elsefor(i=0;i<ni.getrlen();i++){for(j=0;j<SUM;j++)if(ni.getrg()[i]==n[j].getlf()[0]){ni.newselect(n[j].getfirst());if(n[j].getfirst().find('@')>n[j].getfirst().length())return;}}}//输出集合void out(string p){int i;if(p.length()==0)return;cout<<"{";for(i=0;i<p.length()-1;i++){cout<<p[i]<<",";}cout<<p[i]<<"}";}//连续输出符号void outfu(int a,string c){int i;for(i=0;i<a;i++)cout<<c;}//输出预测分析表void outgraph(edge *n,string (*yc)[50]){int i,j,k;bool flag;for(i=0;i<ENODE.length();i++){if(ENODE[i]!='@'){outfu(10," ");cout<<ENODE[i];}}outfu(10," ");cout<<"#"<<endl;int x;for(i=0;i<NODE.length();i++){outfu(4," ");cout<<NODE[i];outfu(5," ");for(k=0;k<ENODE.length();k++){flag=1;for(j=0;j<SUM;j++){if(NODE[i]==n[j].getlf()[0]){x=n[j].getselect().find(ENODE[k]);if(x<n[j].getselect().length()&&x>-1){cout<<"->"<<n[j].getrg();yc[i][k]=n[j].getrg();outfu(9-n[j].getrlen()," ");flag=0;}x=n[j].getselect().find('#');if(k==ENODE.length()-1&&x<n[j].getselect().length()&&x>-1){cout<<"->"<<n[j].getrg();yc[i][j]=n[j].getrg();}}}if(flag&&ENODE[k]!='@')outfu(11," ");}cout<<endl;}}//分析符号串int pipei(string &chuan,string &fenxi,string (*yc)[50],int &b) {char ch,a;int x,i,j,k;b++;cout<<endl<<" "<<b;if(b>9)outfu(8," ");elseoutfu(9," ");cout<<fenxi;outfu(26-chuan.length()-fenxi.length()," ");cout<<chuan;outfu(10," ");a=chuan[0];ch=fenxi[fenxi.length()-1];x=ENODE.find(ch);if(x<ENODE.length()&&x>-1){if(ch==a){fenxi.erase(fenxi.length()-1,1);chuan.erase(0,1);cout<<"'"<<a<<"'匹配";if(pipei(chuan,fenxi,yc,b))return 1;elsereturn 0;}elsereturn 0;}else{if(ch=='#'){if(ch==a){cout<<"分析成功"<<endl;return 1;}elsereturn 0;}elseif(ch=='@'){fenxi.erase(fenxi.length()-1,1);if(pipei(chuan,fenxi,yc,b))return 1;elsereturn 0;}else{i=NODE.find(ch);if(a=='#'){x=ENODE.find('@');if(x<ENODE.length()&&x>-1)j=ENODE.length()-1;elsej=ENODE.length();}elsej=ENODE.find(a);if(yc[i][j].length()){cout<<NODE[i]<<"->"<<yc[i][j];fenxi.erase(fenxi.length()-1,1);for(k=yc[i][j].length()-1;k>-1;k--)if(yc[i][j][k]!='@')fenxi+=yc[i][j][k];if(pipei(chuan,fenxi,yc,b))return 1;elsereturn 0;}elsereturn 0;}}}void main(){edge *n;string str,(*yc)[50];int i,j,k;bool flag=0;cout<<"请输入上下文无关文法的总规则数:"<<endl;cin>>SUM;cout<<"请输入具体规则(格式:左部右部,@为空):"<<endl;n=new edge[SUM];for(i=0;i<SUM;i++)for(j=0;j<n[i].getrlen();j++){str=n[i].getrg();if(NODE.find(str[j])>NODE.length()&&ENODE.find(str[j])>ENODE.length()) ENODE+=str[j];}//计算first集合for(i=0;i<SUM;i++){first(n[i],n,i);}//outfu(10,"~*~");cout<<endl;for(i=0;i<SUM;i++)if(n[i].getfirst().find("@")<n[i].getfirst().length()){if(NODE.find(n[i].getro())<NODE.length()){for(k=1;k<n[i].getrlen();k++){if(NODE.find(n[i].getrg()[k])<NODE.length()){for(j=0;j<SUM;j++){if(n[i].getrg()[k]==n[j].getlf()[0]){n[i].newfirst(n[j].getfirst());break;}}if(n[j].getfirst().find("@")>n[j].getfirst().length()){n[i].delfirst();break;}}}}}//计算follow集合for(k=0;k<SUM;k++){for(i=0;i<SUM;i++){if(n[i].getlf()==n[0].getlf())n[i].newfollow("#");follow(n[i],n,i);}for(i=0;i<SUM;i++){for(j=0;j<SUM;j++)if(n[j].getrg().find(n[i].getlf())==n[j].getrlen()-1)n[i].newfollow(n[j].getfollow());}}//计算select集合for(i=0;i<SUM;i++){select(n[i],n);}for(i=0;i<NODE.length();i++){str.erase();for(j=0;j<SUM;j++)if(n[j].getlf()[0]==NODE[i]){if(!str.length())str=n[j].getselect();else{for(k=0;k<n[j].getselect().length();k++)if(str.find(n[j].getselect()[k])<str.length()){flag=1;break;}}}}//输出cout<<endl<<"非终结符";outfu(SUM," ");cout<<"First";outfu(SUM," ");cout<<"Follow"<<endl;outfu(5+SUM,"-*-");cout<<endl;for(i=0;i<NODE.length();i++){for(j=0;j<SUM;j++)if(NODE[i]==n[j].getlf()[0]){outfu(3," ");cout<<NODE[i];outfu(SUM+4," ");out(n[j].getfirst());outfu(SUM+4-2*n[j].getfirst().length()," ");out(n[j].getfollow());cout<<endl;break;}}outfu(5+SUM,"-*-");cout<<endl<<"判定结论:";if(flag){cout<<"该文法不是LL(1)文法!"<<endl;return;}else{cout<<"该文法是LL(1)文法!"<<endl;}//输出预测分析表cout<<endl<<"预测分析表如下:"<<endl;yc=new string[NODE.length()][50];outgraph(n,yc);string chuan,fenxi,fchuan;cout<<endl<<"请输入符号串:";cin>>chuan;fchuan=chuan;fenxi="#";fenxi+=NODE[0];i=0;cout<<endl<<"预测分析过程如下:"<<endl;cout<<"步骤";outfu(7," ");cout<<"分析栈";outfu(10," ");cout<<"剩余输入串";outfu(8," ");cout<<"推导所用产生式或匹配";if(pipei(chuan,fenxi,yc,i))cout<<endl<<"输入串"<<fchuan<<"是该文法的句子!"<<endl;elsecout<<endl<<"输入串"<<fchuan<<"不是该文法的句子!"<<endl;}截屏如下:三.实验中的问题及心得这次实验让我更加熟悉了LL(1)的工作流程以及LL(1)分析表的构造法。
编译原理实验报告《LL(1)语法分析器构造》(推荐文档)
《LL(1)分析器的构造》实验报告一、实验名称LL(1)分析器的构造二、实验目的设计、编制、调试一个LL(1)语法分析器,利用语法分析器对符号串的识别,加深对语法分析原理的理解。
三、实验内容和要求设计并实现一个LL(1)语法分析器,实现对算术文法:G[E]:E->E+T|TT->T*F|FF->(E)|i所定义的符号串进行识别,例如符号串i+i*i为文法所定义的句子,符号串ii+++*i+不是文法所定义的句子。
实验要求:1、检测左递归,如果有则进行消除;2、求解FIRST集和FOLLOW集;3、构建LL(1)分析表;4、构建LL分析程序,对于用户输入的句子,能够利用所构造的分析程序进行分析,并显示出分析过程。
四、主要仪器设备硬件:微型计算机。
软件: Code blocks(也可以是其它集成开发环境)。
五、实验过程描述1、程序主要框架程序中编写了以下函数,各个函数实现的作用如下:void input_grammer(string *G);//输入文法Gvoid preprocess(string *G,string *P,string &U,string &u,int &n,int &t,int &k);//将文法G预处理得到产生式集合P,非终结符、终结符集合U、u,int eliminate_1(string *G,string *P,string U,string *GG);//消除文法G中所有直接左递归得到文法GGint* ifempty(string* P,string U,int k,int n);//判断各非终结符是否能推导为空string* FIRST_X(string* P,string U,string u,int* empty,int k,int n);求所有非终结符的FIRST集string FIRST(string U,string u,string* first,string s);//求符号串s=X1X2...Xn的FIRST集string** create_table(string *P,string U,string u,int n,int t,int k,string* first);//构造分析表void analyse(string **table,string U,string u,int t,string s);//分析符号串s2、编写的源程序#include<cstdio>#include<cstring>#include<iostream>using namespace std;void input_grammer(string *G)//输入文法G,n个非终结符{int i=0;//计数char ch='y';while(ch=='y'){cin>>G[i++];cout<<"继续输入?(y/n)\n";cin>>ch;}}void preprocess(string *G,string *P,string &U,string &u,int &n,int &t,int &k)//将文法G预处理产生式集合P,非终结符、终结符集合U、u,{int i,j,r,temp;//计数char C;//记录规则中()后的符号int flag;//检测到()n=t=k=0;for( i=0;i<50;i++) P[i]=" ";//字符串如果不初始化,在使用P[i][j]=a时将不能改变,可以用P[i].append(1,a)U=u=" ";//字符串如果不初始化,无法使用U[i]=a赋值,可以用U.append(1,a) for(n=0;!G[n].empty();n++){ U[n]=G[n][0];}//非终结符集合,n为非终结符个数for(i=0;i<n;i++){for(j=4;j<G[i].length();j++){if(U.find(G[i][j])==string::npos&&u.find(G[i][j])==string::npos)if(G[i][j]!='|'&&G[i][j]!='^')//if(G[i][j]!='('&&G[i][j]!=')'&&G[i][j]!='|'&&G[i][j]!='^')u[t++]=G[i][j];}}//终结符集合,t为终结符个数for(i=0;i<n;i++){flag=0;r=4;for(j=4;j<G[i].length();j++){P[k][0]=U[i];P[k][1]=':';P[k][2]=':';P[k][3]='=';/* if(G[i][j]=='('){ j++;flag=1;for(temp=j;G[i][temp]!=')';temp++);C=G[i][temp+1];//C记录()后跟的字符,将C添加到()中所有字符串后面}if(G[i][j]==')') {j++;flag=0;}*/if(G[i][j]=='|'){//if(flag==1) P[k][r++]=C;k++;j++;P[k][0]=U[i];P[k][1]=':';P[k][2]=':';P[k][3]='=';r=4;P[k][r++]=G[i][j];}else{P[k][r++]=G[i][j];}}k++;}//获得产生式集合P,k为产生式个数}int eliminate_1(string *G,string *P,string U,string *GG)//消除文法G1中所有直接左递归得到文法G2,要能够消除含有多个左递归的情况){string arfa,beta;//所有形如A::=Aα|β中的α、β连接起来形成的字符串arfa、betaint i,j,temp,m=0;//计数int flag=0;//flag=1表示文法有左递归int flagg=0;//flagg=1表示某条规则有左递归char C='A';//由于消除左递归新增的非终结符,从A开始增加,只要不在原来问法的非终结符中即可加入for(i=0;i<20&&U[i]!=' ';i++){ flagg=0;arfa=beta="";for(j=0;j<100&&P[j][0]!=' ';j++){if(P[j][0]==U[i]){if(P[j][4]==U[i])//产生式j有左递归{flagg=1;for(temp=5;P[j][temp]!=' ';temp++) arfa.append(1,P[j][temp]);if(P[j+1][4]==U[i]) arfa.append("|");//不止一个产生式含有左递归}else{for(temp=4;P[j][temp]!=' ';temp++) beta.append(1,P[j][temp]);if(P[j+1][0]==U[i]&&P[j+1][4]!=U[i]) beta.append("|");}}}if(flagg==0)//对于不含左递归的文法规则不重写{GG[m]=G[i]; m++;}else{flag=1;//文法存在左递归GG[m].append(1,U[i]);GG[m].append("::=");if(beta.find('|')!=string::npos) GG[m].append("("+beta+")");else GG[m].append(beta);while(U.find(C)!=string::npos){C++;}GG[m].append(1,C);m++;GG[m].append(1,C);GG[m].append("::=");if(arfa.find('|')!=string::npos) GG[m].append("("+arfa+")");else GG[m].append(arfa);GG[m].append(1,C);GG[m].append("|^");m++;C++;}//A::=Aα|β改写成A::=βA‘,A’=αA'|β,}return flag;}int* ifempty(string* P,string U,int k,int n){int* empty=new int [n];//指示非终结符能否推导到空串int i,j,r;for(r=0;r<n;r++) empty[r]=0;//默认所有非终结符都不能推导到空int flag=1;//1表示empty数组有修改int step=100;//假设一条规则最大推导步数为100步while(step--){for(i=0;i<k;i++){r=U.find(P[i][0]);if(P[i][4]=='^') empty[r]=1;//直接推导到空else{for(j=4;P[i][j]!=' ';j++){if(U.find(P[i][j])!=string::npos){if(empty[U.find(P[i][j])]==0) break;}else break;}if(P[i][j]==' ') empty[r]=1;//多步推导到空else flag=0;}}}return empty;}string* FIRST_X(string* P,string U,string u,int* empty,int k,int n){int i,j,r,s,tmp;string* first=new string[n];char a;int step=100;//最大推导步数while(step--){// cout<<"step"<<100-step<<endl;for(i=0;i<k;i++){//cout<<P[i]<<endl;r=U.find(P[i][0]);if(P[i][4]=='^'&&first[r].find('^')==string::npos) first[r].append(1,'^');//规则右部首符号为空else{for(j=4;P[i][j]!=' ';j++){a=P[i][j];if(u.find(a)!=string::npos&&first[r].find(a)==string::npos)//规则右部首符号是终结符{first[r].append(1,a);break;//添加并结束}if(U.find(P[i][j])!=string::npos)//规则右部首符号是非终结符,形如X::=Y1Y2...Yk{s=U.find(P[i][j]);//cout<<P[i][j]<<":\n";for(tmp=0;first[s][tmp]!='\0';tmp++){a=first[s][tmp];if(a!='^'&&first[r].find(a)==string::npos)//将FIRST[Y1]中的非空符加入first[r].append(1,a);}}if(!empty[s]) break;//若Y1不能推导到空,结束}if(P[i][j]==' ')if(first[r].find('^')==string::npos)first[r].append(1,'^');//若Y1、Y2...Yk都能推导到空,则加入空符号}}}return first;}string FIRST(string U,string u,string* first,string s)//求符号串s=X1X2...Xn的FIRST集{int i,j,r;char a;string fir;for(i=0;i<s.length();i++){if(s[i]=='^') fir.append(1,'^');if(u.find(s[i])!=string::npos&&fir.find(s[i])==string::npos){ fir.append(1,s[i]);break;}//X1是终结符,添加并结束循环if(U.find(s[i])!=string::npos)//X1是非终结符{r=U.find(s[i]);for(j=0;first[r][j]!='\0';j++){a=first[r][j];if(a!='^'&&fir.find(a)==string::npos)//将FIRST(X1)中的非空符号加入fir.append(1,a);}if(first[r].find('^')==string::npos) break;//若X1不可推导到空,循环停止}if(i==s.length())//若X1-Xk都可推导到空if(fir.find(s[i])==string::npos) //fir中还未加入空符号fir.append(1,'^');}return fir;}string** create_table(string *P,string U,string u,int n,int t,int k,string* first)//构造分析表,P为文法G的产生式构成的集合{int i,j,p,q;string arfa;//记录规则右部string fir,follow;string FOLLOW[5]={")#",")#","+)#","+)#","+*)#"};string **table=new string*[n];for(i=0;i<n;i++) table[i]=new string[t+1];for(i=0;i<n;i++)for(j=0;j<t+1;j++)table[i][j]=" ";//table存储分析表的元素,“ ”表示error for(i=0;i<k;i++){arfa=P[i];arfa.erase(0,4);//删除前4个字符,如:E::=E+T,则arfa="E+T"fir=FIRST(U,u,first,arfa);for(j=0;j<t;j++){p=U.find(P[i][0]);if(fir.find(u[j])!=string::npos){q=j;table[p][q]=P[i];}//对first()中的每一终结符置相应的规则}if(fir.find('^')!=string::npos){follow=FOLLOW[p];//对规则左部求follow()for(j=0;j<t;j++){if((q=follow.find(u[j]))!=string::npos){q=j;table[p][q]=P[i];}//对follow()中的每一终结符置相应的规则}table[p][t]=P[i];//对#所在元素置相应规则}}return table;}void analyse(string **table,string U,string u,int t,string s)//分析符号串s{string stack;//分析栈string ss=s;//记录原符号串char x;//栈顶符号char a;//下一个要输入的字符int flag=0;//匹配成功标志int i=0,j=0,step=1;//符号栈计数、输入串计数、步骤数int p,q,r;string temp;for(i=0;!s[i];i++){if(u.find(s[i])==string::npos)//出现非法的符号cout<<s<<"不是该文法的句子\n";return;}s.append(1,'#');stack.append(1,'#');//’#’进入分析栈stack.append(1,U[0]);i++;//文法开始符进入分析栈a=s[0];//cout<<stack<<endl;cout<<"步骤分析栈余留输入串所用产生式\n";while(!flag){// cout<<"步骤分析栈余留输入串所用产生式\n"cout<<step<<" "<<stack<<" "<<s<<" ";x=stack[i];stack.erase(i,1);i--;//取栈顶符号x,并从栈顶退出//cout<<x<<endl;if(u.find(x)!=string::npos)//x是终结符的情况{if(x==a){s.erase(0,1);a=s[0];//栈顶符号与当前输入符号匹配,则输入下一个符号cout<<" \n";//未使用产生式,输出空}else{cout<<"error\n";cout<<ss<<"不是该文法的句子\n";break;}}if(x=='#'){if(a=='#') {flag=1;cout<<"成功\n";}//栈顶和余留输入串都为#,匹配成功else{cout<<"error\n";cout<<ss<<"不是该文法的句子\n";break;}}if(U.find(x)!=string::npos)//x是非终结符的情况{p=U.find(x);q=u.find(a);if(a=='#') q=t;temp=table[p][q];cout<<temp<<endl;//输出使用的产生式if(temp[0]!=' ')//分析表中对应项不为error{r=9;while(temp[r]==' ') r--;while(r>3){if(temp[r]!='^'){stack.append(1,temp[r]);//将X::=x1x2...的规则右部各符号压栈i++;}r--;}}else{cout<<"error\n";cout<<ss<<"不是该文法的句子\n";break;}}step++;}if(flag) cout<<endl<<ss<<"是该文法的句子\n";}int main(){int i,j;string *G=new string[50];//文法Gstring *P=new string[50];//产生式集合Pstring U,u;//文法G非终结符集合U,终结符集合uint n,t,k;//非终结符、终结符个数,产生式数string *GG=new string[50];//消除左递归后的文法GGstring *PP=new string[50];//文法GG的产生式集合PPstring UU,uu;//文法GG非终结符集合U,终结符集合uint nn,tt,kk;//消除左递归后的非终结符、终结符个数,产生式数string** table;//分析表cout<<" 欢迎使用LL(1)语法分析器!\n\n\n";cout<<"请输入文法(同一左部的规则在同一行输入,例如:E::=E+T|T;用^表示空串)\n";input_grammer(G);preprocess(G,P,U,u,n,t,k);cout<<"\n该文法有"<<n<<"个非终结符:\n";for(i=0;i<n;i++) cout<<U[i];cout<<endl;cout<<"该文法有"<<t<<"个终结符:\n";for(i=0;i<t;i++) cout<<u[i];cout<<"\n\n 左递归检测与消除\n\n";if(eliminate_1(G,P,U,GG)){preprocess(GG,PP,UU,uu,nn,tt,kk);cout<<"该文法存在左递归!\n\n消除左递归后的文法:\n\n"; for(i=0;i<nn;i++) cout<<GG[i]<<endl;cout<<endl;cout<<"新文法有"<<nn<<"个非终结符:\n";for(i=0;i<nn;i++) cout<<UU[i];cout<<endl;cout<<"新文法有"<<tt<<"个终结符:\n";for(i=0;i<tt;i++) cout<<uu[i];cout<<endl;//cout<<"新文法有"<<kk<<"个产生式:\n";//for(i=0;i<kk;i++) cout<<PP[i]<<endl;}else{cout<<"该文法不存在左递归\n";GG=G;PP=P;UU=U;uu=u;nn=n;tt=t;kk=k;}cout<<" 求解FIRST集\n\n";int *empty=ifempty(PP,UU,kk,nn);string* first=FIRST_X(PP,UU,uu,empty,kk,nn);for(i=0;i<nn;i++)cout<<"FIRST("<<UU[i]<<"): "<<first[i]<<endl;cout<<" 求解FOLLOW集\n\n";for(i=0;i<nn;i++)cout<<"FOLLOW("<<UU[i]<<"): "<<FOLLOW[i]<<endl; cout<<"\n\n 构造文法分析表\n\n"; table=create_table(PP,UU,uu,nn,tt,kk,first);cout<<" ";for(i=0;i<tt;i++) cout<<" "<<uu[i]<<" ";cout<<"# "<<endl;for( i=0;i<nn;i++){cout<<UU[i]<<" ";for(j=0;j<t+1;j++)cout<<table[i][j];cout<<endl;}cout<<"\n\n 分析符号串\n\n";cout<<"请输入要分析的符号串\n";cin>>s;analyse(table,UU,uu,tt,s);return 0;}3、程序演示结果(1)输入文法(2)消除左递归(3)求解FIRST和FOLLOW集(4)构造分析表(5)分析符号串匹配成功的情况:匹配失败的情况五、思考和体会1、编写的LL(1)语法分析器应该具有智能性,可以由用户输入任意文法,不需要指定终结符个数和非终结符个数。
编译原理课程设计LL文法分析器
目录引言 (1)第一章概述 (4)1.1设计内容 (4)1.2设计要求 (4)第二章设计的基本原理 (4)2.1预测分析表的构成原理 (4)2.2预测分析程序的生成 (5)第三章程序设计 (5)3.1总体方案设计 (6)3.2各模块设计 (6)第四章程序测试 (7)附录程序清单 (8)课 程 设 计L L (1)文法分析器2010 年 12 月设计题目学 号 专业班级 学生姓名指导教师合肥工业大学课程设计任务书第一章概述1.1 设计内容:1:预测分析表自动构造程序的实现2:预测分析程序的实现1.2 设计要求1:设计内容及要求:对于任意输入的一个LL(1)文法,构造其预测分析表。
要求:首先实现集合FIRST(X)构造算法和集合FOLLOW(A)构造算法,再实现教材P.79给出的预测分析表构造算法。
程序显示输出预测分析表或输出到指定文件中。
2:设计内容及要求:对文法 G: E→E+T|T 按教材P.76表4.1构造出G的预测分析程序,T→T*F|F 程序显示输出如P.78那样的匹配过程。
F→(E)|i第二章设计的基本原理2.1预测分析表的构成原理对于任意给定的LL(1) 文法G,为了构造它的预测分析表M,我们就必须构造与文法G有关的集合First和fellow.首先我们对每一个X∈V T U Vn ,构造FIRST(X),办法是,连续使用下面的规则,直至每个集合FIRST不再增大为止.(1)若X∈V T,,则FIRST(X)={X}.(2)若X∈Vn ,且有产生式X->a……,则把a加入到FIRST(X)中,若X->ε,也是一条产生式,则把ε也加到FIRST(X)中.(3)若X->Y……是一个产生式且Y∈Vn,则把FIRST(Y)中所有非ε-元素都加到FIRST(X)中,若X->Y1Y2……Y K ,是一个连续的产生式, Y1Y2……Y i-1 都是非终结符,而且,对于任何j,1≤j≤i-1,FIRST(Y j) 都含有ε(即Y1Y2……Y i-1=>ε),则把FIRST(Y i) 中的所有非ε-元素都加到FIRST(X)中,特别是,若所有的FIRST(Y j)均含有ε,j=1,2,……,k,则把ε加到FIRST(X)中.对于文法G中每个非终结符A构造FOLLOW(A)的办法是,连续使用下面的规则,直到每个FOLLOW不在增大为止.(1)对于文法的开始符号S,置#于FOLLOW(S)中;(2)若A->aBb是一个产生式,则把FIRST(b)\{ ε}加至FOLLOW(B)中;(3)若A->aB是一个产生式,或A->aBb是一个产生式而b=>ε(即ε∈FIRST( b))则把FOLLOW(A)加至FOLLOW(B)中构造分析表M的算法是:(1)对文法G的每个产生式A->a执行第二步和第三步;(2)对每个终结符a∈FIRST(a), 把A->a加至M[A,a]中;(3)若ε∈FIRST(a),则把任何b∈FOLLOW(A)把A->a加至M[A,b]中;(4)把所有无定义的M[A,a]标上出错标志.2.2 预测分析程序的生成预测分析程序的总控程序在任何时候都是按STACK栈顶符号X和当前的输入符号行事的,对于任何(X,a),总控程序每次都执行下述三种可能的动作之一;(1)若X=a=”#”,则宣布分析成功,停止分析过程.(2)若X=a≠”#”,则把X从STACK栈顶逐出,让a指向下一个输入符号.(3)若X是一个非终结符,则查看分析表M,若M[A,a]中存放着关于X的一个产生式,那么,首先把X逐出STACK栈顶,然后,把产生式的右部符号串按反序一一推进STACK栈(若右部符号为ε,则意味着不推什么东西进栈).在把产生式的右部符号推进栈的同时应做这个产生式相应得语义动作,若M[A,a]中存放着”出错标志”,则调用出错诊察程序ERROR.第三章程序设计3.1 总体方案设计在看到这个题目后,首先想到的就是要分模块进行设计.(1)第一模块:把文本文件中的LL(1)文法读入到程序中grammer类中的数组成员g中.(2)第二模块:通过对已输入到数组g中的文法,进行扫描,把相应的非终结符和终结符输入到非终结符数组VN中和终结符数组VT中.(3)第三模块:生成所有的非终结符的FIRST集合(4)第四模块:生成所有的非终结符的FOLLOW集合(5)第五模块:生成文法的预测分析表(6)第六模块:生成文法的预测分析程序通过这六模块的设计,最后可连接成一个预测分析程序.3.2 各模块程序设计首先要建立两个类,分别是grammer类和SeqStack类Grammer类中有保存从文本文件读入的LL(1)文法,用一个二维字符数组g保存, 保存非终结符的字符数组VN,保存终结符的字符数组VT,文法开始符号字符变量begin ,元素对应first集合中的有空字符的非终结符数组emptychar,预测分析表为二维整形数组form.SeqStack类主要的作用为在预测分析时作为符号栈.(1)第一模块的设计:对于这个模块的设计,就是用输入流对文本文件中的文法进行读入当读到字符’|’或’/n’时意味着一个产生式已结束,那么相应数组中相应的下标变量+1;数组g[i][0]所存放着这个产生式对应的字符的数量.g[i][1]为这个产生式左边的非终结符.(2)第二模块的设计:在已把文法读入到数组g中后,那么相应的g[i][0]为每个产生式的非终结符,若此非终结符不在数组VN中,那么把此字符加入到VN中对终结符的读入,则是从每个g[i][2]开始扫描,若此字符不在非终结符数组VN中,也不在VT 中,那么就把此字符加入到VT中.(3)第三模块的设计:生成FIRST集合这个算法基本上按照书上的原理,如对每个产生式进行扫描,当扫描到非终结符时,把此字符加入到相应非终结符的FIRST集合中,若遇到非终结符时,需把此非终结符的FIRST集合中除了空字符外全加入到对应的非终结符的first集合中,这就涉及到算法的一个递归算法,我是利用在函数的参数表中设置俩个参数,一个是FIRST数组,另外一个是非终结符,在用到递归时,我是利用把FIRST数组设为本产生式第一个非终结符的FIRST数组,而非终结符参数则设置为在扫描产生式右部过程中所遇到的非终结符.然后通过循环对这个文法中的所有非终结符进行函数的调用,这样来求到所有非终结符的FIRST集合.(4)第四模块的设计:生成FOLLOW集合这个算法,关键就是求某非终结符A的FOLLOW集合,那么就是扫描到A后面的字符,若为终结符,则把此终结符加入到A的FOLLOW集合,那么若为非终结符,则把此非终结符的FIRST集合加入到A的FOLLOW集合中,若A为某个产生式最后一个字符,则把这个产生式的第一个字符的FOLLOW集合加入到A的FOLLOW集合中,在这个算法的过程中叶涉及到运用递归,此递归的方法同样与上述求FIRST集合中运用的递归方法类似(5)第五模块的设计:求预测分析表的过程同样是对每个产生式进行扫描,对每个产生式的FIRST集合中的元素,都把相应的产生式的编号写入到对应的预测分析表中对应的位置(6)第六模块的设计:生成预测分析程序,就是把’#’和文法开始符号进入到栈中,然后把相应的分析语句中当前的输入符号对应,在每一步过程中按照书上讲到的原理,在预测分析表中找到相应的产生式.第四章程序测试附录程序清单class SeqStack;//声明栈类class grammer//定义grammer类,此类的作用把文本文件中的文法保存,并且产生这个文法的非终结符集合,终结符集合,first集合,fellow集合,预测分析表等{public:grammer();~grammer();void openfile(char *);void prepareform();void buildform();void buildProcess(SeqStack& ss);private:char begin;char *vt;char **g;char *vn;char **first;//这时所有非终结符的first集合char **fellow;//这是所有非终结符的fellow集合char *emptychar;//这个集合中的元素为对应first集合中的有空字符的非终结符int **form;//这是对应文法的预测分析表int count;void buildVn();void buildVt();void buildemptychar();void buildfirst();void buildfellow();void fellowzh(char *,char);void firstzh(char *,char);int search(char *,char);void printform();void outputblank(int);};const int stackIncreament=20;class SeqStack//定义SeqStack类,这个类的主要作用是在对语句的预测分析过程中作符号栈{public:friend grammer;SeqStack(int sz=50);~SeqStack();void Push(char x);bool Pop(char& x);bool getTop(char& x);bool IsEmpty();bool IsFull();int getSize();void MakeEmpty();void showPlay();private:char *elements;int top;int maxSize;void overflowProcess();};#include<fstream>#include<iostream>#include<stdio.h>#include<stdlib.h>#include<assert.h>#include<windows.h>#include "编译.h"using namespace std;grammer::grammer(){count=0;}grammer::~grammer(){int i;for(i=0;i<count;i++)delete g[i];delete g;delete vt;delete vn;}void grammer::openfile(char *file)//这个函数的主要功能在于对文本文件中的文法进行读入,并保存在对应的数组中,一并产生对应文法的终结符集合和非终结符集合{char ch;int i,j;ifstream infile(file,ios::in);//定义文件流if(!infile){cout<<"open error!"<<endl;exit(1);}while((ch=infile.get())!=EOF){if(ch=='-'){if((ch=infile.get())=='>'){count++;}else{infile.seekg(-1,ios::cur);}}else if(ch=='|'){count++;}else{}}g=new char *[count];for(i=0;i<count;i++){g[i]=new char [15];g[i][0]=0;}infile.clear();//能重新激活文件流infile.seekg(0,ios::beg);//定位i=0;j=1;while((ch=infile.get())!=EOF){if(ch=='-'){if(infile.get()!='>'){g[i][j]=ch;g[i][0]++;j++;if(ch==EOF)break;elseinfile.seekg(-1,ios::cur);}}else if(ch=='|'){i++;g[i][1]=g[i-1][1];g[i][0]=1;j=2;}else if(ch=='\n'){infile.seekg(-3,ios::cur);ch=infile.get();if(ch!='\n'){i++;j=1;}infile.seekg(2,ios::cur);}else{g[i][j]=ch;g[i][0]++;j++;}}cout<<count<<endl;for(i=0;i<count;i++){for(j=1;j<=g[i][0];j++){cout<<g[i][j]<<" ";}cout<<endl;}buildVn();//建立非终结符集合buildVt();//建立终结符集合}void grammer::buildVn()int i=1,j=0;vn=new char[count+1];vn[i]=g[j++][1];for(;j<count;j++)if(g[j][1]!=g[j-1][1]){i++;vn[i]=g[j][1];}vn[0]=i;begin=vn[1];cout<<"本文法开始符为:"<<begin<<endl;cout<<"本文法非终结符为:"<<" ";for(i=1;i<=vn[0];i++)cout<<vn[i]<<" ";cout<<endl;}void grammer::buildVt(){int i=1,j=0,t;char ch;vt=new char[100];vt[0]=0;for(;j<count;j++){t=2;for(;t<=g[j][0];t++){ch=g[j][t];if(!search(vt,ch)&&!search(vn,ch)){vt[i++]=g[j][t];vt[0]++;}}}cout<<"本文法终结符为:"<<" ";for(i=1;i<=vt[0];i++)cout<<vt[i]<<" ";cout<<endl;}int grammer::search(char *a,char ch)//搜索函数,用于在指定数组中对指定字符进行搜寻,若存在输出对应的序号,若不在则输出0for(int i=1;i<=a[0];i++){if(ch==a[i])return i;}return 0;}void grammer::buildemptychar()//建立对应first集合中含有空字符的的非终结符集合{int i=0,j=2,t=1;bool flag=true,flag1;emptychar=new char[vn[0]+1];emptychar[0]=0;for(;i<count;i++){if(g[i][2]=='@'&&!search(emptychar,g[i][1])){emptychar[t++]=g[i][1];emptychar[0]++;}}while(flag){flag=false;for(i=0;i<count;i++){for(j=2;j<=g[i][0];j++){if(search(emptychar,g[i][j])){flag1=true;}else{flag1=false;break;}}if(flag1==true&&!search(emptychar,g[i][1])){emptychar[t++]=g[i][1];emptychar[0]++;flag=true;}}cout<<"First集中含有空字符的有: ";for(i=1;i<=emptychar[0];i++){cout<<emptychar[i]<<" ";}cout<<endl;}void grammer::buildfirst(){int i;first=new char* [vn[0]];for(i=0;i<vn[0];i++){first[i]=new char[vt[0]+1];}for(i=0;i<vn[0];i++)first[i][0]=0;for(i=1;i<=vn[0];i++){firstzh(first[i-1],vn[i]);}}void grammer::buildfellow(){int i,j;fellow=new char* [vn[0]];for(i=0;i<vn[0];i++){fellow[i]=new char[vt[0]+1];}for(i=0;i<vn[0];i++)fellow[i][0]=0;for(i=1;i<=vn[0];i++){fellowzh(fellow[i-1],vn[i]);}for(i=0;i<vn[0];i++){cout<<vn[i+1]<<"的fellow集合为: ";for(j=1;j<=fellow[i][0];j++){cout<<fellow[i][j]<<" ";cout<<endl;}}void grammer::firstzh(char *a,char ch)//对指定非终结符建立对应的first集合{int i,j,t=1;for(i=0;i<count;i++){for(j=2;j<=g[i][0];j++){if(g[i][1]==ch){if(!search(vn,g[i][j])&&g[i][j]!='@')//找到对应产生式中的终结符时{if(!search(a,g[i][j])){a[t++]=g[i][j];a[0]++;}break;}else if(g[i][j]!='@')//找到对应的产生式中的非终结符时{firstzh(a,g[i][j]);//用递归的方法算出此非终结符的first集合if(!search(emptychar,g[i][j]))//当此非终结符的first集合中无空字符时,对此产生式扫描完毕break;}else{}}elsebreak;}}}void grammer::fellowzh(char *a,char ch)//对指定非终结符建立fellow集合{int i,j,k,m,n,t=a[0];if(ch==begin)//把#字符放入开始符的fellow集合{if(!search(a,'#'))a[++t]='#';a[0]++;}}for(i=0;i<count;i++){for(j=2;j<=g[i][0];j++){if(g[i][j]==ch){for(m=j;m<=g[i][0];m++){if(m==g[i][0]){if(g[i][1]!=ch)fellowzh(a,g[i][1]);//发现要求的非终结符在此产生式的末尾时elsebreak;}else{if(!search(vn,g[i][m+1]))//当此非终结符后面的字符为终结字符时,放入对应的fellow集合{if(!search(a,g[i][m+1])){a[++t]=g[i][m+1];a[0]++;}break;}else{k=search(vn,g[i][m+1]);//把此非终结符后面的非终结符的first集合中的元素放入对应的fellow集合for(n=1;n<=first[k-1][0];n++){if(!search(a,first[k-1][n])){a[++t]=first[k-1][n];a[0]++;}}if(!search(emptychar,g[i][m+1]))break;}}}}}}void grammer::prepareform(){int i,j;buildemptychar();buildfirst();buildfellow();for(i=0;i<vn[0];i++){if(search(emptychar,vn[i+1])){j=first[i][0];first[i][++j]='@';first[i][0]++;}}for(i=0;i<vn[0];i++){cout<<vn[i+1]<<"的first集合为: ";for(j=1;j<=first[i][0];j++){cout<<first[i][j]<<" ";}cout<<endl;}}void grammer::buildform(){int i,j,k,t,m,n;bool flag;form=new int*[vn[0]];for(i=0;i<vn[0];i++)form[i]=new int[vt[0]];for(i=0;i<vn[0];i++){for(j=0;j<vt[0];j++){form[i][j]=-1;}for(i=0;i<count;i++){t=search(vn,g[i][1]);flag=true;for(j=2;j<=g[i][0];j++){k=search(vt,g[i][j]);//若发现这个产生式的first集合中的对应的终结符时if(k){if(g[i][j]!='@'){if(form[t-1][k-1]!=-1){cout<<"本终结符错误!"<<endl;exit(1);}form[t-1][k-1]=i;flag=false;break;}else//若发现对应产生式中的first集合中含有空字符时{for(m=1;m<=fellow[t-1][0];m++){if(fellow[t-1][m]!='#')//可把对应的非终结符的fellow集合中的元素对应的表项中填入该产生式的标号{n=search(vt,fellow[t-1][m]);if(form[t-1][n-1]!=-1){cout<<"有终结符@本fellow集合中非#错误!"<<endl;exit(1);}form[t-1][n-1]=i;}else{if(form[t-1][k-1]!=-1){cout<<"有终结符@本fellow集合中#错误!"<<endl;exit(1);}form[t-1][k-1]=i;}flag=false;break;}}else//找到该产生式中的非终结符时{k=search(vn,g[i][j]);for(m=1;m<=first[k-1][0];m++){if(first[k-1][m]!='@'){n=search(vt,first[k-1][m]);if(form[t-1][n-1]!=-1){cout<<"本first集合中非@!"<<endl;exit(1);}form[t-1][n-1]=i;}else{}}if(!search(first[k-1],'@'))//若在此终结符对应的first集合中无空字符时{flag=false;break;}}}if(flag==true)//说明该产生式对应的first集合中含有空字符{for(m=1;m<=fellow[t-1][0];m++){if(fellow[t-1][m]!='#'){n=search(vt,fellow[t-1][m]);if(form[t-1][n-1]!=-1){cout<<"本fellow集合中非#错误!"<<endl;exit(1);}form[t-1][n-1]=i;}{n=search(vt,'@');if(form[t-1][n-1]!=-1){cout<<"本fellow集合中#错误!"<<endl;exit(1);}form[t-1][n-1]=i;}}}}printform();}void grammer::outputblank(int i){int j;for(j=0;j<i;j++)cout<<" ";}void grammer::printform(){int i,j,k,t,m;cout<<"-----------------------------预测分析表如下所示------------------------------"<<endl;outputblank(6);for(i=1;i<=vt[0];i++){if(vt[i]=='@'){cout<<"#";outputblank(10);}else{cout<<vt[i];outputblank(10);}}cout<<endl;for(i=0;i<vn[0];i++){cout<<" "<<vn[i+1];outputblank(4);{k=form[i][j];if(k==-1){Sleep(500);cout<<"error";outputblank(6);}else{Sleep(1000);t=9-g[k][0];cout<<g[k][1]<<"->";for(m=2;m<=g[k][0];m++){cout<<g[k][m];}outputblank(t);}}cout<<endl;}}void grammer::buildProcess(SeqStack& ss) {char *dia,ch;int i,j,inlen,m,n,index=0,proc=0;bool flag=true,flag1=false;dia=new char[20];cout<<"请输入待分析的字符串"<<endl;cin>>dia;for(i=0,inlen=0;i<20;i++){if(dia[i]!='\0')inlen++;elsebreak;}cout<<"步骤";outputblank(8);cout<<"符号栈";outputblank(15);cout<<"输入串";outputblank(15);cout<<"所用产生式"<<endl;dia[inlen++]='#';ss.Push('#');ss.Push(begin);while(flag){Sleep(1500);cout<<proc;if(proc>=10)outputblank(11);elseoutputblank(12);++proc;ss.showPlay();outputblank(21-ss.getSize());for(j=index;j<inlen;j++)cout<<dia[j];outputblank(21-inlen+index);if(flag1==true){cout<<g[form[m-1][n-1]][1]<<"->";for(j=2;j<=g[form[m-1][n-1]][0];j++)cout<<g[form[m-1][n-1]][j];cout<<endl;}elsecout<<endl;ss.getTop(ch);m=search(vn,ch);if(dia[index]!='#')n=search(vt,dia[index]);elsen=search(vt,'@');if(search(vt,ch))//当栈顶是终结符{if(ch==dia[index])//且此终结符与输入串此时检测的终结符符号相同{index++;ss.Pop(ch);flag1=false;}else{cout<<"该字符串不能由该文法推出"<<endl;exit(1);}}else if(ch=='#'){if(ch==dia[index]){cout<<endl;cout<<"---------------------------------分析完成------------------------------"<<endl;flag=false;}else{cout<<"该字符串不能由该文法推出"<<endl;exit(1);}}else if(form[m-1][n-1]!=-1)//当栈顶的非终结符与输入串对应的终结符在预测分析表中相应的项存在时{if(g[form[m-1][n-1]][2]!='@'){ss.Pop(ch);for(i=g[form[m-1][n-1]][0];i>=2;i--){ss.Push(g[form[m-1][n-1]][i]);}}elsess.Pop(ch);flag1=true;}else{cout<<"该字符串不能由该文法推出"<<endl;exit(1);}}}void SeqStack::overflowProcess(){char *newArray=new char[maxSize+stackIncreament];if(newArray==NULL){cerr<<"存储分配失败!"<<endl;exit(1);}for(int i=0;i<=top;i++)newArray[i]=elements[i];maxSize=maxSize+stackIncreament;delete []elements;elements=newArray;}void SeqStack::Push(char x){if(IsFull()==true)overflowProcess();elements[++top]=x;}bool SeqStack::Pop(char &x){if(IsEmpty()==true)return false;x= elements[top--];return true;}bool SeqStack::getTop(char &x){if(IsEmpty()==true)return false;x=elements[top];return true;}void SeqStack::showPlay(){for(int i=0;i<=top;i++)cout<<elements[i];}SeqStack::SeqStack(int sz):top(-1),maxSize(sz) {elements=new char[maxSize];assert(elements!=NULL);}SeqStack::~SeqStack(){delete []elements;}bool SeqStack::IsEmpty(){return(top==-1)?true:false;}bool SeqStack::IsFull(){return (top==maxSize-1)?true:false;}int SeqStack::getSize(){return top+1;}void SeqStack::MakeEmpty(){top=-1;}#include<iostream>#include"编译.h"using namespace std;void main(){//char ch;grammer ga;SeqStack ss;char filename[20];cout<<"欢迎来到本LL(1)文法预测分析表自动生成程序"<<endl;cout<<endl;cout<<endl;cout<<"请输入文法所在的文件名"<<endl;cin>>filename;ga.openfile(filename);ga.prepareform();ga.buildform();ga.buildProcess(ss);}。
编译原理语法分析——LL(1)分析表的实现
printf("Please input your chioc : ");
ch = getche();
printf("\n");
if(ch == 'I' || ch == 'i')
{
printf("Input a string end up with \'#\':");
gets(string);
i = strlen(string);
if(string[i-1] != '#')
{
string[i] = '#';
string[i+1] = '\0';
}
AnalysisProcess();
goto re2;
}
else if(ch == 'Q' || ch == 'q')
{
Quit();
return ;
int i;
int j;
count = 0;
ch = fgetc(f);
while(!feof(f))
{
if (ch == '-')
{
if ( (ch2=fgetc(f)) == '>' )
{
count++; //累计产生式的字符数条数
}
else
{
fseek(f,-1L, 1);
}
}//if
else if( ch == '|' )
fclose(f);
}//Input
LL(1)语法分析程序实验报告
LL1实验报告1.设计原理所谓LL(1)分析法,就就是指从左到右扫描输入串(源程序),同时采用最左推导,且对每次直接推导只需向前瞧一个输入符号,便可确定当前所应当选择得规则。
实现LL(1)分析得程序又称为LL(1)分析程序或LL1(1)分析器。
我们知道一个文法要能进行LL(1)分析,那么这个文法应该满足:无二义性,无左递归,无左公因子。
当文法满足条件后,再分别构造文法每个非终结符得FIRST与FOLLOW集合,然后根据FIRST与FOLLOW集合构造LL(1)分析表,最后利用分析表,根据LL(1)语法分析构造一个分析器。
LL(1)得语法分析程序包含了三个部分,总控程序,预测分析表函数,先进先出得语法分析栈,本程序也就是采用了同样得方法进行语法分析,该程序就是采用了C++语言来编写,其逻辑结构图如下:LL(1)预测分析程序得总控程序在任何时候都就是按STACK栈顶符号X与当前得输入符号a做哪种过程得。
对于任何(X,a),总控程序每次都执行下述三种可能得动作之一:(1)若X = a =‘#’,则宣布分析成功,停止分析过程。
(2)若X = a ‘#’,则把X从STACK栈顶弹出,让a指向下一个输入符号。
(3)若X就是一个非终结符,则查瞧预测分析表M。
若M[A,a]中存放着关于X得一个产生式,那么,首先把X弹出STACK栈顶,然后,把产生式得右部符号串按反序一一弹出STACK 栈(若右部符号为ε,则不推什么东西进STACK栈)。
若M[A,a]中存放着“出错标志”,则调用出错诊断程序ERROR。
事实上,LL(1)得分析就是根据文法构造得,它反映了相应文法所定义得语言得固定特征,因此在LL(1)分析器中,实际上就是以LL(1)分析表代替相应方法来进行分析得。
2、分析LL ( 1) 分析表就是一个二维表,它得表列符号就是当前符号,包括文法所有得终结与自定义。
得句子结束符号#,它得表行符号就是可能在文法符号栈SYN中出现得所有符号,包括所有得非终结符,所有出现在产生式右侧且不在首位置得终结符, 自定义得句子结束符号#表项。
编译原理LL(1)语法分析实验报告
学号 E 专业计算机科学与技术姓名万学进实验日期2010-5-11教师签字成绩实验报告【实验名称】 LL(1)语法分析【实验目的】通过完成预测分析法的语法分析程序,了解预测分析法和递归子程序法的区别和联系。
使了解语法分析的功能,掌握语法分析程序设计的原理和构造方法,训练掌握开发应用程序的基本方法。
【实验内容】根据某一文法编制调试 LL ( 1 )分析程序,以便对任意输入的符号串进行分析。
构造预测分析表,并利用分析表和一个栈来实现对上述程序设计语言的分析程序。
分析法的功能是利用LL(1)控制程序根据显示栈栈顶内容、向前看符号以及LL(1)分析表,对输入符号串自上而下的分析过程。
【设计思想】(1)定义部分:定义常量、变量、数据结构。
(2)初始化:设立LL(1)分析表、初始化变量空间(包括堆栈、结构体、数组、临时变量等);(3)控制部分:从键盘输入一个表达式符号串;(4)利用LL(1)分析算法进行表达式处理:根据LL(1)分析表对表达式符号串进行堆栈(或其他)操作,输出分析结果,如果遇到错误则显示错误信息。
【实验要求】1、编程时注意编程风格:空行的使用、注释的使用、缩进的使用等。
2、如果遇到错误的表达式,应输出错误提示信息。
3、对下列文法,用LL(1)分析法对任意输入的符号串进行分析:(1)S->TE(2)E->+TE|$(3)T->FM(4)M->*FM|$(5)F->(E)|i#【流程图】【源代码】#include<>#include<>int vnNum,grammarNum,vtNum=6;int order;int count=1;charGrammar[20][10],BlankTerminate[20][2] ;char First[5][4]={'S','(','i','\0','E','+','$','\0','T','(','i','\0','M','*','$','\0','F','(','i','\0'}; charFollow[5][6]={'S',')','#','\0','\0',' \0','E',')','#','\0','\0','\0','T','+',')','#','\0','\0','M','+',')','#','\0','\0','F','*','+',')','#','\0'};char Select[8][4]={'(','i','\0','\0','+','\0','\0','\0',')','#','\0','\0', '(','i','\0','\0','*','\0','\0','\0','+',')','#','\0','(','\0','\0','\0','i','\0','\0','\0'};int IndiBlanket[6][7];char VT[10]={'i','+','*','(',')','#'};typedef struct {char *base;char *top;int stacksize;}AnalStack;AnalStack S;int ScanGrammar(){FILE *fp=fopen("文法.txt","r"); FILE *tp;char singleChar,nextChar;int i=0,j=0;while(!feof(fp)){fscanf(fp,"%c",&singleChar);if(singleChar=='#'){Grammar[i][j]='\0';break;}if(singleChar=='\n'){Grammar[i][j]='\0';i++;j=0;continue;}if(singleChar=='-'){tp=fp;fscanf(tp,"%c",&nextChar);if(nextChar=='>'){fp=tp;continue;}}if(singleChar=='|'){Grammar[i+1][0]=Grammar[i][0];Grammar[i][j]='\0';i++;j=1;continue;}Grammar[i][j]=singleChar;j++;}// printf("输入的文法:\n");for(int k=0;k<=i;k++){j=0;while(Grammar[k][j]!='\0'){if(j==1){// printf("->");}//printf("%c",Grammar[k][j]);j++;}// printf("\n");}// printf("%d\n",i);fclose(fp);return i;}int Fill(char gi,char sij,int grammarOrder){int i,j;for(i=0;i<vnNum;i++){if(First[i][0]==gi)break;}j=0;while(VT[j]!='\0'){if(VT[j]==sij)break;j++;}IndiBlanket[i][j]=grammarOrder;return 0;}int Indicate(){int i,j;for(i=0;i<vnNum;i++){for(j=0;j<vtNum;j++){IndiBlanket[i][j]=-1;}}for(i=0;i<=grammarNum;i++){j=0;while(Select[i][j]!='\0'){Fill(Grammar[i][0],Select[i][j],i );j++;}}printf("预测分析表如下:\n");for(i=0;i<vnNum;i++){for(j=0;j<vtNum;j++){printf("%3d",IndiBlanket[i][j]);}printf("\n");}return 0;}int Terminate_$(int grammarNum){int j=0;int count;for(int i=0;i<=grammarNum;i++){BlankTerminate[i][1]='0';}BlankTerminate[0][0]=Grammar[0][0];if(Grammar[0][1]=='$'){BlankTerminate[0][1]='1';}count=1;for(i=1;i<=grammarNum;i++){for(j=0;j<count;j++){if(Grammar[i][0]==BlankTerminate[ j][0]){if(Grammar[i][1]=='$'){BlankTerminate[j][1]='1';break;}}}if(j==count){BlankTerminate[count][0]=Grammar[i][0 ];if(Grammar[i][1]=='$'){BlankTerminate[count][1]='1';}count++;}}count--;// printf("$的终结符表:\n");/*for(i=0;i<j;i++){printf("%c:%c\n",BlankTerminate[i][0],BlankTerminate[i][1]);}*/return count;}AnalStack InitStack(){=(char *)malloc(100*sizeof(char));if(!exit(1);=;=100;*='#';++;*='S';return S;}int Print(char AnalStr[],int i,int sign){int startpos=i;printf("%d\t",count);count++;char *p=;while(p!=+2){printf("%c",*p);p++;}printf("\t");while(AnalStr[i]!='\0'){printf("%c",AnalStr[i]);i++;}printf("\t\t");if(sign==0){int j=0;while(Grammar[order][j]!='\0'){printf("%c",Grammar[order][j]);if(j==0)printf("->");j++;}printf("\n");}if(sign==1){printf("%c匹配\n",AnalStr[startpos]);}return 0;}int Push(char topChar,char curChar,int sign,int ii,char AnalStr[]){int i,j;for(i=0;i<vnNum;i++){if(First[i][0]==topChar)break;}j=0;while(VT[j]!='\0'){if(VT[j]==curChar)break;j++;}order=IndiBlanket[i][j];Print(AnalStr,ii,sign);j=1;while(Grammar[order][j]!='\0'){j++;}j--;while(j!=0){if(Grammar[order][j]!='$'){++;*=Grammar[order][j];}j--;}return 0;}int Analysis(){int i=0;int sign=0;int count=1;char curChar;InitStack();char AnalStr[10]={'\0'};printf("输入产生式:\n");scanf("%s",&AnalStr);printf("步骤\t分析栈\t剩余输入串\t产生式\n");while(AnalStr[i]!='\0'){sign=0;curChar=AnalStr[i];char *p=;char topChar=*p;;if(topChar<'A'||topChar>'Z'){if(topChar==curChar){sign=1;Print(AnalStr,i,sign);i++;continue;}else{printf("Analysis ERROR!\n");return 0;}}if(topChar=='#'){if(topChar==curChar){Print(AnalStr,i,sign);break;}else{return 0;}}else{Push(topChar,curChar,sign,i,AnalS tr);}}printf("预测分析成功!\n");return 0;}int main(){int i,m;grammarNum=ScanGrammar();vnNum=Terminate_$(grammarNum); // printf("Select集:\n");for(i=0;i<=grammarNum;i++){m=0;while(Select[i][m]!='\0'){// printf("%c",Select[i][m]);m++;}// printf("\n");}Indicate();Analysis();return 0;}【运行结果】。
合肥工业大学编译原理实验报告(完整代码版)
计算机与信息学院之欧侯瑞魂创作创作时间:二零二一年六月三十日编译原理实验陈说专业班级信息平安13-1班学生姓名及学号马骏 2013211869课程教学班号任课教师李宏芒实验指导教师李宏芒实验地址实验楼机房2015 ~2016 学年第二学期实验1 词法分析设计一、实验目的通过本实验的编程实践, 使学生了解词法分析的任务, 掌握词法分析法式设计的原理和构造方法, 使学生对编译的基本概念、原理和方法有完整的和清楚的理解, 并能正确地、熟练地运用二、实验要求1、编程时注意编程风格:空行的使用、注释的使用、缩进的使用等.2、将标识符填写的相应符号表须提供给编译法式的以后各阶段使用.3、根据测试数据进行测试.测试实例应包括以下三个部份:全部合法的输入.各种组合的非法输入.由记号组成的句子.4、词法分析法式设计要求输出形式:例:输入VC++语言的实例法式:If i=0 then n++;a﹤= 3b %);输出形式为:单词二元序列类型位置(行, 列)(单词种别, 单词属性)for (1,for ) 关键字(1, 1)i ( 6,i ) 标识符(1, 2)= ( 4, = ) 关系运算符(1, 3) 120 ( 5, 0 ) 常数(1, 4)then ( 1, then) 关键字(1, 5)n (6,n ) 标识符(1, 6)++ Error Error (1, 7);( 2, ; ) 分界符(1, 8)a (6,a ) 标识符(2, 1)﹤= (4,<= ) 关系运算符(2, 2)3b Error Error (2, 4)% Error Error (2, 4)) ( 2, ) ) 分界符(2, 5);( 2, ; ) 分界符(2, 6)三、实验内容用 VC++/VB/JAVA 语言实现对 C 语言子集的源法式进行词法分析.通过输入源法式从左到右对字符串进行扫描和分解, 依次输出各个单词的内部编码及单词符号自身值;若遇到毛病则显示“Error”, 然后跳过毛病部份继续显示;同时进行标识符挂号符号表的管理.以下是实现词法分析设计的主要工作:(1)从源法式文件中读入字符.(2)统计行数和列数用于毛病单词的定位.(3)删除空格类字符, 包括回车、制表符空格.(4)按拼写单词, 并用(内码, 属性)二元式暗示.(属性值——token的机内暗示)(5)如果发现毛病则陈说犯错 7(6)根据需要是否填写标识符表供以后各阶段使用.四、实验步伐1、根据流程图编写出各个模块的源法式代码上机调试.2、编制好源法式后, 设计若干用例对系统进行全面的上机测试, 并通过所设计的词法分析法式;直至能够获得完全满意的结果.3、书写实验陈说;实验陈说正文的内容:功能描述:该法式具有什么功能?法式结构描述:函数调用格式、参数含义、返回值描述、函数功能;函数之间的调用关系图.详细的算法描述(法式总体执行流程图) .给出软件的测试方法和测试结果.实验总结(设计的特点、缺乏、收获与体会).五、实验截图输入If i=0 then n++;a<= 3b %);六、核心代码#include<iostream>#include<string>#include<fstream>#include <sstream>using namespace std;const char* salaryfile="salaryfile.txt";const int max=40;stringid[max]={"do","end","for","if","printf","scanf","then"," while"};//关键字表string s[max]={",",";","(",")","[","]","+","-","*","/","<","<=","=",">",">=","<>"};//分界符表算数运算符表关系运算符表string k[max];// 标识符string ci[max];// 常数int fjfpoint=5;//分界符表尾int mathpoint=9;//算数运算符表尾int cipointer=0;//常数表尾int idpointer=0;//关键字表尾int kpointer=0;//标识符表尾int fjf;//0 不是分界符 1是int rowy=1;//识别输入行位置int rowx=1;//识别输入列位置int outkey=0;//打印控制 0为数字后有字母其他可以void searcht(int i,string m)//根据已识另外首字母识别字符串{//cout<<"enter searcht!!"<<endl;int x;if(i==0)//首字符是字母识别关键字{//cout<<" a word!!"<<endl;for(x=0;x<max;x++){if(id[x]==m){cout<<"(1,"<<id[x]<<")"<<" 关键字("<<rowy<<","<<rowx<<")"<<endl;break;}}if(x==max)//不是关键字再识别标识符{for(x=0;x<max;x++){if(k[x]==m){cout<<"(6,"<<m<<") "<<"标识符("<<rowy<<","<<rowx<<")"<<endl;break;}}if(x==max)//标识符表没有时拔出标识符{cout<<"(6,"<<m<<") "<<"标识符("<<rowy<<","<<rowx<<")"<<endl;k[kpointer]=m;kpointer++;}}}if(i==1)//识别常数{//cout<<" a number!!"<<endl;for(x=0;x<max;x++){if(ci[x]==m){cout<<"(5,"<<x<<")"<<endl;break;}}if(x==max){cout<<"(5,"<<m<<") 常数("<<rowy<<","<<rowx<<")"<<endl;ci[cipointer]=m;cipointer++;}}if(i==2)//识别分界符算数运算符关系运算符{//cout<<" a signal!!"<<endl;for(x=0;x<max;x++){if(s[x]==m)break;}//x--;if(x<6){fjf=1;}if(x>5&&x<10){if(outkey==1){cout<<"(3,"<<s[x]<<") 算数运算符("<<rowy<<","<<rowx<<")"<<endl;outkey=0;}fjf=0;}if(x>9&&x<max-1){if(outkey==1){cout<<"(4,"<<s[x]<<") 关系运算符("<<rowy<<","<<rowx<<")"<<endl;outkey=0;}fjf=0;}if(x==max){if(outkey==1){cout<<"Error Error ("<<rowy<<","<<rowx<<")"<<endl; outkey=0;}fjf=0;}}};void wordlook(char t,string sn)//识别首字符, 分类识别字符串{if(t>=48&&t<=57)searcht(1,sn);else{if((t>64&&t<91)||(t>96&&t<123))searcht(0,sn);else searcht(2,sn);}};void split(string s)//分割字符串{//cout<<s<<endl;string now[max];string sn;int nowpointer=0;int i=0;int x;int sign=2;//非法数字标识表记标帜int diannumber=0;//数中点的个数for(x=0;x<s.length();x++){if((s[x]>64&&s[x]<91)||(s[x]>96&&s[x]<123)||(s[x]>=48&&s [x]<=57)||(x>0&&s[x]==46&&sign==1))//判断数字后跟字母还是字母后有数字{if(i==0){if(s[x]>=48&&s[x]<=57)sign=1;else sign=2;}else{if(sign==1){if(s[x]>=48&&s[x]<=57||s[x]==46){if(s[x]==46){if(diannumber==0)diannumber++;else sign=0;}}else sign=0;}}i++;if(x==(s.length()-1)){sn=s.substr(x-i+1,i);if(i>0){// cout<<sn<<" i="<<i<<endl;cout<<sn<<" ";if(sign==0)//数字后有字母的情况cout<<" Error Error ("<<rowy<<","<<rowx<<")"<<endl;else //字母开头的字符串{// cout<<" true"<<endl;wordlook(sn[0],sn);rowx++;}}}}else{if(x>0&&(s[x-1]>64&&s[x-1]<91)||(s[x-1]>96&&s[x-1]<123)||(s[x-1]>=48&&s[x-1]<=57))//遇到分界符运算符如果前面是数字或字母{sn=s.substr(x-i,i);if(i>0){// cout<<sn<<" i="<<i<<endl;cout<<sn<<" ";if(sign==0)cout<<" Error Error ("<<rowy<<","<<rowx<<")"<<endl;else{// cout<<" true"<<endl;wordlook(sn[0],sn);rowx++;}}i=0;}string ll=s.substr(x,1);//判断是运算符还是分界符wordlook(s[x],ll);if(fjf==0)//是运算符{i++;if((s[x+1]>64&&s[x+1]<91)||(s[x+1]>96&&s[x+1]<123)||(s[x +1]>=48&&s[x+1]<=57))//如果后面是数字或字母{sn=s.substr(x-i+1,i);// cout<<sn<<"运算符 i="<<i<<endl;cout<<sn<<" ";outkey=1;wordlook(sn[0],sn);rowx++;i=0;}}if(fjf==1){if((s[x-1]>64&&s[x-1]<91)||(s[x-1]>96&&s[x-1]<123)||(s[x-1]>=48&&s[x-1]<=57))//如果前面是数字或字母 {}else if(i>0){sn=s.substr(x-i,i);// cout<<sn<<"运算符 i="<<i<<endl;cout<<sn<<" ";outkey=1;wordlook(sn[0],sn);rowx++;i=0;}cout<<s[x]<<" (2,"<<s[x]<<") 分界符("<<rowy<<","<<rowx<<")"<<endl;rowx++;/* if(ll==";"){rowy++;rowx=1;}*/}}};int main(){int x;string instring;//读入一行string sn;/*getline(cin,sn);// string带空格输入cout<<sn<<endl;char t=sn[0];if(t>=48&&t<=57)searcht(1,sn);else{if((t>64&&t<91)||(t>96&&t<123))searcht(0,sn);else searcht(2,sn);}*/ifstream inputfile;//in file stream inputfile.open(salaryfile);//inputfile>>noskipws;if(!inputfile){cout<<"no file"<<endl;}string pp;while(!inputfile.eof()){getline(inputfile,pp); istringstream istr(pp);string ppword;while(istr>>ppword)//依照空格分割字符串{split(ppword);}int begin = 0;//去失落字符串的所有空格begin = pp.find(" ",begin); //查找空格在str中第一次呈现的位置while(begin != -1) //暗示字符串中存在空格{pp.WordStr(begin, 1, ""); // 用空串替换str中从begin开始的1个字符begin = pp.find(" ",begin); //查找空格在替换后的str中第一次呈现的位置}*///cout<<"good "<<pp<<endl;//rowx++;rowy++;//换行rowx=1;}return 0;}七、实验总结通过本次试验使我不单对词法分析器有了更深的了解, 而且提高了编程能力, 希望在以后的学习中可以解决词法分析更多的问题.实验2 LL(1)分析法一、实验目的通过完成预测分析法的语法分析法式, 了解预测分析法和递归子法式法的区别和联系.使学生了解语法分析的功能, 掌握语法分析法式设计的原理和构造方法, 训练学生掌握开发应用法式的基本方法.有利于提高学生的专业素质, 为培养适应社会多方面需要的能力.二、实验要求1、编程时注意编程风格:空行的使用、注释的使用、缩进的使用等.2、如果遇到毛病的表达式, 应输犯毛病提示信息.3、对下列文法, 用 LL(1)分析法对任意输入的符号串进行分析:(1)E->TG(2)G->+TG|—TG(3)G->ε(4)T->FS(5)S->*FS|/FS(6)S->ε(7)F->(E)(8)F->i三、实验内容根据某一文法编制调试 LL ( 1 )分析法式, 以便对任意输入的符号串进行分析.构造预测分析表, 并利用分析表和一个栈来实现对上述法式设计语言的分析法式.分析法的功能是利用 LL(1)控制法式根据显示栈栈顶内容、向前看符号以及 LL(1)分析表, 对输入符号串自上而下的分析过程.四、实验步伐1、根据流程图编写出各个模块的源法式代码上机调试.2、编制好源法式后, 设计若干用例对系统进行全面的上机测试, 并通过所设计的 LL(1)分析法式;直至能够获得完全满意的结果.3、书写实验陈说;实验陈说正文的内容:写出 LL(1)分析法的思想及写出符合 LL(1)分析法的文法.法式结构描述:函数调用格式、参数含义、返回值描述、函数功能;函数之间的调用关系图.详细的算法描述(法式执行流程图) .给出软件的测试方法和测试结果.实验总结(设计的特点、缺乏、收获与体会).五、实验截图六、核心代码#include<iostream>#include<string>using namespace std;string pp;//输出字符串string hh="\r\n";//换行const int max=50;int endfu[max];//终止符序号表int endfupointer=8;char endfureal[max]={'+','-','*','/','(','i',')','#'};int unendfu[max];int unendfupointer=5;char unendfureal[max]={'E','G','T','S','F'};string makemath[max]={"E->TG","G->+TG","G->-TG","G->$","T->FS","S->*FS","S->/FS","S->$","F->(E)","F->i"};//0 E->TG,1 G->+TG,2 G->-TG,3 G->$,4 T->FS,5 S->*FS,6 S->/FS,7 S->$,8 F->(E),9 F->i//$代表空串string behavior[max]={"初始化","POP"};int smarttable[max][max];//分析表int checkendfu(char fu)//查终结符序号{int x;for(x=0;x<endfupointer;x++){if(endfureal[x]==fu){break;}}if(x<endfupointer)return x;else return -1;};int checkunendfu(char fu)//查非终结符序号{int x;for(x=0;x<unendfupointer;x++){if(unendfureal[x]==fu)break;}if(x<unendfupointer)return x;else return-1;};string checkmakemath(int x)//查发生式表{return makemath[x];};int checksmarttable(int x,int y)//查分析表{return smarttable[x][y];};class smartbox{public:smartbox(){box[0]='#';box[1]='E';boxpointer=1;}void push(char fu){boxpointer++;box[boxpointer]=fu;}char pop(){char a=box[boxpointer];if(a!='#'){//cout<<"pop: "<<boxpointer<<" "<<a<<endl; //stringstream oss;/*pp=pp+"pop: ";char buffer[max];sprintf(buffer,"%d",boxpointer);string s=buffer;pp=pp+" ";pp=pp+s;pp=pp+hh;*/boxpointer--;return a;}}void check(){if(checkendfu(box[boxpointer])!=-1){char a;//cout<<box[boxpointer]<<checkendfu(box[boxpointer])<<" ";//char buffer[max];//sprintf(buffer//pp=pp+box[boxpointer];//pp=pp+checkendfu(box[boxpointer]);//pp=pp+" ";a=pop();//cout<<"out "<<a<<endl;。
编译原理 COMPILER__实验2.2-LL(1)分析法(1)
编译原理实验报告—LL(1)分析法程序班级:小组人员:实验2.2 LL(1)分析法一、实验目的:1.根据某一文法编制调试LL(1)分析程序,以便对任意输入的符号串进行分析。
2.本次实验的目的主要是加深对预测分析LL(1)分析法的理解。
二、实验平台Windows + VC++6.0程序:“3-LL1.cpp”三、实验内容1.对下列文法,用LL(1)分析法对任意输入的符号串进行分析:(1)E→TG(2)G→+TG|-TG(3)G→ε(4)T→FS(5)S→*FS|/FS(6)S→ε(7)F→(E)(8)F→i程序功能:输入:一个以# 结束的符号串(包括+ - * /()i # ):例如:i+i*i-i/i#输出: 经完善程序目前能对所有输入串进行正确的分析.算法思想:栈用于存放文法符号,分析开始时,栈底先放一个‘#’,然后,放进文法开始符号。
同时,假定输入串之后也总有一个‘#’,标志输入串结束。
现设置一个文法分析表(见表1),矩阵M[A,a]中存放着一条关于A的产生式,指出当A面临符号a时所采用的侯选。
对任何(X,a)其中X为栈顶符号,程序每次都执行下述动作之一:✧如果X=a=‘#’,则输出分析成功,停止分析过程;✧如果X=a且不等于‘#’,则把X从栈顶逐出,让a指向下一个输入符号;✧如果X是一个非终结符,则查看分析表M.若M[A,a]中存放着关于X的一个产生式,那么首先把X从栈顶逐出,然后,把产生式的右部符号串按反序一一推进栈内,若右部符号为ε,则就什么都不进栈。
把产生式推进栈内的同时应做这个产生式相应的语义动作,例如字符i匹配成功,字符出错,相应的产生式等。
输出如下:输出每一步骤分析栈和剩余串的变化情况, 及每一步所用的产生式都明确显示出来。
运行步骤:首先在相同的路径下建一文本文档例如11.txt,将表达式写入文档内如i+i*i-i/i#;运行程序,显示界面如下,输入相应的文件名字,(输入输出文件名是自行定义)打开pp.txt文件,文法分析结果如下:错误提示:1>.输入i++i*i#,结果如下存在的问题:现在只能是遇到错误就停止,而没能实现同步符号ll(1)分析。
合肥工业的大学编译原理实验报告材料(完整代码版)
计算机与信息学院编译原理实验报告专业班级信息安全13-1班学生姓名及学号马骏 2013211869 课程教学班号任课教师李宏芒实验指导教师李宏芒实验地点实验楼机房2015 ~2016 学年第二学期实验1 词法分析设计一、实验目的通过本实验的编程实践,使学生了解词法分析的任务,掌握词法分析程序设计的原理和构造方法,使学生对编译的基本概念、原理和方法有完整的和清楚的理解,并能正确地、熟练地运用二、实验要求1、编程时注意编程风格:空行的使用、注释的使用、缩进的使用等。
2、将标识符填写的相应符号表须提供给编译程序的以后各阶段使用。
3、根据测试数据进行测试。
测试实例应包括以下三个部分:全部合法的输入。
各种组合的非法输入。
由记号组成的句子。
4、词法分析程序设计要求输出形式:例:输入VC++语言的实例程序:If i=0 then n++;a﹤= 3b %);输出形式为:单词二元序列类型位置(行,列)(单词种别,单词属性)for (1,for ) 关键字(1,1)i ( 6,i ) 标识符(1,2)= ( 4,= ) 关系运算符(1,3) 120 ( 5,0 ) 常数(1,4)then ( 1,then) 关键字(1,5)n (6,n ) 标识符(1,6)++ Error Error (1,7); ( 2, ; ) 分界符(1,8)a (6,a ) 标识符(2,1)﹤= (4,<= ) 关系运算符(2,2)3b Error Error (2,4)% Error Error (2,4)) ( 2, ) ) 分界符(2,5); ( 2, ; ) 分界符(2,6)三、实验内容用 VC++/VB/JAVA 语言实现对 C 语言子集的源程序进行词法分析。
通过输入源程序从左到右对字符串进行扫描和分解,依次输出各个单词的内部编码及单词符号自身值;若遇到错误则显示“Error”,然后跳过错误部分继续显示;同时进行标识符登记符号表的管理。
合肥工业大学编译原理 LL自上而下文法分析
例如,程序描述以下语句:
E = E + T |T
T = T * F |F
F =(E)| 0 |1
在这种情况,我们可以很容易确定E,T和F是非终端,而符号“(”,“)”,“*”和“+”和数字“0”和“1”是在终端。
第一个非终端(第一衍生物)被认为是语法的公理。
4)分析表的结构
具有非递归语法以及“第一个”和“其后”的集合,你的程序现在可以建立预测分析表。
结果以表的形式显示在屏幕上。
图注释:Construction de la table d’analyse分析表的结构
table d’analyse分析表Affichage de la table d’analyse显示分析表
4、开发过程
1)字符要求:
你的程序必须能够根据以下字符来处理语法:
-终端字符:字母,数字,符号例如“+”,“—”,…;
-非终端字母表中的大写字母。
符号“=”,“|”和“#”(替换“ε”,因为它更容易输入到文本文件)被保留用于语法的描述中,因此不能被用作终端。
2)初始状态
您的程序通过读取一个文件中的“文本”格式开始。
结果被存储在数据结构,再次“你的选择。”
然后,这些集合被显示在屏幕上
图注释:Calcul des ensembles « premiers » et « suivants »计算“第一个”和“其后”的集合
Affichage des ensembles显示集合premiers第一个suivants其后
结果必须存储在内存中,是一个您所选择的数据结构。然后,使用一个函数再取出数据,存储在内存中并屏幕上显示(以你选择的格式)。
合肥工业大学编译原理实验报告 完整代码版
cout<<"(5,"<<m<<") 常数 ("<<rowy<<","<<rowx<<")"<<endl; ci[cipointer]=m; cipointer++; } } if(i==2)//识别 分界符 算数运算符 关系运算符 { // cout<<" a signal!!"<<endl; for(x=0;x<max;x++) { if(s[x]==m)
同时
进行标识符登记符号表的管理。
以下是实现词法分析设计的主要工作: (1)从源程序文件中读入字符。 (2)统计行数和列数用于错误单词的定位。 (3)删除空格类字符,包括回车、制表符空格。 (4)按拼写单词,并用(内码,属性)二元式表示。(属性值——token 的机内 表示) (5)如果发现错误则报告出错 7 (6)根据需要是否填写标识符表供以后各阶段使用。
}
else sign=0; }
} i++; if(x==(s.length()-1)) { sn=s.substr(x-i+1,i);
if(i>0)
{
// cout<<sn<<" i="<<i<<endl;
cout<<sn<<" ";
if(sign==0)//数字后有字母的情况
cout<<"
("<<rowy<<","<<rowx<<")"<<endl;
编译原理实验报告
编译原理实验报告合工大编译原理实验报告,后面附代码,孩纸,只能参考不能抄袭哦,好好学习天天向上,编译原理实验报告合肥工业大学计算机科学与技术完成日期:20XX年.6.3实验一词法分析设计一、实验功能:合工大编译原理实验报告,后面附代码,孩纸,只能参考不能抄袭哦,好好学习天天向上,对输入的txt文件内的内容进行词法分析:由文件流输入test.txt中的内容,对文件中的各类字符进行词法分析打印出分析后的结果;二、程序结构描述:(源代码见附录)1、利用Key[]进行构造并存储关键字表;利用optr[]进行构造并存储运算符表;利用separator[]进行构造并存储分界符表;2、bool IsKey(string ss) {}判断是否是关键字函数若是关键字返回true,否则返回false;bool IsLetter(char c) {}判断当前字符是否字母,若是返回true,否则返回false;bool IsDigit(char c) {}判断当前字符是否是数字,若是返回true,否则返回false;bool IsOptr(string ss) {}判断当前字符是否是运算符,若是返回true,否则返回false;bool IsSeparator(string ss) {}判断当前字符是否是分界符,若是返回true,否则返回false;void analyse(ifstream in) {}分析函数构造;关系运算符通过switch来进行判断;三、实验结果合工大编译原理实验报告,后面附代码,孩纸,只能参考不能抄袭哦,好好学习天天向上,实验总结:词法分析的程序是自己亲手做的,在实现各个函数时花了不少功夫,1、要考虑到什么时候该退一字符,否则将会导致字符漏读甚至造成字符重复读取。
2、在实现行数和列数打印时要考虑到row++和line++应该放在什么位置上才可以,如当读取一个\n时line要增加一,而row需要归0处理,在读取某一字符串或字符后row需要加一;3、对于关系运算符用switch结构进行选择判断即可解决一个字符和两个字符的运算符之间的差异;4、将自己学过的知识应用到实践中是件不怎么容易的事情,只有亲身尝试将知识转化成程序才能避免眼高手低,对于知识的理解也必将更加深刻。
编译原理实验 LL(1)分析
实验三语法分析---LL(1)分析器目录一. 实验的目的与思路 (2)(1)目的 (2)(2)思路 (2)二. 基本的功能 (3)三.总体设计 (4)四.详细设计 (5)五.源程序清单 (6)六.源代码 (6)....................................................................................................................................................一. 实验的目的与思路(1)目的1. 用程序的方法实现语法分析的LL(1)方法。
(2)思路本程序是采用的LL(1)方法进行的语法分析,而LL(1)的分析方法是属于自上而下的方法。
自上而下分析的基本思想是:对任意输入串,试图用一切可能的方法,从文法开始符号(根结点)出发,自上而下为输入串建立一棵语法树。
从推导的角度看,它是从文法的开始符号出发,反复使用各种产生式,寻找与输入串匹配的推导。
在输入之前必须要进行该文法是不是LL(1)文法的判断,然后再构造相应的LL(1)分析表来用预测分析方法进行语法分析,依据下面的文法及分析表来设计程序实现预测分析的分析过程。
1.文法G[E]:E --> E+T|TT --> T*F|FF --> (E) | i2.通过观察可知道该文法是一个左递归文法,要进行语法分析就必须消除左递归才能继续判断它是不是LL(1)文法,然后才能用预测分析方法进行语法分析。
3.消除左递归:E -->TMM --> +TM|uT --> FQQ --> *FQ|uF --> (E) | i4.在进行LL(1)文法的判断:(1.)各非终结符的FIRST集如下:FIRST(E)= FIRST(TM)= {(,i }FIRST(M)= { + }FIRST(T)= {(,i }FIRST(Q)= { * }FIRST(F)= { (,i }(2.)各非终结符的FOLLOW集如下:FOLLOW(E)= { ),# }FOLLOW(M)= { ),# }FOLLOW(T)= { + ,),# }FOLLOW(Q)= { + ,),# }FOLLOW(F)= { * ,+ ,),# }(3.)各产生式的SELECT集如下:SELECT(E→TM)={ ( ,i }SELECT(M→+TM)={+}SELECT(M→u)={ }, #}SELECT(T→FQ)={ ( ,i }SELECT(Q→*FQ)={ *}SELECT(Q→u)={ +,), # }SELECT(F→(E))={ ( )SELECT(F→i)={ i }因为:SELECT(M→+TM)∩SELECT(M→u)=ФSELECT(Q→*FQ)∩SELECT(Q→u)=ФSELECT(F→(E))∩SELECT(F→i)=Ф因此可以判断该文法是一个LL(1)文法可以构造预测分析表。
编译原理 语法分析程序设计(LL(1)分析法)
1.实验目的:掌握LL(1)分析法的基本原理,掌握LL(1)分析表的构造方法,掌握LL(1) 驱动程序的构造方法。
2.实验要求:实现LR分析法(P147,例4.6)或预测分析法(P121,例4.3)。
3.实验环境:一台配置为1G的XP操作系统的PC机;Visual C++6.0.4.实验原理:编译程序的语法分析器以单词符号作为输入,分析单词符号串是否形成符合语法规则的语法单位,如表达式、赋值、循环等,最后看是否构成一个符合要求的程序,按该语言使用的语法规则分析检查每条语句是否有正确的逻辑结构,程序是最终的一个语法单位。
编译程序的语法规则可用上下文无关文法来刻画。
语法分析的方法分为两种:自上而下分析法和自下而上分析法。
自上而下就是从文法的开始符号出发,向下推导,推出句子。
而自下而上分析法采用的是移进归约法,基本思想是:用一个寄存符号的先进后出栈,把输入符号一个一个地移进栈里,当栈顶形成某个产生式的一个候选式时,即把栈顶的这一部分归约成该产生式的左邻符号。
自顶向下带递归语法分析:1、首先对所以的生成式消除左递归、提取公共左因子2、在源程序里建立一个字符串数组,将所有的生成式都存在这个数组中。
3、给每个非终结符写一个带递归的匹配函数,其中起始符的函数写在main函数里。
这些函数对生成式右边从左向右扫描,若是终结符直接进行匹配,匹配失败,则调用出错函数。
如果是非终结符则调用相应的非终结符函数。
4、对输入的符号串进行扫描,从起始符的生成式开始。
如果匹配成功某个非终结符生成式右边的首个终结符,则将这个生成式输出。
匹配过程中,应该出现的非终结符没有出现,则出错处理。
5.软件设计与编程:对应源程序代码:#include <iostream.h>#include <stdio.h>#include <stack>using namespace std;struct Node1{ char vn;char vt;char s[10];}MAP[20]; //存储分析预测表每个位置对应的终结符,非终结符,产生式int k; //用R代表E',W代表T',e代表空char start='E';int len=8;charG[10][10]={"E->TR","R->+TR","R->e","T->FW","W->*FW","W->e","F->(E)","F->i"};//存储文法中的产生式char VN[6]={'E','R','T','W','F'}; //存储非终结符char VT[6]={'i','+','*','(',')','#'}; //存储终结符char SELECT[10][10]={"(,i","+","),#","(,i","*","+,),#","(","i"};//存储文法中每个产生式对应的SELECT集charRight[10][8]={"->TR","->+TR","->e","->FW","->*FW","->e","->(E)","->i"};stack <char> stak;bool compare(char *a,char *b){ int i,la=strlen(a),j,lb=strlen(b);for(i=0;i<la;i++){for(j=0;j<lb;j++){ if(a[i]==b[j])return 1; }}return 0;}char *Find(char vn,char vt){ int i;for(i=0;i<k;i++){ if(MAP[i].vn==vn && MAP[i].vt==vt){return MAP[i].s;} } return "error";}char * Analyse(char * word){ char p,action[10],output[10];int i=1,j,l=strlen(word),k=0,l_act,m;while(!stak.empty()){stak.pop();}stak.push('#');stak.push(start);printf("___________________________________________________________\n"); printf("\n 对符号串%s的分析过程\n",word);printf("-----------------------------------------------------------------------\n ");printf("\n");printf(" 步骤栈顶元素剩余输入串动作\n");printf("-----------------------------------------------------------------------\n ");p=stak.top();while(p!='#'){ printf("%7d ",i++);p=stak.top();stak.pop();printf("%6c ",p);for(j=k,m=0;j<l;j++){output[m++]=word[j];}output[m]='\0';printf("%10s",output);if(p==word[k]){ if(p=='#'){ printf(" 分析成功 \n");return "SUCCESS";}printf(" 匹配终结符%c\n",p);k++;}else{ strcpy(action,Find(p,word[k]));if(strcmp(action,"error")==0){ printf(" 没有可用的产生式\n");return "ERROR"; }printf(" 展开非终结符%c%s\n",p,action);int l_act=strlen(action);if(action[l_act-1]=='e'){continue;}for(j=l_act-1;j>1;j--){stak.push(action[j]);}}}if(strcmp(output,"#")!=0)return "ERROR";}int main (){ freopen("in.txt","r",stdin);char source[100];int i,j,flag,l,m;printf("\n***为了方便编写程序,用R代表E',W代表T',e代表空*****\n\n"); printf("该文法的产生式如下:\n");for(i=0;i<len;i++){printf(" %s\n",G[i]);}printf("___________________________________________________________\n"); printf("\n该文法的SELECT集如下:\n");for(i=0;i<len;i++){ printf(" SELECT(%s) = { %s }\n",G[i],SELECT[i]); }printf("___________________________________________________________\n"); //判断是否是LL(1)文法flag=1;for(i=0;i<8;i++){ for(j=i+1;j<8;j++){if(G[i][0]==G[j][0]){ if(compare(SELECT[i],SELECT[j])){flag=0;break;} } }if(j!=8){break;}}if(flag){printf("\n有相同左部产生式的SELECT集合的交集为空,所以文法是LL(1)文法。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
if(c==Vt[i])return i;//在表中,就返回位置 } return -1;//返回-1 表示不在表中 } void addfi(String s, int j){//求关于某一个产生式的 first 集 int v=vn(s.charAt(0));//v 为产生式左边的非终结符 int i; if(vt(s.charAt(j))!=-1){//产生式右边第一个为终结符
fi[v][vt(s.charAt(j))]=true;//就把 s.charAt(j)加入 s.charAt(0)的 first 集
}else{//产生式右边第一个为非终结符 if(!fi[vn(s.charAt(j))][Vt.length]){//如果 s.charAt(j)的
first 集没有求,先求 s.charAt(j)的 first 集 first(s.charAt(j));
int vn(char c){//返回 c 在非终结符表中的位置 int i; for(i=0;i<Vn.length;i++){ if(c==Vn[i])return i;//在表中,就返回位置 } return -1;//返回-1 表示不在表中
} int vt(char c){//返回 c 在终结符表中的位置
4、算法流程图
:50 45. 44. 43. by 42.41.— 4—0.— 3—9.—3—8.by37@.—— 36.35. —34—. ——33.312. 1.2.3.34.0.5.6—.—29.by28.by@27.26.—— 25. 24. 23. 22. by 21.20. — 1—9.by:18.by:17.— 1—6.— 1—5.—1—4.—— 13. 12. 111.0“. ”by: 9M.“OOOKN”b8y.:——7.——6.——5.——4.——3.——2.——1.——
>*FS|/FS","S->ε","F->(E)","F->i"};//文法 LL(){ fir();//求 first 集 fol();//求 follow 集 build_M();//求预测分析表 } int or(int i,String s){//返回最近的在其右边一个“|”位置 for(i=i+1;i<s.length();i++){ if(s.charAt(i)=='|') return i;//存在,就返回位置 } return -1;//返回-1 表示没有“|”在其右边 }
if(s.charAt(0)!=s.charAt(j))//要求的非终结符与右边第一个不 同时,求 first 集
addfi(s,j); //求关于此产生式的 first 集 while(or(j,s)!=-1&&j<s.length())//判断有无‘|’,有就继续 求 first 集 {
j=or(j,s);//得到‘|’位置 if(s.charAt(0)!=s.charAt(j+1))//要求的非终结符与右边第 一个不同时,求 first 集
:50 45. 44. 43. by 42.41.— 4—0.— 3—9.—3—8.by37@.—— 36.35. —34—. ——33.312. 1.2.3.34.0.5.6—.—29.by28.by@27.26.—— 25. 24. 23. 22. by 21.20. — 1—9.by:18.by:17.— 1—6.— 1—5.—1—4.—— 13. 12. 111.0“. ”by: 9M.“OOOKN”b8y.:——7.——6.——5.——4.——3.——2.——1.——
:50 45. 44. 43. by 42.41.— 4—0.— 3—9.—3—8.by37@.—— 36.35. —34—. ——33.312. 1.2.3.34.0.5.6—.—29.by28.by@27.26.—— 25. 24. 23. 22. by 21.20. — 1—9.by:18.by:17.— 1—6.— 1—5.—1—4.—— 13. 12. 111.0“. ”by: 9M.“OOOKN”b8y.:——7.——6.——5.——4.——3.——2.——1.——
3、数据结构及生成的算法描述
事先已经构造好的表: Vn数组------非终结符表 Vt 数组------终结符 Gr 数组------文法 事先定义的表及变量:
非终结符按照在非终结符中的位置与first集follow集对应
fi二维数组------first集,为真表示该终结符在该行对应的非终结符的first集 中 fo二维数组------follow集,为真表示该终结符在该行对应的非终结符的follow 集中 M二维数组------预测分析表 用到的方法: int or(int i,String s)---返回最近的在其右边一个“|”位置 int vn(char c)---返回 c 在非终结符表中的位置 int vt(char c)---返回 c 在终结符表中的位置 void addfi(String s, int j)---求关于某一个产生式的first集 void first(char v)---求非终结符c关于该文法的first集,first调用addfi void fir()---求所以非终结符的 first 集,fir 调用 first void addfo(String s,int j)---求关于某一个产生式的 follow 集 void follow(char v)---求非终结符 v 关于该文法的 follow 集,follow 调用 addfo void fol()---求所以非终结符的 follow 集,fol 调用 follow void MM(int j,int i,String s,int m)---将某一个产生式填入预测分析表中 void build_M()---构造预测分析表,build_M 调用 MM void isright(String s)---分析一个符号串是否符合该文法
一、实验目的
通过完成预测分析法的语法分析程序,了解预测分析法和递归子程序法的区 别和联系。使学生了解语法分析的功能,掌握语法分析程序设计的原理和构造 方法,训练学生掌握开发应用程序的基本方法。有利于提高学生的专业素质, 为培养适应社会多方面需要的能力。
二、实验内容
根据某一文法编制调试 LL ( 1 )分析程序,以便对任意输入的符号 串进行分析。
addfi(s,j+1);//求关于此产生式的 first 集
} } } fi[vn(v(v)][Vt.length]设为 true, 表示已求 v 的 first 集 } void fir(){//求所以非终结符的 first 集 int i,j; for(i=0;i<Vn.length;i++){//非终结符的 first 集未求时,求该非终 结符的 first 集 if(!fi[i][Vt.length]){
fi[v][vt('ε')]=true; return ; } if(s.charAt(j+1)!='|'){//s.charAt(j+1)不是“|”就将 s.charAt(j+1)的 first 集加入 s.charAt(0)的 first 集 j++; addfi(s,j); }else{//s.charAt(j+1)是“|”就将 ε 加入 s.charAt(0)的 first 集 fi[v][vt('ε')]=true; } } } } void first(char v){//求非终结符 v 关于该文法的 first 集 int i,j; String s; for(i=0;i<Gr.length;i++){ s=Gr[i]; if(s.charAt(0)==v){//产生式的左边是要求的非终结符 j=3;
:50 45. 44. 43. by 42.41.— 4—0.— 3—9.—3—8.by37@.—— 36.35. —34—. ——33.312. 1.2.3.34.0.5.6—.—29.by28.by@27.26.—— 25. 24. 23. 22. by 21.20. — 1—9.by:18.by:17.— 1—6.— 1—5.—1—4.—— 13. 12. 111.0“. ”by: 9M.“OOOKN”b8y.:——7.——6.——5.——4.——3.——2.——1.——
实验题目:LL(1)分析法 免费下载,不客气 班级:
学号:
姓名:
Edited by Magic Yang
完成日期:2013-5-28
:50 45. 44. 43. by 42.41.——40.——39.—3—8.by3@7.—— 36.35. —3—4. ——333. 12. 1.2.3.340.5.—.6.—29.by28.by@27.26.—— 25. 24. 23. 22. by 21.20. ——19.by:18.by1:7.——16.——15.——14.—— 13. 12. 1110.“. ”by:M9.O“OOKN”b8y.—: —7.——6.——5.——4.——3.——2.——1.——
:50 45. 44. 43. by 42.41.— 4—0.— 3—9.—3—8.by37@.—— 36.35. —34—. ——33.312. 1.2.3.34.0.5.6—.—29.by28.by@27.26.—— 25. 24. 23. 22. by 21.20. — 1—9.by:18.by:17.— 1—6.— 1—5.—1—4.—— 13. 12. 111.0“. ”by: 9M.“OOOKN”b8y.:——7.——6.——5.——4.——3.——2.——1.——