【實驗目的】
通過完成預測分析法的語法分析程序,了解預測分析法和遞歸子程序法的區別和聯系。使了解語法分析的功能,掌握語法分析程序設計的原理和構造方法,訓練掌握開發應用程序的基本方法。
【實驗內容】
u 根據某一文法編制調試 LL ( 1 )分析程序,以便對任意輸入的符號串進行分析。
u 構造預測分析表,並利用分析表和一個棧來實現對上述程序設計語言的分析程序。
u 分析法的功能是利用LL(1)控制程序根據顯示棧頂內容、向前看符號以及LL(1)分析表,對輸入符號串自上而下的分析過程。
【設計思想】
(1)定義部分:定義常量、變量、數據結構。
(2)初始化:設立LL(1)分析表、初始化變量空間(包括堆棧、結構體、數組、臨時變量等);
(3)控制部分:從鍵盤輸入一個表達式符號串;
(4)利用LL(1)分析算法進行表達式處理:根據LL(1)分析表對表達式符號串進行堆棧(或其他)操作,輸出分析結果,如果遇到錯誤則顯示錯誤信息。
【實驗要求】
(1)編程時注意編程風格:空行的使用、注釋的使用、縮進的使用等。
(2)如果遇到錯誤的表達式,應輸出錯誤提示信息。
(3)畫出流程圖
實驗截圖:
代碼:
1 Base.sh 2 #ifndef _BASE_H_ 3 #define _BASE_H_ 4 #include <iostream> 5 #include <iomanip> 6 #include <string> 7 #include <vector> 8 #include <set> 9 10 #define maxsize 100 11 12 using namespace std; 13 14 struct node { // 產生式的數據結構 15 char left; 16 string right; 17 }; 18 19 class Base { 20 protected: 21 int T; 22 node production[maxsize]; // 產生式集 23 24 set<char> firstSet[maxsize]; // First集 25 set<char> followSet[maxsize]; // Follow集 26 vector<char> terminalNoEmpty; // 去$(空)的終結符 27 vector<char> terminal; // 終結符 28 vector<char> nonterminal; // 非終結符 29 30 bool isNonterminal(char c); 31 int getIndex(char target); // 獲得target在終結符集合中的下標 32 int getNIndex(char target); // 獲得target在非終結符集合中的下標 33 void getFirst(char target); // 得到First(target) 34 void getFollow(char target); // 得到Follow(target) 35 36 public: 37 Base() {}; 38 39 void inputAndSolve(); // 處理和求出First和Follow集 40 void displayFirstAndFollow(); // 輸出First和Follow集 41 42 }; 43 #endif 44 45 Base.cpp 46 #include "Base.h" 47 48 bool Base::isNonterminal(char c) { // 判斷c是否為非終結符 49 if (c >= 'A' && c <= 'Z') 50 return true; 51 return false; 52 } 53 int Base::getNIndex(char target) { // 獲得target在非終結符集合中的下標 54 for (int i = 0; i<nonterminal.size(); i++) { 55 if (target == nonterminal[i]) 56 return i; 57 } 58 return -1; 59 } 60 int Base::getIndex(char target) { // 獲得target在終結符集合中的下標 61 for (int i = 0; i<terminalNoEmpty.size(); i++) { 62 if (target == terminalNoEmpty[i]) 63 return i; 64 } 65 return -1; 66 } 67 68 void Base::getFirst(char target) { // 求FIRST(target) 69 int countEmpty = 0; // 用於最后判斷是否有空 70 int isEmpty = 0; 71 int targetIndex = getNIndex(target); 72 for (int i = 0; i < T; i++) { 73 if (production[i].left == target) { // 匹配產生式左部 74 if (!isNonterminal(production[i].right[0])) { // 對於終結符,直接加入first 75 firstSet[targetIndex].insert(production[i].right[0]); 76 } 77 else { 78 for (int j = 0; j < production[i].right.length(); j++) { // X->Y1..Yj..Yk是一個產生式 79 char Yj = production[i].right[j]; 80 if (!isNonterminal(Yj)) { // Yj是終結符(不能產生空),FIRST(Yj)=Yj加入FIRST(X),不能繼續迭代,結束 81 firstSet[targetIndex].insert(Yj); 82 break; 83 } 84 getFirst(Yj);// Yj是非終結符,遞歸 先求出FIRST(Yj) 85 86 set<char>::iterator it; 87 int YjIndex = getNIndex(Yj); 88 for (it = firstSet[YjIndex].begin(); it != firstSet[YjIndex].end(); it++) { 89 if (*it == '$') // 遍歷查看FIRST(Yj)中是否含有'$'(能產生空) 90 isEmpty = 1; 91 else 92 firstSet[targetIndex].insert(*it);//將FIRST(Yj)中的非$就加入FIRST(X) 93 } 94 if (isEmpty == 0) // Yj不能產生空, 迭代結束 95 break; 96 else { // Yj能產生空 97 countEmpty += isEmpty; 98 isEmpty = 0; 99 } 100 } 101 if (countEmpty == production[i].right.length())//所有右部first(Y)都有$(空),將$加入FIRST(X)中 102 firstSet[getNIndex(target)].insert('$'); 103 } 104 } 105 } 106 } 107 108 void Base::getFollow(char target) { // 求FOLLOW(target) 109 int targetIndex = getNIndex(target); 110 for (int i = 0; i<T; i++) { 111 int index = -1; 112 int len = production[i].right.length(); 113 for (int j = 0; j < len; j++) { // 尋找target在產生式中的位置index 114 if (production[i].right[j] == target) { 115 index = j; 116 break; 117 } 118 } 119 if (index != -1 && index < len - 1) { // 找到target在產生式中的位置index 120 // 存在A->αBβ, 將FIRST(β)中除了空$之外的所有放入FOLLOW(B)中 121 // 這里B對應target, β對應nxt 122 char nxt = production[i].right[index + 1]; 123 if (!isNonterminal(nxt)) { // β是終結符 FIRST(β)=β,直接插入β 124 followSet[targetIndex].insert(nxt); 125 } 126 else { // β是非終結符 127 int hasEmpty = 0; 128 set<char>::iterator it; 129 int nxtIndex = getNIndex(nxt); // 插入FIRST(β)中除了空$之外的所有 130 for (it = firstSet[nxtIndex].begin(); it != firstSet[nxtIndex].end(); it++) { 131 if (*it == '$') 132 hasEmpty = 1; 133 else 134 followSet[targetIndex].insert(*it); 135 } 136 137 if (hasEmpty && production[i].left != target) { // 存在A->αBβ且FIRST(β)->$ 138 // FOLLOW(A)放在FOLLOW(B)中 139 getFollow(production[i].left); 140 set<char>::iterator it; 141 char tmp = production[i].left; 142 int tmpIndex = getNIndex(tmp); 143 for (it = followSet[tmpIndex].begin(); it != followSet[tmpIndex].end(); it++) 144 followSet[targetIndex].insert(*it); 145 } 146 } 147 } 148 else if (index != -1 && index == len - 1 && target != production[i].left) { // 存在A->αB ,FOLLOW(A)放在FOLLOW(B)中 149 getFollow(production[i].left); 150 set<char>::iterator it; 151 char tmp = production[i].left; 152 int tmpIndex = getNIndex(tmp); 153 for (it = followSet[tmpIndex].begin(); it != followSet[tmpIndex].end(); it++) 154 followSet[targetIndex].insert(*it); 155 } 156 } 157 } 158 159 void Base::inputAndSolve() { // 處理和求出First和Follow集 160 string s; 161 cout << "輸入的產生式的個數:" << endl; 162 cin >> T; 163 cout << "輸入的產生式:" << endl; 164 for (int index = 0; index < T; index++) { // 處理每一個產生式 165 cin >> s; 166 string temp = ""; // 存儲去掉空格的產生式 167 for (int i = 0; i < s.length(); i++) { // 去掉產生式中的' ' 168 if (s[i] != ' ') 169 temp += s[i]; 170 } 171 production[index].left = temp[0]; // 產生式的左部 172 for (int i = 3; i<temp.length(); i++) // 產生式的右部 173 production[index].right += temp[i]; 174 175 for (int i = 0; i < temp.length(); i++) { // 存儲所有終結符和非終結符 176 if (i == 1 || i == 2) continue; // 跳過產生符號-> 177 if (isNonterminal(temp[i])) { //插入一個非終結符 178 int flag = 0; 179 for (int j = 0; j < nonterminal.size(); j++) { 180 if (nonterminal[j] == temp[i]) { 181 flag = 1; 182 break; 183 } 184 } 185 if (!flag) nonterminal.push_back(temp[i]); 186 } 187 else { //插入一個終結符 188 int flag = 0; 189 for (int j = 0; j < terminal.size(); j++) { 190 if (terminal[j] == temp[i]) { 191 flag = 1; 192 break; 193 } 194 } 195 if (!flag) terminal.push_back(temp[i]); 196 } 197 } 198 } 199 terminal.push_back('#'); 200 201 for (int i = 0; i < terminal.size(); i++) { // 存儲沒有$符號的終結符 202 if (terminal[i] != '$') 203 terminalNoEmpty.push_back(terminal[i]); 204 } 205 206 // 獲得first集 207 for (int i = 0; i < nonterminal.size(); i++) { 208 getFirst(nonterminal[i]); 209 } 210 211 // 獲得follow集 212 for (int i = 0; i < nonterminal.size(); i++) { 213 if (i == 0) // 開始符號, 先加入結束符號 214 followSet[0].insert('#'); 215 getFollow(nonterminal[i]); 216 } 217 } 218 219 void Base::displayFirstAndFollow() { // 輸出First和Follow集 220 for (int aa = 0; aa < 10; aa++) 221 { 222 cout << "*********"; 223 } 224 cout << "\n歡迎使用周博 20173599 LL1語法分析器(以下是First集合和Follow集合)" << endl; 225 cout << "FIRST集合" << endl; 226 for (int i = 0; i<nonterminal.size(); i++) { 227 cout << nonterminal[i] << ": "; 228 set<char>::iterator it; 229 for (it = firstSet[i].begin(); it != firstSet[i].end(); it++) 230 cout << *it << " "; 231 cout << endl; 232 } 233 cout << endl; 234 235 cout << "FOLLOW集合" << endl; 236 for (int i = 0; i<nonterminal.size(); i++) { 237 cout << nonterminal[i] << ": "; 238 set<char>::iterator it; 239 for (it = followSet[i].begin(); it != followSet[i].end(); it++) 240 cout << *it << " "; 241 cout << endl; 242 } 243 cout << endl; 244 } 245 LL1.h 246 247 #include"Base.h" 248 249 #define maxsize 100 250 #ifndef _LL1_H_ 251 #define _LL1_H_ 252 using namespace std; 253 254 class LL1 : public Base { 255 private: 256 vector<char> analyStack; // 分析棧 257 vector<char> leftExpr; // 剩余輸入串 258 int tableMap[100][100]; // 預測表 259 260 public: 261 LL1(); 262 263 void getTable(); // 生成預測表 264 void analyExpression(string s); // 分析輸入語句s 265 void printPredictTable(); // 輸出預測表 266 void getResult(); // 綜合處理 267 }; 268 #endif 269 LL1.cpp 270 #include"LL1.h" 271 272 LL1::LL1() { 273 memset(tableMap, -1, sizeof(tableMap)); 274 } 275 276 void LL1::getTable() { 277 for (int index = 0; index < T; index++) { // 對於每個產生式(編號index):A->α 278 int row = getNIndex(production[index].left); 279 int emptyCount = 0; 280 for (int i = 0; i < production[index].right.size(); i++) { // 1) 對FIRST(α)中的每個終結符號a,將index加入(A, a)中 281 char tmp = production[index].right[i]; 282 if (!isNonterminal(tmp)) { // tmp是終結符 283 if (tmp != '$') 284 tableMap[row][getIndex(tmp)] = index; 285 if (tmp == '$') { 286 emptyCount++; 287 } 288 break; 289 } 290 else { // tmp是非終結符 291 set<char>::iterator it; 292 int tmpIndex = getNIndex(tmp); 293 // 對FIRST(tmp)中的每個終結符號a,將i加入(A, a)中 294 for (it = firstSet[tmpIndex].begin(); it != firstSet[tmpIndex].end(); it++) { 295 tableMap[row][getIndex(*it)] = index; 296 } 297 if (firstSet[tmpIndex].count('$') != 0) { // 2) 如果空$在FIRST(tmp)中,繼續看α中的下一個符號 298 emptyCount++; 299 } 300 else { 301 break; 302 } 303 } 304 } 305 306 // 2) 如果空$在FIRST(α)中,對FOLLOW(A)中的每個終結符或結束符b,將i加入(A,b)中 307 if (emptyCount == production[index].right.size()) { 308 set<char>::iterator it; 309 for (it = followSet[row].begin(); it != followSet[row].end(); it++) { 310 tableMap[row][getIndex(*it)] = index; 311 } 312 } 313 } 314 } 315 316 void LL1::analyExpression(string s) { 317 318 for (int i = 0; i < s.size(); i++) 319 leftExpr.push_back(s[i]); 320 leftExpr.push_back('#'); 321 322 analyStack.push_back('#'); 323 analyStack.push_back(nonterminal[0]); // 加入開始符號 324 325 while (analyStack.size() > 0) { 326 //cout<<"分析棧:"; 327 string outs = ""; 328 for (int i = 0; i < analyStack.size(); i++) 329 outs += analyStack[i]; 330 cout << setw(15) << outs; 331 332 //cout<<"剩余輸入串:"; 333 outs = ""; 334 for (int i = 0; i < leftExpr.size(); i++) 335 outs += leftExpr[i]; 336 cout << setw(15) << outs; 337 338 // 匹配 339 char char1 = analyStack.back(); 340 char char2 = leftExpr.front(); 341 if (char1 == char2 && char1 == '#') { 342 cout << setw(15) << "Accepted!" << endl; 343 return; 344 } 345 if (char1 == char2) { 346 analyStack.pop_back(); 347 leftExpr.erase(leftExpr.begin()); 348 cout << setw(15) << "匹配:" << char1 << endl; 349 } 350 else if (tableMap[getNIndex(char1)][getIndex(char2)] != -1) { // 預測表中有推倒項,可進行推導 351 int tg = tableMap[getNIndex(char1)][getIndex(char2)]; 352 analyStack.pop_back(); 353 354 if (production[tg].right != "$") { 355 for (int i = production[tg].right.length() - 1; i >= 0; i--) // 注意這里是反向的 356 analyStack.push_back(production[tg].right[i]); 357 } 358 359 cout << setw(15) << "推導:" << production[tg].left << "->" << production[tg].right << endl; 360 } 361 else { // 錯誤 362 cout << setw(15) << "error!" << endl; 363 return; 364 } 365 } 366 } 367 368 void LL1::printPredictTable() { 369 // 表頭 370 for (int aa = 0; aa < 10; aa++) 371 { 372 cout << "*********"; 373 } 374 cout << "\n以下是預測分析表" << endl; 375 for (int i = 0; i < terminalNoEmpty.size(); i++) { 376 cout << setw(10) << terminalNoEmpty[i]; 377 } 378 cout << endl; 379 for (int i = 0; i < nonterminal.size(); i++) { 380 cout << nonterminal[i] << ": "; 381 for (int j = 0; j < terminalNoEmpty.size(); j++) { 382 if (tableMap[i][j] == -1) 383 cout << setw(10) << " "; 384 else 385 cout << setw(10) << production[tableMap[i][j]].right; 386 } 387 cout << endl; 388 } 389 cout << endl; 390 } 391 392 void LL1::getResult() { 393 inputAndSolve(); 394 displayFirstAndFollow(); 395 getTable(); 396 printPredictTable(); 397 //棧匹配 398 string ss; 399 cout << "請輸入符號串:" << endl; 400 cin >> ss; 401 for (int aa = 0; aa < 10; aa++) 402 { 403 cout << "*********"; 404 } 405 cout << "\n句子" << ss << "分析過程" << endl; 406 cout << setw(15) << "分析棧" << setw(15) << "剩余輸入串" << setw(15) << "推導式" << endl; 407 analyExpression(ss); 408 409 } 410 411 412 Main.cpp 413 #include "LL1.h" 414 #include<stdlib.h> 415 416 int main() { 417 // $表示空, #表示終止 418 LL1 res; 419 res.getResult(); 420 system("pause"); 421 return 0; 422 }