基於算符優先分析法的語法分析器(編譯原理之自底向上分析技術)

先用代碼佔個坑,等期末結束了再補詳細解釋。。。

/*
	2020-06-20
	by 軟件工程172 202171139
	TDM-GCC 4.9.2 64-bit
	-std=C++11	
*/
#include <bits/stdc++.h>
#define pcc pair<char, char>
#define fi first
#define sc second
#define mp(a, b) make_pair(a, b)

using namespace std;

string S;
map<char, vector<char> > fvt, lvt;      //firstVT & LastVt
int table[130][130];      //1 2 3 => < = > 
vector<char> K, T;   //非終結符 終結符 
map<char, bool> ist;  //是否爲終結符
map<char, vector<string> > rule;  //文法規則 
map<string, char> inc;       //規約 

void init_() {
	int n;
	cout << "請輸入文法規則數:";
	cin >> n;
	cout << "請輸入開始狀態:";
	cin >> S;
	cout << "請輸入文法規則:\n";
	string line;
	vector<string> x;
	vector<char> y;
	for (int i = 0; i <= n; ++i) {
		if(i) cin >> line;
		else line = "X->#" + S + "#";
		ist[line[0]] = true;
		for (int j = 3; j < line.length(); ++j) if (line[j] != '|') ist[line[j]];
		for (int j = 3; j < line.length(); ++j) {
			for (int k = 1; j + k <= line.length(); ++k)
			if (j + k == line.length() || line[j + k] == '|') {
				rule[line[0]].push_back(line.substr(j, k));
				x.push_back(line.substr(j, k));
				y.push_back(line[0]);
				j = j + k;
				break;
			}
		}
	}
	for (auto & e : ist) {
		e.sc = !e.sc;
		if (e.sc) T.push_back(e.fi);
		else K.push_back(e.fi);
	}
	for(int i = 0; i < x.size(); i++) {
		for(char & c : x[i]) if(!ist[c]) c = 'N';
		inc[x[i]] = ist[y[i]] ? y[i] : 'N';
	}
}

void getFirstVT() {
	bool F[130][130]; 
	memset(F, 0, sizeof(F));
	stack<pcc> st;     //序偶(P, a) 
	for (auto r : rule) for (auto s : r.sc) {
		if (ist[s[0]]) {
			F[r.fi][s[0]] = true;
			st.push(mp(r.fi, s[0]));
		} else if (ist[s[1]]) {
			F[r.fi][s[1]] = true;
			st.push(mp(r.fi, s[1]));
		}
	}
	while (!st.empty()) {
		pcc p = st.top();
		st.pop();
		for (auto r : rule) for (auto s : r.sc) {
			if (s[0] == p.fi && !F[r.fi][p.sc]) {
				F[r.fi][p.sc] = true;
				st.push(mp(r.fi, p.sc));
			}
		}
	}
	for (char k : K) for (char t : T) {
		if(F[k][t]) fvt[k].push_back(t);
	}
}

void printFirstVT() {
	cout << "-------------------------------\n";
	cout << "FirstVT集爲:\n"; 
	for (auto e : fvt) {
		cout << e.fi << ':';
		for (char c : e.sc) cout << ' ' << c;
		cout << '\n';	
	}
}

void getLastVT() {
	bool F[130][130];
	memset(F, 0, sizeof(F));
	stack<pcc> st;     //序偶(P, a) 
	for (auto r : rule) for (auto s : r.sc) {
		reverse(s.begin(), s.end());
		if (ist[s[0]]) {
			F[r.fi][s[0]] = true;
			st.push(mp(r.fi, s[0]));
		} else if (ist[s[1]]) {
			F[r.fi][s[1]] = true;
			st.push(mp(r.fi, s[1]));
		}
	}
	while (!st.empty()) {
		pcc p = st.top();
		st.pop();
		for (auto r : rule) for (auto s : r.sc) {
			reverse(s.begin(), s.end());
			if (s[0] == p.fi && !F[r.fi][p.sc]) {
				F[r.fi][p.sc] = true;
				st.push(mp(r.fi, p.sc));
			}
		}
	}
	for (char k : K) for (char t : T) {
		if (F[k][t]) lvt[k].push_back(t);
	}
}

void printLastVT() {
	cout << "-------------------------------\n";
	cout << "LastVT集爲:\n"; 
	for (auto e : lvt) {
		cout << e.fi << ':';
		for (char c : e.sc) cout << ' ' << c;
		cout << '\n';	
	}
}

void getTable() {
	for (auto r : rule) for (auto s : r.sc) {
		for (int i = 1; i < s.length(); ++i) {
			if (i > 1 && ist[s[i - 2]] && !ist[s[i - 1]] && ist[s[i]]) {
				table[s[i - 2]][s[i]] = 2;	
			}
			if (ist[s[i - 1]] && !ist[s[i]]) {
				for (char c : fvt[s[i]]) table[s[i - 1]][c] = 1;	
			}
			if (!ist[s[i - 1]] && ist[s[i]]) {
				for (char c : lvt[s[i - 1]]) table[c][s[i]] = 3;	
			}
		}
	}
}

#define putc(c) cout << c << "   "
void printTable() {
	cout << "-------------------------------\n";
	cout << "算符優先分析表爲:\n"; 
	putc(' ');
	for (char c : T) putc(c);
	cout << '\n';
	for (char i : T)	{
		putc(i);
		for (char j : T) {
			if(i == j && i == '#') putc(' ');
			else if (table[i][j] == 1) putc('<');
			else if (table[i][j] == 2) putc('=');
			else if (table[i][j] == 3) putc('>');
			else putc(' ');
		}
		cout << '\n';
	}
}

void putstr(string & s) {
	cout << s;
	for(int i = 0; i < 10 - s.length(); ++i) {
		putchar(' ');
	}
}

void findl(string & s, int & a, int & len) {         //尋找最左質短語 
	vector<char> v;
	vector<int> pos;
	for (int i = 0; i < s.length(); ++i) if (ist[s[i]]) {
		v.push_back(s[i]);
		pos.push_back(i);
	}
	for(int i = 1; i < v.size(); i++) {
		if(table[v[i - 1]][v[i]] == 3) continue;
		int j = i;
		while(j + 1 < v.size() && table[v[j]][v[j + 1]] == 2) ++j;
		if(j == v.size() - 1 || table[v[j]][v[j + 1]] == 3) {
			a = pos[i];
			while(a - 1 >= 0 && !ist[s[a - 1]]) --a;
			len = pos[j] - a + 1;
			while(a + len < s.length() && !ist[s[a + len]]) ++len;
			return;
		}
	}
}

void run() {
	cout << "-------------------------------\n";
	cout << "請輸入以#結尾的符號串:\n";
	string st = "#", que;
	cin >> que;
	cout << "棧        輸入部分  操作      最左素短語\n"; 
	while (que.length() >= 1) {
		if(st == "#N" && que == "#") {
			putstr(st), putstr(que);
			cout << "結束\n"; 
			cout << "輸入串符合文法定義!\n"; 
			return;
		}
		putstr(st);
		putstr(que);
		int p = st.length() - 1;
		while(!ist[st[p]]) --p;
		int x = table[st[p]][que[0]];
		if(que[0] == '#' || x == 3) {
			cout << "規約      ";
			int a, len;
			findl(st, a, len);
			cout << st.substr(a, len) << '\n';
			if(inc[st.substr(a, len)] == 0) break;	
			else {
				st[a] = inc[st.substr(a, len)];
				st.replace(a + 1, len - 1, "");
				continue;
			}
		}
		if(x == 1 || !ist[st[st.length() - 1]]) {
			cout << "移進\n";
			st += que.substr(0, 1);
			que.erase(0, 1);
		}	
	}
	cout << "輸入串不符合文法定義!\n";
}

int main () {
//	freopen("in.txt", "r", stdin);
	init_();
	getFirstVT();
	getLastVT();
	getTable();
	cout << "1.FirstVt\n2.LastVT\n3.算符優先分析表\n4.檢測輸入串\n5.退出\n"; 
	while(true) {
		cout << "請輸入您所需要執行的功能:";
		int op;
		cin >> op;
		if(op == 0) break;
		if (op == 1) printFirstVT();
		else if (op == 2) printLastVT();
		else if (op == 3) printTable();
		else run();	
	}
	return 0;	
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章