基本思想:( $ 表示空,即ε)
(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;
}