文法判断
编译原理课程设计_LL(1)文法的判定
课程设计报告课程:编译原理课程设计学号:姓名:班级:教师:时间:2015.05.20-2015.07.02计算机学院图4 输入LL(1)文法并测试图7 测试非LL(1)文法附录:程序代码#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,k,m=0,n=3;char ch,temp[20];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);/*从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];else{left[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];else{left[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("请输入文法的非终结符号串:");scanf("%s",vn);//getchar(); /*取出缓冲区剩余的回车键,不要也可*/ i=strlen(vn);memcpy(n,vn,i);n[i]='\0';printf("\n请输入文法的终结符号串:");scanf("%s",vt);getchar();i=strlen(vt);memcpy(t,vt,i);t[i]='\0';printf("\n请输入文法的开始符号:");scanf("%c",&s);//getchar();printf("\n请输入文法产生式的条数:");scanf("%d",&i);//getchar();for(j=1;j<=i;j++){printf("\n请输入文法的第%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!\n");validity=0;return('\0');} /*检测输入错误*/for(k=0;k<=i-1;k++){ /*分解输入的各产生式*/if(p[k][3]==p[k][0]) recur(p[k]);else non_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]=='^');else{for(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);else{for(k=0;k<=j-1;k++)if(in(right[i][k],empt)==1) mark=1;if(mark==1) continue;else{for(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("\nLeft error!");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("\nRight error!");validity=0;return(0);}}}return(1);}/*******************************************求单个符号的FIRST集********************************************/void first2(int i){ /*i为符号在所有输入符号中的序号*/char c,ch='^',temp[20];int j,k,m;c=v[i];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);}else break;}}}}}f[i]='1';}/*******************************************求各产生式右部的FIRST集********************************************/ void 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';}else{TEMP[0]='^';TEMP[1]='\0';}}else{for(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';}else{memcpy(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);else merge(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);else merge(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);else merge(TEMP,temp,1);}else if(_emp(p[k])==0) break;}}}/******************************************* 求各产生式左部的FOLLOW集********************************************/ void 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_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集*/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);}else{temp[0]='\0';memcpy(temp,select[i],strlen(select[i]));temp[strlen(select[i])]='\0';}}return(1);}/*******************************************构造分析表M********************************************/void 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,S[50],str[50];printf("\n请输入该文法的句型:");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;}else{S[strlen(S)-1]='\0';j++;ch=str[j];}}else{for(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;}else{m=M[i][k];if(right[m][0]=='^') S[strlen(S)-1]='\0';else{p=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("S:%s str:",S);for(p=j;p<=strlen(str)-1;p++) printf("%c",str[p]);printf(" \n");}}/*******************************************一个用户调用函数********************************************/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){ll=ll1();printf("\nll=%d",ll);if(ll==0) printf("\n该文法不是一个LL(1)文法!");else{MM();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]);menu();}}}。
如何判断一个文法是ll课件文法
03
LL(k)文法的定义基于预测分析 器,该分析器在解析文法时, 可以查看未来的k个符号来决定 如何进行解析。
02
LL(k)文法的识别
预测分析算法
预测分析算法是一种用于判断文法是否为LL(k)文法的算法,其基本思想是通过预测下一个产生式来逐个排除非LL(k)文法的可 能性。
预测分析算法的步骤包括:对文法的每个产生式进行编号,并按照左部符号的字典序对所有产生式进行排序;然后从文法的 第一个产生式开始,逐个判断每个产生式的预测情况,如果所有产生式的预测情况都满足LL(k)文法的条件,则该文法为LL(k) 文法。
05
LL(k)文法的优缺点
优点
预测性
LL(k)文法具有预测性,可以在语 法分析过程中提前预测可能的语 法结构,从而提高语法分析的效 率和准确性。
简洁性
LL(k)文法的语法规则通常比较简 洁,易于理解和实现,降低了语 法分析的复杂度。
可维护性
由于LL(k)文法的规则相对较少, 因此更易于维护和修改,适应了 语言的发展和变化。
规范分析算法
规范分析算法是一种基于自顶向下的语法分析算法, 其基本思想是从文法的起始符号出发,按照文法的产 生式逐步推导,直到推导出输入符号串为止。
规范分析算法的步骤包括:从文法的起始符号开始, 依次匹配输入符号串中的每个符号,并按照文法的产 生式进行推导;在推导过程中,需要记录下当前已经 匹配的符号串和产生式编号,以便于回溯和判断是否 能够成功匹配整个输入符号串。如果能够成功匹配整 个输入符号串,则说明该文法是LL(k)文法。
03
当k=1时,表示预测分析器在任何时候都可以查看一 个符号或两个连续的符号。
LL(k)文法的定义
01
LL(k)文法是一种形式文法,其 中LL表示“Left to Right, Leftmost derivation”,即从 左到右、最左推导。
日语文法第1课判断句一
日语文法第1课判断句一在日语中,凡用体言加指定助动词做谓语的句子称为判断句。
它的构成形式是:主语+谓语。
例如:1。
これはなんですか。
这是什么?2。
それは本(ほん)です。
那是书。
3。
あれも本ですか。
那也是书吗?4。
いいえ、あれは本ではありません。
不,那不是书。
句型……はなんですか。
.……是什么……可以是指示代词,也可以是名词。
AはBです。
A是B。
CもBです。
C也是B。
DはBではありません。
D不是B。
在日语中,表达……是……的时候,使用”.……は……です”这一句型。
这种判断事物是什么的句子叫做判断句。
句型中的「は」是提示助词,读做「わ(WA)」,附在体言后面,表示句子中的主语。
「も」也是一种助词,接在体言后面,构成主语,而且表示「同样也是」的意思。
句型中的「です」是判断助动词,相当于汉语的「是」。
「です」接在体言后面共同构成谓语。
表达……不是……的时候,使用”.……は……ではありません”这一句型。
句型中的「ではありません」是判断助动词「です」的否定式,相当于汉语的「不是」。
句型中的「か」是在句尾表示疑问语气的助词,相当于中文的「吗」。
指示代词指示事物的代词叫做指示代词。
按十品词分类法,属于名词的范畴。
指示代词分近称、中称、远称、不定称四种。
近称中称远称不定称これ(这个)それ(那个)あれ(那个)どれ(哪个)この人(这个人)その人(那个人)あの人(那个人)どの人(哪个人)「これ」是指自己身边的事物,故称为近称。
「それ」和「あれ」的区别是说话的人感觉较近的事物称为「それ」,故叫中称,不在自己的身边也不在对方身边的,感觉较远的事物称为「あれ」,故叫「远称」。
因为在中文中并没有「それ」和「あれ」的区别,因此在使用时要特别注意,不然会引起各种误会的。
表示疑问或者不确定的事物一般用不定称。
指示代词后面跟有名词时要变为「この……或者その……」等形式。
豆知識(まめちしき)日语中的汉字有「音读」和「训读」两种读法。
模仿汉字读音的读法称做「音读」,按照日本固有的语言读汉字的,称做「训读」。
二义文法的判断方法
二义文法的判断方法二义文法是指产生二义句的文法,句子在结构、词法或语义方面存在多种解释或理解的情况。
判断一个文法是否为二义文法可以从以下几个方面进行分析。
第一,结构歧义。
结构歧义是指一个句子的结构可以按照不同的方式进行解析,这也是导致二义的主要原因之一、结构歧义的判断可以从以下几个角度出发。
1.句子成分的歧义:看句子中的各个成分是否有多种可能的解释。
比如,动词短语是否可以被解释为动词加上宾语或是形容词加上一个补语等。
2.句法分析的歧义:通过进行句法分析,判断句子的具体结构是否存在歧义。
这可以通过分析句子的树状结构图或利用句法分析器进行分析。
3.上下文歧义:考虑句子所在的上下文,看是否存在根据具体语境进行不同解释的可能。
同一句子在不同语境下会有不同的含义。
第二,词法歧义。
词法歧义是指一个词有多个意义,导致句子在词语的选择上存在歧义。
要判断一个文法是否存在词法歧义,可以从以下几个方面进行思考。
1.单词的多义性:考察句子中所使用的词语是否有多种含义。
这可以通过查阅词典或语境来判断。
2.词类歧义:对于一些词来说,它们的词性可以根据上下文的不同而变化。
比如,“轻”可以作为动词、形容词、副词等。
3.词的构词歧义:有些词的词义和构词方式有关。
比如,“红色”可以表示颜色,也可以表示共产主义。
第三,语义歧义。
语义歧义是指句子在语义上存在多种解释的情况,这是由于词与词之间以及句子整体的语义关系导致的。
要判断一个文法是否存在语义歧义,可以考虑以下几点。
1.词语之间的关系:考察句子中的词与词之间的关系,看是否存在多种搭配方式。
比如,“中心”可以表示位置,也可以表示核心。
2.上下文关系:看句子所在的上下文是否会对句子的语义产生影响。
同一句子在不同语境下会有不同的解释。
3.词语的指称关系:考虑句子中的词语是否有多个可能的指称对象。
比如,“他”可以指代男性、单数的人。
综上所述,判断一个文法是否为二义文法需要从结构歧义、词法歧义和语义歧义等多个方面进行分析。
lr0文法的辨别
LR(0)文法的辨别方法如下:
1.判断是否存在归约-归约和移进-归约冲突。
如果没有冲突,则是LR(0)文法(如果是LR(0)文法则四种都是);如果有冲突,则不是LR(0)文法。
2.如果不是LR(0)文法,再判断是否为SLR(1)文法。
DFA中存在冲突项目(归约-归约,归约-移进)且FOLLOW(B1),FOLLOW(B2)两两互
不相交时是SLR(1)项目。
3.如果不是SLR(1)文法,再判断是否为LR(1)文法。
构造带向前搜索符的DFA,无归约-归约冲突则是LR(1)文法。
4.如果不是LR(1)文法,最后判断是否为LALR(1)文法。
合并同心集后无(归约-归约)冲突(在之前的基础上)(核相同,向前搜索符不同)(B->a,a
B->a,a|b 同心集)。
如需了解更多关于LR(0)文法的辨别方法,建议咨询计算机科学领域业内人士或查阅相关论坛资料。
ll1文法的判定条件
ll1文法的判定条件
LL(1)文法是一种上下文无关文法,用于描述一类非常有限的语言结构。
LL(1)文法有以下几个判定条件:
1. 无左递归:LL(1)文法不能包含直接左递归。
直接左递归是指产生式右部的第一个符号是产生式的左部非终结符本身。
2. 消除间接左递归:如果存在间接左递归,即产生式右部可以通过一系列的推导最终回到产生式左部的情况,需要将间接左递归转化为直接左递归,使得文法不包含间接左递归。
3. 消除左公因子:在LL(1)文法中,产生式右部的第一个符号不能相同。
如果存在左公因子,即产生式右部的某个前缀相同,需要对左公因子进行提取,得到新的产生式。
4. First集不相交:对于文法中每个非终结符A,其First集合与其他非终结符的First集合应该互斥,即不相交。
First集合是从一个非终结符开始的所有可能的终结符的集合。
5. Follow集不相交:同样,对于文法中的每个非终结符A,其Follow集合与其他非终结符的Follow集合应该互斥,即不相交。
Follow集合是在一个推导过程中,紧跟在非终结符后面的所有可能的终结符的集合。
通过满足以上五个条件,我们可以确定一个文法是否为LL(1)文法。
LL(1)文法具有预测性,即在每个输入符号位置,根据当前的输入符号和推导栈中的符号,就可以确定接下来使用哪个产生式进行推导。
这种特性使得LL(1)文法适用于递归下降分析法和预测分析表的构建。
LL(1)文法的判定条件包括无左递归、消除间接左递归、消除左公因子、First集不相交和Follow集不相交。
满足这些条件的文法可以被用于构建预测分析表,实现语法分析。
ll1文法判别条件
ll1文法判别条件LL(1)文法是一种用于描述上下文无关文法(CFG)的形式化表示方法。
它具有一些特定的判别条件,以便能够被编译器有效地解析。
首先,一个上下文无关文法被认为是LL(1)文法,需要满足文法的产生式具有以下两个属性:1. 产生式左部不含有相同的非终结符。
即,对于任意的两个产生式A->α和B->β,其中A和B是非终结符,α和β是文法中的串,如果A=B,则α必须等于β。
2. 当两个产生式的左部相同时,它们的右部能够根据输入符号的“向前看”符号(lookahead symbols)进行唯一选择。
这意味着,对于任意的两个产生式A->α和A->β,其中A是非终结符,α和β是文法中的串,如果存在一个输入符号a,使得在A的上下文中,α可以被选择,而β不能被选择,那么α和β不能有任何一个前缀串是相同的。
除了上述产生式的属性外,LL(1)文法还需要满足以下两个条件:1. 对于文法中的每个非终结符A,使用它的所有产生式的右部的First集合中的符号,这些符号不应该有重叠。
First(α)表示产生式α的第一个(最左端)终结符集合。
2. 如果一个产生式右部能够推导为空串(ε),那么该产生式右部的Follow集合和非终结符A的Follow集合应该没有交集。
Follow(A)表示在整个文法中,紧随非终结符A右边的符号的集合。
通过满足以上条件,我们可以判断一个上下文无关文法是否是LL(1)文法。
若满足条件,则可以使用预测分析表来解析此文法,有效地构建编译器。
总结起来,LL(1)文法的判别条件包括产生式左部不含有相同的非终结符、根据“向前看”符号唯一选择产生式右部、非终结符的产生式右部的First集合无重叠、产生式右部能够推导为空串时,Follow集合和非终结符的Follow集合无交集。
只有满足这些条件的文法才能被称为LL(1)文法,并应用于编译器的解析过程中。
XXX-编译原理-命题作业-LL(1)文法的判断(完整答案)
XXX-编译原理-命题作业-LL(1)文法的判断(完整答案)LL(1)文法的判断LL(1)文法本质含义是第一个L表明自顶向下分析是从左向右扫描输入串,第2个L表明分析过程中将使用最左推导,1表明只需向右看一个符号便可决定如何推导,即选择哪个产生式进行推导。
给定文法G:E ->TE'E'->+E|εT ->FT'T' ->T|εF-。
PF'F'-。
*F'|εP->(E)|a|b|^1) 计算该文法每个非终结符的FIRST集和FOLLOW集。
首先计算FIRST集合:FIRST(E) = FIRST(T) = FIRST(F) = FIRST(P) = {(。
a。
b。
^)}FIRST(E') = {+。
ε}FIRST(T') = FIRST(T) + {ε} = {(。
a。
b。
^。
ε)}FIRST(F') = {*。
ε}FIRST(P) = {(。
a。
b。
^)}然后计算FOLLOW集合:FOLLOW(E) = {)。
#}FOLLOW(E') = FOLLOW(E) = {)。
#}FOLLOW(T) = FIRST(E') ∪ FOLLOW(E) = {+。
)。
#}FOLLOW(T') = FOLLOW(T) = FIRST(E') ∪ FOLLOW(E) = {+。
)。
#}FOLLOW(F) = FIRST(T') ∪ FOLLOW(T) = {(。
a。
b。
^。
+。
)。
#}FOLLOW(F') = FOLLOW(F) = FIRST(T') ∪ FOLLOW(T) = {(。
a。
b。
^。
+。
)。
#}FOLLOW(P) = FIRST(F') ∪ FOLLOW(F) = {*。
(。
a。
b。
^。
+。
)。
#}2) 证明该方法是LL(1)的。
《编译原理》总复习-07级
《编译原理》总复习-07级第一章编译程序的概述(一)内容本章介绍编译程序在计算机科学中的地位和作用,介绍编译技术的发展历史,讲解编译程序、解释程序的基本概念,概述编译过程,介绍编译程序的逻辑结构和编译程序的组织形式等。
(二)本章重点编译(程序),解释(程序),编译程序的逻辑结构。
(三)本章难点编译程序的生成。
(四)本章考点全部基本概念。
编译程序的逻辑结构。
(五)学习指导引论部分主要是解释什么是编译程序以及编译的总体过程。
因此学习时要对以下几个点进行重点学习:翻译、编译、目标语言和源语言这几个概念的理解;编译的总体过程:词法分析,语法分析、语义分析与中间代码的生成、代码优化、目标代码的生成,以及伴随着整个过程的表格管理与出错处理。
第三章文法和语言课外训练(一)内容本章是编译原理课程的理论基础,主要介绍与课程相关的形式语言的基本概念,包括符号串的基本概念和术语、文法和语言的形式定义、推导与归约、句子和句型、语法分析树和二义性文法等定义、文法和语言的Chomsky分类。
(二)本章重点上下文无关文法,推导,句子和句型,文法生成的语言,语法分析树和二义性文法。
(三)本章难点上下文无关文法,语法分析树,文法的分类。
(四)本章考点上下文无关文法的定义。
符号串的推导。
语法分析树的构造。
(五)学习指导要构造编译程序,就要把源语言用某种方式进行定义和描述。
学习高级语言的语法描述是学习编译原理的基础。
上下文无关文法及语法树是本章学习的重点。
语法与语义的概念;程序的在逻辑上的层次结构;文法的定义,文法是一个四元组:终结符号集,非终结符号集,开始符号、产生式集;与文法相关的概念,字符,正则闭包,积(连接),或,空集,产生式,推导,直接推导,句子,句型,语言,最左推导,最右推导(规范推导);学会用文法来描述语言及通过文法能分析该文法所描述的语言;语法树及二义性的概念、能通过画语法树来分析一个文法描述的语言是否具有二义性;上下文无关文法的定义和正规文法的定义,能判断一个语言的文法是哪一类文法。
Chomsky 文法类型判断试验报告-推荐下载
如果对于某文法 G,P 中的每个规则具有下列形式: U :: = u
其中 U∈VN;u∈V+,则称该文法 G 为 2 型文法或上下文无关文法,简 写为 CFG。
按照这条规则,对于上下文无关文法,利用该规则进行推导时,无需考虑 非终结符 U 所在的上下文,总能用 u 替换 U,或者将 u 归约为 U,显示了上下 文无关的特点。
for(j=0;j<p[i].left.length();j++) //遍历产生式左部每一个字 符
{ if(p[i].left[j]>='A'&&p[i].left[j]<='Z') //判断字符是否 是非终结符 break; } if(j==p[i].left.length()) { cout<<"该文法不是0型文法"<<endl; return 0; break;
2 型文法所确定的语言为 2 型语言 L2,2 型语言可由非确定的下推自动机 来识别。
一般定义程序设计语言的文法是上下文无关的。如 C 语言便是如此。因此, 上下文无关文法及相应语言引起了人们较大的兴趣与重视。
4.3 型文法(正则文法,线性文法) 如果对于某文法 G,P 中的每个规则具有下列形式:
U :: = T 或 U :: = WT 其中 T∈VT;U,W∈VN,则称该文法 G 为左线性文法。 如果对于某文法 G,P 中的每个规则具有下列形式:
对全部高中资料试卷电气设备,在安装过程中以及安装结束后进行高中资料试卷调整试验;通电检查所有设备高中资料电试力卷保相护互装作置用调与试相技互术关,系电通,力1根保过据护管生高线产中0不工资仅艺料可高试以中卷解资配决料置吊试技顶卷术层要是配求指置,机不对组规电在范气进高设行中备继资进电料行保试空护卷载高问与中题带资2负料2,荷试而下卷且高总可中体保资配障料置各试时类卷,管调需路控要习试在题验最到;大位对限。设度在备内管进来路行确敷调保设整机过使组程其高1在中正资,常料要工试加况卷强下安看与全22过,22度并22工且22作尽22下可护都能1关可地于以缩管正小路常故高工障中作高资;中料对资试于料卷继试连电卷接保破管护坏口进范处行围理整,高核或中对者资定对料值某试,些卷审异弯核常扁与高度校中固对资定图料盒纸试位,卷置编工.写况保复进护杂行层设自防备动腐与处跨装理接置,地高尤线中其弯资要曲料避半试免径卷错标调误高试高等方中,案资要,料求编试技5写、卷术重电保交要气护底设设装。备备置管4高调、动线中试电作敷资高气,设料中课并技3试资件且、术卷料中拒管试试调绝路包验卷试动敷含方技作设线案术,技槽以来术、及避管系免架统不等启必多动要项方高方案中式;资,对料为整试解套卷决启突高动然中过停语程机文中。电高因气中此课资,件料电中试力管卷高壁电中薄气资、设料接备试口进卷不行保严调护等试装问工置题作调,并试合且技理进术利行,用过要管关求线运电敷行力设高保技中护术资装。料置线试做缆卷到敷技准设术确原指灵则导活:。。在对对分于于线调差盒试动处过保,程护当中装不高置同中高电资中压料资回试料路卷试交技卷叉术调时问试,题技应,术采作是用为指金调发属试电隔人机板员一进,变行需压隔要器开在组处事在理前发;掌生同握内一图部线纸故槽资障内料时,、,强设需电备要回制进路造行须厂外同家部时出电切具源断高高习中中题资资电料料源试试,卷卷线试切缆验除敷报从设告而完与采毕相用,关高要技中进术资行资料检料试查,卷和并主检且要测了保处解护理现装。场置设。备高中资料试卷布置情况与有关高中资料试卷电气系统接线等情况,然后根据规范与规程规定,制定设备调试高中资料试卷方案。
二义文法的判断方法
二义文法的判断方法一、什么是二义文法二义文法是指在语法结构上容易产生歧义的一类文法,即同一句子可以有多种不同的解释或理解方式。
这种歧义的产生主要是由于句子中的词语、短语或句子结构等引起的。
二、二义文法的判断方法为了判断一个句子是否存在二义性,我们可以采取以下方法:1. 上下文判断法通过分析上下文,了解句子所在的语境,从而确定句子的具体含义。
上下文判断法是判断二义性的一种常用方法,因为语言是一种交际工具,其含义往往依赖于具体的语境。
例如,句子“我看见他打狗了。
”如果没有上下文,我们无法确定“打狗了”是指“他打了狗”还是“他被狗打了”。
但是如果上下文是“他们之间一直有矛盾,今天他打狗了。
”,那么我们就可以确定“打狗了”是指“他打了狗”。
2. 语法分析法通过对句子的语法结构进行分析,查找可能存在的二义性。
一般来说,二义性常常出现在句子的短语、修饰语、从句等部分。
例如,句子“她见到了那位老师的儿子。
”如果没有上下文,我们无法确定“那位老师的儿子”是指“她见到了那位老师的儿子”还是“她见到了那位老师的儿子的别人”。
但是如果上下文是“她见到了那位老师的儿子,他长得很帅。
”,那么我们就可以确定“那位老师的儿子”是指“她见到了那位老师的儿子”。
3. 逻辑推理法通过逻辑推理,分析句子的意义是否合理,进而判断是否存在二义性。
例如,句子“他是个大学生。
”如果没有上下文,我们无法确定“他是个大学生”是指他是大学生还是他是个大学生的学生。
但是从逻辑上来看,他是个大学生的学生是不合理的,因此我们可以确定“他是个大学生”是指他是大学生。
4. 语用分析法通过对句子的语用信息进行分析,判断句子的具体含义。
例如,句子“请你帮我倒杯水。
”如果没有上下文,我们无法确定“倒杯水”是指请你帮我把杯子倒满水还是请你帮我把杯子里的水倒掉。
但是从语用角度来看,如果是在酒店或者餐厅等场合,我们更容易理解为请你帮我把杯子倒满水。
以上就是判断二义文法的常用方法,但是需要注意的是,判断二义性需要综合考虑上下文、语法、逻辑和语用等多方面因素,不能仅凭一种方法进行判断。
算符优先文法最左素短语的一种判断算法
算符优先文法最左素短语的一种判断算法
本文旨在介绍计算符优先文法最左素短语的一种判断算法,以帮助读者更加了
解此领域的知识。
计算符优先文法最左素短语算法(简称LP)是一种基于自动机的判断文法的
算法,它的任务是判断一个表达式的最左子程序中的符号是否为最左素短语。
LP算法根据文法产生式的属性构造一个状态转换图(简称状态图),根据该
状态图建立一个有限状态自动机(简称FSM),并根据FSM的状态变化进行判断。
状态转换图由状态和转换组成,它标识自动机在文法分析中所承担的每一个状态,转换总是于每个字符符号有关,其中转换是由当前状态和当前符号所确定的,并且一个特定的转换总是指向一个特定的状态。
LP算法在判断最左素短语时,首先根据文法和符号列表构造状态转换图和FSM,然后比较非终结符号和终结符号,如果当前输入的符号是非终结符号,则进行转换,如果当前输入的符号是终结符号,则停止判断并进行下一个符号的判断。
如果所有的符号都被判断完毕,则表明此表达式的最左子程序是最左素短语。
总的来说,计算符优先文法最左素短语的一种判断算法的基本思路是构造状态
转换图,根据文法构造FSM,并根据FSM进行状态转换和符号判断,最终来确定表
达式的最左子程序是否是最左素短语。
LP算法为文法分析和程序设计提供了高效
的算法,使文法分析更加简单易懂,从而为程序设计提供了更多可能性。
如何判断一个文法是LL1文法
又E’ε, ∴ FOLLOW(E’)加入FOLLOW(T)
FOLLOW(T’)= FOLLOW(T)= {+,),#}
∵T → FT’ ∴ FOLLOW(T)加入FOLLOW(T’)
FOLLOW(F)={*,+,),#}
∵T → FT’ ∴ FOLLOW(F)=FIRST(T’)-{ε}
又T’ε ∴ FOLLOW(T)加入FOLLOW(F)
注意:要顺序往下做,一旦不满足条件, 过程就要中断进行
2024/7/20 编 译 原 理
2024年7月20日
4
FIRST(F)={(,i} FIRST(T’)={*,ε} FIRST(T)=FIRST(F)-{ε}={(,i} FIRST(E’)={+,ε} FIRST(E)= FIRST(T)-{ε}={(,i}
FOLLOW(E)={#,)} ∵E是开始符号∴#∈FOLLOW(E)
又F →(E)
∴ )∈FOLLOW(E)
FOLLOW(E’)={#,)} ∵E → TE’ ∴FOLLOW(E)加入 FOLLOW(E’)
FOLLOW(T)={+,),#} ∵E’ → +TE’ ∴FIRST(E’)-{ε}加入FOLLOW(T)
2024/7/20 编 译 原 理
2024年7月20日
5
2. FOLLOW集
对于文法G的非终结符的后继符号集称为 FOLLOW集,定义如下:
FOLLOW(A) ={a|S …Aa…,a ∈VT} 若S …A,则规定#∈FOLLOW(A) FOLLOW(A):是所有句型中紧接A之后的终结符号或#
E→TE' E'→+TE'| T→FT' T'→*FT'| F→(E)|i
如何判断一个文法是ll课件文法
非互斥的FIRST集
两个产生式非终结符的FIRST集不重叠,FIRST 集唯一
如何使用预测分析表判断文法是否是LL(1) 文法?
预测分析表可以用于判断一个文法是否为LL(1)文法,如果预测分析表中每个格子最多只有一个产生式, 则该文法为LL(1)文法。
存在可空产生式
一些非终结符的派生可以推导出空串,即Λ
不存在可空产生式
没有一个非终结符可以推出空串
如何确定每个非终结符的FIRST集和 FOLLOW集?
为了判断一个文法是否为LL文法,需要明确每个非终结符的FIRST集和FOLLOW集,利用以下方法来 解决此问题。
1
FOLLOW集的求法
2
找到一个非终结符A,看一下整个文 法中的table中使用到了这个非终结符 后面的符号有哪些,对于这一串拿出 来,如果to的FIRST集中有Λ就继续找, 否则FIRST集直接加入A的FOLLOW
步骤
1. 求解各非终结符的 FIRST集和FOLLOW
2. 集根据FIRST集、 FOLLOW集填表
3. 检查各表格是否唯一
优点
• 简单、直接,效率更高
缺点
• 仅适用于LL(1)文法
如何使用递归下降分析器分析文法?
递归下降分析器是一种自顶向下的分析器,它通过各产生式的递归调用实现对输入串的分析。如果递归 下降分析器能够正确处理输入串,则该文法是LL(1)文法。
如何判断一个文法是LL文 法
学习LL文法的定义和特点,查看文法是否存在左递归,二义性,可空产生式, 确定每个非终结符的FIRST集和FOLLOW集,检查FIRST集是否互斥等方法。
什么是LL文法?
Word技巧使用自动纠错和文法检查功能
Word技巧使用自动纠错和文法检查功能Microsoft Word是一款功能强大的文字处理软件,能够有效提升我们的工作效率。
其中,自动纠错和文法检查功能是Word中非常实用的工具。
本文将介绍如何使用这两个功能,帮助您轻松规避拼写和语法错误,提高文章质量。
一、自动纠错功能的使用方法自动纠错功能可以帮助我们在输入文字时自动检查和修正拼写错误,避免出现低级错误。
下面是使用自动纠错功能的具体方法:1. 打开Word文档,在顶部菜单栏中选择“文件”。
2. 在弹出的选项中选择“选项”。
3. 在“Word选项”窗口中选择“校对”选项卡。
4. 在“校对”选项卡下方的“自动更正选项”中勾选“自动更正拼写错误”。
5. 确认设置后,点击“确定”按钮。
此时,当您输入文本时,Word会自动检查并修正拼写错误。
同时,您还可以在自动更正选项中添加自定义的纠错规则。
比如,当您常常出现某个单词的拼写错误时,可以将其添加至自定义列表中,以便Word能及时提醒您。
二、文法检查功能的使用方法文法检查功能可以帮助我们发现和纠正文法错误,提高文章的准确性和可读性。
下面是使用文法检查功能的具体方法:1. 打开Word文档,在顶部菜单栏中选择“文件”。
2. 在弹出的选项中选择“选项”。
3. 在“Word选项”窗口中选择“校对”选项卡。
4. 在“校对”选项卡下方的“启用自动检查”中勾选“语法检查”。
5. 确认设置后,点击“确定”按钮。
此时,当您输入文本时,Word会自动检查语法错误并给出相应的提示。
需要注意的是,Word的文法检查功能只能检测一些基本的语法错误,对于复杂的语法错误可能无法准确判断。
在使用文法检查功能时,我们仍然需要保持对文章语法的仔细审查。
结语通过合理利用Word的自动纠错和文法检查功能,我们可以轻松避免拼写和语法错误,提高文章的质量。
在实际使用中,除了依靠这两个功能,我们还需要注重自己的语言表达能力和文法知识的提升。
通过不断学习和实践,我们能够写出更加规范准确的文章,并提升个人的写作能力。
chomsky文法类型的判断
编译原理实验报告实验名称Ch omsky文法类型判断实验时间2014-4-2院系计算机科学与技术学院班级2011级科技(3)班学号E01114375姓名张练钢1.实验目的(1)通过实验进一步理解chomsky文法类型判断的的依据,理解每个类型文法的特点。
(2)进一步理解4种文法类型之间的包含关系。
(3)体会这种理论对于计算机科学发展的深刻影响,特别是对程序设计语言的设计、编译方法和计算复杂性等方面的重大作用。
通过上机实现文法类型的自动判别。
2.实验原理1.0型文法(短语文法)如果对于某文法G,P中的每个规则具有下列形式:u:: = v其中u∈V+,v∈V*,则称该文法G为0型文法或短语文法,简写为PSG。
0型文法或短语结构文法的相应语言称为0型语言或短语结构语言L0。
这种文法由于没有其他任何限制,因此0型文法也称为无限制文法,其相应的语言称为无限制性语言。
任何0型语言都是递归可枚举的,故0型语言又称递归可枚举集。
这种语言可由图灵机(Turning)来识别。
2.1型文法(上下文有关文法)如果对于某文法G,P中的每个规则具有下列形式:xUy:: = xuy其中U∈V N;u∈V+;x,y∈V*,则称该文法G为1型文法或上下文有关文法,也称上下文敏感文法,简写为CSG。
1型文法的规则左部的U和右部的u具有相同的上文x和下文y,利用该规则进行推导时,要用u替换U,必须在前面有x和后面有y的情况下才能进行,显示了上下文有关的特性。
1型文法所确定的语言为1型语言L1,1型语言可由线性有界自动机来识别。
3.2型文法(上下文无关文法)如果对于某文法G,P中的每个规则具有下列形式:U :: = u其中U∈V N;u∈V+,则称该文法G为2型文法或上下文无关文法,简写为CFG。
按照这条规则,对于上下文无关文法,利用该规则进行推导时,无需考虑非终结符U所在的上下文,总能用u替换U,或者将u归约为U,显示了上下文无关的特点。
文法类型判断
学号:专业:姓名:实验日期:2012.4.27 教师签字:成绩:实验名称:试验一:Chomsky文法类型判断实验目的:1. 掌握四种文法类型的定义,及其区别;2.熟悉各种文法类型的判断,能够快速按照要求写出对应文法类型的文法用例。
实验原理:1.0型文法,产生式左右部可以使用"非终结符"和"终结符"随意组合,但左部不能为空,如DAaBb->CcdD;2.1型文法,在0型文法的基础上,要求右部的符号长度大于左部(空除外),如AaBb->CcddDd3.2型文法,在1型文法的基础上,要求左部必须由非终结符号组成,且左部只能拥有一个非终结符,如A->CcdddDd4.3型文法,在2型文法的基础上,产生式必须型如:A->Aa|a或A->aA|a,比如:A->AA,A->aa,这些都不是实验内容:1.实验要求:输入一组任意的规则,输出相应的Chomsky 文法的类型。
实验代码:#include <iostream>#include <fstream>#include <string>#include <algorithm>#include <vector>using namespace std;bool mark[4];struct relation{string _left;string _right;};vector<relation> rel;bool cmp(const relation &r1,const relation &r2){if(r1._left>r2._left) return true;else if(r1._left==r2._left&&r1._right >r2._right) return true;return false;}relation get_realation(string str){ //将一个字符串生成式分为左右部输入格式为->,返回生成式结构体int t=str.find('-');relation r;r._left=str.substr(0,t);r._right=str.substr(t+2,str.length()-t);return r;}void print(){cout<<" [乔姆斯基文法判别——————copyright from 宁宇2012/4/13]"<<endl; }void init(){ //录入产生式print();memset(mark,0,sizeof(mark));cout<<"请输入产生式,以Ctrl+Z结束"<<endl;string s;relation r;while(cin>>s){r=get_realation(s);rel.push_back(r);}}bool hasVn(string s){ //判断s中是否含有非终结符(以大写形式表示)for(int i=0;i<s.length();i++)if(s[i]<='Z'&&s[i]>='A')return true;return false;};bool hasFullVn(string s){for(int i=0;i<s.length();i++)if(s[i]<='z'&&s[i]>='a')return false;return true;}bool is0(){ //判断是否为0行文法:左部长度不为0且至少有一个非终结符for(int i=0;i<rel.size();i++)if(!(rel[i]._left.length()!=0&&hasVn(rel[i]._left)))return false;}bool is1(){ //判断是否为1行文法(上下文有关文法):对于每一个A->b,都有|A|->|B|,for(int i=0;i<rel.size();i++){if(rel[i]._right.length()==1&&rel[i]._right[0]=='#')continue;if(rel[i]._left.length()>=rel[i]._right.length())return false;}return true;}bool is2(){for(int i=0;i<rel.size();i++)if(rel[i]._left.length()==1&&hasFullVn(rel[i]._left))return true;else return false;}bool is3(){for(int i=0;i<rel.size();i++)if(rel[i]._right.length()<=2){if(rel[i]._right.length()==1){if(hasVn(rel[i]._right)) //右部只有一个字母return false;else return true;}else { //右部有两个字母string s=rel[i]._right;int coun=0;if(s[0]<='Z'&&s[0]>='A')coun++;if(s[1]<='Z'&&s[1]>='A')coun++;if(coun==2||coun==0)return false;else return true;}}else return false;}int main(){init();mark[0]=is0();if(mark[0]){mark[1]=is1();if(mark[1]){mark[2]=is2();if(mark[2])mark[3]=is3();}}int i;for(i=3;i>=0;i--)if(mark[i]){cout<<i<<endl;break;}if(i<0)cout<<"非法文法!"<<endl;print();return 0;}3.实验结果:非法文法0型文法1型文法2型文法3型文法。
编译原理-文法的判断
编译原理-⽂法的判断四种⽂法的判断就是规定产⽣式左边和右边的字符组成规则不同⽽已。
从0型到3型,其限制条件越来越多。
判断时从最复杂的3型进⾏判断,若不符合,依次向下。
✔3型⽂法(正规⽂法或右线性⽂法)
A->α或A->αB
①左边有且仅有⼀个⾮终结符。
②右边有⼀个或两个字符。
若有⼀个字符,是终结符;
若有两个字符,左边终结符,右边⾮终结符。
✔2型⽂法(上下⽂⽆关⽂法)
①左边有且仅有⼀个⾮终结符。
②右边可以有若⼲个(有限)字符。
✔1型⽂法(上下⽂有关⽂法)
α->β
①左边⾄少有⼀个⾮终结符。
②|α|≤|β|,仅S->ε除外
✔0型⽂法(⽆限制⽂法)
左边⾄少有⼀个⾮终结符
判断时,取其最⾼的符合规则。
二义文法的判断方法
二义文法的判断方法
二义文法是指一个单词或短语在特定的上下文中可能有多种不同的意思,这种上下文可能是无关的,也可能是相关的。
判断二义文法的方法通常包括以下步骤:
1. 确定上下文:上下文是任何情况下都存在的,与单词或短语相关的背景信息,例如人名、地名、时间、事件等。
在判断二义文法时,需要确定上下文,了解上下文中单词或短语的含义。
2. 比较单词或短语的上下文:在确定单词或短语的含义后,需要比较它与其他单词或短语的含义,以确定它是否为二义文法。
这通常需要对单词或短语的上下文进行深入的研究和思考。
3. 使用词典:在判断二义文法时,使用词典非常重要。
词典可以提供单词或短语的多个含义,并且可以解释这些含义之间的关系。
通过查阅词典,可以更准确地理解单词或短语的含义,并确定它是否为二义文法。
4. 练习:练习是判断二义文法的关键。
通过练习,可以更好地理解上下文和单词或短语的含义,并且可以更准确地判断二义文法。
拓展:二义文法的出现是语言学中一个重要的问题,它使得语言更加复杂和多样化。
有些二义文法可能随着时间和地点的变化而发生变化,而有些二义文法可能保持不变。
因此,研究二义文法的发展和变化,对于了解语言的历史和演变具有重要意义。
此外,对于学习者来说,了解二义文法的含义和判断方法可以帮助他们更好地理解和使用语言。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
Ps.在程序创建的根目录下创建test.txt文件#include <iostream>#include <string>#include<fstream>using namespace std;int m; //文法产生式的个数char Vn[100];//记录非终结字符char Vt[100];//记录终结字符typedef struct GZ//定义一个产生式结构体{string left; //定义产生式的左部string right; //定义产生式的右部string whole;//定义整个产生式}GZ;bool wenfa0(GZ *p,int m)//判断0型文法{int i,j;for(i=0;i<m;i++)//遍历所有的产生式{for(j=0;j<p[i].left.length();j++)//遍历整个产生式左式每一个字符{if((p[i].left.at(j)>='A')&&(p[i].left.at(j)<='Z'))//判断产生式左边是否含有非终结符break;//break只能跳出产生式左边的本次遍历,0型文法需要满足左边有1个非终结符}if(j==p[i].left.length())break;//左边全是终结符,有一个aaa→b,就认为不是0型文法,就不继续执行下去,i<melsecontinue;//左边有非终结符}if(i==m)return 1;//说明该文法是0型else{cout<<"该文法不是0型文法!"<<endl;return 0;}}char choose(string s,int num){return s.at(num);}bool wenfa1(GZ *p,int m)//判断1型文法{int i;if(wenfa0(p,m)){for(i=0;i<m;i++)//遍历所有的产生式{if(p[i].right.length()>=p[i].left.length())//判断产生式右边是否大于左边continue;elsebreak;}if(i==m)return 1;//说明该文法是1型else{cout<<"该文法是0型文法!"<<endl;return 0;}}elsereturn 0;}bool wenfa2(GZ *p,int m)//判断2型文法{int i;if(wenfa1(p,m)){for(i=0;i<m;i++)//遍历所有的产生式{if(p[i].left.length()==1&&(p[i].left.at(0)>='A'&&p[i].left.at(0)<='Z'))//满足二型文法的结构A→aAcontinue;elsebreak;}if(i==m)return 1;//说明该文法是2型else{cout<<"该文法是1型文法!"<<endl;return 0;}}elsereturn 0;}bool wenfa3(GZ *p,int m)//判断3型文法{int i;if(wenfa2(p,m)){for(i=0;i<m;i++)//遍历所有的产生式{if(p[i].right.length()==1&&(p[i].right.at(0)>='a'&&p[i].right.at(0)<='z')||(p[i].right.at(0)>=' 0'&&p[i].right.at(0)<='9'))//判断产生式右边第一个字符是否是终结符以及规定左边的字符个数为1或2{}elseif((p[i].right.length()==2)&&((p[i].right.at(0)>='a'&&p[i].right.at(0)<='z')||(p[i].right.at(0)>='0' &&p[i].right.at(0)<='9'))&&((p[i].right.at(1)>='A'&&p[i].right.at(1)<='Z')))//||(p[i].right.at(1)>=' 0'&&p[i].right.at(1)<='9'))){}else{break;}}if(i==m){cout<<"该文法是3型文法!"<<endl;return 1;}else{cout<<"该文法是2型文法!"<<endl;return 0;}}elsereturn 0;}void output(GZ *p,int m)//输出终结符和非终结符{int i,j,k;int vn=0;//记录非终结字符个数int vt=0;//记录终结字符个数for(i=0;i<m;i++)//遍历整个产生式{for(j=0;j<p[i].whole.length();j++)//遍历产生式的整个字符{if(p[i].whole.at(j)>='A'&&p[i].whole.at(j)<='Z')//判断字符是否为非终结字符{for(k=0;k<=vn;k++)//遍历整个非终结符集合,判断是否有重复{if(Vn[k]==p[i].whole.at(j))break;elsecontinue;}if(k>vn)//说明没有重复{Vn[vn]=p[i].whole.at(j);vn++;}}if((p[i].whole.at(j)>='a'&&p[i].whole.at(j)<='z')||(p[i].whole.at(j)>='0'&&p[i].whole.at(j)<=' 9'))//判断字符是否为终结字符{for(k=0;k<=vt;k++)//遍历整个终结符集合,判断是否有重复{if(Vt[k]==p[i].whole.at(j))break;elsecontinue;}if(k>vt)//说明没有重复{Vt[vt]=p[i].whole.at(j);vt++;}}}}cout<<endl;cout<<" Vn={";if(vn!=1){for(i=0;i<vn-1;i++)//输出非终结字符cout<<Vn[i]<<",";cout<<Vn[i];}elsecout<<Vn[0];cout<<"}";cout<<" Vt={";if(vt!=1){for(i=0;i<vt-1;i++)//输出终结字符cout<<Vt[i]<<",";cout<<Vt[i];}elsecout<<Vt[0];cout<<"}"<<endl;cout<<" P={";if(m!=1){for(i=0;i<m-1;i++)cout<<p[i].whole<<",";cout<<p[i].whole;}elsecout<<p[0].whole;cout<<"}"<<endl;cout<<" S={S}";cout<<endl;}void main(){cout<<"\t \t *****欢迎使用文法识别程序*****\t \t"<<endl;cout<<"\t 程序功能说明:该程序根据用户输入的规则识别对应的文法类型以及生成对应的文法四元组\n";cout<<"\t 程序输入格式说明:A…-a… ,本程序Vn∈{A-Z},Vt∈{a-z}支持数字型终结符\n";cout<<endl;char ch;int k=0;int i=0,j;char ino[100];string in;//记录输入的产生式//ifstream in;//cout<<"\t请输入文法产生式的个数!\n";//cin>>m;GZ *p=new GZ[100];//cout<<"\t请再输入文法规则:\n";ifstream input("test.txt",ios::in);//for(i=0;i<m;i++)//输入产生式数组while(input.getline(ino,sizeof(ino))){in=ino;for(j=0;j<in.length();j++)//将产生式分为左式和右式{if(in[j]=='-'){p[i].left=in.substr(0,j);p[i].right=in.substr(j+1,in.length()-j-1);p[i].whole=in.substr(0,in.length());i++;}/*cout<<p[i].left<<endl;cout<<p[i].right<<endl;cout<<p[i].whole<<endl;*/}}cout<<"\n\t";wenfa3(p,i);cout<<"\tG[";cout<<k;cout<<"]={Vn,Vt,P,S}"<<endl;output(p,i);//printf("\t是否继续检测?(Y/N):");//fflush(stdin); //虽然C标准不支持这种用法,但是VC++支持//ch = getchar();//} while (ch == 'Y' || ch == 'y');cout<<"\t \t *****感谢使用本系统*****\t \t "<<endl;system("pause");getchar(); }。