LL(1)预测分析法实验报告

合集下载

编译原理实验LL1分析法

编译原理实验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)分析法消除了文法的左递归性,而且克服了回溯,使程序运行的效率大大提升。

《预测分析法》实验报告

《预测分析法》实验报告

《编译原理》课程实验报告实验名称:预测分析法姓名:LZ学号:110地点:实验楼教师:老师院系:计算机专业:计算机时间:一.实验目的1.构造文法的语法分析程序,要求采用预测分析法对输入的字符串进行语法分析。

2.加深对预测分析LL(1)分析法的理解和掌握。

二.实验内容#include <stdio.h>#include <stdlib.h>#include <string.h>char str[100]; //存储待分析的句子const char T[ ] = "a^(),#"; //终结符,分析表的列符const char NT[ ] = "STW"; //非终结符,分析表的行符/*指向产生式右部符号串*/const char *p[] = {/*0. S→a */ "a",/*1. S→^ */ "^",/*2. S→(T) */ "(T)",/*3. T→SW */ "SW",/*4. W→,SW */ ",SW",/*5. W→ε; */ ""};//设M[i][j]=x,通过p[M[i][j]]=p[x]获取右部符号串。

const int M[][6] = {/* a ^ ( ) , # *//*S*/ { 0, 1, 2, -1, -1, -1 },/*T*/ { 3, 3, 3, -1, -1, -1 },/*W*/ { -1, -1,-1, 5, 4, -1 }};void init()//输入待分析的句子{printf(" 请输入待分析的句子(以$结束):\n");scanf("%s",str);}int lin(char c);//非终结符转换为行号int col(char c);//终结转换为列号bool isNT(char c);//isNT判断是否是非终结符bool isT(char c);//isT判断是否是终结符。

编译原理实验报告材料LL(1)分析报告法84481

编译原理实验报告材料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)分析表的构造方法。

LL1分析法实验报告

LL1分析法实验报告

实验二LL(1)分析法一、实验目的通过完成预测分析法的语法分析程序,了解预测分析法和递归子程序法的区别和联系。

了解语法分析的功能,掌握语法分析程序设计的原理和构造方法,训练学生掌握开发应用程序的基本方法。

有利于提高学生的专业素质,为培养适应社会多方面需要的能力。

二、实验内容◆根据某一文法编制调试LL (1 )分析程序,以便对任意输入的符号串进行分析。

◆构造预测分析表,并利用分析表和一个栈来实现对上述程序设计语言的分析程序。

◆分析法的功能是利用LL(1)控制程序根据显示栈栈顶内容、向前看符号以及LL(1)分析表,对输入符号串自上而下的分析过程。

三、LL(1)分析法实验设计思想及算法◆模块结构:(1)定义部分:定义常量、变量、数据结构。

(2)初始化:设立LL(1)分析表、初始化变量空间(包括堆栈、结构体、数组、临时变量等);(3)控制部分:从键盘输入一个表达式符号串;(4)利用LL(1)分析算法进行表达式处理:根据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五、实验步骤1、根据流程图编写出各个模块的源程序代码上机调试。

LL(1)分析法的实验源程序代码如下:#include<iostream.h>#include <stdio.h>#include<stdlib.h>#include<string.h>char A[20]; /*分析栈*/char B[20]; /*剩余串*/char v1[20]={'i','+','*','(',')','#'}; /*终结符*/char v2[20]={'E','G','T','S','F'}; /*非终结符*/int j=0,b=0,top=0,l; /*L为输入串长度*/class type /*产生式类型定义*/ {public:char origin; /*大写字符*/char array[5]; /*产生式右边字符*/ int length; /*字符个数*/};type e,t,g,g1,s,s1,f,f1; /*类对象*/type C[10][10]; /*预测分析表*/void print() /*输出分析栈*/{int a;for(a=0;a<=top+1;a++)cout<<A[a];cout<<"\t\t";}void print1() /*输出剩余串*/{int j;for(j=0;j<b;j++) /*输出对齐符*/ cout<<" ";for(j=b;j<=l;j++)cout<<B[j];cout<<"\t\t\t";}void main(){int m,n,k=0,flag=0,finish=0;char ch,x;type cha; /*用来接受C[m][n]*/ /*把文法产生式赋值结构体*/e.origin='E';strcpy(e.array,"TG");e.length=2;t.origin='T';strcpy(t.array,"FS");t.length=2;g.origin='G';strcpy(g.array,"+TG");g.length=3;g1.origin='G';g1.array[0]='^';g1.length=1;s.origin='S';strcpy(s.array,"*FS");s.length=3;s1.origin='S';s1.array[0]='^';s1.length=1;f.origin='F';strcpy(f.array,"(E)");f.length=3;f1.origin='F';f1.array[0]='i';f1.length=1;for(m=0;m<=4;m++) /*初始化分析表*/ for(n=0;n<=5;n++)C[m][n].origin='N'; /*全部赋为空*//*填充分析表*/C[0][0]=e;C[0][3]=e;C[1][1]=g;C[1][4]=g1;C[1][5]=g1;C[2][0]=t;C[2][3]=t;C[3][1]=s1;C[3][2]=s;C[3][4]=C[3][5]=s1;C[4][0]=f1;C[4][3]=f;cout<<"提示:本程序只能对由'i','+','*','(',')'构成的以'#'结束的字符串进行分析,\n"; cout<<"请输入要分析的字符串:";do/*读入分析串*/{cin>>ch;if ((ch!='i') &&(ch!='+') &&(ch!='*')&&(ch!='(')&&(ch!=')')&&(ch!='#')) {cout<<"输入串中有非法字符\n";exit(1); //强制退出程序}B[j]=ch;j++;}while(ch!='#');l=j;/*分析串长度*/ch=B[0];/*当前分析字符*/A[top]='#'; A[++top]='E';/*'#','E'进栈*/cout<<"步骤\t\t分析栈\t\t剩余字符\t\t所用产生式\n";do{x=A[top--];/*x为当前栈顶字符*/cout<<k++;cout<<"\t\t";for(j=0;j<=5;j++)/*判断是否为终结符*/if(x==v1[j]){flag=1;break;}if(flag==1)/*如果是终结符*/{if(x=='#'){finish=1;/*结束标记*/cout<<"acc!\n";/*接受*/getchar();getchar();exit(1); //退出程序}/*if*/if(x==ch){print();print1();cout<<"匹配\n"<<ch;ch=B[++b];/*下一个输入字符*/flag=0;/*恢复标记*/}else/*出错处理*/{print();print1();cout<<"出错\n"<<ch;/*输出出错终结符*/exit(1);}}else/*非终结符处理*/{for(j=0;j<=4;j++)if(x==v2[j]){m=j;/*行号*/break;}for(j=0;j<=5;j++)if(ch==v1[j]){n=j;/*列号*/break;}cha=C[m][n];if(cha.origin!='N')/*判断是否为空*/{print();print1();cout<<cha.origin<<"->"; /*输出产生式*/for(j=0;j<cha.length;j++)cout<<cha.array[j];cout<<"\n";for(j=(cha.length-1);j>=0;j--) /*产生式逆序入栈*/A[++top]=cha.array[j];if(A[top]=='^')/*为空则不进栈*/top--;}else/*出错处理*/{print();print1();cout<<"出错"<<x;/*输出出错非终结符*/exit(1);}}}while(finish==0);}程序的运行结果如下:六.实验心得经过这个实验的练习,通过对程序的分析,让我进一步了解LL(1)算法的思想以及它的进一步程序实现,让我对它的了解从简单的理论上升到程序实现的级别,有理论上升到实际,让我更清楚它的用途。

实验3预测分析法模板

实验3预测分析法模板

一、分析语法分析部分我们我们采用LL(1)方法实现,采用LL(1)方法实现语法发分析要求文法满足以下要求:一个文法能否用确定的自顶向下分析与文法中相同左部的每个产生式右部的开始符号集合有关,当有右部能=*=>ε时则与其左部非终结符的后跟符号集合也有关,此外在产生式中不存在左递归,无回溯。

它的基本思想是从左到右扫描源程序,同时从识别符号开始生成句子的最左推导,并只向前查看一个输入符号,便能唯一确定应选择的规则。

下面将确切地定义满足确定的自顶向下分析条件的文法即LL(1)文法及LL(1)文法的判别并介绍如何对非LL(1)文法进行等价变换问题,也就是消除一个文法中的左递归和左公共因子。

注意:一个文法中含有左递归和左公共因子绝对不是LL(1)文法,所以也就不可能用确定的自顶向下分析法,对此结论可以证明。

然而,某些含有左递归和左公共因子的文法在通过等价变换把它们消除以后可能变为LL(1)文法,但需要用LL(1)文法的定义判别,也就是说文法中不含左递归和左公共因子,只是LL(1)文法的必要条件。

LL(1) 文法的定义(5种定义):一个文法符号串的开始符号集合定义如下:定义 1.设G=(VT,VN,S,P)是上下文无关文法,α是任意的文法符号串,FIRST(α)是从α推导出的串的开始符号的终结符集合。

FIRST(α)={a|α=*=>aβ,a∈VT,α,β∈V*}若α=*=>ε,则规定ε∈FIRST(α).当一个文法中相同左部非终结符的右部存在能=*=>ε的情况则必须知道该非终结符的后跟符号的集合中是否含有其它右部开始符号集合的元素。

为此,我们定义一个文法非终结符的后跟符号的集合如下:定义2.设G=(VT,VN,S,P)是上下文无关文法,A∈VN,S是开始符号FOLLOW(A)={a|S=*=>μAβ,且a∈VT,a∈FIRST(β),μ∈VT* ,β∈V+}若S=*=>μAβ,且βε, 则#∈FOLLOW(A)。

LL1语法分析

LL1语法分析

北华航天工业学院《编译原理》课程实验报告课程实验题目:LL(1)语法分析实验作者所在系部:计算机科学与工程系作者所在专业:计算机科学与技术作者所在班级:xxx作者学号:xxxxx _ 作者姓名:xxxx指导教师姓名:xxxx完成时间:2011年4月28日一、实验目的理解预测分析表方法的实现原理。

二、实验内容及要求编写一通用的预测法分析程序,要求有一定的错误处理能力,出错后能够使程序继续运行下去,直到分析过程结束。

可通过不同的文法(通过数据表现)进行测试。

给定算术表达式文法,编写程序。

测试数据:1.算术表达式文法E→TE’E’→ +TE’|- TE’|εT→FT’T’→*FT’ |/ FT’ |%FT’|εF→(E) |id|num2.作业3.10 文法三、实验程序设计说明1.实验方案设计主要函数之间的调用关系如下图所示:2.程序源代码源代码如下:#include <iostream>#include <cstdio>#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集char Right[10][8]={"->TR","->+TR","->e","->FW","->*FW","->e","->(E)","->i"}; //用R代表A',W代表B',e代表空/*char start='A';int len=6;char G[10][10]={"A->aR","R->ABl","R->e","B->dW","W->bW","W->e"};char VN[6]={'A','R','B','W'};char VT[6]={'a','d','b','#','l'};char SELECT[10][10]={"a","a","d,#","d","b","l"};char Right[10][6]={"->aR","->ABl","->e","->dW","->bW","->e"};*/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("in1.txt","r",stdin);//freopen("in2.txt","r",stdin);char source[100];int i,j,flag,l,m;//printf("\n***为了方便编写程序,用R代表E',W代表T',e代表空*****\n\n");printf("\n****为了方便编写程序,用R代表A',W代表B',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、学会⽤C/C++⾼级程序设计语⾔编写⼀个LL(1)分析法程序⼆、实验内容及要求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。

1、给定⽂法S -> a | b | (T)T -> SH | dH -> ,SH | ε2、该⽂法对应的预测分析表3、编写预测分析程序对句⼦进⾏分析三、试验程序设计说明1、相关函数说明分析栈可以采取许多的存储⽅法来设计,在这⾥采⽤的顺序栈。

根据预测分析原理,LL(1)分析程序的实现关键在于分析栈和分析表是采⽤何种数据结构来实现。

分析表是⼀个矩阵,当我们要调⽤分析表来分析时,就根据栈顶的⾮终结符和当前输⼊的终结符来决定执⾏哪种过程。

具体设计思想如下:printStack()输出分析栈内内容;printinputString()输出⽤户输⼊的字符串;Pop()弹出栈顶元素;Push()向栈内添加⼀个元素;Search()查找⾮终结符集合VT 中是否存在输⼊的⾮终结符;yuCeFenXi()进⾏输⼊串的预测分析的主功能函数;M(char A, char a)查看预测分析表M[A,a]中是否存在相应产⽣式。

编译原理预测分析法C语言的实验报告

编译原理预测分析法C语言的实验报告

题目:编写识别由下列文法所定义的表达式的预测分析程序。

E→E+T | E-T | TT→T*F | T/F |FF→(E) | i输入:每行含一个表达式的文本文件。

输出:分析成功或不成功信息。

(题目来源:编译原理实验(三)--预测(LL(1))分析法的实现)解答:(1)分析a) ∵E=>E+T=>E+T*F=>E+T*(E)即有E=>E+T*(E)存在左递归。

用直接改写法消除左递归,得到如下:E →TE’ E’ →+TE’ | −TE’|εT →FT’ T’ →*FT’ | /FT’|εF → (E) | i对于以上改进的方法。

可得:对于E’:FIRST( E’ )=FIRST(+TE’)∪FIRST(-TE’)∪{ε}={+,−,ε}对于T’:FIRST( T’ )=FIRST(*FT’)∪FIRST(/FT’)∪{ε}={*,∕,ε} 而且:FIRST( E ) = FIRST( T ) = FIRST( F )=FIRST((E))∪FIRST(i)={(,i }由此我们容易得出各非终结符的FOLLOW集合如下:FOLLOW( E )= { ),#}FOLLOW(E’)= FOLLOW(E)={ ),#}FOLLOW( T )= FIRST(E’)\ε∪FOLLOW(E’)={+,−,),#}FOLLOW( T’ ) = FOLLOW( T ) ={+,−,),#}FOLLOW( F )=FIRST(T’)\ε∪FOLLOW(T’)={*,∕,+,−,),#}由以上FOLLOW集可以我们可以得出SELECT集如下:对E SELECT(E→TE’)=FIRST(TE’)=FIRST(T)={ (,i }对E’ SELECT(E’ →+TE’)={ + }SELECT(E’ →−TE’)={ − }SELECT(E’ →ε)={ε,),#}对T SELECT(T→FT’)={(,i}对T’ SELECT(T’ →*FT’)={ * }SELECT(T’ →∕FT’)={ ∕ }SELECT(T’ →ε)={ε,+,−,),#}对F SELECT(F→(E) )={ ( }SELECT(F→i)={ i }∴SELECT(E’ →+TE’)∩SELECT(E’ →−TE’)∩SELECT(E’ →ε)=ΦSELECT(T’ →*FT’)∩SELECT(T’ →∕FT’)∩SELECT(T’ →ε)=ΦSELECT(F→(E) )∩SELECT(F→i)= Φ由上可知,有相同左部产生式的SELECT集合的交集为空,所以文法是LL(1)文法。

LL1语法分析程序实验报告

LL1语法分析程序实验报告

LL1语法分析程序实验报告实验目的:通过编写LL(1)语法分析程序,加深对语法分析原理的理解,掌握语法分析方法的实现过程,并验证所编写的程序的正确性。

实验准备:1.了解LL(1)语法分析的原理和步骤;2.根据语法规则,构建一个简单的文法;3.准备一组测试用例,包括符合语法规则的输入和不符合语法规则的输入。

实验步骤:1.根据文法规则,构建预测分析表;2.实现LL(1)语法分析程序;3.编写测试用例进行测试;4.分析测试结果。

实验结果:我根据上述步骤,编写了一个LL(1)语法分析程序,并进行了测试。

以下是我的测试结果:测试用例1:输入:9+7*(8-5)分析结果:成功测试用例2:输入:3+*5分析结果:失败测试用例3:输入:(3+5)*分析结果:失败测试用例4:输入:(3+5)*2+4分析结果:成功分析结果符合预期,说明我编写的LL(1)语法分析程序是正确的。

在测试用例1和测试用例4中,分析结果是成功的,而在测试用例2和测试用例3中,分析结果是失败的,这是因为输入不符合文法规则。

实验总结:通过本次实验,我进一步理解了LL(1)语法分析的原理和步骤。

编写LL(1)语法分析程序不仅要根据文法规则构建预测分析表,还要将预测分析表与输入串进行比对,根据匹配规则进行预测分析,最终得到分析结果。

在实验过程中,我发现在构建预测分析表和编写LL(1)语法分析程序时需要仔细思考和调试才能保证正确性。

通过本次实验,我对语法分析方法的实现过程有了更深入的认识,对于将来在编译原理方面的学习和工作有了更好的准备。

LL(1)实验报告(附代码)

LL(1)实验报告(附代码)

实验二LL(1)分析法实验学时:4实验类型:综合实验要求:必修一、实验目的通过完成预测分析法的语法分析程序,了解预测分析法和递归子程序法的区别和联系。

使学生了解语法分析的功能,掌握语法分析程序设计的原理和构造方法,训练学生掌握开发应用程序的基本方法。

有利于提高学生的专业素质,为培养适应社会多方面需要的能力。

二、实验内容◆根据某一文法编制调试LL (1 )分析程序,以便对任意输入的符号串进行分析。

◆构造预测分析表,并利用分析表和一个栈来实现对上述程序设计语言的分析程序。

◆分析法的功能是利用LL(1)控制程序根据显示栈栈顶内容、向前看符号以及LL(1)分析表,对输入符号串自上而下的分析过程。

三、LL(1)分析法实验设计思想及算法◆模块结构:(1)定义部分:定义常量、变量、数据结构。

(2)初始化:设立LL(1)分析表、初始化变量空间(包括堆栈、结构体、数组、临时变量等);(3)控制部分:从键盘输入一个表达式符号串;(4)利用LL(1)分析算法进行表达式处理:根据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)分析法是一种无回溯的自上而下分析算法,其本质即为求句柄,将输入串逐字的压入栈中,一旦发现栈中存在句柄,即对其进行归约算法,在实际操作中,通过求解算法的First()及Follow()集,构造文法的分析表,在分析过程中,通过查表得到要进行的动作,以此实现文法的分析。

语法分析_预测分析法_实验报告

语法分析_预测分析法_实验报告
ProcessT();
}
else if ( IsSymbolEnd(StackGet()) )
{
//栈顶为开始符
ProcessEnd();
}
else
{
//栈顶为非终结符
ProcessN();
}
}
void ProcessEnd()
{
if (StackGet() != ComingToken())
{
//非正常结尾
}
}
/*
*
*将产生式反向入栈
**/
void StackPushProfom(int buf[], int length)
{
int i;
_ASSERT(length > 0);
for (i = length - 1; i >= 0; i--)
{
StackPush(buf[i]);
}
}
/**
*由当前栈顶符及当前输入符取得产生式
}
}
void ProcessT()
{
if (StackGet() == ComingToken())
{
//match success, pop stack
StackPop();
//get next token
NextToken();
}
else
{
Leave(ANA_ERROR_UNEXPECTED_VALUE);
SELECT(F→( E )) SELECT(F→i)
= { ( } { i }
=
因而改写后的文法为LL(1)文法,可使用预测分析法自顶向下分析。
3)预测分析表
对每个表达式求其SELECT集。

实验五 LL(1)分析步骤和讲解

实验五 LL(1)分析步骤和讲解

实验五LL(1) 分析法一、实验目的:一、实验目的:根据某一文法编制调试LL (1)分析程序,以便对任意输入的符号串进行)分析程序,以便对任意输入的符号串进行析。

本次实验的目主要是加深对预测分析。

本次实验的目主要是加深对预测分LL (1)分析法的理解。

)分析法的理解。

(所需学时:4学时)二、实验二、实验原理1、LL (1)分析法的功能)分析法的功能LL (1)分析法的功能是利用)分析法的功能是利用)分析法的功能是利用LL (1)控制程序根据显示栈顶内容、向前)控制程序根据显示栈顶内容、向前)控制程序根据显示栈顶内容、向前)控制程序根据显示栈顶内容、向前看符号以及LL (1)分析表,对输入符号串自上而下的过程。

)分析表,对输入符号串自上而下的过程。

2、LL (1)分析法的前提)分析法的前提改造文法:消除二义性、左递归提取因子,判断是否为改造文法:消除二义性、左递归提取因子,判断是否为改造文法:消除二义性、左递归提取因子,判断是否为改造文法:消除二义性、左递归提取因子,判断是否为改造文法:消除二义性、左递归提取因子,判断是否为LL (1)文法,3、LL (1)分析法实验设计思想及算)分析法实验设计思想及算X∈VN‘#’‘ S’ 进栈,当前输入符送进栈,当前输入符送进栈,当前输入符送进栈,当前输入符送a栈顶符号放入栈顶符号放入X若产生式为若产生式为X X1X2…X n按逆序即Xn…X 2X1入栈出错X=’ X=’ X=’ #’X∈VTX=aX=aM[X,a] M[X,a]M[X,a] M[X,a]是产生式吗是产生式吗出错X=a读入下一个符号读入下一个符号结束是是是是否否否否否是三、实验要求对文法G(E) 如下,用LL(1)分析法对任意输入的符号串进行分析:E→E+T│TT→T*F│FF→(E)│i消除文法左递归,改写为:E →TE'E' →+TE' | εT →FT'T' →*FT' | εF →( E ) | i(1)计算每个语法单位的first 和follow 集合;(2)构造预测分析表;(3)写出分析程序。

LL(1)分析法

LL(1)分析法

LL(1)分析法编译原理实验报告日期:班级:题目:LL(1)分析法组员:LL(1)语法分析程序1. 实验目的:1.根据某一文法编制调试LL (1)分析程序,以便对任意输入的符号串进行分析。

2.本次实验的目的主要是加深对预测分析LL (1)分析法的理解。

2. 实验平台Windows + VC + Win32 Console范例程序: “3-LL1.c ”3. 实验内容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 # )输出: 只能输出步骤1, 格式如下:程序目前还不能对所有输入串进行正确的分析. 需要完善的功能:(1) 请输出完整的分析过程。

即详细输出每一步骤分析栈和剩余串的变化情况, 及每一步所用的产生式.(2) 请输出最终的分析结果, 即输入串 “合法”或 “非法”.(3)示例程序只能完成 + 、* 、(、)的语法分析, 请加入 - 和 / 的语法分析(4)可将测试用的表达式事先放在文本文件中,一行存放一个表达式,以分号分割。

同时将预期的输出结果写在另一个文本文件中,以便和输出进行对照;备注:1. 在“所用产生式”一列中,如果对应有推导,则写出所用产生式;如果为匹配终结符,则写明匹配的终结符; 如分析异常出错则,写为“分析出错”;如成功结束则写为“分析成功”。

步骤 分析栈 剩余输入串 所用产生式 1 #E i+i*i# E →TG2. 对一个新的文法实现LL(1)分析。

4.程序代码第一种文法#include<stdio.h>#include<stdlib.h>#include<string.h>#include<dos.h>char A[20];/*分析栈*/char B[20];/*剩余串*/char v1[20]={'i','+','-','*','/','(',')','#'};/*终结符*/ char v2[20]={'E','G','T','S','F'};/*非终结符*/ int j=0,b=0,top=0,l;/*L为输入串长度*/ typedef struct type/*产生式类型定义*/ char origin;/*大写字符*/char array[7];/*产生式右边字符*/int length;/*字符个数*/}type;type e,t,g,g0,g1,s,s0,s1,f,f1;/*结构体变量*/ type C[10][10];/*预测分析表*/void print()/*输出分析栈*/int a;/*指针*/for(a=0;a<=top+1;a++)printf("%c",A[a]);printf("\t\t");}/*print*/void print1()/*输出剩余串*/int j;for(j=0;j<b;j++)/*输出对齐符*/printf(" ");for(j=b;j<=l;j++)printf("%c",B[j]);printf("\t\t\t");}/*print1*/void main()int m,n,k=0,flag=0,finish=0;char ch,x;type cha;/*用来接受C[m][n]*//*把文法产生式赋值结构体*/e.origin='E';strcpy(e.array,"TG");e.length=2;t.origin='T';strcpy(t.array,"FS");t.length=2;g.origin='G';strcpy(g.array,"+TG");g.length=3;g0.origin='G';strcpy(g0.array,"-TG");g0.length=3;g1.origin='G';g1.array[0]='^';g1.length=1;s.origin='S';strcpy(s.array,"*FS");s.length=3;s0.origin='S';strcpy(s0.array,"/FS");s0.length=3;s1.origin='S';s1.array[0]='^';s1.length=1;f.origin='F';strcpy(f.array,"(E)");f.length=3;f1.origin='F';f1.array[0]='i';f1.length=1;for(m=0;m<=4;m++)/*初始化分析表*/for(n=0;n<=7;n++)C[m][n].origin='N';/*全部赋为空*//*填充分析表*/C[0][0]=e;C[0][5]=e;C[1][1]=g;C[1][2]=g0;C[1][6]=g1;C[1][7]=g1;C[2][0]=t;C[2][5]=t;C[3][1]=s1;C[3][2]=s1;C[3][3]=s;C[3][4]=s0;C[3][6]=s1;C[3][7]=s1;C[4][0]=f1;C[4][5]=f;printf("提示:本程序只能对由'i','+','-','*','/','(',')'构成的以'#'结束的字符串进行分析,\n");printf("请输入要分析的字符串:\n");do/*读入分析串*/scanf("%c",&ch);if ((ch!='i') &&(ch!='+') &&(ch!='-') &&(ch!='*') &&(ch!='/') &&(ch!='(') &&(ch!=')') &&(ch!='#')) printf("输入串中有非法字符\n");exit(1);B[j]=ch;j++;}while(ch!='#');l=j;/*分析串长度*/ch=B[0];/*当前分析字符*/A[top]='#'; A[++top]='E';/*'#','E'进栈*/printf("步骤\t\t分析栈\t\t剩余字符\t\t所用产生式\n"); dox=A[top--];/*x为当前栈顶字符*/printf("%d",k++);printf("\t\t");for(j=0;j<=7;j++)/*判断是否为终结符*/if(x==v1[j])flag=1;break;if(flag==1)/*如果是终结符*/if(x=='#')finish=1;/*结束标记*/printf("合法\n");/*接受*/getchar();getchar();exit(1);}/*if*/if(x==ch)print();print1();printf("%c匹配\n",ch);ch=B[++b];/*下一个输入字符*/flag=0;/*恢复标记*/}/*if*/else/*出错处理*/print();print1();printf("%c出错\n",ch);/*输出出错终结符*/exit(1);}/*else*/}/*if*/else/*非终结符处理*/for(j=0;j<=4;j++)if(x==v2[j])m=j;/*行号*/break;for(j=0;j<=7;j++)if(ch==v1[j])n=j;/*列号*/break;cha=C[m][n];if(cha.origin!='N')/*判断是否为空*/print();print1();printf("%c->",cha.origin);/*输出产生式*/for(j=0;j<cha.length;j++)printf("%c",cha.array[j]);printf("\n");for(j=(cha.length-1);j>=0;j--)/*产生式逆序入栈*/A[++top]=cha.array[j];if(A[top]=='^')/*为空则不进栈*/top--;}/*if*/else/*出错处理*/print();print1();printf("%c出错\n",x);/*输出出错非终结符*/exit(1);}/*else*/}/*else*/}while(finish==0);}/*main*/测试一(1)测试i+i#(2)测试i-i(3)测试i*i#(4)测试i/i#(5)测试i+i*i#(6)测试输入非法字符i+i*#第二中文发#include<stdlib.h>#include<stdio.h>#include<string.h>int count=0; /*分解的产生式的个数*/int number; /*所有终结符和非终结符的总数*/char start; /*开始符号*/char termin[50]; /*终结符号*/char non_ter[50]; /*非终结符号*/char v[50]; /*所有符号*/char left[50]; /*左部*/char right[50][50]; /*右部*/char first[50][50],follow[50][50]; /*各产生式右部的FIRST和左部的FOLLOW集合*/char first1[50][50]; /*所有单个符号的FIRST集合*/char select[50][50]; /*各单个产生式的SELECT集合*/char f[50],F[50]; /*记录各符号的FIRST和FOLLOW是否已求过*/ char empty[20]; /*记录可直接推出^的符号*/char TEMP[50]; /*求FOLLOW时存放某一符号串的FIRST集合*/ int validity=1; /*表示输入文法是否有效*/int ll=1; /*表示输入文法是否为LL(1)文法*/int M[20][20]; /*分析表*/char choose; /*用户输入时使用*/char empt[20]; /*求_emp()时使用*/char fo[20]; /*求FOLLOW集合时使用*/判断一个字符是否在指定字符串中int in(char c,char *p)int i;if(strlen(p)==0)return(0);for(i=0;;i++)if(p[i]==c)return(1); /*若在,返回1*/if(i==strlen(p))return(0); /*若不在,返回0*/得到一个不是非终结符的符号char c()char c='A';while(in(c,non_ter)==1)c++;return(c);分解含有左递归的产生式void recur(char *point){ /*完整的产生式在point[]中*/int j,m=0,n=3,k;char temp[20],ch;ch=c(); /*得到一个非终结符*/k=strlen(non_ter);non_ter[k]=ch;non_ter[k+1]='\0';for(j=0;j<=strlen(point)-1;j++)if(point[n]==point[0]){ /*如果'|'后的首符号和左部相同*/ for(j=n+1;j<=strlen(point)-1;j++)while(point[j]!='|'&&point[j]!='\0')temp[m++]=point[j++];left[count]=ch;memcpy(right[count],temp,m);right[count][m]=ch;right[count][m+1]='\0';m=0;count++;if(point[j]=='|')n=j+1;break;else{ /*如果'|'后的首符号和左部不同*/ left[count]=ch;right[count][0]='^';right[count][1]='\0';count++;for(j=n;j<=strlen(point)-1;j++)if(point[j]!='|')temp[m++]=point[j];elseleft[count]=point[0];memcpy(right[count],temp,m);right[count][m]=ch;right[count][m+1]='\0';printf(" count=%d ",count);m=0;count++;left[count]=point[0];memcpy(right[count],temp,m);right[count][m]=ch;right[count][m+1]='\0';count++;m=0;分解不含有左递归的产生式void non_re(char *point)int m=0,j;char temp[20];for(j=3;j<=strlen(point)-1;j++)if(point[j]!='|')temp[m++]=point[j];elseleft[count]=point[0];memcpy(right[count],temp,m);right[count][m]='\0';m=0;count++;left[count]=point[0];memcpy(right[count],temp,m);right[count][m]='\0';count++;m=0;读入一个文法char grammer(char *t,char *n,char *left,char right[50][50]) char vn[50],vt[50];char s;char p[50][50];int i,j,k;printf("\n请输入文法的非终结符号串:");scanf("%s",vn);getchar();i=strlen(vn);memcpy(n,vn,i);n[i]='\0';printf("请输入文法的终结符号串:");scanf("%s",vt);getchar();i=strlen(vt);memcpy(t,vt,i);t[i]='\0';printf("请输入文法的开始符号:");scanf("%c",&s);getchar();printf("请输入文法产生式的条数:");scanf("%d",&i);getchar();for(j=1;j<=i;j++)printf("请输入文法的第%d条(共%d条)产生式:",j,i);scanf("%s",p[j-1]);getchar();for(j=0;j<=i-1;j++)if(p[j][1]!='-'||p[j][2]!='>'){ printf("\ninput error!");validity=0;return('\0');} /*检测输入错误*/for(k=0;k<=i-1;k++){ /*分解输入的各产生式*/if(p[k][3]==p[k][0])recur(p[k]);elsenon_re(p[k]);return(s);将单个符号或符号串并入另一符号串void merge(char *d,char *s,int type){ /*d是目标符号串,s是源串,type=1,源串中的' ^ '一并并入目串;type=2,源串中的' ^ '不并入目串*/int i,j;for(i=0;i<=strlen(s)-1;i++)if(type==2&&s[i]=='^')elsefor(j=0;;j++)if(j<strlen(d)&&s[i]==d[j])break;if(j==strlen(d))d[j]=s[i];d[j+1]='\0';break;求所有能直接推出^的符号void emp(char c){ /*即求所有由' ^ '推出的符号*/char temp[10];int i;for(i=0;i<=count-1;i++)if(right[i][0]==c&&strlen(right[i])==1)temp[0]=left[i];temp[1]='\0';merge(empty,temp,1);emp(left[i]);求某一符号能否推出' ^ 'int _emp(char c){ /*若能推出,返回1;否则,返回0*/int i,j,k,result=1,mark=0;char temp[20];temp[0]=c;temp[1]='\0';merge(empt,temp,1);if(in(c,empty)==1)return(1);for(i=0;;i++)if(i==count)return(0);if(left[i]==c) /*找一个左部为c的产生式*/j=strlen(right[i]); /*j为右部的长度*/if(j==1&&in(right[i][0],empty)==1)return(1);else if(j==1&&in(right[i][0],termin)==1)return(0);elsefor(k=0;k<=j-1;k++)if(in(right[i][k],empt)==1)mark=1;if(mark==1)continue;elsefor(k=0;k<=j-1;k++)result*=_emp(right[i][k]);temp[0]=right[i][k];temp[1]='\0';merge(empt,temp,1);if(result==0&&i<count)continue;else if(result==1&&i<count)return(1);判断读入的文法是否正确int judge()int i,j;for(i=0;i<=count-1;i++)if(in(left[i],non_ter)==0){ /*若左部不在非终结符中,报错*/printf("\nerror1!");validity=0;return(0);for(j=0;j<=strlen(right[i])-1;j++)if(in(right[i][j],non_ter)==0&&in(right[i][j],termin)==0&&right[i][j]!='^'){ /*若右部某一符号不在非终结符、终结符中且不为' ^ ',报错*/ printf("\nerror2!");validity=0;return(0);return(1);求单个符号的FIRSTvoid first2(int i){ /*i为符号在所有输入符号中的序号*/char c,temp[20];int j,k,m;c=v[i];char ch='^';emp(ch);if(in(c,termin)==1) /*若为终结符*/first1[i][0]=c;first1[i][1]='\0';else if(in(c,non_ter)==1) /*若为非终结符*/for(j=0;j<=count-1;j++)if(left[j]==c)if(in(right[j][0],termin)==1||right[j][0]=='^')temp[0]=right[j][0];temp[1]='\0';merge(first1[i],temp,1);else if(in(right[j][0],non_ter)==1)if(right[j][0]==c)continue;for(k=0;;k++)if(v[k]==right[j][0])break;if(f[k]=='0')first2(k);f[k]='1';merge(first1[i],first1[k],2);for(k=0;k<=strlen(right[j])-1;k++)empt[0]='\0';if(_emp(right[j][k])==1&&k<strlen(right[j])-1)for(m=0;;m++)if(v[m]==right[j][k+1])break;if(f[m]=='0')first2(m);f[m]='1';merge(first1[i],first1[m],2);else if(_emp(right[j][k])==1&&k==strlen(right[j])-1)temp[0]='^';temp[1]='\0';merge(first1[i],temp,1);elsebreak;f[i]='1';求各产生式右部的FIRSTvoid FIRST(int i,char *p)int length;int j,k,m;char temp[20];length=strlen(p);if(length==1) /*如果右部为单个符号*/if(p[0]=='^')if(i>=0)first[i][0]='^';first[i][1]='\0';elseTEMP[0]='^';TEMP[1]='\0';elsefor(j=0;;j++)if(v[j]==p[0])break;if(i>=0)memcpy(first[i],first1[j],strlen(first1[j]));first[i][strlen(first1[j])]='\0';elsememcpy(TEMP,first1[j],strlen(first1[j]));TEMP[strlen(first1[j])]='\0';else /*如果右部为符号串*/ for(j=0;;j++)if(v[j]==p[0])break;if(i>=0)merge(first[i],first1[j],2);elsemerge(TEMP,first1[j],2);for(k=0;k<=length-1;k++)empt[0]='\0';if(_emp(p[k])==1&&k<length-1)for(m=0;;m++)if(v[m]==right[i][k+1])break;if(i>=0)merge(first[i],first1[m],2);elsemerge(TEMP,first1[m],2);else if(_emp(p[k])==1&&k==length-1)temp[0]='^';temp[1]='\0';if(i>=0)merge(first[i],temp,1);elsemerge(TEMP,temp,1);else if(_emp(p[k])==0)break;求各产生式左部的FOLLOWvoid FOLLOW(int i)int j,k,m,n,result=1;char c,temp[20];c=non_ter[i]; /*c为待求的非终结符*/ temp[0]=c;temp[1]='\0';merge(fo,temp,1);if(c==start){ /*若为开始符号*/temp[0]='#';temp[1]='\0';merge(follow[i],temp,1);for(j=0;j<=count-1;j++)if(in(c,right[j])==1) /*找一个右部含有c的产生式*/for(k=0;;k++)if(right[j][k]==c)break; /*k为c在该产生式右部的序号*/for(m=0;;m++)if(v[m]==left[j])break; /*m为产生式左部非终结符在所有符号中的序号*/ if(k==strlen(right[j])-1){ /*如果c在产生式右部的最后*/if(in(v[m],fo)==1)merge(follow[i],follow[m],1);continue;if(F[m]=='0')FOLLOW(m);F[m]='1';merge(follow[i],follow[m],1);else{ /*如果c不在产生式右部的最后*/for(n=k+1;n<=strlen(right[j])-1;n++)empt[0]='\0';result*=_emp(right[j][n]);if(result==1){ /*如果右部c后面的符号串能推出^*/if(in(v[m],fo)==1){ /*避免循环递归*/merge(follow[i],follow[m],1);continue;if(F[m]=='0')FOLLOW(m);F[m]='1';merge(follow[i],follow[m],1);for(n=k+1;n<=strlen(right[j])-1;n++)temp[n-k-1]=right[j][n];temp[strlen(right[j])-k-1]='\0';FIRST(-1,temp);merge(follow[i],TEMP,2);F[i]='1';判断读入文法是否为一个LL(1)文法int ll1()int i,j,length,result=1;char temp[50];for(j=0;j<=49;j++){ /*初始化*/first[j][0]='\0';follow[j][0]='\0';first1[j][0]='\0';select[j][0]='\0';TEMP[j]='\0';temp[j]='\0';f[j]='0';F[j]='0';for(j=0;j<=strlen(v)-1;j++)first2(j); /*求单个符号的FIRST集合*/ printf("\nfirst1:");for(j=0;j<=strlen(v)-1;j++)printf("%c:%s ",v[j],first1[j]);printf("\nempty:%s",empty);printf("\n:::\n_emp:");for(j=0;j<=strlen(v)-1;j++)printf("%d ",_emp(v[j]));for(i=0;i<=count-1;i++)FIRST(i,right[i]); /*求FIRST*/printf("\n");for(j=0;j<=strlen(non_ter)-1;j++){ /*求FOLLOW*/if(fo[j]==0)fo[0]='\0';FOLLOW(j);printf("\nfirst:");for(i=0;i<=count-1;i++)printf("%s ",first[i]);printf("\nfollow:");for(i=0;i<=strlen(non_ter)-1;i++)printf("%s ",follow[i]);for(i=0;i<=count-1;i++){ /*求每一产生式的SELECT集合*/ memcpy(select[i],first[i],strlen(first[i]));select[i][strlen(first[i])]='\0';for(j=0;j<=strlen(right[i])-1;j++)result*=_emp(right[i][j]);if(strlen(right[i])==1&&right[i][0]=='^')result=1;if(result==1)for(j=0;;j++)if(v[j]==left[i])break;merge(select[i],follow[j],1);printf("\nselect:");for(i=0;i<=count-1;i++)printf("%s ",select[i]);memcpy(temp,select[0],strlen(select[0]));temp[strlen(select[0])]='\0';for(i=1;i<=count-1;i++){ /*判断输入文法是否为LL(1)文法*/length=strlen(temp);if(left[i]==left[i-1])merge(temp,select[i],1);if(strlen(temp)<length+strlen(select[i]))return(0);elsetemp[0]='\0';memcpy(temp,select[i],strlen(select[i]));temp[strlen(select[i])]='\0';return(1);构造分析表Mvoid MM()int i,j,k,m;for(i=0;i<=19;i++)for(j=0;j<=19;j++)M[i][j]=-1;i=strlen(termin);termin[i]='#'; /*将#加入终结符数组*/termin[i+1]='\0';for(i=0;i<=count-1;i++)for(m=0;;m++)if(non_ter[m]==left[i])break; /*m为产生式左部非终结符的序号*/ for(j=0;j<=strlen(select[i])-1;j++)if(in(select[i][j],termin)==1)for(k=0;;k++)if(termin[k]==select[i][j])break; /*k为产生式右部终结符的序号*/ M[m][k]=i;总控算法void syntax()int i,j,k,m,n,p,q;char ch;char S[50],str[50];printf("请输入该文法的句型:");scanf("%s",str);getchar();i=strlen(str);str[i]='#';str[i+1]='\0';S[0]='#';S[1]=start;S[2]='\0';j=0;ch=str[j];while(1)if(in(S[strlen(S)-1],termin)==1)if(S[strlen(S)-1]!=ch)printf("\n该符号串不是文法的句型!");return;else if(S[strlen(S)-1]=='#')printf("\n该符号串是文法的句型.");return;elseS[strlen(S)-1]='\0';j++;ch=str[j];elsefor(i=0;;i++)if(non_ter[i]==S[strlen(S)-1])break;for(k=0;;k++)if(termin[k]==ch)break;if(k==strlen(termin))printf("\n词法错误!");return;if(M[i][k]==-1)printf("\n语法错误!");return;elsem=M[i][k];if(right[m][0]=='^')S[strlen(S)-1]='\0';elsep=strlen(S)-1;q=p;for(n=strlen(right[m])-1;n>=0;n--)S[p++]=right[m][n];S[q+strlen(right[m])]='\0';printf("\nS:%s str:",S);for(p=j;p<=strlen(str)-1;p++)printf("%c",str[p]);printf(" ");一个用户调用函数void menu()syntax();printf("\n是否继续?(y or n):");scanf("%c",&choose);getchar();while(choose=='y')menu();主函数void main()int i,j;start=grammer(termin,non_ter,left,right); /*读入一个文法*/ printf("count=%d",count);printf("\nstart:%c",start);strcpy(v,non_ter);strcat(v,termin);printf("\nv:%s",v);printf("\nnon_ter:%s",non_ter);printf("\ntermin:%s",termin);printf("\nright:");for(i=0;i<=count-1;i++)printf("%s ",right[i]);printf("\nleft:");for(i=0;i<=count-1;i++)printf("%c ",left[i]);if(validity==1)validity=judge();printf("\nvalidity=%d",validity);if(validity==1)printf("\n文法有效");ll=ll1();printf("\nll=%d",ll);if(ll==0)printf("\n该文法不是一个LL1文法!");elseMM();printf("\n");for(i=0;i<=19;i++)for(j=0;j<=19;j++)if(M[i][j]>=0)printf("M[%d][%d]=%d ",i,j,M[i][j]);printf("\n");menu();测试二(1)测试输入一个文法(2)测试输入一个符号串(3)测试再次输入一个符号串,然后退出程序5.缺少功能要求(4)可将测试用的表达式事先放在文本文件中,一行存放一个表达式,以分号分割。

LL(1)文法预测分析法实验报告

LL(1)文法预测分析法实验报告

一、实验原理LL(1)分析法,就是指从左到右扫描输入串(源程序),同时采用最左推导,且对每次直接推导只需向前看一个输入符号,便可确定当前所应当选择的规则。

实现LL(1)分析的程序又称为LL(1)分析程序或LL(1)分析器。

一个文法要能进行LL(1)分析,那么这个文法应该满足:无二义性,无左递归,无左公因子。

当文法满足条件后,再分别构造文法每个非终结符的FIRST和FOLLOW集合,然后根据FIRST和FOLLOW集合构造LL(1)分析表,最后利用分析表,根据LL(1)语法分析构造一个分析器。

LL(1)的语法分析程序包含了三个部分:控制程序,预测分析表函数,先进先出的语法分析栈。

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。

1 LL(1)分析法LL(1)分析法又称预测分析法,是一种不带回溯的非递归自顶向下分析法。

LL(1)的含义是:第一个L表明自顶向下分析是从左至右扫描输入串的;第二个L 表明分析过程中将用最左推导;“1”表明只需向右查看一个符号就可以决定如何推导(即可知用哪一个产生式进行推导)。

LL(1)分析器结构如图1:图 1 LL(1)分析器使用 L L(1)分析法将会涉及到 L L(1)分析表,而分析表又会涉及到 FIRST 集 和 F OLLOW 集。

FIRST 集构造对文法中的每一个非终结符 X 构造 F IRST(X),其方法是连续使用以下规则, 直到每个集合的 F IRST 不再增大为止。

LL(1)语法分析实验报告

LL(1)语法分析实验报告

编译原理实验报告
(1)设计思路
输入文法规则、非终结符和终结符先求出first集合,然后根据first集合和文法规则再求出follow集合,最后求出LL(1)预测分析表,最后通过分析表识别字符串是否符合文法规则。

(2)流程图
(3)具体过程:
(a)first和follow集合的计算:
对G中每个文法符号X∈VT∪VN,构造FIRST(X)。

连续使用下述规则,直至每个FIRST集合不再增大:
a、若X∈ VT,则FIRST(X)={X};
b、若X∈ VN,且有产生式X→a…,则把a加入FIRST(X) ;若X→ε也是一条产生式,则把ε也加入
c、若X→Y…是一个产生式且Y∈ VN,则把FIRST(Y)中的所有非ε元素都加入FIRST(X)中;若X→Y1Y2…Yk是一个产生式,Y1,Y2,…,Yi-1都是非终结符,而且,对任意j(1≤j≤i-1),FIRST(Yj)都含有ε,则把FIRST(Yi)
(2)产生各个符合的FIRST集合及FOLLOW集合:
(3)构造M[A,a]
(4)输入字符串:i*(i+i)进行分析:
该字符串是文法的句型
(5)输入另一个字符串:i+i(i*i)进行分析:
该字符串不是文法的句型。

实验3预测分析法(DOC)

实验3预测分析法(DOC)

一、分析语法分析部分我们我们采用LL(1)方法实现,采用LL(1)方法实现语法发分析要求文法满足以下要求:一个文法能否用确定的自顶向下分析与文法中相同左部的每个产生式右部的开始符号集合有关,当有右部能=*=>ε时则与其左部非终结符的后跟符号集合也有关,此外在产生式中不存在左递归,无回溯。

它的基本思想是从左到右扫描源程序,同时从识别符号开始生成句子的最左推导,并只向前查看一个输入符号,便能唯一确定应选择的规则。

下面将确切地定义满足确定的自顶向下分析条件的文法即LL(1)文法及LL(1)文法的判别并介绍如何对非LL(1)文法进行等价变换问题,也就是消除一个文法中的左递归和左公共因子。

注意:一个文法中含有左递归和左公共因子绝对不是LL(1)文法,所以也就不可能用确定的自顶向下分析法,对此结论可以证明。

然而,某些含有左递归和左公共因子的文法在通过等价变换把它们消除以后可能变为LL(1)文法,但需要用LL(1)文法的定义判别,也就是说文法中不含左递归和左公共因子,只是LL(1)文法的必要条件。

LL(1) 文法的定义(5种定义):一个文法符号串的开始符号集合定义如下:定义 1.设G=(VT,VN,S,P)是上下文无关文法,α是任意的文法符号串,FIRST(α)是从α推导出的串的开始符号的终结符集合。

FIRST(α)={a|α=*=>aβ,a∈VT,α,β∈V*}若α=*=>ε,则规定ε∈FIRST(α).当一个文法中相同左部非终结符的右部存在能=*=>ε的情况则必须知道该非终结符的后跟符号的集合中是否含有其它右部开始符号集合的元素。

为此,我们定义一个文法非终结符的后跟符号的集合如下:定义2.设G=(VT,VN,S,P)是上下文无关文法,A∈VN,S是开始符号FOLLOW(A)={a|S=*=>μAβ,且a∈VT,a∈FIRST(β),μ∈VT* ,β∈V+}若S=*=>μAβ,且βε, 则#∈FOLLOW(A)。

LL(1)语法分析程序实验报告

LL(1)语法分析程序实验报告

LL(1)语法分析程序实验报告——糖拌咸鱼/coser 实验目的与要求:通过设计、编写和调试构造First集合、Follow集合和LL(1)预测分析表,利用LL(1)预测分析表来分析给定的符号串的程序,了解构造LL(1)分析表的构造步骤、分析方法、对文法的要求。

能够从文法G出发,自动生成对应的分析表,并分析给定的符号串,并通过表格和图形的方式实现。

实验环境:开发语言:C#开发平台:Visual Studio 2010运行平台:windows平台,并装有.net 3.5以上输入:一个文法以及一个待分析的给定符号串输出:该文法的中所有非终结符的First和Follow集合该文法的LL(1)预测分析表根据LL(1)预测分析表分析符号串的过程和分析树实验的测试语法:E->TAA->+TA|εT->FBB->*FB|εF->(E)|i实验的测试符号串:合法:i*i+i非法:i*i+i-i实验设计:1.LL(1)语法分析程序的详细数据流图设计2.数据结构设计a)类设计b)数据成员设计3.函数子模块设计4.算法设计a)求各个文法符号X的First集合算法1.如果X是一个终结符号,那么First(X)=X。

2.如果X是一个非终结符号,且X->Y1Y2…..YK是一个产生式,其中k>=1,那么如果对于某个i,a在First(Yi)中且ε在所有的First(Y1), First(Y2)…….First(Yi-1)中,就把a加入到First(X)中。

3.如果X->ε是一个产生式,那么将ε加入到First(X)中。

4.不断应用上述规则,直到再没有新的终结符号或ε可以被加入任何First集合中为止。

算法实现:b)计算所有非终结符A的Follow(A) 集合算法1.将#放入到Follow(S)中,其中S是开始符号,而#是输入右端的结束标记。

2.如果存在一个表达式A->XBY,那么First(Y)中除了ε之外的所有符号都在Follow(B)中3.如果存在一个产生式A->XB,或存在产生式A->XBY,且First(Y)包含ε,那么Follow(A)中的所有符号都在Follow(B)中。

LL(1)语法分析实验报告

LL(1)语法分析实验报告

实验报告姓名:***学号:**********班级:惠普开发142学校:青岛科技大学Mail:****************电话:178****6475教师:宮生文实验报告:实验名称:LL(1)语法分析实验目的和要求编制一个能识别由词法分析给出的单词符号序列是否是给定文法的正确句子(程序),输出对输入符号串的分析过程。

实验内容和步骤:一、实验内容对于这个实验,总共用了三个函数,即主函数、输出分析栈函数、输出剩余串函数。

在主函数中,还要构造预测分析表。

二、实验步骤1、基于实验的内容,构造程序所需的模块2、根据已建构的模块,写出各个模块的相应程序代码3、在主函数中调用模块来完成所要得到的效果在本程序中,首先使用了结构体类型定义来定义产生式,用字符串数组存放分析栈、剩余串、终结符和非终结符,用二维数组存放预测分析表,利用指针对栈中数据进行读取。

在本程序中,总共用了三个函数,即主函数、输出分析栈函数、输出剩余串函数。

在主函数中,还要构造预测分析表,对输入的字符串进行分析,调用另外两个函数。

实验代码如下:#include<stdio.h>#include<stdlib.h>#include<string.h>#include<dos.h>char A[20];/*分析栈*/char B[20];/*剩余串*/char v1[20]={'i','+','*','(',')','#'};/*终结符*/char v2[20]={'E','G','T','S','F'};/*非终结符*/int j=0,b=0,top=0,l;/*L为输入串长度*/typedef struct type/*产生式类型定义*/{char origin;/*大写字符*/char array[5];/*产生式右边字符*/int length;/*字符个数*/}type;type e,t,g,g1,s,s1,f,f1;/*结构体变量*/type C[10][10];/*预测分析表*/void print()/*输出分析栈*/{int a;/*指针*/for(a=0;a<=top+1;a++)printf("%c",A[a]);printf("\t\t");}/*print*/void print1()/*输出剩余串*/{int j;for(j=0;j<b;j++)/*输出对齐符*/printf(" ");for(j=b;j<=l;j++)printf("%c",B[j]);printf("\t\t\t");}/*print1*/void main(){int m,n,k=0,flag=0,finish=0;char ch,x;type cha;/*用来接受C[m][n]*//*把文法产生式赋值结构体*/e.origin='E';strcpy(e.array,"TG");e.length=2;t.origin='T';strcpy(t.array,"FS");t.length=2;g.origin='G';strcpy(g.array,"+TG");g.length=3;g1.origin='G';g1.array[0]='^';g1.length=1;s.origin='S';strcpy(s.array,"*FS");s.length=3;s1.origin='S';s1.array[0]='^';s1.length=1;f.origin='F';strcpy(f.array,"(E)");f.length=3;f1.origin='F';f1.array[0]='i';f1.length=1;for(m=0;m<=4;m++)/*初始化分析表*/for(n=0;n<=5;n++)C[m][n].origin='N';/*全部赋为空*//*填充分析表*/C[0][0]=e;C[0][3]=e;C[1][1]=g;C[1][4]=g1;C[1][5]=g1;C[2][0]=t;C[2][3]=t;C[3][1]=s1;C[3][2]=s;C[3][4]=C[3][5]=s1;C[4][0]=f1;C[4][3]=f;printf("提示:本程序只能对由'i','+','*','(',')'构成的以'#'结束的字符串进行分析,\n"); printf("请输入要分析的字符串:");do/*读入分析串*/{scanf("%c",&ch);if ((ch!='i') &&(ch!='+') &&(ch!='*')&&(ch!='(')&&(ch!=')')&&(ch!='#')){printf("输入串中有非法字符\n");exit(1);}B[j]=ch;j++;}while(ch!='#');l=j;/*分析串长度*/ch=B[0];/*当前分析字符*/A[top]='#'; A[++top]='E';/*'#','E'进栈*/printf("步骤\t\t分析栈\t\t剩余字符\t\t所用产生式\n");do{x=A[top--];/*x为当前栈顶字符*/printf("%d",k++);printf("\t\t");for(j=0;j<=5;j++)/*判断是否为终结符*/if(x==v1[j]){flag=1;break;}if(flag==1)/*如果是终结符*/{if(x=='#'){finish=1;/*结束标记*/printf("acc!\n");/*接受*/getchar();getchar();exit(1);}/*if*/if(x==ch){print();print1();printf("%c匹配\n",ch);ch=B[++b];/*下一个输入字符*/flag=0;/*恢复标记*/}/*if*/else/*出错处理*/{print();print1();printf("%c出错\n",ch);/*输出出错终结符*/exit(1);}/*else*/}/*if*/else/*非终结符处理*/{for(j=0;j<=4;j++)if(x==v2[j]){m=j;/*行号*/break;}for(j=0;j<=5;j++)if(ch==v1[j]){n=j;/*列号*/break;}cha=C[m][n];if(cha.origin!='N')/*判断是否为空*/{print();print1();printf("%c-",cha.origin);/*输出产生式*/for(j=0;j<cha.length;j++)printf("%c",cha.array[j]);printf("\n");for(j=(cha.length-1);j>=0;j--)/*产生式逆序入栈*/A[++top]=cha.array[j];if(A[top]=='^')/*为空则不进栈*/top--;}/*if*/else/*出错处理*/{print();print1();printf("%c出错\n",x);/*输出出错非终结符*/exit(1);}/*else*/}/*else*/}while(finish==0);}/*main*/三、实验过程记录:实验截图:当输入内容不匹配或输入内容非法时要退出程序,此时若不关闭已经打开的文件可能导致文件内容受到破坏;解决方法是给error()函数设置一个文件指针变量参数FILE* fp,在退出程序之前通过fp关闭文件四、实验总结:通过本次实验我锻炼了自己的上机操作能力及编程能力,并对理论知识有了进一步的了解。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

编译原理实验报告一、实验目的及要求1.通过本次实验,加深对LL(1)预测分析法原理的认识和理解。

2.构造LR(1)分析程序,利用它进行语法分析,判断给出的符号串是否为该文法识别的句子。

3.了解LR(K)分析方法是严格的从左向右扫描,和自底向上的语法分析方法。

二、运行环境:硬件:windows xp软件:visual c++6.0三、实验内容1、分析使用LR(1)的优点:(1)LR分析器能够构造来识别所有能用上下文无关文法写的程序设计语言的结构。

(2)LR分析方法是已知的最一般的无回溯移进-归约方法,它能够和其他移进-归约方法一样有效地实现。

(3)LR方法能分析的文法类是预测分析法能分析的文法类的真超集。

(4)LR分析器能及时察觉语法错误,快到自左向右扫描输入的最大可能。

为了使一个文法是LR的,只要保证当句柄出现在栈顶时,自左向右扫描的移进-归约分析器能够及时识别它便足够了。

当句柄出现在栈顶时,LR分析器必须要扫描整个栈就可以知道这一点,栈顶的状态符号包含了所需要的一切信息。

如果仅知道栈内的文法符号就能确定栈顶是什么句柄。

LR分析表的转移函数本质上就是这样的有限自动机。

不过,这个有限自动机不需要根据每步动作读栈,因为,如果这个识别句柄的有限自动机自底向上读栈中的文法符号的话,它达到的状态正是这时栈顶的状态符号所表示的状态,所以,LR分析器可以从栈顶的状态确定它需要从栈中了解的一切。

2、LR分析器由三个部分组成:(1)总控程序,也可以称为驱动程序。

对所有的LR分析器总控程序都是相同的。

(2)分析表或分析函数,不同的文法分析表将不同,同一个文法采用的LR分析器不同时,分析表将不同,分析表又可以分为动作表(ACTION)和状态转换(GOTO)表两个部分,它们都可用二维数组表示。

(3)分析栈,包括文法符号栈和相应的状态栈,它们均是先进后出栈。

分析器的动作就是由栈顶状态和当前输入符号所决定。

四、程序源代码://edge.h#ifndef HEAD_EDGE#define HEAD_EDGE#include<string>using namespace std;extern int SUM;extern string NODE,ENODE;class edge{public:edge();string getlf();string getrg();string getfirst();string getfollow();string getselect();string getro();int getrlen();void newfirst(string w);void newfollow(string w);void newselect(string w);void delfirst();private:string left,right,first,follow,select;int rlen;};#endif///////////////////////////////////////////////////////// //////////////////////edge.cpp#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);}//LL1.cpp#include<iostream>#include<string>#include "edge.h"using namespace std;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){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.lengt h())ENODE+=str[j];}//计算first集合for(i=0;i<SUM;i++){first(n[i],n,i);/*cout<<"First("<<n[i].getlf()<<")=";out(n[i].getfirst());cout<<endl;*/}//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;}}}}}/*for(i=0;i<SUM;i++){cout<<"First("<<n[i].getlf()<<")=";out(n[i].getfirst());cout<<endl;}outfu(10,"~*~");cout<<endl;*///计算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());/*cout<<"Follow("<<n[i].getlf()<<")=";out(n[i].getfollow());cout<<endl;*/}}//outfu(10,"~*~");cout<<endl;//计算select集合for(i=0;i<SUM;i++){select(n[i],n);/*cout<<"Select("<<n[i].getlf()<<"->"<<n[i].getrg()<<")=";out(n[i].getselect());cout<<endl;*/}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;}}}}/*for(i=0;i<SUM;i++){cout<<"Select("<<n[i].getlf()<<"->"<<n[i].getrg()<<")=";out(n[i].getselect());cout<<endl;}*///输出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);/*for(i=0;i<NODE.length();i++){for(j=0;j<ENODE.length();j++)if(yc[i][j].length())cout<<yc[i][j]<<" ";else outfu(10," ");cout<<endl;}*/string chuan,fenxi,fchuan;cout<<endl<<"请输入符号串:";cin>>chuan;fchuan=chuan;fenxi="#";fenxi+=NODE[0];//cout<<"chuan="<<chuan<<endl<<"fenxi="<<fenxi<<endl;//分析符号串i=0;cout<<endl<<"预测分析过程如下:"<<endl;cout<<"步骤";outfu(8," ");cout<<"分析栈";outfu(10," ");cout<<"剩余输入串";outfu(10," ");cout<<"动作";if(pipei(chuan,fenxi,yc,i))cout<<endl<<"输入串"<<fchuan<<"是该文法的句子!"<<endl;elsecout<<endl<<"输入串"<<fchuan<<"不是该文法的句子!"<<endl;}五、解析结果:测试数据一:S→a︳^︳(T)T→SFF→,SFF→ε实验截图输入(a,(a))#后测试结果为测试数据二:S →ABS→bCA →*A →bB →*B →aDC →ADC →bD →aSD →c实验结果截图六、实验总结分析通过本次上机实验,我加深了对预测分析LL(1)分析法的理解,同时体验到了编译原理中一些算法的巧妙。

相关文档
最新文档