求文法的FIRST集,FOLLOW集

之前学编译原理做实验做了一个求first集,follow集的程序,一直想在网上保存一下,最近才有时间,之前做时也算是花了好几天。也算是体验了一把之前学数据结构栈的操作(最后想想好像用数组可以直接实现。。。)

#include<stdio.h>
#include<string.h>
#include<ctype.h>
#include<malloc.h>

/*
	规定文法大写字母为非终结符,小写字母为终结符
	文法格式:E->E+T|a 
	用@代替ε 
*/

typedef struct{
	char *base;
	char *top;
	int stacksize;
}Stack;
Stack analyzeStack;

typedef struct{
    char formula[200]; //产生式
	char right[100][100]; //产生式右部
	int rightLen;	//产生式右部个数
	char left;	//产生式左部
	int ifnull; //是否有ε产生式
}grammarElement;
grammarElement  gramOldSet[200];//原始文法的产生式集

int gramOldSetLen=0; 

char terSymbol[200];//终结符号
char non_ter[200];//非终结符号
char allSymbol[400];//所有符号
char firstSet[100][100];//各产生式右部的FIRST集
char followSet[100][100];//各产生式左部的FOLLOW集
int M[200][200];//分析表 
int N[200][200];//进一步预测分析表 

char b[100];//待分析的字符串

void inputSource();
void precope(); 
void getFirstSet(); 
int isNon_ter(char c);
int isTerSymbol(char c);
char *addtoFirstSet(char *s,char *t); 
void getFollowSet();
void createAnalyseTable();
int analyzeString();
void initStack();
int push(char c);
int pop(); 
void destroyStack();

int main(){
	printf("请输入文法(以#结束):\n"); 
	inputSource();
	precope();
	
	printf("----------------------------------\n");
	printf("文法为:\n"); 
	for(int i=0;i<gramOldSetLen;i++){
		printf("%s\n",gramOldSet[i].formula);
		printf("left %c\n",gramOldSet[i].left);
		for(int temp=0;temp<gramOldSet[i].rightLen;temp++){
			printf("right[%d] %s\n",temp+1,gramOldSet[i].right[temp]);
		}
	}
	printf("----------------------------------\n");
	printf("终结符为:\n"); 
	for(int i=0;i<strlen(terSymbol);i++){
		printf("%c\n",terSymbol[i]);
	}
	printf("----------------------------------\n");
	printf("非终结符为:\n"); 
	for(int i=0;i<strlen(non_ter);i++){
		printf("%c\n",non_ter[i]);
	}
	printf("----------------------------------\n");
	getFirstSet();
	printf("FIRST集:\n");
	for(int i=0;i<gramOldSetLen;i++){
		printf("FIRST(%c)={%s}\n",gramOldSet[i].left,firstSet[i]);
	}
	printf("----------------------------------\n");
	getFollowSet();
	printf("FOLLOW集:\n");
	for(int i=0;i<gramOldSetLen;i++){
		printf("FOLLOW(%c)={%s}\n",gramOldSet[i].left,followSet[i]);
	}
	printf("-----------------\n");
	createAnalyseTable();
	printf("----------------------------------\n");
	printf("请输入要分析的字符串:\n");
	gets(b);
	int bLen=strlen(b);
	b[bLen]='#';
	b[bLen+1]='\0'; 
	printf("----------------------------------\n");
	int mark=analyzeString(); 
	if(mark==0){
		printf("error!\n");
	}else{
		printf("correct!\n");
	}
	return 0;
}

//输入文法 
void inputSource(){
	int i=0;
	char a[500];
	while(true){
		gets(a);
		if(a[0]=='#'){
			break;
		}
		strcpy(gramOldSet[i].formula,a);
		gramOldSetLen++; 
		i++;
	}
}

//处理文法产生式
void precope(){
	for(int i=0;i<gramOldSetLen;i++){
		int formulaLen=strlen(gramOldSet[i].formula);
		int mark1=0,mark2=-1;
		gramOldSet[i].rightLen=0;
		gramOldSet[i].ifnull=0;
		for(int j=0;j<formulaLen;j++){ 
			int flag=0;
			//扫描到->则跳过
			if(gramOldSet[i].formula[j]=='-'&&gramOldSet[i].formula[j+1]=='>'){
				gramOldSet[i].left=gramOldSet[i].formula[j-1];
				j++;
				mark1=j+1;
				mark2++;
				gramOldSet[i].rightLen++;
				flag=1; 
				continue;
			}
			//扫描到或运算符 '|' 跳过 
			if(gramOldSet[i].formula[j]=='|'){
				for(int temp=mark1;temp<j;temp++){
					gramOldSet[i].right[mark2][temp-mark1]=gramOldSet[i].formula[temp];
				}
				mark1=j+1;
				mark2++;
				gramOldSet[i].rightLen++;
				flag=2; 
				continue; 
			}
			//扫描到非终结符 
			if(isupper(gramOldSet[i].formula[j])){
				flag=3; 
				int non_terLen=strlen(non_ter); 
				for(int count=0;count<non_terLen;count++){
					if(gramOldSet[i].formula[j]==non_ter[count]){ 
						flag=4;
						break; 
					} 
				}
				if(flag==3){
					non_ter[non_terLen]=gramOldSet[i].formula[j];
					non_ter[non_terLen+1]='\0';
					int allSymbolLen=strlen(allSymbol);
					allSymbol[allSymbolLen]=gramOldSet[i].formula[j];
					allSymbol[allSymbolLen+1]='\0';
				}
			}
			//扫描到终结符 
			if(flag==0){
				if(gramOldSet[i].formula[j]=='@'){
					gramOldSet[i].ifnull=1;
					break;
				}
				flag=5; 
				int terSymbolLen=strlen(terSymbol); 
				for(int count=0;count<terSymbolLen;count++){
					if(gramOldSet[i].formula[j]==terSymbol[count]){ 
						flag=6;
						break; 
					} 
				}
				if(flag==5){
					terSymbol[terSymbolLen]=gramOldSet[i].formula[j];
					terSymbol[terSymbolLen+1]='\0'; 
					int allSymbolLen=strlen(allSymbol);
					allSymbol[allSymbolLen]=gramOldSet[i].formula[j];
					allSymbol[allSymbolLen+1]='\0';
				}
			}
		}
		for(int temp=mark1;temp<formulaLen;temp++){
			gramOldSet[i].right[mark2][temp-mark1]=gramOldSet[i].formula[temp];
		}
	}
	//将#加入终结符	
	int terSymbolLen=strlen(terSymbol);
	terSymbol[terSymbolLen]='#';
	terSymbol[terSymbolLen+1]='\0'; 
	int allSymbolLen=strlen(allSymbol);
	allSymbol[allSymbolLen]='#';
	allSymbol[allSymbolLen+1]='\0';
} 

//判断是否为终结符 
int isTerSymbol(char c){
	int terSymbolLen=strlen(terSymbol);
	for(int i=0;i<terSymbolLen;i++){
		if(terSymbol[i]==c)
			return 1;
	}
	return 0;
}

//判断是否为非终结符 
int isNon_ter(char c){
	int non_terLen=strlen(non_ter);
	for(int i=0;i<non_terLen;i++){
		if(non_ter[i]==c)
			return 1;
	}
	return 0;
}

将t中的元素添加到s,去掉共同元素 
//char *addtoFirstSet(char *s,char *t){
//	int slen=strlen(s);
//	int tlen=strlen(t);	
//	for(int i=0;i<tlen;i++){
//		int flag=0;
//		for(int j=0;j<slen;j++){
//			if(t[i]==s[j]){
//				flag=1;
//			}
//		}
//		if(flag==0){
//			s[slen]=t[i];
//			slen++;
//			s[slen]='\0';
//		}
//	}
//	return s;
//}

//求first集
void getFirstSet(){
//	int k=0; //测试使用 
	while(1){
	int judge=0,temp1=-1,mark=0; 	//判断一次循环后first集是否改变 
	for(int i=0;i<gramOldSetLen;i++){
//		printf("%d\n",++k);
		for(int j=0;j<gramOldSet[i].rightLen;j++){
			int rightContentLen=strlen(gramOldSet[i].right[j]);
			for(int m=0;m<rightContentLen;m++){
				
				if(isTerSymbol(gramOldSet[i].right[j][m])){
					mark=1;
					int firstSetLen=strlen(firstSet[i]);
					int flag=0;
					for(int n=0;n<firstSetLen;n++){
						if(firstSet[i][n]==gramOldSet[i].right[j][m]){
							flag=1;
							break;
						}
					}
					if(flag==0){
						firstSet[i][firstSetLen]=gramOldSet[i].right[j][m];
						firstSet[i][firstSetLen+1]='\0';
						judge=1; 	
					}
					break;
				}else if(gramOldSet[i].right[j][m]=='@'){
					mark=2;
					int firstSetLen=strlen(firstSet[i]);
					int flag=0;
					for(int n=0;n<firstSetLen;n++){
						if(firstSet[i][n]==gramOldSet[i].right[j][m]){
							flag=1;
							break;
						}
					}
					if(flag==0){
						firstSet[i][firstSetLen]=gramOldSet[i].right[j][m];
						firstSet[i][firstSetLen+1]='\0';
						judge=1; 	
					}

				}else{
					mark=3;
					for(int n=0;n<gramOldSetLen;n++){
						if(gramOldSet[n].left==gramOldSet[i].right[j][m]){
							int slen=strlen(firstSet[i]);
							int tlen=strlen(firstSet[n]);
							for(int p=0;p<tlen;p++){
								int flag=0;
								for(int q=0;q<slen;q++){
									if(firstSet[n][p]==firstSet[i][q]){
										flag=1;
									}
								}
								if(flag==0){
									firstSet[i][slen]=firstSet[n][p];
									slen++;
									firstSet[i][slen]='\0';
									judge=1;
								}
							}
							temp1=n;
						}
					}
				}
				if(mark==3){
					//如果当前扫描到的非终结符没有ε产生式,不会扫描到下一字符 
					if(!gramOldSet[temp1].ifnull){
						break; 
					}
				}
				
			}

		}
	}
	if(judge==0){
		break;
	}
	}
} 

void getFollowSet(){
//	int k=0;
	while(1){
		//temp1,temp2分别表示当前扫描到的非终结符和前一次扫描到的非终结符 
		int judge=0,mark=0,temp1=-1,temp2=-1; 	//judge判断一次循环后follow集是否改变 
		for(int i=0;i<gramOldSetLen;i++){
//			printf("%d\n",++k);
			if(i==0){
				int followSetLen=strlen(followSet[i]);
				int flag=0;
				for(int n=0;n<followSetLen;n++){
					if(followSet[i][n]=='#'){
						flag=1;
						break;
					}
				}
				if(flag==0){
					followSet[i][followSetLen]='#';
					followSet[i][followSetLen+1]='\0';
					judge=1; 	
				}
			}
			for(int j=0;j<gramOldSet[i].rightLen;j++){
				int rightContentLen=strlen(gramOldSet[i].right[j]);
				for(int m=rightContentLen-1;m>=0;m--){
					if(isNon_ter(gramOldSet[i].right[j][m])){
						for(int n=0;n<gramOldSetLen;n++){
							if(gramOldSet[n].left==gramOldSet[i].right[j][m]){
								temp1=n;
							}
						}
						if(m<rightContentLen-1){
							//A->αBβ是一个产生式,β为终结符把β 加至FOLLOW(B)
							if(isTerSymbol(gramOldSet[i].right[j][m+1])){		
								int followSetLen=strlen(followSet[temp1]);
								int flag=0;
								for(int t=0;t<followSetLen;t++){
									if(followSet[temp1][t]==gramOldSet[i].right[j][m+1]){
										flag=1;
										break;
									}
								}
								if(flag==0){
									followSet[temp1][followSetLen]=gramOldSet[i].right[j][m+1];
									followSet[temp1][followSetLen+1]='\0';
									judge=1; 	
								}													
							}else{
								//A->αBβ是一个产生式,β为非终结符把FIRST(β) 加至FOLLOW(B)
//								printf("temp2=%d\n",temp2); 
								int slen=strlen(firstSet[temp2]);
								int tlen=strlen(followSet[temp1]);
								for(int p=0;p<slen;p++){
									if(firstSet[temp2][p]=='@'){
										continue;
									}
									int flag=0;
									for(int q=0;q<tlen;q++){
										if(followSet[temp1][q]==firstSet[temp2][p]){
											flag=1;
										}
									}
									if(flag==0){
										followSet[temp1][tlen]=firstSet[temp2][p];
										tlen++;
										followSet[temp1][tlen]='\0';
										judge=1;
									}
								}	
							}

						}
						//若A->αB是一个产生式,或者A->αBβ是一个产生式 而ε属于FIRST(β) 则把FOLLOW(A)加至FOLLOW(B)中 
						int tflag=0;
						for(int t=m+1;t<rightContentLen;t++){
							if(isNon_ter(gramOldSet[i].right[j][t])){
								for(int n=0;n<gramOldSetLen;n++){
									if(gramOldSet[n].left==gramOldSet[i].right[j][t]){
										if(!gramOldSet[n].ifnull){
											tflag=1;
										}
									}	
								}									
							}else{
								tflag=1;
							}
						}
						if(tflag==0){
							int slen=strlen(followSet[i]);
							int tlen=strlen(followSet[temp1]);
							for(int p=0;p<slen;p++){
								int flag=0;
								for(int q=0;q<tlen;q++){
									if(followSet[temp1][q]==followSet[i][p]){
										flag=1;
									}
								}
								if(flag==0){
									followSet[temp1][tlen]=followSet[i][p];
									tlen++;
									followSet[temp1][tlen]='\0';
									judge=1;
								}
							}
						}
					}else if(gramOldSet[i].right[j][m]=='@'){
						break;
					}
					temp2=temp1;
				}

			}
		}
		if(judge==0){
			break;
		}
	}
}

//构造预测分析表
void createAnalyseTable(){
	
	for(int i=0;i<gramOldSetLen;i++){
		int terSymbolLen=strlen(terSymbol);
		int flag=0; 
		for(int j=0;j<terSymbolLen;j++){
			M[i][j]=0;
			N[i][j]=0;
			int firstSetLen=strlen(firstSet[i]);
			for(int k=0;k<firstSetLen;k++){
				if(firstSet[i][k]==terSymbol[j]){
					M[i][j]=1;
				}
				if(firstSet[i][k]=='@'){
					 flag=1;
				}	
			}
		}
		if(flag==1){
			for(int j=0;j<terSymbolLen;j++){
				int followSetLen=strlen(followSet[i]);
				for(int k=0;k<followSetLen;k++){
					if(followSet[i][k]==terSymbol[j]){
						M[i][j]=2;
					}
				}
			}
		}
	}
	
	printf("预测分析表:\n");
	printf("|\t\t|");
	int terSymbolLen=strlen(terSymbol);
	for(int i=0;i<terSymbolLen;i++){
		printf("|\t%c\t|",terSymbol[i]);
	}
	printf("\n");
	for(int i=0;i<gramOldSetLen;i++){
		for(int j=-1;j<terSymbolLen;j++){
			
			if(j==-1){
				printf("|\t%c\t|",gramOldSet[i].left);
			}else{
				if(M[i][j]==0){
					printf("|\t\t|");
				}else if(M[i][j]==1){
					for(int m=0;m<gramOldSet[i].rightLen;m++){
						if(gramOldSet[i].right[m][0]!='@'){
							int rightContentLen=strlen(gramOldSet[i].right[m]);
							for(int k=0;k<rightContentLen;k++){
								if(isTerSymbol(gramOldSet[i].right[m][k])){
									if(gramOldSet[i].right[m][k]==terSymbol[j]){
										printf("|\t%c->%s\t|",gramOldSet[i].left,gramOldSet[i].right[m]);
										N[i][j]=m;		//N[i][j]记录预测表 文法对应右部 
										break;
									}else{
										break;
									}
								}else{
									for(int n=0;n<gramOldSetLen;n++){
										if(gramOldSet[n].left==gramOldSet[i].right[m][k]){
											int flag=0;
											int firstSetLen=strlen(firstSet[n]);
											for(int p=0;p<firstSetLen;p++){
												if(firstSet[n][p]==terSymbol[j]){
													flag=1;
												}
											}
											if(flag==1){
												printf("|\t%c->%s\t|",gramOldSet[i].left,gramOldSet[i].right[m]);
												N[i][j]=m;
												break;
											}else if(!gramOldSet[i].ifnull){
												break;
											}
										}
									}
								}
							}	
						}
					}
				}else if(M[i][j]==2){
					printf("|\t%c->ε\t|",gramOldSet[i].left);					
				}
			}
		}
		printf("\n");
	}
}

//初始化栈 
void initStack(){
	analyzeStack.base=(char*)malloc(50*sizeof(char));
	analyzeStack.stacksize=50;
	analyzeStack.top=analyzeStack.base;
}

//入栈操作
int push(char c){
	if(analyzeStack.top-analyzeStack.base>analyzeStack.stacksize){
		return 0;
	}
	*analyzeStack.top++=c;
	return 1;
}

//出栈操作 
int pop(){
	if(analyzeStack.top==analyzeStack.base){
		return 0;
	}
	*--analyzeStack.top;
	return 1;
}

//遍历栈
void stackTraverse(){
	char *temp=analyzeStack.base;
	printf("|\t"); 
	while(temp!=analyzeStack.top){
		printf("%c",*temp);
		temp++;
	}
	printf("\t|"); 
} 

//销毁栈操作 
void destroyStack(){
	free(analyzeStack.base);
	analyzeStack.base=NULL;
	analyzeStack.top=NULL;
	analyzeStack.stacksize=0;
}

int analyzeString(){
	printf("错误分析表:\n");
	printf("|\t分析栈\t||\t输入串\t||\t附注\t|\n");
	initStack();
	char *stringPoint=b;//扫描字符串的指针
	push('#');
//	printf("%c\n",*(analyzeStack.top-1));
	push(gramOldSet[0].left);
	stackTraverse();
	printf("|\t%s\t|",stringPoint);
	printf("|\t\t|\n");
	int temp1=-1,temp2=-1,t=0;
	int blen=strlen(b);
	while(1){ 
		//栈顶指针和输入串指针都指向#,宣布分析成功 
		if(*(analyzeStack.top-1)=='#'&&*stringPoint=='#'){
			stackTraverse();
			printf("|\t%s\t|",stringPoint);
			printf("|\tcorrect\t|\n");
			return 1;
		} 
		//当前扫描字符不在非终结符内,则分析出错
		if(!isTerSymbol(*stringPoint)){
			stackTraverse();
			printf("|\t%s\t|",stringPoint);
			printf("|\terror\t|\n");
			return 0;
		}
		//扫描字符与当前栈顶字符匹配,则出栈,扫描下一字符 
		if(*(analyzeStack.top-1)==*stringPoint){//*(analyzeStack.top-1)表示当前栈顶元素 
			pop();
			stringPoint++;
			t++;
			stackTraverse();
			printf("|\t%s\t|",stringPoint);
			printf("|\t\t|\n");
		}else{
			for(int i=0;i<gramOldSetLen;i++){
				if(gramOldSet[i].left==*(analyzeStack.top-1)){
					temp1=i;
				}
			}
			int terSymbolLen=strlen(terSymbol);
			for(int i=0;i<terSymbolLen;i++){
				if(terSymbol[i]==*stringPoint){
					temp2=i;
				}
			}
			if(M[temp1][temp2]==0){
				stackTraverse();
				printf("|\t%s\t|",stringPoint);
				printf("|\terror\t|\n");
				return 0;
			}else if(M[temp1][temp2]==1){
				pop();
				int k=N[temp1][temp2];
				int rightContentLen=strlen(gramOldSet[temp1].right[k]);
				for(int i=rightContentLen-1;i>=0;i--){
					push(gramOldSet[temp1].right[k][i]); 
				} 
				stackTraverse();
				printf("|\t%s\t|",stringPoint);
				printf("|\t\t|\n");
			}else if(M[temp1][temp2]==2){
				pop();
				stackTraverse();
				printf("|\t%s\t|",stringPoint);
				printf("|\t\t|\n");
			} 
		} 
	} 
	destroyStack();
} 

运行输入(用@代替ε):

运行结果:

最后结果有点乱。。但也分析成功了,虽然不知道有什么用

  • 8
    点赞
  • 34
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
文法的 First Follow 是在语法分析中用于构造预测分析表的重要工具。下面是解算法的具体步骤: 1. 文法中每个非终结符的 First : 对于文法中的每个非终结符 A,解 First(A) 的方法如下: - 如果 A 是一个终结符,则 First(A) = {A}。 - 如果 A 是一个空串,则 First(A) = {ε}。 - 如果 A 是一个非终结符,则将 A 的产生式逐一分析: - 如果产生式的第一个符号是终结符,则将该终结符加入到 First(A) 中。 - 如果产生式的第一个符号是非终结符 B,则将 First(B) 中的所有符号加入到 First(A) 中。 - 如果产生式的第一个符号是空串,则将 First(B) 中的所有符号加入到 First(A) 中,直到找到一个非空串的符号,或者所有产生式都分析完毕。 2. 文法中每个非终结符的 Follow : 对于文法中的每个非终结符 A,Follow(A) 的方法如下: - 如果 A 是文法的开始符号,则将 $符号加入到 Follow(A) 中。 - 对于文法中的每个产生式 B → αAβ,将 Follow(B) 中的所有符号加入到 Follow(A) 中。 - 如果存在产生式 B → αA,或者存在产生式 B → αAβ,且 First(β) 包含空串,则将 Follow(B) 中的所有符号加入到 Follow(A) 中。 3. 构造预测分析表: 对于文法中的每个产生式 A → α,以及 A 的 First 中的每个符号 a,将产生式 A → α 加入到预测分析表 M[A,a] 中。 这就是文法中 First Follow 的基本算法。注意,如果文法中存在左递归或者其他特殊情况,解过程可能需要进行一些额外的处理。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值