合肥工业大学编译原理 LL(1)自上而下文法分析
- 格式:docx
- 大小:736.17 KB
- 文档页数:31
本次课程设计主要是介绍LL(1)文法的一般原理,根据给定的一文法编制调试LL(1)文法语法分析程序,以便对任意输入的符号串进行分析。
本次课程设计的目的主要是加深对预测分析LL(1)文法语法分析的理解,加深对自顶向下语法分析方法的认识。
具体如下:1、对语法规则有明确的定义;2、编写的分析程序能够对给定文法进行正确的语法分析;3、对输入给定的文法,手工计算First、Follow集合以及各产生式的Select 集合,再根据Select集合构造出预测分析表;4、对于输入串,应能根据预测分析表判断识别该输入串是否为给定文法的句子;5、对于遇到的错误,给出简单的错误信息提示,保证能够顺利完成语法分析过程。
前言------------------------------------------------------------- Ⅰ目录------------------------------------------------------------- Ⅱ一、系统分析------------------------------------------------------ 11.1 判断LL(1)文法---------------------------------------------- 11.2 构造预测分析表---------------------------------------------- 1二、系统设计------------------------------------------------------ 22.1 基本设计---------------------------------------------------- 22.2 程序流程图-------------------------------------------------- 2三、系统实现------------------------------------------------------ 33.1 程序主要函数------------------------------------------------ 33.2 程序主要代码------------------------------------------------ 3四、系统测试------------------------------------------------------ 7五、总结---------------------------------------------------------- 8 参考文献---------------------------------------------------------- 9一、系统分析有文法G[E]:E->TG T->FSG->+TG|ε S->*FS|ε F->(E)|i 1.1 判断LL(1)文法当我们需选用自顶向下分析技术时,首先必须判别所给文法是否是LL(1)文法,分析所给文法可知文法中不含左公因子,也不存在左递归,因而再对给定文法计算First 集、Follow 集以及Select 集,对于求出的每个产生式的Select 集,看对于同一个左部非终结符是否存在交集,如果它们的交为空则表示所给文法是LL(1)文法,否则不是L(1)文法。
目录引言 (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);}。
1.课程设计目的:1.1 设计目的:通过编程实现语法分析(自上而下,自下而上)的可视化过程,加深对两法分析原理思想的理解。
[目的要求]通过设计编制调试一个具体的语法分析程序,加深对语法分析原理的理解。
并掌握在对程序设计语言源程序进行扫描过程中将其进行语法分析的方法。
[题目分析]递归下降分析方法是一种确定的自上而下分析方法。
它的基本思想是给文法的每一个非终结符均设计一个相应的子程序。
由于文法的产生式往往是递归的,因为这些子程序往往也是递归的。
1.2 开发环境:操作系统:Windows XP辅助工具:Visual Studio 2008编程语言:C#2. 课程设计要求(1)选定一文法,选定一种分析方法(自上而下、自下而上)(2)允许用户输入语句并对该语句进行相应的语法分析(3)要求显示语法树的建立过程以及跟踪分析表和分析栈的状态(4)要提供单步运行,让用户跟踪分析器工作的每一个步骤。
3. 总体设计3.1 设计框架:3.2 程序流程图:4. 设计功能描述:(1)该课程设计对语法分析指定了固定的文法,运行界面为:“开始”,会出现提示:。
(3)用户输入字符串,可以点击“”,软件根据该输入字符串做好初始化工作,再点击“”,开始分析,每一次点击“下一次”,就做分析的一个步骤,并且此时分析栈和输入栈做相应的出栈、入栈的的动作,同时在“分析栈”,“输入栈”,“输出栈”会显示出相应的状态。
(4)分析结果显示在中(5)如果在分析完后,还需要继续输入字符串分析的画,点击“”,可以再次作上述的操作。
(6)如果想退出程序,点击““,此时会弹出提示窗口:,点击“确定”,便退出程序。
分析实例:输入分析的字符串为i*(i+i)结果如下:5. 源程序代码:#region相关初始量(都是全局的)public string[] mystring = { "TC", "FALSE", "FALSE", "TC", "FALSE", "FALSE", "FALSE", "+TC", "FALSE", "FALSE", "ε", "ε", "FD", "FALSE", "FALSE", "FD", "FALSE", "FALSE", "FALSE", "ε", "*FD", "FALSE", "ε", "ε", "i", "FALSE", "FALSE", "(E)", "FALSE", "FALSE" };//分析表数组bool con = true;//控制显示的布尔量private Stack MyStack = new Stack(); //申请一个分析栈private Stack MyInputstack = new Stack();//申请一个输入栈public string[] Term = { "i", "+", "*", "(", ")", "&" }; //终结符数组public string[] unTerm = { "E", "C", "T", "D", "F" };//非终结符数组private int line, row; //定义行,列的全局变量string MyNowString;#endregion“开始”按钮实现的函数private void开始_Click(object sender, EventArgs e){if (Input_richTextBox1.Text == ""){MessageBox.Show("请输入要分析的字符串!");}else{this.MyOutput_listBox3.Items.Add("");MyStack.Push("&");MyStack.Push("E");MyStack_listBox1.Items.Add("&E");MyInput_listBox2.Items.Add(Input_richTextBox1.Text + "&");MyInputstack.Push("&");for (int i = Input_richTextBox1.Text.Length - 1; i >= 0; i--){MyInputstack.Push(Input_richTextBox1.Text[i]);}begin.Enabled = false;}}#region“下一步”按钮实现的函数private void下一步_Click(object sender, EventArgs e){int loc;string MyStackTop, MyStackInputTop;MyStackTop = MyStack.Peek().ToString();MyStackInputTop = MyInputstack.Peek().ToString();MyStackTopOne(MyStackTop);if (MyStackTopOne(MyStackTop)){MyStackTopTwo(MyStackTop, MyStackInputTop);}else if (MyStackTopThree(MyStackTop) &&MyInputStackTopOne(MyStackInputTop)){loc = line * 6 + row;MyNowString = mystring[loc];this.MyOutput_listBox3.Items.Add(MyStack.Peek().ToString() + "-->" + mystring[loc]);Analyse();}else{Rezult_richTextBox2.Text = "分析出错!";nextStep.Enabled = false;con = false;}if (con){ShowMyStack();ShowMyInpuStack();}}#endregion#region显示分析栈里的字符private void ShowMyStack(){string ch = "";int len = MyStack.Count;string display = "";for (int i = 0; i < len; i++){string t;t = MyStack.Pop().ToString();display = display + t;}for (int i = len - 1; i >= 0; i--){ch = ch + display[i];MyStack.Push(display[i]);this.MyStack_listBox1.Items.Add(ch);}#endregion#region显示输入栈里的字符private void ShowMyInpuStack(){int len = MyInputstack.Count;string display = "";for (int i = 0; i < len; i++){string t;t = MyInputstack.Pop().ToString();display = display + t;}for (int i = len - 1; i >= 0; i--){MyInputstack.Push(display[i]);}this.MyInput_listBox2.Items.Add(display);}#endregion#region判断状态栈栈顶元素是否为终结符public bool MyStackTopOne(string stack){bool symbol = false;for (int i = 0; i < Term.Length; i++){if (stack == Term[i]){symbol = true;break;}}return symbol;}#endregion#region状态栈栈顶元素是终结符的处理方法private void MyStackTopTwo(string stack, string input) {if (stack == input)if (stack == "&"){Rezult_richTextBox2.Text = "分析成功!"; nextStep.Enabled = false;con = false;}else{MyStack.Pop();MyInputstack.Pop();this.MyOutput_listBox3.Items.Add(""); }}}#endregion#region返回状态栈栈顶元素在非终结符数组里的下标public bool MyStackTopThree(string stack){bool symbol = false;for (int i = 0; i < unTerm.Length; i++){if (unTerm[i] == stack){line = i;symbol = true;break;}}return symbol;}#endregion#region返回输入栈栈顶元素在终结符数组里的下标private bool MyInputStackTopOne(string myinput){bool symbol = false;for (int i = 0; i < Term.Length; i++){if (Term[i] == myinput){row = i;symbol = true;break;}return symbol;}#endregion#region分析表字符入栈private void Analyse(){if (MyNowString == "FALSE"){Rezult_richTextBox2.Text = "分析出错!";nextStep.Enabled = false;con = false;}else if (MyNowString == "ε"){MyStack.Pop();}else{MyStack.Pop();for (int i = MyNowString.Length - 1; i >= 0; i--) {MyStack.Push(MyNowString[i]);}}}#endregion#region“退出”按钮实现的函数private void exit_button2_Click(object sender, EventArgs e) {DialogResult ret;ret = MessageBox.Show("确定要退出吗?","退出",MessageBoxButtons.OKCancel,MessageBoxIcon.Question,MessageBoxDefaultButton.Button2);if (ret == DialogResult.OK){this.Close();}}#endregion#region“重置”按钮实现的功能private void clear_Button_Click(object sender, EventArgs e){Input_richTextBox1.Clear();Rezult_richTextBox2.Clear();this.MyStack_listBox1.Items.Clear();this.MyInput_listBox2.Items.Clear();this.MyOutput_listBox3.Items.Clear();MyStack.Clear();MyInputstack.Clear();begin.Enabled = true;nextStep.Enabled = true;con = true;}#endregionprivate void button1_Click(object sender, EventArgs e){pictureBox1.Visible = true;}}6. 总结:通过本次课程设计,对于语法分析的原理与方法有了进一步的体会,在通过使用visual studio 2008的同时让我们对c#和语法分析有了更深的理解。
河南工业大学实验报告课程编译原理实验名称实验二 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)分析表的构造方法。
课程设计报告设计题目17.递归下降分析程序的实现设计要求对文法 G:E→E+T|TT→T*F|FF→(E)|i构造出G的递归下降分析程序。
程序显示输出匹配过程(即自上而下生成语法分析树的步骤,输出各匹配产生式序号即可)。
设计思路(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) | ib) 对于以上改进的方法。
可得:对于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集如下:对ESELECT(E→TE’)=FIRST(TE’)=FIRST(T)={ (,i }对E’SELECT(E’→+TE’)={ + }SELECT(E’→−TE’)={ − }SELECT(E’→ε)={ε,),#}对TSELECT(T→FT’)={(,i}对T’SELECT(T’→*FT’)={ * }SELECT(T’→∕FT’)={ ∕ }SELECT(T’→ε)={ε,+,−,),#}对FSELECT(F→(E) )={ ( }SELECT(F→i)={ i }∴SELECT(E’→+TE’)∩SELECT(E’→−TE’)∩SELECT(E’→ε)=ΦSE LECT(T’→*FT’)∩SELECT(T’→∕FT’)∩SELECT(T’→ε)=ΦSELECT(F→(E) )∩SELECT(F→i)= Φ由上可知,有相同左部产生式的SELECT集合的交集为空,所以文法是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”, 然后跳过毛病部份继续显示;同时进行标识符挂号符号表的管理.以下是实现词法分析设计的主要工作:(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;。
编译原理课程设计报告选题名称:LL(1)语法分析系(院):计算机工程系专业:计算机科学与技术学年学期:2010 ~ 2011 学年第 1 学期2010 年12 月30 日设计任务书指导教师(签章):年月日摘要:语法分析是编译程序的核心部分。
语法分析的作用是识别由词法分析给出的单词符号序列是否是给定的文法的正确句子。
目前语法分析常用的方法右自顶向下分析和自底向上分析两大类.确定的自顶向下方法,是从文法的开始符号,考虑如何根据当前的输入符号(单词)唯一的确定选用哪个产生式替换相应非终结符往下推导。
LL(1)文法是一种确定的自顶向下的分析方法.LL(1)分析法的功能是利用LL(1)控制程序根据显示栈顶内容、向前看符号以及LL(1)分析表,对输入符号串自上而下的分析过程。
可通过消除左递归、提取左因子把非LL(1)文法改造成LL(1)文法。
当文法满足条件后,分别构造出文法的每个非终结符的FIRST、FOLLOW集合和SELECT集,根据SELECT 集合判断是否是LL(1)文法.在LL(1)预测分析程序设计过程中,最重要的两个问题是预测分析表的构造和相关数据结构的设计。
而预测分析表的构造首先必须计算文法每个非终结符的FIRST集和FOLLOW集。
要知道一串符号是不是该文法的一个句子,只要判断是否能从文法的开始符号出发推导出这个输入串。
语法分析可以分为两类,一类是自上而下的分析法,一类是自下而上的分析法。
自上而下的主旨是,对任何输入串,试图用一切可能的办法,从文法开始符号出发,自上而下的为输入串建立一棵语法树。
或者说,为输入串寻找一个最左推倒,这种分析过程的本质是一种试探过程,是反复使用不同产生式谋求匹配输入串的过程我主要是自上而下的过程。
关键词:语法分析;LL(1)分析;FIRST集合;FOLLOW集合;自上而下分析目录1 课题综述 (1)1.1课题来源和意义 (1)1。
2预期目标 (1)1.3解决问题 (1)2 系统分析 (1)2.1涉及的知识基础 (1)2.1.1LL(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)文法。