- 根據某一文法編制調試 LL ( 1 )分析程序,以便對任意輸入的符號串進行分析。
- 構造預測分析表,並利用分析表和一個棧來實現對上述程序設計語言的分析程序。
- 分析法的功能是利用LL(1)控制程序根據顯示棧頂內容、向前看符號以及LL(1)分析表,對輸入符號串自上而下的分析過程。
【設計思想】
(1)定義部分:定義常量、變量、數據結構。
(2)初始化:設立LL(1)分析表、初始化變量空間(包括堆棧、結構體、數組、臨時變量等);
(3)控制部分:從鍵盤輸入一個表達式符號串;
(4)利用LL(1)分析算法進行表達式處理:根據LL(1)分析表對表達式符號串進行堆棧(或其他)操作,輸出分析結果,如果遇到錯誤則顯示錯誤信息。
流程圖
源程序
#include<iostream>
#include<string>
#include<map>
#include<vector>
#include<stack>
#include<set>
#include<cstring>
using namespace std;
map<char, int>getnum;
char text[100]; //獲得對應字符
vector<string>proce;
int table[100][100]; //預測分析表
int num = 0; int numvt = 0; //numvt是終結符集合,0是'#',numvt表空字
string first[100];
string follow[200];
void readin()
{
memset(table, -1, sizeof(table));
getnum['#'] = 0;
text[0] = '#';
cout << "請輸入所有的終結符:" << endl;
char x;
do
{
cin >> x;
getnum[x] = ++num;
text[num] = x;
} while (cin.peek() != '\n');
numvt = ++num;
getnum['@'] = numvt; //kong zi
text[num] = ('@');
cout << "請輸入所有非終結符:" << endl;
do
{
cin >> x;
getnum[x] = ++num;
text[num] = x;
} while (cin.peek() != '\n');
cout << "輸入產生式集合(空字用'@'表示),以'end'結束:" << endl;
string pro;
while (cin >> pro&&pro != "end")
{
string ss;
ss += pro[0];
for (int i = 3; i<pro.size(); i++)
{
if (pro[i] == '|')
{
proce.push_back(ss);
ss.clear(); ss += pro[0];
}
else
{
ss += pro[i];
}
}
proce.push_back(ss);
}
}
void jiaoji(string &a, string b) //a=a or b 取a,b交集賦值給a
{
set<char>se;
for (int i = 0; i<a.size(); i++)
se.insert(a[i]);
for (int i = 0; i<b.size(); i++)
se.insert(b[i]);
string ans;
set<char>::iterator it;
for (it = se.begin(); it != se.end(); it++)
ans += *it;
a = ans;
}
string get_f(int vn, int & has_0) //dfs:vn能推出的不含空字的vt集合,並且判斷vn能否推出空字
{
if (vn == numvt)has_0 = 1;
if (vn<numvt)return first[vn];
string ans;
for (int i = 0; i<proce.size(); i++)
{
if (getnum[proce[i][0]] == vn)
ans += get_f(getnum[proce[i][1]], has_0);
}
return ans;
}
void getfirst()
{
for (int i = 1; i <= numvt; i++) //終結符,first集是其本身。
{
first[i] += ('0' + i);
}
for (int j = 0; j<proce.size(); j++) //掃描所有產生式
{
int k = 0; int has_0 = 0; //k掃瞄該產生式
do{
has_0 = 0;
k++;
if (k == proce[j].size()) //推到最后一個了,則附加空字
{
first[getnum[proce[j][0]]] += ('0' + numvt);
break;
} //合並之
jiaoji(first[getnum[proce[j][0]]], get_f(getnum[proce[j][k]], has_0));
} while (has_0); //到無法推出空字為止
}
}
void print_first()
{
cout << "first集:" << endl;
for (int i = 1; i <= num; i++)
{
cout << "first [" << text[i] << "]: ";
for (int j = 0; j<first[i].size(); j++)
cout << text[first[i][j] - '0'] << " ";
cout << endl;
}
cout << endl;
}
void getfollow()
{
jiaoji(follow[getnum[proce[0][0]]], "0"); //先添加'#';
for (int j = 0; j<proce.size(); j++) //掃所有產生式
{
for (int jj = 1; jj<proce[j].size(); jj++) //每個非終結符的follow集
{
if (getnum[proce[j][jj]] <= numvt)continue; //vt無follow集
int k = jj; int has_0;
do
{
has_0 = 0;
k++;
if (k == proce[j].size()) //都能推出空字,follow集=產生式左邊的vn,
{
jiaoji(follow[getnum[proce[j][jj]]], follow[getnum[proce[j][0]]]);
break;
}
jiaoji(follow[getnum[proce[j][jj]]], get_f(getnum[proce[j][k]], has_0));
} while (has_0);
}
}
}
void gettable() //得預測分析表
{
for (int i = 0; i<proce.size(); i++) //掃所有產生式
{
if (proce[i][1] == '@') //直接推出空字的,特判下(follow集=產生式左邊的vn中元素填)
{
string flw = follow[getnum[proce[i][0]]];
for (int k = 0; k<flw.size(); k++)
{
table[getnum[proce[i][0]]][flw[k] - '0'] = i;
}
}
string temps = first[getnum[proce[i][1]]];
for (int j = 0; j<temps.size(); j++) //考察first集
{
if (temps[j] != ('0' + numvt))
{
table[getnum[proce[i][0]]][temps[j] - '0'] = i;
}
else //有空字的,考察follw集
{
string flw = follow[getnum[proce[i][1]]];
for (int k = 0; k<flw.size(); k++)
{
table[getnum[proce[i][0]]][flw[k] - '0'] = i;
}
}
}
}
}
string get_proce(int i) //由對應下標獲得對應產生式。
{
if (i<0)return " "; //無該產生式
string ans;
ans += proce[i][0];
ans += "->";
//ans+=(proce[i][0]+"->"); 注意這樣不行!思之即可。
for (int j = 1; j<proce[i].size(); j++)
ans += proce[i][j];
return ans;
}
void print_table()
{
cout << "預測分析表:" << endl;
for (int i = 0; i<numvt; i++)
cout << '\t' << text[i];
cout << endl;
for (int i = numvt + 1; i <= num; i++)
{
cout << text[i];
for (int j = 0; j<numvt; j++)
{
cout << '\t' << get_proce(table[i][j]);
}
cout << endl;
}
cout << endl;
}
void print_follow()
{
cout << "follow集:" << endl;
for (int i = numvt + 1; i <= num; i++)
{
cout << "follow [" << text[i] << "]: ";
for (int j = 0; j<follow[i].size(); j++)
cout << text[follow[i][j] - '0'] << " ";
cout << endl;
}
cout << endl;
}
string word;
bool analyze() //總控,分析字word的合法性,若合法,輸出所有產生式。
{
stack<char>sta;
sta.push('#'); sta.push(proce[0][0]);
int i = 0;
while (!sta.empty())
{
int cur = sta.top();
sta.pop();
if (cur == word[i]) //是終結符,推進
{
i++;
}
else if (cur == '#') //成功,結束
{
return 1;
}
else if (table[getnum[cur]][getnum[word[i]]] != -1) //查表
{
int k = table[getnum[cur]][getnum[word[i]]];
cout << proce[k][0] << "->";
for (int j = 1; j<proce[k].size(); j++)
cout << proce[k][j];
cout << endl;
for (int j = proce[k].size() - 1; j>0; j--) //逆序入棧
{
if (proce[k][j] != '@')
sta.push(proce[k][j]);
}
}
else //失敗!
{
return 0;
}
}
return 1;
}
int main()
{
readin();
getfirst();
getfollow();
getfollow();
gettable();
print_first();
print_follow();
print_table();
cout << "請輸入字:" << endl;
cin >> word;
if (analyze())
cout << "succeed!該字有效,所用產生式如上。" << endl;
else cout << "error!" << endl;
return 0;
}
結果

