编译原理SELECT()集合的求法

合集下载

编译原理习题

编译原理习题

编译原理习题⼀、填空题:1-01.编译程序的⼯作过程⼀般可以划分为词法分析,语法分析,语义分析,之间代码⽣成,代码优化等⼏个基本阶段,同时还会伴有表格处理和出错处理.1-02.若源程序是⽤⾼级语⾔编写的,⽬标程序是机器语⾔程序或汇编程序,则其翻译程序称为编译程序.1-03.编译⽅式与解释⽅式的根本区别在于是否⽣成⽬标代码.1-04.翻译程序是这样⼀种程序,它能够将⽤甲语⾔书写的程序转换成与其等价的⽤⼄语⾔书写的程序. 1-05.对编译程序⽽⾔,输⼊数据是源程序,输出结果是⽬标程序.1-06.如果编译程序⽣成的⽬标程序是机器代码程序,则源程序的执⾏分为两⼤阶段:编译阶段和运⾏阶段.如果编译程序⽣成的⽬标程序是汇编语⾔程序,则源程序的执⾏分为三个阶段:编译阶段,汇编阶段和运⾏阶段.1-07.若源程序是⽤⾼级语⾔编写的,⽬标程序是机器语⾔程序或汇编程序,则其翻译程序称为编译程序。

1-08.⼀个典型的编译程序中,不仅包括词法分析、语法分析、中间代码⽣成、代码优化、⽬标代码⽣成等五个部分,还应包括表格处理和出错处理。

其中,词法分析器⽤于识别单词。

1-09.编译⽅式与解释⽅式的根本区别为是否⽣成⽬标代码。

2-01.所谓最右推导是指:任何⼀步αβ都是对α中最右⾮终结符进⾏替换的。

2-02.⼀个上下⽂⽆关⽂法所含四个组成部分是⼀组终结符号、⼀组⾮终结符号、⼀个开始符号、⼀组产⽣式。

2-03.产⽣式是⽤于定义语法成分的⼀种书写规则。

2-04.设G[S]是给定⽂法,则由⽂法G所定义的语⾔L(G)可描述为:L(G)={x│S x,x∈V T*}。

2-05.设G是⼀个给定的⽂法,S是⽂法的开始符号,如果S x(其中x∈V*),则称x是⽂法的⼀个句型。

2-06.设G是⼀个给定的⽂法,S是⽂法的开始符号,如果S x(其中x∈V T*),则称x是⽂法的⼀个句⼦。

3-01.扫描器的任务是从源程序中识别出⼀个个单词符号。

4-01.语法分析最常⽤的两类⽅法是⾃上⽽下和⾃下⽽上分析法。

编译原理_习题

编译原理_习题

第2章 习题及解答: 习题及解答:
试求下述文法G(Z)所定义的语言: 试求下述文法G(Z)所定义的语言: G(Z)所定义的语言 Z,BG(Z): Z->b|bB ,B->bZ + 【解】 L(G)={ x | Z => x, x∈VT* } 文法所定 义的语言
推导运算法: ⒈ 推导运算法: ∵ Z => b Z => bB => bbZ => bbb Z => bB => bbZ => bbbB => bbbbZ => bbbbb
第2章
习题及解答: 习题及解答:
试构造下述语言L的文法: 试构造下述语言L的文法: L={ ambn |m≥0,n≥1}; 【解】 • 分析: 1. 此语言仅有一种句型: 分析:
a mb n ; 2. ambn 中包含有两个短语:am 和 bn

S(句子 句子),A( 设:S(句子),A(短语1), B(短语2) • 于是: ※产生式形式: 于是: 产生式形式: 【解1】 G1(S): S -> AB |ε A -> Aa |ε B -> Bb | b 或 G2(S): S -> AB |ε A -> aA |ε B -> bB | b
G(S): S -> a A S b ① | B d ② A -> c S ③ | ε ④ B -> b B ⑤ | d ⑥ 三对选择集合两两不相交! ∵ 三对选择集合两两不相交! ∴ G(S)是 LL(1)文法! G(S)是 LL(1)文法! 文法 LL(1)分析表 分析表: (2) LL(1)分析表: a S b c d #
b
②-
a 无用 状态

编译原理课程设计_LL(1)文法的判定

编译原理课程设计_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();}}}。

编译原理课后习题答案(清华大学_张素琴)复习例题

编译原理课后习题答案(清华大学_张素琴)复习例题

编译原理复习例题(有些内容没有覆盖,比如优化、SLR(1)、LR(1)、LALR(1)等。

但要求至少要按照作业题的范围复习。

)一选择题1.编译的各阶段工作都涉及。

[A]词法分析[B]表格管理 [C]语法分析 [D]语义分析2.型文法也称为正规文法。

[A] 0 [B] 1 [C] 2 [D] 33.文法不是LL(1)的。

[A]递归 [B]右递归 [C]2型 [D]含有公共左因子的4.文法E→E+E|E*E|i的句子i*i+i*i有棵不同的语法树。

[A] 1 [B] 3 [C] 5 [D] 75.文法 S→aaS|abc 定义的语言是。

[A]{a2k bc|k>0} [B]{a k bc|k>0}[C]{a2k-1bc|k>0} [D]{a k a k bc|k>0}6.若B为非终结符,则 A→α.Bβ为。

[A]移进项目 [B]归约项目 [C]接受项目 [D]待约项目7.同心集合并可能会产生新的冲突。

[A]二义 [B]移进/移进 [C]移进/归约 [D]归约/归约8.代码优化时所依据的是。

[A]语法规则 [B]词法规则[C]等价变换规则 [D]语义规则9.表达式a-(-b)*c的逆波兰表示(@为单目减)为。

[A]a-b@c* [B]ab@c*- [C]ab@- [D]ab@c-*10.过程的DISPLAY表是用于存取过程的。

[A]非局部变量[B]嵌套层次 [C]返回地址 [D]入口地址二填空题1.词法分析阶段的任务式从左到右扫描字符流,从而逐个识别一个个的单词。

2.对于文法G[E]:E→T|E+T T→F|T*F F→P^F|P P→(E)|i,句型T+T*F+i的句柄是。

3.最右推导的逆过程称为规范归约,也称为最左归约。

4.符号表的每一项是由名字栏和两个栏目组成。

在目标代码生成阶段,符号表是的依据。

三判断题(认为正确的填“T”,错的填“F”)【】1.同心集的合并有可能产生“归约/归约”冲突。

select函数详细用法解析

select函数详细用法解析

select函数详细⽤法解析1.表头⽂件#include#include#include2.函数原型int select(int n,fd_set * readfds,fd_set * writefds,fd_set * exceptfds,struct timeval * timeout);3.函数说明select()⽤来等待⽂件描述词状态的改变。

参数n代表最⼤的⽂件描述词加1,参数readfds、writefds和exceptfds 称为描述词组,是⽤来回传该描述词的读,写或例外的状况。

底下的宏提供了处理这三种描述词组的⽅式:FD_CLR(inr fd,fd_set* set);⽤来清除描述词组set中相关fd的位FD_ISSET(int fd,fd_set *set);⽤来测试描述词组set中相关fd的位是否为真FD_SET(int fd,fd_set*set);⽤来设置描述词组set中相关fd的位FD_ZERO(fd_set *set);⽤来清除描述词组set的全部位4.结构体说明先说明两个结构体:1) struct fd_set可以理解为⼀个集合,这个集合中存放的是⽂件描述符(filedescriptor),即⽂件句柄,这可以是我们所说的普通意义的⽂件,当然Unix下任何设备、管道、FIFO等都是⽂件形式,全部包括在内,所以毫⽆疑问⼀个socket就是⼀个⽂件,socket句柄就是⼀个⽂件描述符。

fd_set集合可以通过⼀些宏由⼈为来操作,⽐如清空集合FD_ZERO(fd_set *);将⼀个给定的⽂件描述符加⼊集合之中FD_SET(int ,fd_set*);将⼀个给定的⽂件描述符从集合中删除FD_CLR(int,fd_set*);检查集合中指定的⽂件描述符是否可以读写FD_ISSET(int ,fd_set* )。

⼀会⼉举例说明。

2) struct timeval是⼀个⼤家常⽤的结构,⽤来代表时间值,有两个成员,⼀个是秒数,另⼀个是毫秒数。

18秋《编译原理》作业1234满分答案

18秋《编译原理》作业1234满分答案
D. Ml和M2状态数和有向弧条数相等
10.通常一个编译程序中,不仅包含词法分析,语法分析,中间代码生成,代码优化,目标代码生成等五个部分,还应包括_____。
A.模拟执行器
B.解释器
C.符号表处理和出错处理
D.符号执行器
11.一个编译程序中,不仅包含词法分析,_____,中间代码生成,代码优化,目标代码生成等五个部分,还应包括符号表处理和出错处理。
A. L(G[N])={bi│i≥0}
B. L(G[N])={b2i│i≥0}
C. L(G[N])={b2i+1│i≥0}
D. L(G[N])={b2i+1│i≥1}
9.正规式MI和M2等价是指_____。
A. MI和M2的状态数相等
B. Ml和M2的有向弧条数相等
C. M1和M2所识别的语言集相等
A.提高程序的执行效率
B.使程序的结构更加清晰
C.利用有限的机器内存并提高机器的执行效率
D.利用有限的机器内存但降低了机器的执行效率
二、判断题(每题4分,共10道小题,总分值40分)
1.
2.所有的编译程序都需要生成中间代码。
3.一个数组是由同一类型数据所组成的某种n维矩形结构。
4.决定目标代码的因素主要取决于具体的机器结构、指令格式、字长及寄存器的个数和种类,并与指令的语义和所用操作系统、存储管理等都密切相关。
5.一个上下文无关文法G包括四个组成部分,它们是:一组非终结符号,一组终结符号,一个开始符号,以及一组_____。
A.句子
B.句型
C.单词
D.产生式
6._____是一种典型的解释型语言。
A. BASIC
B. C
C. FORTRAN

LL(1)文法分析.

LL(1)文法分析.

构造预测分析表
在确定的自顶向下分析方法中,又有递归子程序法和预测分 析方法,我们采用的是预测分析的方法。一个预测分析器 由三部分组成: (1)预测分析程序 (2)先进后出栈 (3)预测分析表 其中,只有预测分析表与文法有关。分析表可用矩阵M 表示。M(A,a)中的下标A表示非终结符,a为终结符 或括号,矩阵元素M(A,a)中的内容是一条关于A的产 生式,表明当用非终结符A往下推导时,面临输入符A时, 所应采取的候选产生式,元素内容无产生式时,则表明出 错。为便于辨认,我们令M数组为 Analyze数组。
算法介绍
1、在对输入序列进行LL(1)文法分析之前,首先要对文法进行判 别,看文法是不是LL(1)文法。这个文法应该满足无二义性,无 左递归,无公因子。具体的判别过程是,求出能推出ε的非终结 符,求出FIRST集,求出FOLLOW集,求出SELLECT集,看相 同左部的产生式的SELLECT集是否有交集,有就不是LL(1)文 法。 2、如果输入文法不是LL(1)文法,可以进行转换,转换一般有两 种方法:提取左公因子法和消除左递归法。 3、构造预测分析表,设二维矩阵M。
4、预测分析。
人员分工
• 负责MFC界面制作,程序总控,各个非终结 符能否推出ε的计算,判断是否LL(1),以及人员 分工。 • 消除左递归的实现 • 提取公因子的实现 • 求FIRST集 • 求FOLLOW集 • 求SELLECT集 • 构造预测分析表,分析输入的句子
程序流程
程序开始 InitAndConvertPt(); //读入文法、消除左递归、提取公因子 InitArray(); //初始化N[ ]数组 VnRefresh(Pt); //构造非终结符集 VtRefresh(Pt);//构造终结符集 Create_N_Table(); //判断哪些非终结符可以推出空,存入N[ ]

编译原理-期末复习

编译原理-期末复习

编译原理-期末复习编译原理⼀、单选题1、将编译程序分为若⼲个“遍”是为了()。

BA.提⾼程序的执⾏效率B.使程序的结构更加清晰C.利⽤有限的机器内存并提⾼机器的执⾏效率D.利⽤有限的机器内存但降低了机器的执⾏效率2、构造编译程序应掌握()。

DA.源程序B.⽬标语⾔C.编译⽅法D.以上三项都是3、变量应当()。

CA.持有左值B.持有右值C.既持有左值⼜持有右值D.既不持有左值也不持有右值4、编译程序绝⼤多数时间花在()上。

DA.出错处理B.词法分析C.⽬标代码⽣成D.管理表格5、()不可能是⽬标代码。

DA.汇编指令代码B.可重定位指令代码C.绝对指令代码D.中间代码6、编译程序是对()。

DA.汇编程序的翻译B.⾼级语⾔程序的解释执⾏C.机器语⾔的执⾏D.⾼级语⾔的翻译7、正规式M1和M2等价是指()。

CA.M1和M2的状态数相等B.M1和M2的有象弧条数相等C.M1和M2所识别的语⾔集相等D.M1和M2状态数和有象弧条数相等8、如果⽂法G是⽆⼆义的,则它的任何句⼦()。

AA.最左推导和最右推导对应的语法树必定相同。

B.最左推导和最右推导对应的语法树可能相同。

C.最左推导和最右推导必定相同。

D.可能存在两个不同的最左推导,但它们对应的语法树相同。

9、⽂法G:S→S+T|TT→T*P|PP→(S)|i句型P+T+i的短语有()BA.i,P+TB. P,P+T,i,P+T +iB.P+T + i D. P,P+T,i10、产⽣正规语⾔的⽂法为()。

DA.0型B.1型C.2型D.3型11、⽂法G:S→b|?|(T)T→T?S|S则FIRSTVT(T)=() CA.{b,?,(}B.{b,?,)}C.{b,?,(,?}D.{b,?,),?}12、给定⽂法:A→bA | cc,下⾯的符号串中,为该⽂法句⼦的是()。

A①cc ②bcbc ③bcbcc ④bccbcc ⑤bbbcc可选项有:A.①B.①③④⑤C.①④D.①④⑤13、采⽤⾃上⽽下分析,必须()。

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

first(C)={first(A)-{}} ∪first(D) ∪first(b)={a,b, c} first(D)={a} ∪{c}={a,c}
一个文法符号串的first集合计算方法:
如果文法符号串V*, =X1X2…Xn,
*
1、当X1ε,则first()=first(X1)
2、当对任何j(1≤j≤i-1,2 ≤i ≤n),εfirst(Xj)
Select( SaAS ) ∩Select(Sb ) ={a}∩{ b }= Select(A bA) ∩Select(A ε)={b}∩{a,b} 因此,该文法不是LL(1)文法,因而也就不可能 用确定的自顶向下分析。
• 当需要选用自顶向下分析技术时,首先必须判 定所给的文法是否是LL(1)文法。
自顶向下语法分析要解决的关键问题
假定要被代换的最左非终结符号是B,且 有n条规则:B→A1|A2|…|An,那么如何 确定用哪个右部去替代B?
自顶向下语法分析方法
• 自顶向下分析法分确定性和不确定性两 种。 • 自顶向下的确定性分析法对文法有一定 的限制,但实现简单直观,便于手工或 自动构造; • 自顶向下的不确定性分析法是带有回溯 的分析方法,效率低,代价高,极少使 用。
一、确定的自顶向下分析思想
1、方法:从开始符号出发,不断替换非终结符, 根据当前的单词符号就可以唯一选定要替换的产生 式。 例1:文法G(S):S→pA S→qB A→cAd A→a 输入串 W=pccadd 自顶向下的推导过程为:
相应的语法树: S S
SpA pcAd pccAdd pccadd
例:设文法G[S]为:
S aAS | b A bA |ε 判别是否是LL(1)文法。
解:Select(S aAS)=first(aAS)={a}
Select ( S b ) ={b}
Select ( A bA ) ={b}
Select ( A ε) =(first(ε)-{ε})∪follow(A)={a,b}
例2:文法G(S)为: S →Ap S → Bq A →a∣cA
B→b∣dB
该文法的特点:
(1)产生式的右部不全是由终结符号开始;
(2 )如果两个产生式有相同的左部,则它们的右 部由不同的终结符或非终结符开始。
(3)无空产生式。 ccap
如何根据输入串的第1个符号来确定产生式呢?
例2:文法G(S)为: S →Ap S → Bq A →a∣cA
*
A a | cA
B b | dB
则:FIRST(Ap)=?; FIRST(Bq)=?
针对产生式规则的右部产生开始符号集合
2、开始符号集合的定义: 设G=(VT,VN, P ,S )是上下文无关文法, 开始符号集合为First()={ a | *aβ,a∈VT, 、 β∈V*} 规则右部的开始符号集包括所有终结符 a,使得规则右部经
语法分析是编译程序的核心部分:在词法分析 的基础上,识别单词符号序列是否是给定文法 的正确句子(程序)。
确定
自顶向下分析
常用方法
不确定
算符优先分析
自底向上分析
LR分析
自顶向下语法分析方法
• 自顶向下分析法就是从文法的开始符号 出发,试图推导出与输入的单词串完全 匹配的句子。 • 如果能够推导出,则该输入串是给定文 法的句子; • 如果不能推导出,则该输入串不是给定 文法的句子。
第5章 自顶向下语法分析方法
一、确定的自顶向下分析思想
二、LL(1)文法的判别 三、某些非LL(1)文法到LL(1)文法等价变换 四、不确定的自顶向下分析思想 五、确定的自顶向下分析方法
自顶向下语法分析要解决的关键问题
假定要被代换的最左非终结符号是B,且 有n条规则:B→A1|A2|…|An,那么如何 确定用哪个右部去替代B?
例3:文法G[S] :
S aA | d
A bAS|ε
若输入W=abd,则推导过程为:
例3:文法G[S] :
S aA | d
A bAS|ε
若输入W=abd,则推导过程为: S aA abAS abS abd 语法树为:
S S a A b A S d a A S A
a) 若xVT,则first(x)={x}
b) 若xVN,且有xa…,aVT,则afirst(x)
c) 若xVN,x ,则first(x)
d) 若xVN,y1,y2,…,yi都VN,产生式 * xy1y2…yn,当y1,y2,…yi-1都 时(1≤i≤n), 则first(y1)-{}, first(y2)-{},…, first(yi-1)-{}, first(yi)都包含在first(x)中。
B→b∣dB
当输入W=ccap推导: 自顶向下的推导过程为:
例2:文法G(S)为: S →Ap S → Bq A →a∣cA
B→b∣dB
当输入W=ccap推导: 自顶向下的推导过程为: S Ap cAp ccAp ccap 语法树为: S A P A P A c A S S A S P
针对产生式规则的右部产生开始符号集合
2、开始符号集合的定义:
设G=(VT,VN, P ,S )是上下文无关文法,
开始符号集合为First()={ a | *aβ,a∈VT, 、 β∈V*} 规则右部的开始符号集包括所有终结符 a,使得规则右部经
过若干推导后得到的字符串以a为起始。
若 ε,则规定∈First() 。 例3:上例中文法是: SAp|Bq
* e) 当上式中所有yi (1≤i≤n),
则first(x)=first(y1) ∪first(y2) ∪…∪first(yn) ∪ {}
按上面的规则可得上例文法中每个文法符号的 first集合如下: S AB | bC first(S)=
first(A)= first(B)= first(C)= first(D)= A ε | b B ε | aD C AD | b D aS | c
给定输入串,就可以根据产生式规则的选择集合确定唯 一的产生式进行推导。
• LL(1)的含义:从左L向右扫描输入串,分析过 程中采用最左L推导,只需向右看1个符号就可 确定如何推导(选择哪个产生式进行推导)。
例5:上例3文法: SaA|d AbAS|ε 证明该文法为LL(1)文法。
例5:上例3文法: SaA|d AbAS|ε 证明该文法为LL(1)文法。
A
P

c
c
A
A a
c
c
A
例2:文法G(S)为: S →Ap S → Bq A →a∣cA
B→b∣dB
该文法的特点:
(1)产生式的右部不全是由终结符号开始;
(2 )如果两个产生式有相同的左部,则它们的右 部由不同的终结符或非终结符开始。
(3)无空产生式。 ccap
如何根据输入串的第1个符号来确定产生式呢?
Follow(A)是所有句型中出现在紧接A之后的终结 符或“#”。
例4:在例2中文法G[S]为:S Ap | Bq A a | cA
B b | dB
求Follow集。
解:Follow(S)={?}
Follow(A)={?} Follow(B)={?}
换句话说:
Follow(A)是所有句型中出现在紧接A之后的终结 符或“#”。 例4:在例2中文法G[S]为:S Ap | Bq A a | cA
过若干推导后得到的字符串以a为起始。
若 ε,则规定∈First() 。 例3:上例中文法是: SAp|Bq
*
A a |IRST(Ap)={a,c}; FIRST(Bq)={b,d}
• 如何根据输入串的第1个符号来确定产生式呢? • 根据当前输入符号属于哪个产生式右部的开始 符号集合而决定选择相应产生式进行推导。
给定上下文无关文法的产生式A,AVN,
* V*,若ε,则Select(A)=First(), * 若ε,则Select(A)=(First()-{ε})∪Follow(A)
给定输入串,根据产生式规则的选择集合选择产生 式进行推导。
5、LL(1)文法的定义:
一个上下文无关文法是LL(1)文法的充分必要条 件是对每个非终结符A的两个不同产生式: A,Aβ满足Select(A)∩Select(Aβ)=,其 中、β不同时推出 • 只有对满足LL(1)文法的句子,才能进行确定的自 顶向下分析:
B b | dB
求Follow集。
解:Follow(S)={#}
Follow(A)={p} Follow(B)={q}
自上而下语法分析要解决的关键问题
假定要被代换的最左非终结符号是B,且 有n条规则:B→A1|A2|…|An,那么如何 确定用哪个右部去替代B? 根据规则的选择集合来确定。
4、选择集合的定义
则first()=(first(X1)-{ε}) ∪(first(X2)-{ε}) ∪…∪(first(Xi-1)-{ε}) ∪first(Xi)
3、当first(Xj)都含有ε时(1 ≤ j ≤ n),则 first()=first(X1) ∪first(X2) ∪…∪first(Xj) ∪{ε}
按上面的规则可得上例文法中每个文法符号的 first集合如下: S AB | bC first(S)={first(A)-{}} ∪{first(B)-{}} A ε | b B ε | aD ∪{} ∪{b}={a,b, }
first(A)={b} ∪{}={b, } first(B)={} ∪{a}={a, } C AD | b D aS | c
SAa * aA ε
不难看出:Select(Sa A)=First(aA)={a}
Select (Sd)= First(d)={d} Select (AbAS)={b} Select (Aε)=(first(ε)-{ε} )∪follow(A)={a,d,#} Select (S aA) ∩Select(Sd)= { a}∩{d}= Select(AbAS) ∩ Select(Aε) ={b}∩{a,d,#}={ } 所以上述文法是LL(1)文法。 SaA abAS abAd S aA abAS abAaA 所以Follow(A)={a,d,#}
相关文档
最新文档