【编译原理】C++实现LR(1)分析法(源码+结果+总结)

1.实验目的

根据预先由文法规则建立的LR(1)分析表对任意的输入串进行语法分析。要求输出分析过程表。

2.实验步骤

1、先读入终结符,非终结符,和所有产生式。
2、预处理:初始化;getpp()获得每个非终结符在产生式左边时的产生式编号,
记录在 string getp[]中(可以多个)。
3.获得所有的符号的first集:dfs法,从S开始DFS,遇到终结符则是递归出口,回溯时候沿路保存记录所有路径上VN的first,(遇到有左递归的,continue,左递归的产生式不用不影响求fisrt集)
4:获得项目集族:一个lr(1)项目用一个结构体记录,get_close(项目 t):bfs来完成对t的闭包。getxmjizu():bfs,并用链式前向星记录图。
5.获得分析表table[][]:遍历对于图的所有边,状态i->j有权为w的边,置action(i,w)=j;go,本质是一样的.其次扫描所有项目,对于归约项目,置归约
6总控程序:俩个栈:状态栈和符号栈,无非移进、归约,接受保存。

3.源程序如下:

#include<iostream>
#include<string>
#include<unordered_map>
#include<stack>
using namespace std;
/*
E->S
S->BB
B->aB
B->b
*/

unordered_map<string, unordered_map<string, string>>analy_map;
unordered_map<int, unordered_map<string, string>>p;

int main() {
	p[0]["S"] = "E";
	p[1]["BB"] = "S";
	p[2]["aB"] = "B";
	p[3]["b"] = "B";
	string input;
	cin >> input;
	while (input != "end") {
		int start = 0;
		string lleft;
		string rleft;
		for (int i = 0; i < input.size(); i++) {
			if (input[i] == '+') {
				lleft = input.substr(start, i - start);
				start = i;
			}
			else if (input[i] == '-') {
				rleft = input.substr(start + 1, i - start - 1);
				start = i + 1;
				i++;
			}
		}
		analy_map[lleft][rleft] = input.substr(start + 1);
		cin >> input;
	}

	cout << "请输入输入串:" << endl;
	string input_str;
	cin >> input_str;
	vector<string> symbol_st;
	vector<string> state_st;
	state_st.push_back("S0");
	symbol_st.push_back("#");
	for (int i = 0; i < input_str.size(); i++) {
		string str;
		str.push_back(input_str[i]);
		string state = state_st[state_st.size() - 1];
		string curr_str = "";
		cout << "状态栈: ";
		for (auto out : state_st) {
			cout << out << " ";
		}
		//cout << endl;
		cout << "符号栈: ";
		for (auto out : symbol_st) {
			cout << out << " ";
		}
		cout << "当前输入串: " << input_str.substr(i) << " ";
		if (analy_map[state].count(str) == 0) {
			cout << "Find Error !!!" << endl;
			cout << "current symbol&input_str is" << state << " " << input_str << endl;
			break;
		}
		else {
			curr_str = analy_map[state][str];
		}
		int lenOfcurr_str = curr_str.size();
		if (curr_str == "acc") {
			cout << "acc" << endl;
			break;
		}
		if (lenOfcurr_str == 0) {
			cout << "curr_str's size is zero,please examine your code" << endl;
			break;
		}
		else {
			if (curr_str[0] == 'r') {
				string stipulation_str = p[curr_str[1] - '0'].begin()->second;
				string other_str = p[curr_str[1] - '0'].begin()->first;
				int cnt = 0;
				while (symbol_st.size() > 0 && state_st.size() > 0 && cnt < other_str.size()) {
					symbol_st.pop_back();
					state_st.pop_back();
					cnt++;
				}
				curr_str = analy_map[state_st[state_st.size() - 1]][stipulation_str];
				state_st.push_back(curr_str);
				symbol_st.push_back(stipulation_str);
				i--;
				cout << "GOTO:" << curr_str << endl;
			}
			else {
				state_st.push_back(curr_str);
				symbol_st.push_back(str);
				cout << "ACTION:" << curr_str << endl;
			}
		}
	}
}

4.实验结果

文法如下:

S0+a->S3 S0+b->S4

S0+S->S1 S0+B->S2

S1+#->acc S2+a->S6

S2+b->S7 S2+B->S5

S3+a->S3 S3+b->S4 S3+B->S8

S4+a->r3 S4+b->r3 S5+#->r1 S6+a->S6

S6+b->S7 S6+B->S9

S7+#->r3 S8+a->r2 S8+b->r2 S9+#->r2

 

5.实验总结

1.本次实验是利用LR(1)分析法进行语法分析,通过代码实现后更加了解了LR(K)分析方法是严格的从左向右扫描,和自底向上的语法分析方法。
2.LR分析法小结:
LR(0)构造的DFA,但是由LR(0)的DFA来构造分析表往往是不可行的,也就是说很少有语言是LR(0)的。
如果LR(0)的冲突可以根据当前输入的字符来解决,则构造的分析表为SLR分析表,SLR分析表跟LR(0)的dfa是相同的。
LR(1)构造的DFA考虑当前输入的字符,所以构造的DFA中存在的冲突比较少,也就是说它接受的语言就比较多。构造分析表时,不用额外的约束,因为它在构造dfa时就已经考虑了当前的输入字符。
考虑到LR(1)的dfa包含的状态太多,而且许多状态的不同仅仅是因为预测符的不同而已。通过合并不会产生冲突的状态,可以减少dfa的状态数,这就产生了LALR分析法。所以说LALR分析法只是对LR(1)的一种简化:通过合并同心集。
分析法的分析能力比较:LR(1)>LALR>SLR(1)>LR(0)。

  • 14
    点赞
  • 84
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小树ぅ

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

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

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

打赏作者

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

抵扣说明:

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

余额充值