【编译原理】LL1文法的语法分析器(预测分析表)

输入LL(1)文法
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

#include<iostream>
#include<vector>
#include<map>
#include<cstring>
#include<stack>
using namespace std;
/*定义产生式的语法集结构*/
typedef struct {
	char formula[200];//产生式
	int length;
} grammarElement;
grammarElement  gramOldSet[200];//原始文法的产生式集
typedef struct {
	char set[100];
	int length;
	bool is;
} Set;
Set firstSET[100];//first集合
Set followSET[100];//follow集合
string M[100][100];//预测分析表
vector <char> non_ter;//非终结符
vector <char> terSymbol;//终结符
vector <char> Symbol;//产生式右侧所有符号
map<char,int> symbol;
int count;//产生式个数
void get_first(char E);
bool is_non_ter(char E) { //判断E是否为非终结符
	for(int i=0; i<non_ter.size(); i++)
		if(non_ter[i]==E)
			return true;
	return false;
}
bool is_terSymbol(char E) { //判断E是否为终结符
	for(int i=0; i<terSymbol.size(); i++)
		if(terSymbol[i]==E)
			return true;
	return false;
}
bool is_Symbol(char E) { //判断E是否已经存在
	for(int i=0; i<Symbol.size(); i++)
		if(Symbol[i]==E)
			return true;
	return false;
}
bool is_first(char E) { //判断E的first是否已经求出
	int i=symbol.at(E);
	if(firstSET[i].is) {
		return true;
	} else return false;
}
bool is_follow(char E) { //判断E的follow是否已经求出
	int i=symbol.at(E);
	if(followSET[i].is) {
		return true;
	} else return false;
}
bool is_null(char E) {//非终结符E能否推出@
	if(!firstSET[symbol.at(E)].is)
		get_first(E);
	for(int i=0; i<firstSET[symbol.at(E)].length; i++) {
		if(firstSET[symbol.at(E)].set[i]=='@')
			return true;
	}
	return false;
}
int is_have(grammarElement g,char E) { //检测产生式g的右部是否含有非终结符E
	for(int i=3; i<g.length; i++) { //遍历产生式的右部,不足:无法检测产生式右部含有多个E
		if(g.formula[i]==E)
			return i;
	}
	return 0;
}
Set add(Set S1,Set S2) { //将F1和F2中除@外的元素的并集添到F1中
	if(S1.length==0) {
		for(int i=0; i<S2.length; i++) {
			if(S2.set[i]=='@') {
				S2.set[i]=S2.set[S2.length-1];
				S2.length--;
			}
		}
		return S2;
	}

	for(int i=0; i<S2.length; i++)
		for(int j=0; j<S1.length; j++) {
			if(S2.set[i]==S1.set[j])
				break;
			if(j==S1.length-1&&S2.set[i]!='@') {
				S1.set[S1.length]=S2.set[i];
				S1.length++;
			}
		}
	return S1;
}
Set add_null(Set S1,Set S2) { //将F1和F2中的元素的并集添到F1中
	if(S1.length==0) {
		return S2;
	}
	for(int i=0; i<S2.length; i++)
		for(int j=0; j<S1.length; j++) {
			if(S2.set[i]==S1.set[j])
				break;
			if(j==S1.length-1) {
				S1.set[S1.length]=S2.set[i];
				S1.length++;
			}
		}
	return S1;
}
void get_first(char E) {
	int i=symbol.at(E);
	if(firstSET[i].is)
		return;
	firstSET[i].length=0;
	for(int j=0; j<count; j++) { //遍历所有产生式
		if(gramOldSet[j].formula[0]==E) { //查找该非终结符所在的产生式
			int x=3; //指向产生式右部字符的指针
			if(is_terSymbol(gramOldSet[j].formula[x])) { //产生式右部第一个字符为终结符
				Set n;
				n.is=true;
				n.length=1;
				n.set[0]=gramOldSet[j].formula[x];
				firstSET[i]=add_null(firstSET[i],n);//将该终结符加入first集
				//	printf("2\n");
			}
			if(is_non_ter(gramOldSet[j].formula[x])) { //产生式右部第一个字符为非终结符
				if(gramOldSet[j].formula[x]==E) { //产生式右部第一个字符等于当前字符,跳到下一条产生式
					//	printf("3\n");
					continue;
				}
				if(is_first(gramOldSet[j].formula[x])) { //当前非终结符其FIRST集是否已求出
					//	printf("5\n");
					firstSET[i]=add(firstSET[i],firstSET[symbol.at(gramOldSet[j].formula[x])]);//交集并入
				} else {
					//	printf("6\n");
					get_first(gramOldSet[j].formula[x]);//求first集
					firstSET[i]=add(firstSET[i],firstSET[symbol.at(gramOldSet[j].formula[x])]);//交集并入
				}
				while(is_null(gramOldSet[j].formula[x])) { //当前非终结符能推出@
					x++;//指针右移 
					if(x>=gramOldSet[j].length) { //当前字符是右部最后一个字符
						//	printf("7\n");
						Set n;
						n.is=true;
						n.length=1;
						n.set[0]='@';
						firstSET[i]=add_null(firstSET[i],n);//将@加入first集
						break;
					}
					if(is_terSymbol(gramOldSet[j].formula[x])){//若是终结符,加入该终结符后结束循环 
						Set n;
						n.is=true;
						n.length=1;
						n.set[0]=gramOldSet[j].formula[x];
						firstSET[i]=add_null(firstSET[i],n);//将@加入first集
						break; 						
						} 
					if(is_first(gramOldSet[j].formula[x])) { //当前非终结符其FIRST集是否已求出
						//	printf("8\n");
						firstSET[i]=add(firstSET[i],firstSET[symbol.at(gramOldSet[j].formula[x])]);//交集并入
					} else {
						//	printf("9\n");
						get_first(gramOldSet[j].formula[x]);//求first集
						firstSET[i]=add(firstSET[i],firstSET[symbol.at(gramOldSet[j].formula[x])]);//交集并入
					}
				}
			}
		}
	}
	firstSET[i].is=true;
	//printf("%c的first已求出\n",E);
}
void get_follow() {
	bool flag=true;
	for(int i=0; i<non_ter.size(); i++)//遍历所有非终结符
		followSET[i].length=0;
	while(flag) {
		flag=false;
		for(int i=0; i<non_ter.size(); i++) {//遍历所有非终结符
			char E=non_ter[i];
			if(E==gramOldSet[0].formula[0]) { //E为开始符号
				Set n;
				n.is=true;
				n.length=1;
				n.set[0]='#';
				followSET[i]=add_null(followSET[i],n);//将@加入first集
			}
			for(int j=0; j<count; j++) { //遍历所有产生式
				if(is_have(gramOldSet[j],E)!=0) {//找出右部含有E的产生式
					int x=is_have(gramOldSet[j],E);//x为产生式E的位置
					if(x>=gramOldSet[j].length-1) { //E在产生式最后
						if(is_follow(gramOldSet[j].formula[0])) { //已求出follow集合,则follow并入
							//printf("0\n");
							int before=followSET[i].length;
							followSET[i]=add(followSET[i],followSET[symbol.at(gramOldSet[j].formula[0])]);
							if(before!=followSET[i].length) {
								flag=true;//继续循环
							}
						} else {
							//printf("1\n");
							flag=true;//继续循环
						}
					} else {//E不在产生式的最后
						//printf("2\n");
						//求E后边串的first集合
						Set str;//E后的串的first集合
						str.length=0;
						while(x<gramOldSet[j].length-1) {
							x++;//产生式的指针往后移一个
							if(is_non_ter(gramOldSet[j].formula[x])) { //该字符是非终结符
								//该终结符的非空字符并入first
								if(is_first(gramOldSet[j].formula[x])) { //当前非终结符其FIRST集已求出
									str=add(str,firstSET[symbol.at(gramOldSet[j].formula[x])]);//其first集合的非@元素交集并入
								} else {
									get_first(gramOldSet[j].formula[x]);//求first集
									str=add(str,firstSET[symbol.at(gramOldSet[j].formula[x])]);//交集并入
								}
								if(is_null(gramOldSet[j].formula[x])) {//该非终结符能推出@
									if(x==gramOldSet[j].length-1) {//所有字符都能推出@
										Set n;
										n.is=true;
										n.length=1;
										n.set[0]='@';
										str=add_null(str,n);//将@加入first集
									}
									continue;//继续循环
								} else {	//该非终结符不能推出@
									break;//停止循环
								}
							} else { //E后边的字符是终结符
								Set n;
								n.is=true;
								n.length=1;
								n.set[0]=gramOldSet[j].formula[x];
								str=add_null(str,n);//将该终结符加入first集
								break;
							}
						}
//						for(int x=0; x<str.length; x++)
//							cout<<" "<<str.set[x]<<endl;
						int before=followSET[i].length;
						//把str的first集合中的非@元素加到E的follow中
						followSET[i]=add(followSET[i],str);
						for(int z=0; z<str.length; z++) {
							if(str.set[z]=='@') { //str中含有@
								followSET[i]=add(followSET[i],followSET[symbol.at(gramOldSet[j].formula[0])]);
							}
						}
						if(before!=followSET[i].length) {
							flag=true;
						}
					}
				}
			}
			followSET[i].is=true;
		}

	}
}
void table() {
	for(int i=0; i<count; i++) { //遍历所有的产生式
		int x=3;
		//cout<<gramOldSet[i].formula<<endl;
		//产生式右边串的first集合
		Set st;
		st.length=0;
		while(x<gramOldSet[i].length) {
			if(is_non_ter(gramOldSet[i].formula[x])) { //该字符是非终结符
				//该终结符的非空字符并入first
				if(is_first(gramOldSet[i].formula[x])) { //当前非终结符其FIRST集已求出
					st=add(st,firstSET[symbol.at(gramOldSet[i].formula[x])]);//其first集合的非@元素交集并入
				} else {
					printf("error!\n");
				}
				if(is_null(gramOldSet[i].formula[x])) {//该非终结符能推出@
					if(x==gramOldSet[i].length-1) {//所有字符都能推出@
						Set n;
						n.is=true;
						n.length=1;
						n.set[0]='@';
						st=add_null(st,n);//将@加入first集
					}
					x++;
					continue;//继续循环
				} else {	//该非终结符不能推出@
					break;//停止循环
				}
			} else { //字符是终结符
				Set n;
				n.is=true;
				n.length=1;
				n.set[0]=gramOldSet[i].formula[x];
				st=add_null(st,n);//将该终结符加入first集
				break;
			}
			x++;
		}

		for(int j=0; j<st.length; j++) {
			if(st.set[j]=='@') {
				for(int z=0; z<followSET[symbol.at(gramOldSet[i].formula[0])].length; z++) {
					int x=symbol.at(gramOldSet[i].formula[0]);
					int y=symbol.at(followSET[symbol.at(gramOldSet[i].formula[0])].set[z]);
					M[x][y]=gramOldSet[i].formula;
				}
			} else {
				int x=symbol.at(gramOldSet[i].formula[0]);
				int y=symbol.at(st.set[j]);
//				printf("\n~~~~~~~~~~~~~~~~~~~~~~~~~~\n");
//				for(int c=0; c<terSymbol.size(); c++)
//					cout<<terSymbol[c]<<": "<<M[x][symbol.at(terSymbol[c])]<<"{"<<x<<" "<<symbol.at(terSymbol[c])<<endl;
				M[x][y]=gramOldSet[i].formula;
			}
		}

	}

}
void init() {
	non_ter.clear();
	terSymbol.clear();
	Symbol.clear();
	symbol.clear();
	for(int z=0; z<100; z++) {
		memset(firstSET[z].set, 0, sizeof firstSET[z].set);
		memset(followSET[z].set, 0, sizeof followSET[z].set);
		firstSET[z].is=false;
		followSET[z].is=false;
		for(int y=0; y<100; y++)
			M[z][y]="error";
	}
}
int main() {
	init();
	printf("输入产生式格式为 X->YYY.. ,@表示空,以end结束:\n");
	string temp_pro="";
	cin>>temp_pro;
	int i=0;
	count=0;//产生式的个数
	while(temp_pro!="end") {
		int j;
		for(j=0; j<temp_pro.length(); j++) {
			gramOldSet[i].formula[j] = temp_pro[j];
			if(j>=3&&!is_Symbol(gramOldSet[i].formula[j]))
				Symbol.push_back(gramOldSet[i].formula[j]);
		}
		//gramOldSet[i].formula[j] = '\0';
		gramOldSet[i].length=temp_pro.length();
		if(!is_non_ter(gramOldSet[i].formula[0])) {
			non_ter.push_back(gramOldSet[i].formula[0]);//非终结符
			symbol.insert(pair<char,int>(gramOldSet[i].formula[0],non_ter.size()-1));
		}
		count++;
		i++;
		temp_pro="";
		cin>>temp_pro;
	}
	for(int j=0; j<Symbol.size(); j++) {
		if(!is_non_ter(Symbol[j])) {
			terSymbol.push_back(Symbol[j]);//终结符
			symbol.insert(pair<char,int>(Symbol[j],99-(terSymbol.size()-1)));
		}
	}
	terSymbol.push_back('#');//把#写入终结符
	symbol.insert(pair<char,int>('#',99-(terSymbol.size()-1)));
	cout<<"产生式的个数:"<<count<<endl;
	cout<<"非终结符:"<<endl;
	for(int j=0; j<non_ter.size(); j++)
		cout<<non_ter[j]<<" ";
	cout<<"\n终结符:"<<endl;
	for(int j=0; j<terSymbol.size(); j++)
		cout<<terSymbol[j]<<" ";
	//求first集合
	cout<<"\nfirst集:";
	for(i=0; i<non_ter.size(); i++) { //遍历所有的非终结符
		get_first(non_ter[i]);
		int j=0;
		cout<<"\n"<<non_ter[i]<<":";
		while(j<firstSET[i].length) {
			printf("%c ",firstSET[i].set[j]);
			j++;
		}
	}
	//求follow集
	cout<<"\nfollow集:";
	get_follow();
	for(i=0; i<non_ter.size(); i++) {
		int j=0;
		cout<<"\n"<<non_ter[i]<<":";
		while(j<followSET[i].length) {
			printf("%c ",followSET[i].set[j]);
			j++;
		}
	}
	//构造分析表
	table();
	printf("\n~~~~~~~预测分析表~~~~~~~~~\n");
	for(int j=0; j<terSymbol.size(); j++)
		cout<<"      "<<terSymbol[j]; 
	for(i=0; i<non_ter.size(); i++) {
		printf("\n%c   ",non_ter[i]);		
		//	cout<<terSymbol[j]<<": "<<M[symbol.at(non_ter[i])][symbol.at(terSymbol[j])]<<endl;
		for(int j=0; j<terSymbol.size(); j++)
			cout<<" "<<M[symbol.at(non_ter[i])][symbol.at(terSymbol[j])];
	}
	printf("\n~~~~~~~~~~~~~~~~~~~~~~~~~~\n");
	//程序检测
	cout<<"请输入一段语句进行判断:"<<endl;
	char in[100];
	int p=0;//指向输入串的指针
	scanf("%s",in);
	int c=0;//输入串的长度
	while(in[c]!='\0')
		c++;
	//cout<<"输入的字符串长度为 "<<c<<endl;
	int FLAG=true;
	stack <char> S;
	char TOP;//分析栈栈顶元素 
	S.push('#');
	S.push(gramOldSet[0].formula[0]);//把开始符压入栈 
	while(FLAG) {
		TOP=S.top();//栈顶出栈 
		S.pop();
		if(!is_non_ter(*(in+p))) {//违法字符报错 
			if(!is_terSymbol(*(in+p))) {
				printf("error!\n");
				cout<<"不是已知的非终结符或终结符"<<endl;
				break;
			}
		}
	//	cout<<TOP<<" "<<*(in+p)<<endl;
		if(TOP=='#'){
			if(*(in+p)=='#'){
				printf("\n成功规约\n");
				break;
			}
			else{
				printf("error!\n");
				break;
			}
		} 
		else if(TOP==*(in+p)){//如果终结符匹配,则读进下一个输入串 
			p++;
			TOP=S.top();
		}
		else if(M[symbol.at(TOP)][symbol.at(*(in+p))]!="error") {//存在归约式 
			string temp=M[symbol.at(TOP)][symbol.at(*(in+p))];
			cout<<"产生式逆序入栈:                                "<<temp<<endl;
			for(int z=temp.length()-1; z>2; z--) {
				if(temp[z]!='@'){ //不为空,推入分析栈 			
					S.push(temp[z]);
				}
				else{
					break;//否则不推入 
				}
			}
		} else {//不存在归约式,报错 
			printf("error!!\n");
			printf("不存在归约式\n");
			break;
		}				
		cout<<"剩余输入串:                      "<<in+p<<endl;
		stack <char> SS=S;
		printf("栈内剩余元素:        ");
		while(!SS.empty()){
			printf("%c",SS.top());
			SS.pop();
		}
		printf("\n");
	}
}

 
评论 7 您还未登录,请先 登录 后发表或查看评论
©️2022 CSDN 皮肤主题:编程工作室 设计师:CSDN官方博客 返回首页

打赏作者

啊,我醉了

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值