编译原理:LL1(1)文法的语法分析器(通过文法构造分析表)

基本思想:( $ 表示空,即ε)
(1)first集的算法思想
如果产生式右部第一个字符为终结符,则将其计入左部first集
如果产生式右部第一个字符为非终结符执行以下步骤
求该非终结符的first集
将该非终结符的非 $ first集计入左部的first集
若存在 $,则将指向产生式的指针右移
若不存在 $ ,则停止遍历该产生式,进入下一个产生式
若已经到达产生式的最右部的非终结符,则将$加入左部的first集
处理数组中重复的first集中的终结符

(2)follow集的算法思想
对于文法G中每个非终结符A构造FOLLOW(A)的办法是,连续使用下面的规则,直到每个FOLLOW不在增大为止.
对于文法的开始符号S,置#于FOLLOW(S)中;
若A->aBb是一个产生式,则把FIRST(b)加至FOLLOW(B)中;
若A->aB是一个产生式,或A->aBb是一个产生式而b=>$ (即$∈FIRST(b))则把FOLLOW(A)加至FOLLOW(B)中

(3)生成预测分析表的算法思想
构造分析表M的算法是:
对文法G的每个产生式A->a执行第二步和第三步;
对每个终结符a∈FIRST(a),把A->a加至M[A,a]中;
若$∈FIRST(a),则把任何b∈FOLLOW(A)把A->a加至M[A,b]中;
把所有无定义的M[A,a]标上出错标志.

参考了大佬的代码,代码贴在这里,注释尽快补上:
(使用了一些c++11的特性)

#include 

using namespace std;

const int maxn = 1005;

struct node {
	char left;
	string right;
};

map <char , int>mp , mp1; //记录非终结符和非终结符 
vector <node> input;
vector <char> non_c , ter_c , sta , vs;
set <char> first[maxn];
set <char> follow[maxn];
int f[maxn] , f1[maxn];
int tableMap[maxn][maxn];
int n;

void getFirst(char t) {
	if(!f[mp[t]]) return; 
	for(int i = 0 ; i < n ; i++) {
		if(input[i].left == t) {
			if(!mp.count(input[i].right[0])) {
				first[mp[t]].insert(input[i].right[0]);
			}
			else {	
				int num = 0;
				for(int j = 0 ; j < input[i].right.length() ; j++) {
					if(!mp.count(input[i].right[j])) {
						first[mp[t]].insert(input[i].right[j]);
						break;
					}
					getFirst(input[i].right[j]);
					bool flag = 0;
					for(auto it = first[mp[input[i].right[j]]].begin() ; it != first[mp[input[i].right[j]]].end() ; it++) {
						if(*it == '$')flag = 1;
						else first[mp[t]].insert(*it);
					}
					if(!flag) break;
					else {
						num += flag; flag = 0;
					}
				}
				//cout << "num = " << num << "\n";
				if(num == input[i].right.length()) {
					first[mp[t]].insert('$');
				}
			}
		}
	}
	f[mp[t]] = 0;
}

void getFollow(char tmp) {
	if(!f1[mp[tmp]])return;
	for(int i = 0 ; i < n ; i++) {
		int index = -1;
		for(int j = 0 ; j < input[i].right.length() ; j++) {
			if(input[i].right[j] == tmp) {
					index = j; break;
			}
		}
		if(index > -1 && index < input[i].right.length() - 1) {
			char nxt = input[i].right[index + 1];
			if(!mp.count(nxt)) {
				follow[mp[tmp]].insert(nxt);
			}
			else {
				int flag = 0 , j;
				for(j = index + 1; j < input[i].right.length() ; j++) {
					nxt = input[i].right[j];
					if(!mp.count(nxt)) {
						follow[mp[tmp]].insert(nxt);
						break;
					}
					for(auto it = first[mp[nxt]].begin() ; it != first[mp[nxt]].end() ; it++) {
						if(*it == '$')flag = 1;
						else follow[mp[tmp]].insert(*it);
					}
					if(!flag)break;
				}
				if(j == input[i].right.length() && flag) {
					getFollow(input[i].left);
					for(auto it = follow[mp[input[i].left]].begin() ; it != follow[mp[input[i].left]].end() ; it++) {
						follow[mp[tmp]].insert(*it);
					}		
				}
			}
		}
		else if(index == input[i].right.length() - 1 && input[i].left != input[i].right[index]) {
			getFollow(input[i].left);
			for(auto it = follow[mp[input[i].left]].begin() ; it != follow[mp[input[i].left]].end() ; it++) {
				follow[mp[tmp]].insert(*it);
			}
		}
	}
	f1[mp[tmp]] = 0;
}

void getTable() {
	for(int i = 0 ; i < n ; i++) {
		char tmp = input[i].right[0];
		if(!mp.count(tmp)) {
			if(tmp != '$')tableMap[mp[input[i].left]][mp1[tmp]] = i;
			else {
				for(auto it = follow[mp[input[i].left]].begin() ; it != follow[mp[input[i].left]].end() ; it++) {
					tableMap[mp[input[i].left]][mp1[*it]] = i;
				}
			}
		}
		else {
			int j;
			bool flag = 0;
			for(j = 0; j < input[i].right.length() ; j++) {
				tmp = input[i].right[j];
				if(mp1.count(tmp)) {
					tableMap[mp[input[i].left]][mp1[tmp]] = i;
					break;
				}
				for(auto it = first[mp[tmp]].begin() ; it != first[mp[tmp]].end() ; it++) {
					if(*it == '$')flag = 1;
					else tableMap[mp[input[i].left]][mp1[*it]] = i;
				}
				if(!flag)break;
			}
			if(j == input[i].right.length() && flag) {
				for(auto it = follow[mp[input[i].left]].begin() ; it != follow[mp[input[i].left]].end() ; it++) {
					tableMap[mp[input[i].left]][mp1[*it]] = i;
				}		
			}
		} 
	}
}

void analyExp(string s) {
	for(int i = s.length() - 1 ; i >= 0 ; i--) {
		vs.push_back(s[i]);
	}
	sta.push_back('#');
	sta.push_back(non_c[0]);
	while(vs.size() > 0) {
		string outs , outs1; 
		//输出分析栈
		 for(int i = 0 ; i < sta.size() ; i++) {
		 	outs += sta[i];
		 }
		  for(int i = vs.size() - 1 ; i >= 0 ; i--) {
		 	outs1 += vs[i];
		 }
		 cout << setw(16) << outs << setw(16)<<outs1;
		 
		 
		 char c1 = sta[sta.size() - 1] , c2 = vs[vs.size() - 1];
		 if(c1 == c2) {
		 	if(c1 == '#') {
		 		cout << setw(16)<<"Accepted!\n";
		 		break;	
			}
			else {
				sta.pop_back(); vs.pop_back();
				cout << setw(16)<<c1 << "\n";
			}
		 } 
		 else if(tableMap[mp[c1]][mp1[c2]] != -1) {
		 	int t = tableMap[mp[c1]][mp1[c2]];
		 	sta.pop_back();
		 	if(input[t].right != "$") {
		 		for(int i = input[t].right.length() - 1 ; i >= 0 ; i--)sta.push_back(input[t].right[i]);	
			}
			cout << setw(16) <<input[t].right << "\n";
		 } 
		 else {
		 	cout <<setw(16) <<"error\n";
		 	break;
		 }
	}
}

void showFirst() {
	cout << "first集合\n";
	for(int i = 0 ; i < non_c.size() ; i++) {
		cout << non_c[i] << ":";
		for(auto it = first[mp[non_c[i]]].begin() ; it != first[mp[non_c[i]]].end() ; it++) {
			cout << *it << " ";
		}
		cout << "\n";
	}	
}

void showFollow() {
	cout << "follow集合\n";
	for(int i = 0 ; i < non_c.size() ; i++) {
		cout << non_c[i] << ":";
		for(auto it = follow[mp[non_c[i]]].begin() ; it != follow[mp[non_c[i]]].end() ; it++) {
			cout << *it << " ";
		}
		cout << "\n";
	}
}

void showTable() {
	for(int i = 0 ; i < ter_c.size() ; i++) {
		cout <<setw(6)<< ter_c[i] ;
	}
	cout << "\n";
	for(int i = 0 ; i < non_c.size() ; i++) {
		cout << non_c[i] << ":";
		for(int j = 0 ; j < ter_c.size() ; j++) {
			if(tableMap[i][j] == -1) {
				cout << setw(6)<< "error";
			}
			else cout << setw(6)<< input[tableMap[i][j]].right;
		}
		cout << "\n";
	}
}


int main() {
	cout << "请输入文法的行数\n";
	ios::sync_with_stdio(0);
	cin >> n;
	int flag = 0;
	cin.get();
	int tag;
	memset(tableMap , -1 ,sizeof(tableMap));
	for(int i = 0 ; i < n ; i++) {
		string s;
		node t;
		getline(cin , s);
		t.left = s[0];
		if(!mp.count(s[0])) {
			mp[s[0]] = non_c.size();
			f[non_c.size()] = f1[non_c.size()] = 1;
			non_c.push_back(s[0]);
		}
		tag = 0;
		for(int j = 1 ; j < s.length() ; j++) {
			if(!tag && s[j] == '-')tag = 1;
			else if(tag == 1 && s[j] == '>')tag = 2;
			else if(tag == 2) {
				if(!isupper(s[j]) && !mp1.count(s[j])){
					mp1[s[j]] = ter_c.size();
					if(s[j] != '$')ter_c.push_back(s[j]);
				}
				t.right += s[j]; 
			}
			else {
				cout << "读入出错,程序自动关闭,请重新启动\n";
				return 0;
			}
		}
		input.push_back(t); 
	}
	ter_c.push_back('#');
	mp1['#'] = ter_c.size() - 1;
	for(int i = 0 ; i < non_c.size() ; i++) {
		getFirst(non_c[i]);
	}
	showFirst();
	for(int i = 0 ; i < non_c.size() ; i++) {
		if(i == 0)follow[i].insert('#');
		getFollow(non_c[i]);
	}	
	showFollow();
	getTable();
	showTable();
	cout << "请输入要分析的字符串\n";
	string s;
	getline(cin , s);
	cout << setw(16) << "分析栈" << setw(16) << "剩余输入串" << setw(16) << "推导式" << endl;
	analyExp(s);
	return 0;
}

运行结果:
编译原理:LL1(1)文法的语法分析器(通过文法构造分析表)_第1张图片
编译原理:LL1(1)文法的语法分析器(通过文法构造分析表)_第2张图片

你可能感兴趣的:(编译原理)