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)。