【實驗目的】
構造LR分析程序,利用它進行語法分析,判斷給出的符號串是否為該文法識別的句子,了解LR(K)分析方法是嚴格的從左向右掃描,和自底向上的語法分析方法。
【實驗內容】
對下列文法,用SLR(1)分析法對任意輸入的符號串進行分析:
(1)S->E
(2)E->E+T
(3)E->T
(4)T->T*F
(5)T->F
(6)F->(E)
(7)F->i
【設計思想】
(1)總控程序,也可以稱為驅動程序。對所有的LR分析器總控程序都是相同的。
(2)分析表或分析函數,不同的文法分析表將不同,同一個文法采用的LR分析器不同時,分析表將不同,分析表又可以分為動作表(ACTION)和狀態轉換(GOTO)表兩個部分,它們都可用二維數組表示。
(3)分析棧,包括文法符號棧和相應的狀態棧,它們均是先進后出棧。
分析器的動作就是由棧頂狀態和當前輸入符號所決定。
u LR分析器由三個部分組成:
u 其中:SP為棧指針,S[i]為狀態棧,X[i]為文法符號棧。狀態轉換表用GOTO[i,X]=j表示,規定當棧頂狀態為i,遇到當前文法符號為X時應轉向狀態j,X為終結符或非終結符。
u ACTION[i,a]規定了棧頂狀態為i時遇到輸入符號a應執行。動作有四種可能:
(1)移進:
action[i,a]= Sj:狀態j移入到狀態棧,把a移入到文法符號棧,其中i,j表示狀態號。
(2)歸約:
action[i,a]=rk:當在棧頂形成句柄時,則歸約為相應的非終結符A,即文法中有A- B的產生式,若B的長度為R(即|B|=R),則從狀態棧和文法符號棧中自頂向下去掉R個符號,即棧指針SP減去R,並把A移入文法符號棧內,j=GOTO[i,A]移進狀態棧,其中i為修改指針后的棧頂狀態。
(3)接受acc:
當歸約到文法符號棧中只剩文法的開始符號S時,並且輸入符號串已結束即當前輸入符是'#',則為分析成功。
(4)報錯:
當遇到狀態棧頂為某一狀態下出現不該遇到的文法符號時,則報錯,說明輸入端不是該文法能接受的符號串。
【實驗要求】
1、編程時注意編程風格:空行的使用、注釋的使用、縮進的使用等。
2、如果遇到錯誤的表達式,應輸出錯誤提示信息。
3、程序輸入/輸出實例:
輸入一以#結束的符號串(包括+—*/()i#):在此位置輸入符號串
輸出過程如下:
步驟 狀態棧 符號棧 剩余輸入串 動 作
1 0 # i+i*i# 移進
【實驗結果】
代碼:
1 Main.cpp 2 #include<iostream> 3 #include<stack> 4 #include<string> 5 #include <stdlib.h> 6 using namespace std; 7 string action[12][6] = { "S5", "0", "0", "S4", "0", "0", 8 //ACTION 表 9 "0", "S6", "0", "0", "0", "acc", 10 "0", "r2", "S7", "0", "r2", "r2", 11 "0", "r4", "r4", "0", "r4", "r4", 12 "S5", "0", "0", "S4", "0", "0", 13 "0", "r6", "r6", "0", "r6", "r6", 14 "S5", "0", "0", "S4", "0", "0", 15 "S5", "0", "0", "S4", "0", "0", 16 "0", "S6", "0", "0", "S11", "0", 17 "0", "r1", "S7", "0", "r1", "r1", 18 "0", "r3", "r3", "0", "r3", "r3", 19 "0", "r5", "r5", "0", "r5", "r5" }; 20 int gotoarr[12][3] = { 1, 2, 3, //GOTO 表 21 0, 0, 0, 22 0, 0, 0, 23 0, 0, 0, 24 8, 2, 3, 25 0, 0, 0, 26 0, 9, 3, 27 0, 0, 10, 28 0, 0, 0, 29 0, 0, 0, 30 0, 0, 0, 31 0, 0, 0 }; 32 char vt[6] = { 'i', '+', '*', '(', ')', '#' }; //存放終結符 33 char vn[3] = { 'E', 'T', 'F' }; //存放非終結符 34 string Production[6] = { "E->E+T", "E->T", "T->T*F", "T->F", "F->(E)", "F->i" };//產生式集合 35 //int com= 0;//記錄當前進行處理的輸入字符串字符位置 36 int com = 0; 37 int line = 1;//記錄處理的步驟數 38 bool flag = false; 39 int StatusNumber = 1;//棧中狀態數 40 string stacktd = "#";//記錄符號棧中內容 41 int Status[50] = { 0 };//記錄狀態棧 42 stack <char> Stack;//創建一個符號棧 43 stack <int> status;//創建一個狀態棧 44 void Judge(int &i, int j, char arr[], char ch, string s){//判斷輸入串是否由文法終結符組成 45 flag = false; 46 for (int l = 0; l<j; l++){ 47 if (ch == arr[l]){ 48 flag = true; 49 i = l; 50 break; 51 } 52 } 53 if (flag == false){ 54 cout << "\tError" << endl; 55 //com = s.size(); 56 com = s.size(); 57 } 58 } 59 void Outputstatus(){//輸出狀態集 60 for (int i = 0; i<StatusNumber; i++) 61 cout << Status[i]; 62 } 63 void Outputstring(string s){//輸出未處理的字符串 64 for (int i = com; i<s.size(); i++) 65 cout << s.at(i); 66 } 67 void Output(string s){//輸出步驟、 狀態集、 符號集、 輸入串 68 cout << line << "\t"; 69 Outputstatus(); 70 cout << "\t" << stacktd << "\t"; 71 Outputstring(s); 72 cout << "\t\t"; 73 line++; 74 } 75 void Shift(int i, string s){//移進函數 S 76 Output(s); 77 cout << "ACTION[" << status.top() << "," << s.at(com) << "]=S" << i << ",狀態" << i << "入棧" << endl; 78 status.push(i);//將狀態 i 壓進狀態 79 Status[StatusNumber] = i;//Status 記錄狀態棧的內容 80 Stack.push(s.at(com));//將當前面臨的輸入串符號壓進符號棧 81 stacktd = stacktd + s.at(com);//stacktd 記錄符號棧的內容 82 com++;//當前面臨的輸入串字符往后移一位 83 StatusNumber++;//狀態數加一 84 } 85 void Goto(stack <int> st1, stack <char> st2, string s){//GoTo 語句 86 int j = -1; 87 int ch1 = st1.top(); 88 char ch2 = st2.top(); 89 Judge(j, 3, vn, ch2, s);//求得 ch2 在非終結符表中的位置 90 if (gotoarr[ch1][j] == 0){ 91 cout << "\tError" << endl; 92 com = s.size(); 93 } 94 else{ 95 status.push(gotoarr[ch1][j]);//新狀態進棧 96 Status[StatusNumber] = gotoarr[ch1][j]; 97 StatusNumber++; 98 } 99 } 100 void Reduction(int i, string s){//歸約函數 R 101 Output(s); 102 cout << "r" << i << ":" << Production[i - 1] << "歸約, GoTo("; 103 int N = Production[i - 1].length() - 3; 104 for (int j = 0; j<N; j++){//消除要歸約的狀態及符號 105 status.pop(); 106 Stack.pop(); 107 StatusNumber--; 108 stacktd.erase(stacktd.length() - 1); 109 } 110 cout << status.top() << "," << Production[i - 1].at(0) << ")="; 111 Stack.push(Production[i - 1].at(0));//符號進棧 112 stacktd = stacktd + Stack.top(); 113 Goto(status, Stack, s); 114 cout << status.top() << "入棧" << endl; 115 Status[StatusNumber] = status.top(); 116 } 117 void Analyse(string s){//具體分析函數 118 Stack.push('#');//初始化 119 status.push(0); 120 s = s + "#"; 121 int t = -1;//記錄 ch 在數組 vt 的位置 122 while (com<s.size()){ 123 int i = status.top(); 124 char ch = s.at(com); 125 Judge(t, 6, vt, ch, s); 126 if (flag == true){ 127 if (action[i][t] != "acc"&&action[i][t] != "0"){ 128 if (action[i][t].at(0) == 'S'){ 129 action[i][t].erase(0, 1); //刪除 action[i][t]的首字母 S 130 Shift(atoi(action[i][t].c_str()), s);//atoi(action[i][t].c_str()), 將action[i][t]轉換為整型 131 action[i][t].insert(0, "S");//將 S 添加回 action[i][t] 132 } 133 else if (action[i][t].at(0) == 'r'){ 134 action[i][t].erase(0, 1);//刪除 action[i][t]的首字母 r 135 Reduction(atoi(action[i][t].c_str()), s);//atoi(action[i][t].c_str()), 將action[i][t]轉換為整型 136 action[i][t].insert(0, "r");//將 r 添加回 action[i][t] 137 } 138 } 139 else if (action[i][t] == "0"){ 140 cout << "\tError" << endl; 141 break; 142 } 143 else if (action[i][t] == "acc"){ 144 Output(s); 145 cout << "acc" << "\t 分析成功" << endl; 146 break; 147 } 148 } 149 else if (flag == false) 150 break; 151 } 152 } 153 int main(){ 154 string s; 155 cout << "************************20173599周博*************************" << endl; 156 cout << "輸入的文法" << endl; 157 for (int j = 0; j < 6; j++) 158 { 159 cout << Production[j] << endl; 160 } 161 cout << "VT:" << endl; 162 for (int i = 0; i < 6; i++) 163 { 164 cout << vt[i] << "\t"; 165 } 166 cout << endl; 167 for (int i = 0; i <3; i++) 168 { 169 cout << vn[i] << "\t"; 170 } 171 cout << endl; 172 cout << "************************LR(1)分析*************************" << endl; 173 char T; 174 cout << "輸入字符串" << endl; 175 cin >> s;//輸入要分析的字符串 176 cout << "************************現進行如下分析*************************" << endl; 177 cout << "步驟" << "\t" << "狀態棧" << "\t" << "符號棧" << "\t" << "剩余輸入串" << "\t" << "動作說明" << endl; 178 Analyse(s); 179 com = 0;//記錄當前進行處理的輸入字符串字符位置 180 line = 1;//記錄處理的步驟數 181 stacktd = "#"; 182 StatusNumber = 1; 183 while (!Stack.empty()){ 184 Stack.pop(); 185 } 186 while (!status.empty()){ 187 status.pop(); 188 } 189 190 return 0; 191 }