├── 3.in ├── 语法分析.assets ├── image-20191126143323246.png ├── image-20191126144856856.png ├── image-20191126145227507.png ├── image-20191126145547747.png ├── image-20191126151740466.png ├── image-20191126183442960.png ├── image-20191126183810269.png ├── image-20191126184218556.png ├── image-20191126184647328.png ├── image-20191126185427849.png ├── image-20191126190440849.png ├── image-20191223184130454.png ├── image-20191223184158673.png ├── image-20191223184234241.png └── image-20191223184521125.png ├── 2.in ├── 1.in ├── LL1.cpp ├── LR1.cpp ├── SLR1.cpp └── README.md /3.in: -------------------------------------------------------------------------------- 1 | 4 2 | A->S 3 | S->CC 4 | C->cC 5 | C->d 6 | A S C # 7 | c d # 8 | cccdcd -------------------------------------------------------------------------------- /语法分析.assets/image-20191126143323246.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/khuqen/gramma_analysis/HEAD/语法分析.assets/image-20191126143323246.png -------------------------------------------------------------------------------- /语法分析.assets/image-20191126144856856.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/khuqen/gramma_analysis/HEAD/语法分析.assets/image-20191126144856856.png -------------------------------------------------------------------------------- /语法分析.assets/image-20191126145227507.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/khuqen/gramma_analysis/HEAD/语法分析.assets/image-20191126145227507.png -------------------------------------------------------------------------------- /语法分析.assets/image-20191126145547747.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/khuqen/gramma_analysis/HEAD/语法分析.assets/image-20191126145547747.png -------------------------------------------------------------------------------- /语法分析.assets/image-20191126151740466.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/khuqen/gramma_analysis/HEAD/语法分析.assets/image-20191126151740466.png -------------------------------------------------------------------------------- /语法分析.assets/image-20191126183442960.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/khuqen/gramma_analysis/HEAD/语法分析.assets/image-20191126183442960.png -------------------------------------------------------------------------------- /语法分析.assets/image-20191126183810269.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/khuqen/gramma_analysis/HEAD/语法分析.assets/image-20191126183810269.png -------------------------------------------------------------------------------- /语法分析.assets/image-20191126184218556.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/khuqen/gramma_analysis/HEAD/语法分析.assets/image-20191126184218556.png -------------------------------------------------------------------------------- /语法分析.assets/image-20191126184647328.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/khuqen/gramma_analysis/HEAD/语法分析.assets/image-20191126184647328.png -------------------------------------------------------------------------------- /语法分析.assets/image-20191126185427849.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/khuqen/gramma_analysis/HEAD/语法分析.assets/image-20191126185427849.png -------------------------------------------------------------------------------- /语法分析.assets/image-20191126190440849.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/khuqen/gramma_analysis/HEAD/语法分析.assets/image-20191126190440849.png -------------------------------------------------------------------------------- /语法分析.assets/image-20191223184130454.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/khuqen/gramma_analysis/HEAD/语法分析.assets/image-20191223184130454.png -------------------------------------------------------------------------------- /语法分析.assets/image-20191223184158673.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/khuqen/gramma_analysis/HEAD/语法分析.assets/image-20191223184158673.png -------------------------------------------------------------------------------- /语法分析.assets/image-20191223184234241.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/khuqen/gramma_analysis/HEAD/语法分析.assets/image-20191223184234241.png -------------------------------------------------------------------------------- /语法分析.assets/image-20191223184521125.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/khuqen/gramma_analysis/HEAD/语法分析.assets/image-20191223184521125.png -------------------------------------------------------------------------------- /2.in: -------------------------------------------------------------------------------- 1 | 9 2 | A->E 3 | E->E+T 4 | E->E-T 5 | E->T 6 | T->T*F 7 | T->T/F 8 | T->F 9 | F->(E) 10 | F->n 11 | A E T F # 12 | n + - * / ( ) # 13 | (n+n)*n-n/n -------------------------------------------------------------------------------- /1.in: -------------------------------------------------------------------------------- 1 | 10 2 | E->TA 3 | A->+TA 4 | A->-TA 5 | A->& 6 | T->FB 7 | B->*FB 8 | B->/FB 9 | B->& 10 | F->(E) 11 | F->n 12 | E T A F B # 13 | n + - * / ( ) # 14 | (n+n)*n-n/n -------------------------------------------------------------------------------- /LL1.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | using namespace std; 9 | 10 | /* 产生式结构体 */ 11 | struct Production { 12 | char left; // 左部符号 13 | vector rigths; // 右部符号串 14 | }; 15 | 16 | /* 文法结构体 */ 17 | struct Grammar { 18 | int num; // 产生式数量 19 | vector T; // 终结符 20 | vector N; // 非终结符 21 | vector prods; //产生式 22 | } grammar; 23 | 24 | /* FIRST集和FOLLOW集 */ 25 | map > first; 26 | map > follow; 27 | 28 | /* 分析栈 */ 29 | stack ST; 30 | 31 | /* 待分析串 */ 32 | string str; 33 | 34 | /* 预测分析表 */ 35 | vector M[50][50]; 36 | 37 | /* 判断ch是否是终结符 */ 38 | int isInT(char ch) 39 | { 40 | for (int i = 0; i < grammar.T.size(); i++) { 41 | if (grammar.T[i] == ch) { 42 | return i + 1; 43 | } 44 | } 45 | return 0; 46 | } 47 | 48 | /* 判断ch是否是非终结符 */ 49 | int isInN(char ch) 50 | { 51 | for (int i = 0; i < grammar.N.size(); i++) { 52 | if (grammar.N[i] == ch) { 53 | return i + 1; 54 | } 55 | } 56 | return 0; 57 | } 58 | /* 求(T U N)的FIRST集 */ 59 | void getFirstSet() 60 | { 61 | /* 终结符的FIRST集是其本身 */ 62 | for (int i = 0; i < grammar.T.size(); i++) { 63 | char X = grammar.T[i]; 64 | set tmp; 65 | tmp.insert(X); 66 | first[X] = tmp; 67 | } 68 | /* 当非终结符的FIRST集发生变化时循环 */ 69 | bool change = true; 70 | while (change) { 71 | change = false; 72 | /* 枚举每个产生式 */ 73 | for (int i = 0; i < grammar.prods.size(); i++) { 74 | Production &P = grammar.prods[i]; 75 | char X = P.left; 76 | set &FX = first[X]; 77 | /* 如果右部第一个符号是空或者是终结符,则加入到左部的FIRST集中 */ 78 | if (isInT(P.rigths[0]) || P.rigths[0] == '&') { 79 | /* 查找是否FIRST集是否已经存在该符号 */ 80 | auto it = FX.find(P.rigths[0]); 81 | /* 不存在 */ 82 | if (it == FX.end()) { 83 | change = true; // 标注FIRST集发生变化,循环继续 84 | FX.insert(P.rigths[0]); 85 | } 86 | } else { 87 | /* 当前符号是非终结符,且当前符号可以推出空,则还需判断下一个符号 */ 88 | bool next = true; 89 | /* 待判断符号的下标 */ 90 | int idx = 0; 91 | while (next && idx < P.rigths.size()) { 92 | next = false; 93 | char Y = P.rigths[idx]; 94 | set &FY = first[Y]; 95 | for (auto it = FY.begin(); it != FY.end(); it++) { 96 | /* 把当前符号的FIRST集中非空元素加入到左部符号的FIRST集中 */ 97 | if (*it != '&') { 98 | auto itt = FX.find(*it); 99 | if (itt == FX.end()) { 100 | change = true; 101 | FX.insert(*it); 102 | } 103 | } 104 | } 105 | /* 当前符号的FIRST集中有空, 标记next为真,idx下标+1 */ 106 | auto it = FY.find('&'); 107 | if (it != FY.end()) { 108 | next = true; 109 | idx = idx + 1; 110 | } 111 | } 112 | 113 | } 114 | } 115 | } 116 | 117 | printf("FIRST:\n"); 118 | for (int i = 0; i < grammar.N.size(); i++) { 119 | char X = grammar.N[i]; 120 | printf("%c: ", X); 121 | for (auto it = first[X].begin(); it != first[X].end(); it++) { 122 | printf("%c ", *it); 123 | } 124 | printf("\n"); 125 | } 126 | } 127 | /* 产找alpha串的FIRST集, 保存到FS集合中 */ 128 | void getFirstByAlphaSet(vector &alpha, set &FS) 129 | { 130 | /* 当前符号是非终结符,若当前符号可以推出空,则还需判断下一个符号 */ 131 | bool next = true; 132 | int idx = 0; 133 | while (idx < alpha.size() && next) { 134 | next = false; 135 | /* 当前符号是终结符或空,加入到FIRST集中 */ 136 | if (isInT(alpha[idx]) || alpha[idx] == '&') { 137 | /* 判断是否已经在FIRST集中 */ 138 | auto itt = FS.find(alpha[idx]); 139 | if (itt == FS.end()) { 140 | FS.insert(alpha[idx]); 141 | } 142 | } else { 143 | char B = alpha[idx]; 144 | set &FB = first[B]; 145 | for (auto it = first[B].begin(); it != first[B].end(); it++) { 146 | /* 当前符号FIRST集包含空,标记next为真,并跳过当前循环 */ 147 | if (*it == '&') { 148 | next = true; 149 | continue; 150 | } 151 | /* 把非空元素加入到FIRST集中 */ 152 | auto itt = FS.find(*it); 153 | if (itt == FS.end()) { 154 | FS.insert(*it); 155 | } 156 | } 157 | } 158 | idx = idx + 1; 159 | } 160 | /* 如果到达产生式右部末尾next还为真,说明alpha可以推空,将空加入到FIRST集中 */ 161 | if (next) { 162 | FS.insert('&'); 163 | } 164 | } 165 | /* 求非终结符的FOLLOW集 */ 166 | void getFollowSet() 167 | { 168 | /* 初始化终结符的FOLLOW集为空集 */ 169 | for (int i = 0; i < grammar.N.size(); i++) { 170 | char B = grammar.N[i]; 171 | follow[B] = set(); 172 | } 173 | /* 将$加入到文法的开始符号的FOLLOW集中 */ 174 | char S = grammar.N[0]; 175 | follow[S].insert('$'); 176 | 177 | bool change = true; 178 | while (change) { 179 | change = false; 180 | /* 枚举每个产生式 */ 181 | for (int i = 0; i < grammar.prods.size(); i++) { 182 | Production &P = grammar.prods[i]; 183 | for (int j = 0; j < P.rigths.size(); j++) { 184 | char B = P.rigths[j]; 185 | /* 当前符号是非终结符 */ 186 | if (isInN(B)) { 187 | set &FB = follow[B]; 188 | set FS; 189 | /* alpha是从当前符号下一个符号开始的符号串 */ 190 | vector alpha(P.rigths.begin() + j + 1, P.rigths.end()); 191 | /* 求alpha的FIRST集,即FS */ 192 | getFirstByAlphaSet(alpha, FS); 193 | /* 将alpha的FIRST集中所有非空元素加入到当前符号的FOLLOW集中 */ 194 | for (auto it = FS.begin(); it != FS.end(); it++) { 195 | if (*it == '&') { 196 | continue; 197 | } 198 | auto itt = FB.find(*it); 199 | if (itt == FB.end()) { 200 | change = true; 201 | FB.insert(*it); 202 | } 203 | } 204 | /* 如果alpha能推空,或者当前符号是产生式右部末尾,则将文法左部符号的FOLLOW集加入到当前符号的FOLLOW集中 */ 205 | auto itt = FS.find('&'); 206 | if (itt != FS.end() || (j + 1) >= P.rigths.size()) { 207 | char A = P.left; // A为左部符号 208 | for (auto it = follow[A].begin(); it != follow[A].end(); it++) { 209 | auto itt = FB.find(*it); 210 | if (itt == FB.end()) { 211 | change = true; 212 | FB.insert(*it); 213 | } 214 | } 215 | } 216 | } 217 | } 218 | } 219 | } 220 | 221 | printf("FOLLOW:\n"); 222 | for (int i = 0; i < grammar.N.size(); i++) { 223 | char X = grammar.N[i]; 224 | printf("%c: ", X); 225 | for (auto it = follow[X].begin(); it != follow[X].end(); it++) { 226 | printf("%c ", *it); 227 | } 228 | printf("\n"); 229 | } 230 | } 231 | /* 把生成式插入到预测分析表对应的项中 */ 232 | void insertTOForecastAnalysisTable(char A, char a, Production &P) 233 | { 234 | /* 根据A和a找到对应表项 */ 235 | int i = isInN(A) - 1; 236 | int j = isInT(a) - 1; 237 | /* 把P.left->P.rights插入*/ 238 | M[i][j].push_back(P.left); 239 | M[i][j].push_back('-'); 240 | M[i][j].push_back('>'); 241 | for (auto it = P.rigths.begin(); it != P.rigths.end(); it++) { 242 | M[i][j].push_back(*it); 243 | } 244 | } 245 | /* 取出预测分析表对应的项中的产生式 */ 246 | void getFromForecastAnalysisTable(char A, char a, vector &s) 247 | { 248 | /* 根据A和a找到对应表项 */ 249 | int i = isInN(A) - 1; 250 | int j = isInT(a) - 1; 251 | /* 取出 */ 252 | s.assign(M[i][j].begin(), M[i][j].end()); 253 | } 254 | /* 构建预测分析表 */ 255 | void productForecastAnalysisTable() 256 | { 257 | /* 枚举所有产生式 */ 258 | for (int i = 0; i < grammar.prods.size(); i++) { 259 | /* 假设P为 A->alpha */ 260 | Production &P = grammar.prods[i]; 261 | set FS; 262 | /* 对每个 a in FIRST(alpha) 把 A->alpha放入M[A, a]中 */ 263 | getFirstByAlphaSet(P.rigths, FS); 264 | for (auto it = FS.begin(); it != FS.end(); it++) { 265 | insertTOForecastAnalysisTable(P.left, *it, P); 266 | } 267 | /* 如果alpha能推空,则把每个b in FOLLOW(A) 把 A->alpha放入M[A, b]中*/ 268 | auto itt = FS.find('&'); 269 | if (itt != FS.end()) { 270 | for (auto it = follow[P.left].begin(); it != follow[P.left].end(); it++) { 271 | insertTOForecastAnalysisTable(P.left, *it, P); 272 | } 273 | } 274 | } 275 | /* 输出预测分析表 */ 276 | printf("forecast analysis table:\n"); 277 | printf("\t"); 278 | for (int i = 0; i < grammar.T.size(); i++) { 279 | printf("%c\t\t", grammar.T[i]); 280 | } 281 | printf("\n"); 282 | for (int i = 0; i < grammar.N.size(); i++) { 283 | printf("%c\t", grammar.N[i]); 284 | for (int j = 0; j < grammar.T.size(); j++) { 285 | for(auto k = M[i][j].begin(); k != M[i][j].end(); k++) { 286 | printf("%c", *k); 287 | } 288 | printf("\t\t"); 289 | } 290 | printf("\n"); 291 | } 292 | } 293 | /* 读入并初始化语法 */ 294 | void initGrammar() 295 | { 296 | printf("Please enter the num of production:\n"); 297 | cin >> grammar.num; 298 | string s; 299 | printf("Please enter the production:\n"); 300 | for (int i = 0; i < grammar.num; i++) { 301 | cin >> s; 302 | Production tmp; 303 | tmp.left = s[0]; 304 | for (int j = 3; j < s.size(); j++) { 305 | tmp.rigths.push_back(s[j]); 306 | } 307 | grammar.prods.push_back(tmp); 308 | } 309 | printf("Please enter the non-terminators(end with #):\n"); 310 | char ch; 311 | cin >> ch; 312 | while (ch != '#') { 313 | grammar.N.push_back(ch); 314 | cin >> ch; 315 | } 316 | printf("Please enter the terminators(end with #):\n"); 317 | cin >> ch; 318 | while (ch != '#') { 319 | grammar.T.push_back(ch); 320 | cin >> ch; 321 | } 322 | /* 把$当作终结符 */ 323 | grammar.T.push_back('$'); 324 | /* 求FIRST集和FOLLOW集 */ 325 | getFirstSet(); 326 | getFollowSet(); 327 | 328 | /* 生成预测分析表 */ 329 | productForecastAnalysisTable(); 330 | 331 | /* 读入待分析串并初始化分析栈 */ 332 | printf("Please enter the String to be analyzed:\n"); 333 | cin >> str; 334 | str += '$'; 335 | ST.push('$'); 336 | ST.push(grammar.N[0]); 337 | } 338 | /* 分析程序 */ 339 | void process() 340 | { 341 | /* 指向当前字符 */ 342 | int ip = 0; 343 | /* 栈顶符号X, 和当前输入符号a */ 344 | char X, a; 345 | printf("The answer:\n"); 346 | do{ 347 | X = ST.top(); 348 | a = str[ip]; 349 | /* 如果是终结符或者$ */ 350 | if (isInT(X)) { 351 | /* 如果栈顶符号和当前符号匹配,出栈,指针前移 */ 352 | if (X == a) { 353 | ST.pop(); 354 | ip = ip + 1; 355 | } else { /* 不匹配报错 */ 356 | printf("error1\n"); 357 | } 358 | } else { //非终结符 359 | vector s; 360 | /* 取出对应预测分析表的项 */ 361 | getFromForecastAnalysisTable(X, a, s); 362 | /* 预测分析表项中有元素 */ 363 | if (!s.empty()) { 364 | /* 弹栈并将右部符号串逆序入栈 */ 365 | ST.pop(); 366 | for (int i = s.size() - 1; i >= 3; i--) { 367 | if (s[i] != '&') { // 为空时不入栈 368 | ST.push(s[i]); 369 | } 370 | } 371 | /* 输出产生式 */ 372 | for (int i = 0; i < s.size(); i++) { 373 | printf("%c", s[i]); 374 | } 375 | printf("\n"); 376 | } else { // 空,报错 377 | printf("error2\n"); 378 | } 379 | } 380 | } while (X != '$'); 381 | } 382 | 383 | int main() 384 | { 385 | initGrammar(); 386 | process(); 387 | return 0; 388 | } -------------------------------------------------------------------------------- /LR1.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | using namespace std; 10 | 11 | /* 产生式结构体,左部符号和右部符号串 */ 12 | struct Production { 13 | char left; 14 | vector rigths; 15 | /* 重载== */ 16 | bool operator==(Production& rhs) const { 17 | if (left != rhs.left) 18 | return false; 19 | for (int i = 0; i < rigths.size(); i++) { 20 | if (i >= rhs.rigths.size()) 21 | return false; 22 | if (rigths[i] != rhs.rigths[i]) 23 | return false; 24 | } 25 | return true; 26 | } 27 | }; 28 | 29 | /* LR1项目 */ 30 | struct LR1Item { 31 | Production p; 32 | /* 点的位置 */ 33 | int location; 34 | /* 向前看符号 */ 35 | char next; 36 | }; 37 | 38 | /* LR1项目集 */ 39 | struct LR1Items { 40 | vector items; 41 | }; 42 | 43 | /* LR1项目集规范族 */ 44 | struct CanonicalCollection { 45 | /* 项目集集合 */ 46 | vector items; 47 | /* 保存DFA的图,first为转移到的状态序号,second是经什么转移 */ 48 | vector< pair > g[100]; 49 | }CC; 50 | 51 | /* 文法结构体 */ 52 | struct Grammar { 53 | int num; // 产生式数量 54 | vector T; // 终结符 55 | vector N; // 非终结符 56 | vector prods; //产生式 57 | }grammar; 58 | 59 | /* FIRST集和FOLLOW集 */ 60 | map > first; 61 | map > follow; 62 | 63 | /* DFA队列, 用于存储待转移的有效项目集 */ 64 | queue< pair > Q; 65 | 66 | /* action表和goto表 */ 67 | pair action[100][100]; // first表示分析动作,0->ACC 1->S 2->R second表示转移状态或者产生式序号 68 | int goton[100][100]; 69 | 70 | /* 待分析串 */ 71 | string str; 72 | /* 分析栈 */ 73 | stack< pair > ST; // first是state,second 是symble 74 | 75 | /* 判断ch是否是终结符 */ 76 | int isInT(char ch) 77 | { 78 | for (int i = 0; i < grammar.T.size(); i++) { 79 | if (grammar.T[i] == ch) { 80 | return i + 1; 81 | } 82 | } 83 | return 0; 84 | } 85 | /* 判断ch是否是非终结符 */ 86 | int isInN(char ch) 87 | { 88 | for (int i = 0; i < grammar.N.size(); i++) { 89 | if (grammar.N[i] == ch) { 90 | return i + 1; 91 | } 92 | } 93 | return 0; 94 | } 95 | /* 求(T U N)的FIRST集 */ 96 | void getFirstSet() 97 | { 98 | /* 终结符的FIRST集是其本身 */ 99 | for (int i = 0; i < grammar.T.size(); i++) { 100 | char X = grammar.T[i]; 101 | set tmp; 102 | tmp.insert(X); 103 | first[X] = tmp; 104 | } 105 | /* 当非终结符的FIRST集发生变化时循环 */ 106 | bool change = true; 107 | while (change) { 108 | change = false; 109 | /* 枚举每个产生式 */ 110 | for (int i = 0; i < grammar.prods.size(); i++) { 111 | Production &P = grammar.prods[i]; 112 | char X = P.left; 113 | set &FX = first[X]; 114 | /* 如果右部第一个符号是空或者是终结符,则加入到左部的FIRST集中 */ 115 | if (isInT(P.rigths[0]) || P.rigths[0] == '&') { 116 | /* 查找是否FIRST集是否已经存在该符号 */ 117 | auto it = FX.find(P.rigths[0]); 118 | /* 不存在 */ 119 | if (it == FX.end()) { 120 | change = true; // 标注FIRST集发生变化,循环继续 121 | FX.insert(P.rigths[0]); 122 | } 123 | } else { 124 | /* 当前符号是非终结符,且当前符号可以推出空,则还需判断下一个符号 */ 125 | bool next = true; 126 | /* 待判断符号的下标 */ 127 | int idx = 0; 128 | while (next && idx < P.rigths.size()) { 129 | next = false; 130 | char Y = P.rigths[idx]; 131 | set &FY = first[Y]; 132 | for (auto it = FY.begin(); it != FY.end(); it++) { 133 | /* 把当前符号的FIRST集中非空元素加入到左部符号的FIRST集中 */ 134 | if (*it != '&') { 135 | auto itt = FX.find(*it); 136 | if (itt == FX.end()) { 137 | change = true; 138 | FX.insert(*it); 139 | } 140 | } 141 | } 142 | /* 当前符号的FIRST集中有空, 标记next为真,idx下标+1 */ 143 | auto it = FY.find('&'); 144 | if (it != FY.end()) { 145 | next = true; 146 | idx = idx + 1; 147 | } 148 | } 149 | 150 | } 151 | } 152 | } 153 | 154 | printf("FIRST:\n"); 155 | for (int i = 0; i < grammar.N.size(); i++) { 156 | char X = grammar.N[i]; 157 | printf("%c: ", X); 158 | for (auto it = first[X].begin(); it != first[X].end(); it++) { 159 | printf("%c ", *it); 160 | } 161 | printf("\n"); 162 | } 163 | } 164 | /* 产找alpha串的FIRST集, 保存到FS集合中 */ 165 | void getFirstByAlphaSet(vector &alpha, set &FS) 166 | { 167 | /* 当前符号是非终结符,且当前符号可以推出空,则还需判断下一个符号 */ 168 | bool next = true; 169 | int idx = 0; 170 | while (idx < alpha.size() && next) { 171 | next = false; 172 | /* 当前符号是终结符或空,加入到FIRST集中 */ 173 | if (isInT(alpha[idx]) || alpha[idx] == '&') { 174 | /* 判断是否已经在FIRST集中 */ 175 | auto itt = FS.find(alpha[idx]); 176 | if (itt == FS.end()) { 177 | FS.insert(alpha[idx]); 178 | } 179 | } else { 180 | char B = alpha[idx]; 181 | set &FB = first[B]; 182 | for (auto it = first[B].begin(); it != first[B].end(); it++) { 183 | /* 当前符号FIRST集包含空,标记next为真,并跳过当前循环 */ 184 | if (*it == '&') { 185 | next = true; 186 | continue; 187 | } 188 | /* 把非空元素加入到FIRST集中 */ 189 | auto itt = FS.find(*it); 190 | if (itt == FS.end()) { 191 | FS.insert(*it); 192 | } 193 | } 194 | } 195 | idx = idx + 1; 196 | } 197 | /* 如果到达产生式右部末尾next还为真,说明alpha可以推空,将空加入到FIRST集中 */ 198 | if (next) { 199 | FS.insert('&'); 200 | } 201 | } 202 | 203 | /* 判断是LR1项目t否在有效项目集I中 */ 204 | bool isInLR1Items(LR1Items &I, LR1Item &t) 205 | { 206 | for (auto it = I.items.begin(); it != I.items.end(); it++) { 207 | LR1Item &item = *it; 208 | if (item.p == t.p && item.location == t.location && item.next == t.next) 209 | return true; 210 | } 211 | return false; 212 | } 213 | 214 | /* 打印某个项目集 */ 215 | void printLR1Items(LR1Items &I) 216 | { 217 | for (auto it = I.items.begin(); it != I.items.end(); it++) { 218 | LR1Item &L = *it; 219 | printf("%c->", L.p.left); 220 | for (int i = 0; i < L.p.rigths.size(); i++) { 221 | if (L.location == i) 222 | printf("."); 223 | printf("%c", L.p.rigths[i]); 224 | } 225 | if (L.location == L.p.rigths.size()) 226 | printf("."); 227 | printf(",%c ", L.next); 228 | } 229 | printf("\n"); 230 | } 231 | 232 | /* 求I的闭包 */ 233 | void closure(LR1Items &I) 234 | { 235 | bool change = true; 236 | while (change) { 237 | change = false; 238 | LR1Items J; 239 | /* 枚举每个项目 */ 240 | J.items.assign(I.items.begin(), I.items.end()); 241 | for (auto it = J.items.begin(); it != J.items.end(); it++) { 242 | LR1Item &L = *it; 243 | /* 非规约项目 */ 244 | if (L.location < L.p.rigths.size()) { 245 | char B = L.p.rigths[L.location]; 246 | if (isInN(B)) { 247 | /* 把符合条件的LR1项目加入闭包中 */ 248 | 249 | /* 先求出B后面的FIRST集 */ 250 | set FS; 251 | vector alpha; 252 | alpha.assign(L.p.rigths.begin() + L.location + 1, L.p.rigths.end()); 253 | alpha.push_back(L.next); 254 | getFirstByAlphaSet(alpha, FS); 255 | 256 | for (int i = 0; i < grammar.prods.size(); i++) { 257 | Production &P = grammar.prods[i]; 258 | if (P.left == B) { 259 | /* 枚举每个b in B后面的FIRST集 */ 260 | for (auto it = FS.begin(); it != FS.end(); it++) { 261 | char b = *it; 262 | LR1Item t; 263 | t.location = 0; 264 | t.next = b; 265 | t.p.left = P.left; 266 | t.p.rigths.assign(P.rigths.begin(), P.rigths.end()); 267 | if (!isInLR1Items(I, t)) { 268 | /* 标记改变 */ 269 | change = true; 270 | I.items.push_back(t); 271 | } 272 | } 273 | } 274 | } 275 | } 276 | } 277 | } 278 | } 279 | } 280 | /* 判断是否在项目集规范族中,若在返回序号 */ 281 | int isInCanonicalCollection(LR1Items &I) 282 | { 283 | for (int i = 0; i < CC.items.size(); i++) { 284 | LR1Items &J = CC.items[i]; 285 | bool flag = true; 286 | if (J.items.size() != I.items.size()) { 287 | flag = false; 288 | continue; 289 | } 290 | /* 每个项目都在该项目集中,则认为这个两个项目集相等 */ 291 | for (auto it = I.items.begin(); it != I.items.end(); it++) { 292 | LR1Item &t = *it; 293 | if (!isInLR1Items(J, t)) { 294 | flag = false; 295 | break; 296 | } 297 | } 298 | if (flag) { 299 | return i + 1; 300 | } 301 | } 302 | return 0; 303 | } 304 | 305 | /* 转移函数,I为当前的项目集,J为转移后的项目集, 经X转移 */ 306 | void go(LR1Items &I, char X, LR1Items &J) 307 | { 308 | for (auto it = I.items.begin(); it != I.items.end(); it++) { 309 | LR1Item &L = *it; 310 | /* 非规约项目 */ 311 | if (L.location < L.p.rigths.size()) { 312 | char B = L.p.rigths[L.location]; 313 | /* 如果点后面是非终结符,且非终结符为X,点位置加1, 加入到转移项目集中*/ 314 | if (B == X) { 315 | LR1Item t; 316 | t.location = L.location + 1; 317 | t.next = L.next; 318 | t.p.left = L.p.left; 319 | t.p.rigths.assign(L.p.rigths.begin(), L.p.rigths.end()); 320 | J.items.push_back(t); 321 | } 322 | } 323 | } 324 | /* 若J中有项目,则求其闭包 */ 325 | if (J.items.size() > 0) { 326 | closure(J); 327 | } 328 | } 329 | 330 | /* 构建DFA和项目集规范族 */ 331 | void DFA() 332 | { 333 | /* 构建初始项目集 */ 334 | LR1Item t; 335 | t.location = 0; 336 | t.next = '$'; 337 | t.p.left = grammar.prods[0].left; 338 | t.p.rigths.assign(grammar.prods[0].rigths.begin(), grammar.prods[0].rigths.end()); 339 | LR1Items I; 340 | I.items.push_back(t); 341 | closure(I); 342 | /* 加入初始有效项目集 */ 343 | CC.items.push_back(I); 344 | /* 把新加入的有效项目集加入待扩展队列中 */ 345 | Q.push(pair(I, 0)); 346 | while (!Q.empty()) { 347 | LR1Items &S = Q.front().first; 348 | int sidx = Q.front().second; 349 | /* 遍历每个终结符 */ 350 | for (int i = 0; i < grammar.T.size(); i++) { 351 | LR1Items D; 352 | go(S, grammar.T[i], D); 353 | int idx; 354 | /* 若不为空 */ 355 | if (D.items.size() > 0) { 356 | /* 查找是否已经在有效项目集族里 */ 357 | idx = isInCanonicalCollection(D); 358 | if (idx > 0) { 359 | idx = idx - 1; 360 | } else { 361 | idx = CC.items.size(); 362 | CC.items.push_back(D); 363 | /* 把新加入的有效项目集加入待扩展队列中 */ 364 | Q.push(pair(D, idx)); 365 | } 366 | /* 从原状态到转移状态加一条边,边上的值为转移符号 */ 367 | CC.g[sidx].push_back(pair(grammar.T[i], idx)); 368 | } 369 | } 370 | /* 遍历每个非终结符 */ 371 | for (int i = 0; i < grammar.N.size(); i++) { 372 | LR1Items D; 373 | go(S, grammar.N[i], D); 374 | int idx; 375 | if (D.items.size() > 0) { 376 | /* 查找是否已经在有效项目集族里 */ 377 | idx = isInCanonicalCollection(D); 378 | if (idx != 0) { 379 | idx = idx - 1; 380 | } else { 381 | idx = CC.items.size(); 382 | CC.items.push_back(D); 383 | /* 把新加入的有效项目集加入待扩展队列中 */ 384 | Q.push(pair(D, idx)); 385 | } 386 | /* 从原状态到转移状态加一条边,边上的值为转移符号 */ 387 | CC.g[sidx].push_back(pair(grammar.N[i], idx)); 388 | } 389 | } 390 | /* 当前状态扩展完毕,移除队列*/ 391 | Q.pop(); 392 | } 393 | 394 | printf("CC size: %d\n", CC.items.size()); 395 | for (int i = 0; i < CC.items.size(); i++) { 396 | printf("LR1Items %d:\n", i); 397 | printLR1Items(CC.items[i]); 398 | for (int j = 0; j < CC.g[i].size(); j++) { 399 | pair p= CC.g[i][j]; 400 | printf("to %d using %c\n", p.second, p.first); 401 | } 402 | } 403 | } 404 | /* 生成LR1分析表 */ 405 | void productLR1AnalysisTabel() 406 | { 407 | for (int i = 0; i < CC.items.size(); i++) { 408 | LR1Items &LIt= CC.items[i]; 409 | /* 构建action表 */ 410 | for (auto it = LIt.items.begin(); it != LIt.items.end(); it++) { 411 | LR1Item &L = *it; 412 | /* 非规约项目 */ 413 | if (L.location < L.p.rigths.size()) { 414 | char a = L.p.rigths[L.location]; 415 | int j = isInT(a); 416 | /* a是终结符 */ 417 | if (j > 0) { 418 | j = j - 1; 419 | /* 找到对应a的出边,得到其转移到的状态 */ 420 | for (int k = 0; k < CC.g[i].size(); k++) { 421 | pair p = CC.g[i][k]; 422 | if (p.first == a) { 423 | action[i][j].first = 1; // 1->S 424 | action[i][j].second = p.second; //转移状态 425 | break; 426 | } 427 | } 428 | } 429 | } else { // 规约项目 430 | /* 接受项目 */ 431 | if (L.p.left == grammar.prods[0].left) { 432 | if (L.next == '$') 433 | action[i][grammar.T.size() - 1].first = 3; 434 | } else { 435 | /* 终结符 */ 436 | int j = isInT(L.next) - 1; 437 | /* 找到产生式对应的序号 */ 438 | for (int k = 0; k < grammar.prods.size(); k++) { 439 | if (L.p == grammar.prods[k]) { 440 | action[i][j].first = 2; 441 | action[i][j].second = k; 442 | break; 443 | } 444 | } 445 | 446 | } 447 | } 448 | } 449 | /* 构建goto表 */ 450 | for (int k = 0; k < CC.g[i].size(); k++) { 451 | pair p = CC.g[i][k]; 452 | char A = p.first; 453 | int j = isInN(A); 454 | /* 终结符 */ 455 | if (j > 0) { 456 | j = j - 1; 457 | goton[i][j] = p.second; //转移状态 458 | } 459 | } 460 | } 461 | /* 打印LR1分析表 */ 462 | for (int i = 0; i < grammar.T.size() / 2; i++) 463 | printf("\t"); 464 | printf("action"); 465 | for (int i = 0; i < grammar.N.size() / 2 + grammar.T.size() / 2 + 1; i++) 466 | printf("\t"); 467 | printf("goto\n"); 468 | printf("\t"); 469 | for (int i = 0; i < grammar.T.size(); i++) { 470 | printf("%c\t", grammar.T[i]); 471 | } 472 | printf("|\t"); 473 | for (int i = 1; i < grammar.N.size(); i++) { 474 | printf("%c\t", grammar.N[i]); 475 | } 476 | printf("\n"); 477 | for (int i = 0; i < CC.items.size(); i++) { 478 | printf("%d\t", i); 479 | for (int j = 0; j < grammar.T.size(); j++) { 480 | if (action[i][j].first == 1) { 481 | printf("%c%d\t", 'S', action[i][j].second); 482 | } else if (action[i][j].first == 2) { 483 | printf("%c%d\t", 'R', action[i][j].second); 484 | } else if (action[i][j].first == 3) { 485 | printf("ACC\t"); 486 | } else { 487 | printf("\t"); 488 | } 489 | } 490 | printf("|\t"); 491 | for (int j = 1; j < grammar.N.size(); j++) { 492 | if (goton[i][j]) { 493 | printf("%d\t", goton[i][j]); 494 | } else { 495 | printf("\t"); 496 | } 497 | 498 | } 499 | printf("\n"); 500 | } 501 | } 502 | 503 | 504 | void initGrammar() 505 | { 506 | printf("Please enter the num of production:\n"); 507 | cin >> grammar.num; 508 | string s; 509 | printf("Please enter the production:\n"); 510 | for (int i = 0; i < grammar.num; i++) { 511 | cin >> s; 512 | Production tmp; 513 | tmp.left = s[0]; 514 | for (int j = 3; j < s.size(); j++) { 515 | tmp.rigths.push_back(s[j]); 516 | } 517 | grammar.prods.push_back(tmp); 518 | } 519 | printf("Please enter the non-terminators(end with #):\n"); 520 | char ch; 521 | cin >> ch; 522 | while (ch != '#') { 523 | grammar.N.push_back(ch); 524 | cin >> ch; 525 | } 526 | printf("Please enter the terminators(end with #):\n"); 527 | cin >> ch; 528 | while (ch != '#') { 529 | grammar.T.push_back(ch); 530 | cin >> ch; 531 | } 532 | /* 把$当作终结符 */ 533 | grammar.T.push_back('$'); 534 | /* 求FIRST集 */ 535 | getFirstSet(); 536 | 537 | /* 构建DFA和SLR1预测分析表 */ 538 | DFA(); 539 | productLR1AnalysisTabel(); 540 | 541 | /* 读入待分析串并初始化分析栈 */ 542 | printf("Please enter the String to be analyzed:\n"); 543 | cin >> str; 544 | str += '$'; 545 | ST.push(pair(0, '-')); 546 | } 547 | /* 分析程序 */ 548 | void process() 549 | { 550 | int ip = 0; 551 | printf("The ans:\n"); 552 | do { 553 | int s = ST.top().first; 554 | char a = str[ip]; 555 | int j = isInT(a) - 1; 556 | /* 移进 */ 557 | if (action[s][j].first == 1) { 558 | ST.push(pair(action[s][j].second, a)); 559 | ip = ip + 1; 560 | } else if (action[s][j].first == 2) { // 规约 561 | Production &P = grammar.prods[action[s][j].second]; 562 | /* 弹出并输出产生式 */ 563 | printf("%c->", P.left); 564 | for (int i = 0; i < P.rigths.size(); i++) { 565 | ST.pop(); 566 | printf("%c", P.rigths[i]); 567 | } 568 | printf("\n"); 569 | s = ST.top().first; 570 | char A = P.left; 571 | j = isInN(A) - 1; 572 | ST.push(pair(goton[s][j], A)); 573 | } else if (action[s][j].first == 3) { //接受 574 | printf("ACC\n"); 575 | return; 576 | } else { 577 | printf("error\n"); 578 | } 579 | } while(1); 580 | } 581 | int main() 582 | { 583 | initGrammar(); 584 | process(); 585 | return 0; 586 | } -------------------------------------------------------------------------------- /SLR1.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | using namespace std; 10 | 11 | /* 产生式结构体,左部符号和右部符号串 */ 12 | struct Production { 13 | char left; 14 | vector rigths; 15 | /* 重载== */ 16 | bool operator==(Production& rhs) const { 17 | if (left != rhs.left) 18 | return false; 19 | for (int i = 0; i < rigths.size(); i++) { 20 | if (i >= rhs.rigths.size()) 21 | return false; 22 | if (rigths[i] != rhs.rigths[i]) 23 | return false; 24 | } 25 | return true; 26 | } 27 | }; 28 | 29 | /* LR0项目 */ 30 | struct LR0Item { 31 | Production p; 32 | /* 点的位置 */ 33 | int location; 34 | }; 35 | 36 | /* LR0项目集 */ 37 | struct LR0Items { 38 | vector items; 39 | }; 40 | 41 | /* LR0项目集规范族 */ 42 | struct CanonicalCollection { 43 | /* 项目集集合 */ 44 | vector items; 45 | /* 保存DFA的图,first为转移到的状态序号,second是经什么转移 */ 46 | vector< pair > g[100]; 47 | }CC; 48 | 49 | /* 文法结构体 */ 50 | struct Grammar { 51 | int num; // 产生式数量 52 | vector T; // 终结符 53 | vector N; // 非终结符 54 | vector prods; //产生式 55 | }grammar; 56 | 57 | /* FIRST集和FOLLOW集 */ 58 | map > first; 59 | map > follow; 60 | 61 | /* DFA队列, 用于存储待转移的有效项目集 */ 62 | queue< pair > Q; 63 | 64 | /* action表和goto表 */ 65 | pair action[100][100]; // first表示分析动作,0->ACC 1->S 2->R second表示转移状态或者产生式序号 66 | int goton[100][100]; 67 | 68 | /* 待分析串 */ 69 | string str; 70 | /* 分析栈 */ 71 | stack< pair > ST; // first是state,second 是symble 72 | 73 | /* 判断ch是否是终结符 */ 74 | int isInT(char ch) 75 | { 76 | for (int i = 0; i < grammar.T.size(); i++) { 77 | if (grammar.T[i] == ch) { 78 | return i + 1; 79 | } 80 | } 81 | return 0; 82 | } 83 | /* 判断ch是否是非终结符 */ 84 | int isInN(char ch) 85 | { 86 | for (int i = 0; i < grammar.N.size(); i++) { 87 | if (grammar.N[i] == ch) { 88 | return i + 1; 89 | } 90 | } 91 | return 0; 92 | } 93 | /* 求(T U N)的FIRST集 */ 94 | void getFirstSet() 95 | { 96 | /* 终结符的FIRST集是其本身 */ 97 | for (int i = 0; i < grammar.T.size(); i++) { 98 | char X = grammar.T[i]; 99 | set tmp; 100 | tmp.insert(X); 101 | first[X] = tmp; 102 | } 103 | /* 当非终结符的FIRST集发生变化时循环 */ 104 | bool change = true; 105 | while (change) { 106 | change = false; 107 | /* 枚举每个产生式 */ 108 | for (int i = 0; i < grammar.prods.size(); i++) { 109 | Production &P = grammar.prods[i]; 110 | char X = P.left; 111 | set &FX = first[X]; 112 | /* 如果右部第一个符号是空或者是终结符,则加入到左部的FIRST集中 */ 113 | if (isInT(P.rigths[0]) || P.rigths[0] == '&') { 114 | /* 查找是否FIRST集是否已经存在该符号 */ 115 | auto it = FX.find(P.rigths[0]); 116 | /* 不存在 */ 117 | if (it == FX.end()) { 118 | change = true; // 标注FIRST集发生变化,循环继续 119 | FX.insert(P.rigths[0]); 120 | } 121 | } else { 122 | /* 当前符号是非终结符,且当前符号可以推出空,则还需判断下一个符号 */ 123 | bool next = true; 124 | /* 待判断符号的下标 */ 125 | int idx = 0; 126 | while (next && idx < P.rigths.size()) { 127 | next = false; 128 | char Y = P.rigths[idx]; 129 | set &FY = first[Y]; 130 | for (auto it = FY.begin(); it != FY.end(); it++) { 131 | /* 把当前符号的FIRST集中非空元素加入到左部符号的FIRST集中 */ 132 | if (*it != '&') { 133 | auto itt = FX.find(*it); 134 | if (itt == FX.end()) { 135 | change = true; 136 | FX.insert(*it); 137 | } 138 | } 139 | } 140 | /* 当前符号的FIRST集中有空, 标记next为真,idx下标+1 */ 141 | auto it = FY.find('&'); 142 | if (it != FY.end()) { 143 | next = true; 144 | idx = idx + 1; 145 | } 146 | } 147 | 148 | } 149 | } 150 | } 151 | 152 | printf("FIRST:\n"); 153 | for (int i = 0; i < grammar.N.size(); i++) { 154 | char X = grammar.N[i]; 155 | printf("%c: ", X); 156 | for (auto it = first[X].begin(); it != first[X].end(); it++) { 157 | printf("%c ", *it); 158 | } 159 | printf("\n"); 160 | } 161 | } 162 | /* 产找alpha串的FIRST集, 保存到FS集合中 */ 163 | void getFirstByAlphaSet(vector &alpha, set &FS) 164 | { 165 | /* 当前符号是非终结符,且当前符号可以推出空,则还需判断下一个符号 */ 166 | bool next = true; 167 | int idx = 0; 168 | while (idx < alpha.size() && next) { 169 | next = false; 170 | /* 当前符号是终结符或空,加入到FIRST集中 */ 171 | if (isInT(alpha[idx]) || alpha[idx] == '&') { 172 | /* 判断是否已经在FIRST集中 */ 173 | auto itt = FS.find(alpha[idx]); 174 | if (itt == FS.end()) { 175 | FS.insert(alpha[idx]); 176 | } 177 | } else { 178 | char B = alpha[idx]; 179 | set &FB = first[B]; 180 | for (auto it = first[B].begin(); it != first[B].end(); it++) { 181 | /* 当前符号FIRST集包含空,标记next为真,并跳过当前循环 */ 182 | if (*it == '&') { 183 | next = true; 184 | continue; 185 | } 186 | /* 把非空元素加入到FIRST集中 */ 187 | auto itt = FS.find(*it); 188 | if (itt == FS.end()) { 189 | FS.insert(*it); 190 | } 191 | } 192 | } 193 | idx = idx + 1; 194 | } 195 | /* 如果到达产生式右部末尾next还为真,说明alpha可以推空,将空加入到FIRST集中 */ 196 | if (next) { 197 | FS.insert('&'); 198 | } 199 | } 200 | /* 求非终结符的FOLLOW集 */ 201 | void getFollowSet() 202 | { 203 | /* 初始化终结符的FOLLOW集为空集 */ 204 | for (int i = 0; i < grammar.N.size(); i++) { 205 | char B = grammar.N[i]; 206 | follow[B] = set(); 207 | } 208 | /* 将$加入到文法的开始符号的FOLLOW集中 */ 209 | char S = grammar.N[0]; 210 | follow[S].insert('$'); 211 | 212 | bool change = true; 213 | while (change) { 214 | change = false; 215 | /* 枚举每个产生式 */ 216 | for (int i = 0; i < grammar.prods.size(); i++) { 217 | Production &P = grammar.prods[i]; 218 | for (int j = 0; j < P.rigths.size(); j++) { 219 | char B = P.rigths[j]; 220 | /* 当前符号是非终结符 */ 221 | if (isInN(B)) { 222 | set &FB = follow[B]; 223 | set FS; 224 | /* alpha是从当前符号下一个符号开始的符号串 */ 225 | vector alpha(P.rigths.begin() + j + 1, P.rigths.end()); 226 | /* 求alpha的FIRST集,即FS */ 227 | getFirstByAlphaSet(alpha, FS); 228 | // printf("%c:\n", B); 229 | /* 将alpha的FIRST集中所有非空元素加入到当前符号的FOLLOW集中 */ 230 | for (auto it = FS.begin(); it != FS.end(); it++) { 231 | // printf("%c ", *it); 232 | if (*it == '&') { 233 | continue; 234 | } 235 | auto itt = FB.find(*it); 236 | if (itt == FB.end()) { 237 | change = true; 238 | FB.insert(*it); 239 | } 240 | } 241 | // printf("\n"); 242 | /* 如果alpha能推空,或者当前符号是产生式右部末尾,则将文法左部符号的FOLLOW集加入到当前符号的FOLLOW集中 */ 243 | auto itt = FS.find('&'); 244 | if (itt != FS.end() || (j + 1) >= P.rigths.size()) { 245 | char A = P.left; 246 | for (auto it = follow[A].begin(); it != follow[A].end(); it++) { 247 | auto itt = FB.find(*it); 248 | if (itt == FB.end()) { 249 | change = true; 250 | FB.insert(*it); 251 | } 252 | } 253 | } 254 | } 255 | } 256 | } 257 | } 258 | 259 | printf("FOLLOW:\n"); 260 | for (int i = 0; i < grammar.N.size(); i++) { 261 | char X = grammar.N[i]; 262 | printf("%c: ", X); 263 | for (auto it = follow[X].begin(); it != follow[X].end(); it++) { 264 | printf("%c ", *it); 265 | } 266 | printf("\n"); 267 | } 268 | } 269 | /* 判断是LR0项目t否在有效项目集I中 */ 270 | bool isInLR0Items(LR0Items &I, LR0Item &t) 271 | { 272 | for (auto it = I.items.begin(); it != I.items.end(); it++) { 273 | LR0Item &item = *it; 274 | if (item.p == t.p && item.location == t.location) 275 | return true; 276 | } 277 | return false; 278 | } 279 | 280 | /* 打印某个项目集 */ 281 | void printLR0Items(LR0Items &I) 282 | { 283 | for (auto it = I.items.begin(); it != I.items.end(); it++) { 284 | LR0Item &L = *it; 285 | printf("%c->", L.p.left); 286 | for (int i = 0; i < L.p.rigths.size(); i++) { 287 | if (L.location == i) 288 | printf("."); 289 | printf("%c", L.p.rigths[i]); 290 | } 291 | if (L.location == L.p.rigths.size()) 292 | printf("."); 293 | printf(" "); 294 | } 295 | printf("\n"); 296 | } 297 | 298 | /* 求I的闭包 */ 299 | void closure(LR0Items &I) 300 | { 301 | bool change = true; 302 | while (change) { 303 | change = false; 304 | LR0Items J; 305 | /* 枚举每个项目 */ 306 | J.items.assign(I.items.begin(), I.items.end()); 307 | for (auto it = J.items.begin(); it != J.items.end(); it++) { 308 | LR0Item &L = *it; 309 | /* 非规约项目 */ 310 | if (L.location < L.p.rigths.size()) { 311 | char B = L.p.rigths[L.location]; 312 | if (isInN(B)) { 313 | /* 把符合条件的LR0项目加入闭包中 */ 314 | for (int i = 0; i < grammar.prods.size(); i++) { 315 | Production &P = grammar.prods[i]; 316 | if (P.left == B) { 317 | LR0Item t; 318 | t.location = 0; 319 | t.p.left = P.left; 320 | t.p.rigths.assign(P.rigths.begin(), P.rigths.end()); 321 | if (!isInLR0Items(I, t)) { 322 | /* 标记改变 */ 323 | change = true; 324 | I.items.push_back(t); 325 | } 326 | } 327 | } 328 | } 329 | } 330 | } 331 | } 332 | } 333 | /* 判断是否在项目集规范族中,若在返回序号 */ 334 | int isInCanonicalCollection(LR0Items &I) 335 | { 336 | for (int i = 0; i < CC.items.size(); i++) { 337 | LR0Items &J = CC.items[i]; 338 | bool flag = true; 339 | if (J.items.size() != I.items.size()) { 340 | flag = false; 341 | continue; 342 | } 343 | /* 每个项目都在该项目集中,则认为这个两个项目集相等 */ 344 | for (auto it = I.items.begin(); it != I.items.end(); it++) { 345 | LR0Item &t = *it; 346 | if (!isInLR0Items(J, t)) { 347 | flag = false; 348 | break; 349 | } 350 | } 351 | if (flag) { 352 | return i + 1; 353 | } 354 | } 355 | return 0; 356 | } 357 | 358 | /* 转移函数,I为当前的项目集,J为转移后的项目集, 经X转移 */ 359 | void go(LR0Items &I, char X, LR0Items &J) 360 | { 361 | for (auto it = I.items.begin(); it != I.items.end(); it++) { 362 | LR0Item &L = *it; 363 | /* 非规约项目 */ 364 | if (L.location < L.p.rigths.size()) { 365 | char B = L.p.rigths[L.location]; 366 | /* 如果点后面是非终结符,且非终结符为X,点位置加1, 加入到转移项目集中*/ 367 | if (B == X) { 368 | LR0Item t; 369 | t.location = L.location + 1; 370 | t.p.left = L.p.left; 371 | t.p.rigths.assign(L.p.rigths.begin(), L.p.rigths.end()); 372 | J.items.push_back(t); 373 | } 374 | } 375 | } 376 | /* 若J中有项目,则求其闭包 */ 377 | if (J.items.size() > 0) { 378 | closure(J); 379 | } 380 | } 381 | 382 | /* 构建DFA和项目集规范族 */ 383 | void DFA() 384 | { 385 | /* 构建初始项目集 */ 386 | LR0Item t; 387 | t.location = 0; 388 | t.p.left = grammar.prods[0].left; 389 | t.p.rigths.assign(grammar.prods[0].rigths.begin(), grammar.prods[0].rigths.end()); 390 | LR0Items I; 391 | I.items.push_back(t); 392 | closure(I); 393 | /* 加入初始有效项目集 */ 394 | CC.items.push_back(I); 395 | /* 把新加入的有效项目集加入待扩展队列中 */ 396 | Q.push(pair(I, 0)); 397 | while (!Q.empty()) { 398 | LR0Items &S = Q.front().first; 399 | int sidx = Q.front().second; 400 | /* 遍历每个终结符 */ 401 | for (int i = 0; i < grammar.T.size(); i++) { 402 | LR0Items D; 403 | go(S, grammar.T[i], D); 404 | int idx; 405 | /* 若不为空 */ 406 | if (D.items.size() > 0) { 407 | /* 查找是否已经在有效项目集族里 */ 408 | idx = isInCanonicalCollection(D); 409 | if (idx > 0) { 410 | idx = idx - 1; 411 | } else { 412 | idx = CC.items.size(); 413 | CC.items.push_back(D); 414 | /* 把新加入的有效项目集加入待扩展队列中 */ 415 | Q.push(pair(D, idx)); 416 | } 417 | /* 从原状态到转移状态加一条边,边上的值为转移符号 */ 418 | CC.g[sidx].push_back(pair(grammar.T[i], idx)); 419 | } 420 | } 421 | /* 遍历每个非终结符 */ 422 | for (int i = 0; i < grammar.N.size(); i++) { 423 | LR0Items D; 424 | go(S, grammar.N[i], D); 425 | int idx; 426 | if (D.items.size() > 0) { 427 | /* 查找是否已经在有效项目集族里 */ 428 | idx = isInCanonicalCollection(D); 429 | if (idx != 0) { 430 | idx = idx - 1; 431 | } else { 432 | idx = CC.items.size(); 433 | CC.items.push_back(D); 434 | /* 把新加入的有效项目集加入待扩展队列中 */ 435 | Q.push(pair(D, idx)); 436 | } 437 | /* 从原状态到转移状态加一条边,边上的值为转移符号 */ 438 | CC.g[sidx].push_back(pair(grammar.N[i], idx)); 439 | } 440 | } 441 | /* 当前状态扩展完毕,移除队列*/ 442 | Q.pop(); 443 | } 444 | 445 | printf("CC size: %d\n", CC.items.size()); 446 | for (int i = 0; i < CC.items.size(); i++) { 447 | printf("LR0Items %d:\n", i); 448 | printLR0Items(CC.items[i]); 449 | for (int j = 0; j < CC.g[i].size(); j++) { 450 | pair p= CC.g[i][j]; 451 | printf("to %d using %c\n", p.second, p.first); 452 | } 453 | } 454 | } 455 | /* 生成SLR1分析表 */ 456 | void productSLR1AnalysisTabel() 457 | { 458 | for (int i = 0; i < CC.items.size(); i++) { 459 | LR0Items &LIt= CC.items[i]; 460 | /* 构建action表 */ 461 | for (auto it = LIt.items.begin(); it != LIt.items.end(); it++) { 462 | LR0Item &L = *it; 463 | /* 非规约项目 */ 464 | if (L.location < L.p.rigths.size()) { 465 | char a = L.p.rigths[L.location]; 466 | int j = isInT(a); 467 | /* a是终结符 */ 468 | if (j > 0) { 469 | j = j - 1; 470 | /* 找到对应a的出边,得到其转移到的状态 */ 471 | for (int k = 0; k < CC.g[i].size(); k++) { 472 | pair p = CC.g[i][k]; 473 | if (p.first == a) { 474 | action[i][j].first = 1; // 1->S 475 | action[i][j].second = p.second; //转移状态 476 | break; 477 | } 478 | } 479 | } 480 | } else { // 规约项目 481 | /* 接受项目 */ 482 | if (L.p.left == grammar.prods[0].left) { 483 | action[i][grammar.T.size() - 1].first = 3; 484 | } else { 485 | char A = L.p.left; 486 | for (auto a = follow[A].begin(); a != follow[A].end(); a++) { 487 | int j = isInT(*a); 488 | /* 终结符 */ 489 | if (j > 0) { 490 | j = j - 1; 491 | /* 找到产生式对应的序号 */ 492 | for (int k = 0; k < grammar.prods.size(); k++) { 493 | if (L.p == grammar.prods[k]) { 494 | action[i][j].first = 2; 495 | action[i][j].second = k; 496 | break; 497 | } 498 | } 499 | } 500 | } 501 | } 502 | } 503 | } 504 | /* 构建goto表 */ 505 | for (int k = 0; k < CC.g[i].size(); k++) { 506 | pair p = CC.g[i][k]; 507 | char A = p.first; 508 | int j = isInN(A); 509 | /* 终结符 */ 510 | if (j > 0) { 511 | j = j - 1; 512 | goton[i][j] = p.second; //转移状态 513 | } 514 | } 515 | } 516 | /* 打印SLR1分析表 */ 517 | for (int i = 0; i < grammar.T.size() / 2; i++) 518 | printf("\t"); 519 | printf("action"); 520 | for (int i = 0; i < grammar.N.size() / 2 + grammar.T.size() / 2 + 1; i++) 521 | printf("\t"); 522 | printf("goto\n"); 523 | printf("\t"); 524 | for (int i = 0; i < grammar.T.size(); i++) { 525 | printf("%c\t", grammar.T[i]); 526 | } 527 | printf("|\t"); 528 | for (int i = 1; i < grammar.N.size(); i++) { 529 | printf("%c\t", grammar.N[i]); 530 | } 531 | printf("\n"); 532 | for (int i = 0; i < CC.items.size(); i++) { 533 | printf("%d\t", i); 534 | for (int j = 0; j < grammar.T.size(); j++) { 535 | if (action[i][j].first == 1) { 536 | printf("%c%d\t", 'S', action[i][j].second); 537 | } else if (action[i][j].first == 2) { 538 | printf("%c%d\t", 'R', action[i][j].second); 539 | } else if (action[i][j].first == 3) { 540 | printf("ACC\t"); 541 | } else { 542 | printf("\t"); 543 | } 544 | } 545 | printf("|\t"); 546 | for (int j = 1; j < grammar.N.size(); j++) { 547 | if (goton[i][j]) { 548 | printf("%d\t", goton[i][j]); 549 | } else { 550 | printf("\t"); 551 | } 552 | 553 | } 554 | printf("\n"); 555 | } 556 | } 557 | 558 | 559 | void initGrammar() 560 | { 561 | printf("Please enter the num of production:\n"); 562 | cin >> grammar.num; 563 | string s; 564 | printf("Please enter the production:\n"); 565 | for (int i = 0; i < grammar.num; i++) { 566 | cin >> s; 567 | Production tmp; 568 | tmp.left = s[0]; 569 | for (int j = 3; j < s.size(); j++) { 570 | tmp.rigths.push_back(s[j]); 571 | } 572 | grammar.prods.push_back(tmp); 573 | } 574 | printf("Please enter the non-terminators(end with #):\n"); 575 | char ch; 576 | cin >> ch; 577 | while (ch != '#') { 578 | grammar.N.push_back(ch); 579 | cin >> ch; 580 | } 581 | printf("Please enter the terminators(end with #):\n"); 582 | cin >> ch; 583 | while (ch != '#') { 584 | grammar.T.push_back(ch); 585 | cin >> ch; 586 | } 587 | /* 把$当作终结符 */ 588 | grammar.T.push_back('$'); 589 | /* 求FIRST集和FOLLOW集 */ 590 | getFirstSet(); 591 | getFollowSet(); 592 | 593 | /* 构建DFA和SLR1预测分析表 */ 594 | DFA(); 595 | productSLR1AnalysisTabel(); 596 | 597 | /* 读入待分析串并初始化分析栈 */ 598 | printf("Please enter the String to be analyzed:\n"); 599 | cin >> str; 600 | str += '$'; 601 | ST.push(pair(0, '-')); 602 | } 603 | /* 分析程序 */ 604 | void process() 605 | { 606 | int ip = 0; 607 | printf("The ans:\n"); 608 | do { 609 | int s = ST.top().first; 610 | char a = str[ip]; 611 | int j = isInT(a) - 1; 612 | /* 移进 */ 613 | if (action[s][j].first == 1) { 614 | ST.push(pair(action[s][j].second, a)); 615 | ip = ip + 1; 616 | } else if (action[s][j].first == 2) { // 规约 617 | Production &P = grammar.prods[action[s][j].second]; 618 | /* 弹出并输出产生式 */ 619 | printf("%c->", P.left); 620 | for (int i = 0; i < P.rigths.size(); i++) { 621 | ST.pop(); 622 | printf("%c", P.rigths[i]); 623 | } 624 | printf("\n"); 625 | s = ST.top().first; 626 | char A = P.left; 627 | j = isInN(A) - 1; 628 | ST.push(pair(goton[s][j], A)); 629 | } else if (action[s][j].first == 3) { //接受 630 | printf("ACC\n"); 631 | return; 632 | } else { 633 | printf("error\n"); 634 | } 635 | } while(1); 636 | } 637 | int main() 638 | { 639 | initGrammar(); 640 | process(); 641 | return 0; 642 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 语法分析程序的设计与实现 2 | 3 | 4 | 5 | ## 环境 6 | 7 | 1. win10 8 | 2. vscode 9 | 3. mingw 10 | 11 | 12 | 13 | ## 综述 14 | 15 | 共实现了三种语法分析程序,即LL1、SLR1和LR1语法分析程序,对满足条件的输入文法能够自动的生成该文法的语法分析程序并执行分析过程,输出所采用的产生式。 16 | 17 | 对于LL1语法分析程序有以下功能(要求输入文法为LL1文法) 18 | 19 | - 自动构建FIRST集 20 | - 自动构建FOLLOW集 21 | - 自动构建预测分析表 22 | - 执行分析程序分析输入串 23 | - 输出所采用的产生式 24 | 25 | 对于SLR1分析程序有以下功能(要求输入文法为SLR1文法) 26 | 27 | - 自动构建FIRST集 28 | - 自动构建FOLLOW集 29 | - 自动构建有效项目集规范族和DFA 30 | - 自动构建SLR1分析表 31 | - 执行分析程序分析输入串 32 | - 输出所采用的产生式 33 | 34 | 对于LR1分析程序有以下功能(要求输入文法为LR1文法) 35 | 36 | - 自动构建FIRST集 37 | - 自动构建有效项目集规范族和DFA 38 | - 自动构建LR1分析表 39 | - 执行分析程序分析输入串 40 | - 输出所采用的产生式 41 | 42 | 43 | 44 | 三种语法分析程序均要求输入的文法符号为**单个**字符,请将原文法符号不是单个字符自行更换为单文法符号,如S'更换为A,id更换为n,以此类推。具体输入格式见每个程序测试部分的输入样例。 45 | 46 | 47 | 48 | ## LL1语法分析程序 49 | 50 | ### 数据结构 51 | 52 | ```cpp 53 | /* 产生式结构体 */ 54 | struct Production { 55 | char left; // 左部符号 56 | vector rigths; // 右部符号串 57 | }; 58 | 59 | /* 文法结构体 */ 60 | struct Grammar { 61 | int num; // 产生式数量 62 | vector T; // 终结符集 63 | vector N; // 非终结符集 64 | vector prods; //产生式集 65 | } grammar; 66 | 67 | /* FIRST集和FOLLOW集 */ 68 | map > first; 69 | map > follow; 70 | 71 | /* 分析栈 */ 72 | stack ST; 73 | 74 | /* 待分析串 */ 75 | string str; 76 | 77 | /* 预测分析表 */ 78 | vector M[50][50]; 79 | ``` 80 | 81 | ### 辅助函数 82 | 83 | ```cpp 84 | /* 判断ch是否是终结符, 若是返回所在位置 */ 85 | int isInT(char ch); 86 | 87 | /* 判断ch是否是非终结符, 若是返回所在位置 */ 88 | int isInN(char ch); 89 | 90 | /* 读入并初始化语法 */ 91 | void initGrammar(); 92 | 93 | /* 把生成式插入到预测分析表对应的项中 */ 94 | void insertTOForecastAnalysisTable(char A, char a, Production &P); 95 | 96 | /* 取出预测分析表对应的项中的产生式 */ 97 | void getFromForecastAnalysisTable(char A, char a, vector &s); 98 | 99 | ``` 100 | 101 | ### 构建FIRST集和FOLLOW集 102 | 103 | #### 求单个文法符号的FIRST集 104 | 105 | ![image-20191126143323246](%E8%AF%AD%E6%B3%95%E5%88%86%E6%9E%90.assets/image-20191126143323246.png) 106 | 107 | ```cpp 108 | /* 求(T U N)的FIRST集 */ 109 | void getFirstSet() 110 | { 111 | /* 终结符的FIRST集是其本身 */ 112 | for (int i = 0; i < grammar.T.size(); i++) { 113 | char X = grammar.T[i]; 114 | set tmp; 115 | tmp.insert(X); 116 | first[X] = tmp; 117 | } 118 | /* 当非终结符的FIRST集发生变化时循环 */ 119 | bool change = true; 120 | while (change) { 121 | change = false; 122 | /* 枚举每个产生式 */ 123 | for (int i = 0; i < grammar.prods.size(); i++) { 124 | Production &P = grammar.prods[i]; 125 | char X = P.left; 126 | set &FX = first[X]; 127 | /* 如果右部第一个符号是空或者是终结符,则加入到左部的FIRST集中 */ 128 | if (isInT(P.rigths[0]) || P.rigths[0] == '&') { 129 | /* 查找是否FIRST集是否已经存在该符号 */ 130 | auto it = FX.find(P.rigths[0]); 131 | /* 不存在 */ 132 | if (it == FX.end()) { 133 | change = true; // 标注FIRST集发生变化,循环继续 134 | FX.insert(P.rigths[0]); 135 | } 136 | } else { 137 | /* 当前符号是非终结符,若当前符号可以推出空,则还需判断下一个符号 */ 138 | bool next = true; 139 | /* 待判断符号的下标 */ 140 | int idx = 0; 141 | while (next && idx < P.rigths.size()) { 142 | next = false; 143 | char Y = P.rigths[idx]; 144 | set &FY = first[Y]; 145 | for (auto it = FY.begin(); it != FY.end(); it++) { 146 | /* 把当前符号的FIRST集中非空元素加入到左部符号的FIRST集中 */ 147 | if (*it != '&') { 148 | auto itt = FX.find(*it); 149 | if (itt == FX.end()) { 150 | change = true; 151 | FX.insert(*it); 152 | } 153 | } 154 | } 155 | /* 当前符号的FIRST集中有空, 标记next为真,idx下标+1 */ 156 | auto it = FY.find('&'); 157 | if (it != FY.end()) { 158 | next = true; 159 | idx = idx + 1; 160 | } 161 | } 162 | } 163 | } 164 | } 165 | } 166 | ``` 167 | 168 | #### 求一串文法符号的FIRST集 169 | 170 | 要求FIRST($\alpha$),先将$\alpha$的第一个文法符号的FIRST集加入到加入到FIRST($\alpha$),若当前符号的FIRST集含空,则继续将下一个文法符号的FIRST加入到FIRST($\alpha$)中,直至末尾。 171 | 172 | ```cpp 173 | /* 产找alpha串的FIRST集, 保存到FS集合中 */ 174 | void getFirstByAlphaSet(vector &alpha, set &FS) 175 | { 176 | /* 当前符号是非终结符,若当前符号可以推出空,则还需判断下一个符号 */ 177 | bool next = true; 178 | int idx = 0; 179 | while (idx < alpha.size() && next) { 180 | next = false; 181 | /* 当前符号是终结符或空,加入到FIRST集中 */ 182 | if (isInT(alpha[idx]) || alpha[idx] == '&') { 183 | /* 判断是否已经在FIRST集中 */ 184 | auto itt = FS.find(alpha[idx]); 185 | if (itt == FS.end()) { 186 | FS.insert(alpha[idx]); 187 | } 188 | } else { 189 | char B = alpha[idx]; 190 | set &FB = first[B]; 191 | for (auto it = first[B].begin(); it != first[B].end(); it++) { 192 | /* 当前符号FIRST集包含空,标记next为真,并跳过当前循环 */ 193 | if (*it == '&') { 194 | next = true; 195 | continue; 196 | } 197 | /* 把非空元素加入到FIRST集中 */ 198 | auto itt = FS.find(*it); 199 | if (itt == FS.end()) { 200 | FS.insert(*it); 201 | } 202 | } 203 | } 204 | idx = idx + 1; 205 | } 206 | /* 如果到达产生式右部末尾next还为真,说明alpha可以推空,将空加入到FIRST集中 */ 207 | if (next) { 208 | FS.insert('&'); 209 | } 210 | } 211 | ``` 212 | 213 | #### 求非终结符的FOLLOW集 214 | 215 | ![image-20191126144856856](%E8%AF%AD%E6%B3%95%E5%88%86%E6%9E%90.assets/image-20191126144856856.png) 216 | 217 | ```cpp 218 | /* 求非终结符的FOLLOW集 */ 219 | void getFollowSet() 220 | { 221 | /* 初始化终结符的FOLLOW集为空集 */ 222 | for (int i = 0; i < grammar.N.size(); i++) { 223 | char B = grammar.N[i]; 224 | follow[B] = set(); 225 | } 226 | /* 将$加入到文法的开始符号的FOLLOW集中 */ 227 | char S = grammar.N[0]; 228 | follow[S].insert('$'); 229 | 230 | bool change = true; 231 | while (change) { 232 | change = false; 233 | /* 枚举每个产生式 */ 234 | for (int i = 0; i < grammar.prods.size(); i++) { 235 | Production &P = grammar.prods[i]; 236 | for (int j = 0; j < P.rigths.size(); j++) { 237 | char B = P.rigths[j]; 238 | /* 当前符号是非终结符 */ 239 | if (isInN(B)) { 240 | set &FB = follow[B]; 241 | set FS; 242 | /* alpha是从当前符号下一个符号开始的符号串 */ 243 | vector alpha(P.rigths.begin() + j + 1, P.rigths.end()); 244 | /* 求alpha的FIRST集,即FS */ 245 | getFirstByAlphaSet(alpha, FS); 246 | /* 将alpha的FIRST集中所有非空元素加入到当前符号的FOLLOW集中 */ 247 | for (auto it = FS.begin(); it != FS.end(); it++) { 248 | if (*it == '&') { 249 | continue; 250 | } 251 | auto itt = FB.find(*it); 252 | if (itt == FB.end()) { 253 | change = true; 254 | FB.insert(*it); 255 | } 256 | } 257 | /* 如果alpha能推空,或者当前符号是产生式右部末尾,则将文法左部符号的FOLLOW集加入到当前符号的FOLLOW集中 */ 258 | auto itt = FS.find('&'); 259 | if (itt != FS.end() || (j + 1) >= P.rigths.size()) { 260 | char A = P.left; //A为左部符号 261 | for (auto it = follow[A].begin(); it != follow[A].end(); it++) { 262 | auto itt = FB.find(*it); 263 | if (itt == FB.end()) { 264 | change = true; 265 | FB.insert(*it); 266 | } 267 | } 268 | } 269 | } 270 | } 271 | } 272 | } 273 | } 274 | ``` 275 | 276 | ### 构建预测分析表 277 | 278 | ![image-20191126145227507](%E8%AF%AD%E6%B3%95%E5%88%86%E6%9E%90.assets/image-20191126145227507.png) 279 | 280 | ```cpp 281 | /* 构建预测分析表 */ 282 | void productForecastAnalysisTable() 283 | { 284 | /* 枚举所有产生式 */ 285 | for (int i = 0; i < grammar.prods.size(); i++) { 286 | /* 假设P为 A->alpha */ 287 | Production &P = grammar.prods[i]; 288 | set FS; 289 | /* 对每个 a in FIRST(alpha) 把 A->alpha放入M[A, a]中 */ 290 | getFirstByAlphaSet(P.rigths, FS); 291 | for (auto it = FS.begin(); it != FS.end(); it++) { 292 | insertTOForecastAnalysisTable(P.left, *it, P); 293 | } 294 | /* 如果alpha能推空,则把每个b in FOLLOW(A) 把 A->alpha放入M[A, b]中*/ 295 | auto itt = FS.find('&'); 296 | if (itt != FS.end()) { 297 | for (auto it = follow[P.left].begin(); it != follow[P.left].end(); it++) { 298 | insertTOForecastAnalysisTable(P.left, *it, P); 299 | } 300 | } 301 | } 302 | } 303 | ``` 304 | 305 | 306 | 307 | ### 分析程序 308 | 309 | ![image-20191126145547747](%E8%AF%AD%E6%B3%95%E5%88%86%E6%9E%90.assets/image-20191126145547747.png) 310 | 311 | ```cpp 312 | /* 分析程序 */ 313 | void process() 314 | { 315 | /* 指向当前字符 */ 316 | int ip = 0; 317 | /* 栈顶符号X, 和当前输入符号a */ 318 | char X, a; 319 | printf("The answer:\n"); 320 | do{ 321 | X = ST.top(); 322 | a = str[ip]; 323 | /* 如果是终结符或者$ */ 324 | if (isInT(X)) { 325 | /* 如果栈顶符号和当前符号匹配,出栈,指针前移 */ 326 | if (X == a) { 327 | ST.pop(); 328 | ip = ip + 1; 329 | } else { /* 不匹配报错 */ 330 | printf("error1\n"); 331 | } 332 | } else { //非终结符 333 | vector s; 334 | /* 取出对应预测分析表的项 */ 335 | getFromForecastAnalysisTable(X, a, s); 336 | /* 预测分析表项中有元素 */ 337 | if (!s.empty()) { 338 | /* 弹栈并将右部符号串逆序入栈 */ 339 | ST.pop(); 340 | for (int i = s.size() - 1; i >= 3; i--) { 341 | if (s[i] != '&') { // 为空时不入栈 342 | ST.push(s[i]); 343 | } 344 | } 345 | /* 输出产生式 */ 346 | for (int i = 0; i < s.size(); i++) { 347 | printf("%c", s[i]); 348 | } 349 | printf("\n"); 350 | } else { // 空,报错 351 | printf("error2\n"); 352 | } 353 | } 354 | } while (X != '$'); 355 | } 356 | ``` 357 | 358 | 359 | 360 | ### 测试 361 | 362 | #### 编译源程序 363 | 364 | ```shell 365 | g++ -o LL1 LL1.cpp 366 | ``` 367 | 368 | #### 执行LL1分析程序 369 | 370 | ```shell 371 | .\LL1.exe 372 | ``` 373 | 374 | 输入一下内容 375 | 376 | ``` 377 | 10 378 | E->TA 379 | A->+TA 380 | A->-TA 381 | A->& 382 | T->FB 383 | B->*FB 384 | B->/FB 385 | B->& 386 | F->(E) 387 | F->n 388 | E T A F B # 389 | n + - * / ( ) # 390 | (n+n)*n-n/n 391 | ``` 392 | 393 | #### 查看输出结果 394 | 395 | ##### FIRST集和FOLLOW集 396 | 397 | ``` 398 | FIRST: 399 | E: ( n 400 | T: ( n 401 | A: & + - 402 | F: ( n 403 | B: & * / 404 | FOLLOW: 405 | E: $ ) 406 | T: $ ) + - 407 | A: $ ) 408 | F: $ ) * + - / 409 | B: $ ) + - 410 | ``` 411 | 412 | ##### 预测分析表 413 | 414 | ![image-20191126151740466](%E8%AF%AD%E6%B3%95%E5%88%86%E6%9E%90.assets/image-20191126151740466.png) 415 | 416 | ##### 输出产生式 417 | 418 | ``` 419 | The answer: 420 | E->TA 421 | T->FB 422 | F->(E) 423 | E->TA 424 | T->FB 425 | F->n 426 | B->& 427 | A->+TA 428 | T->FB 429 | F->n 430 | B->& 431 | A->& 432 | B->*FB 433 | F->n 434 | B->& 435 | A->-TA 436 | T->FB 437 | F->n 438 | B->/FB 439 | F->n 440 | B->& 441 | A->& 442 | ``` 443 | 444 | LL1输出**最左推导**,下面验证其正确性。 445 | 446 | E=>TA=>FBA=>(E)BA=>(TA)BA=>(FBA)BA=>(nBA)BA=>(nA)BA=>(n+TA)BA=>(n+FBA)BA=>(n+nBA)BA=>(n+nA)BA=>(n+n)BA=>(n+n)*FBA=>(n+n)\*nBA=>(n+n)\*nA=>(n+n)\*n-TA=>(n+n)\*n-FBA=>(n+n)\*n-nBA=>(n+n)\*n-n/FBA=>(n+n)\*n-n/nBA=>(n+n)\*n-n/nA=>(n+n)\*n-n/n 447 | 448 | 可以看到,从输出的产生式可以**最左推导**出我们输入的分析串。 449 | 450 | 经验证,上述所求的FIRST集、FOLLOW集、预测分析表和输出的产生式均正确。LL1语法分析程序工作正常。 451 | 452 | 453 | 454 | ## SLR1语法分析程序 455 | 456 | 457 | 458 | ### 数据结构 459 | 460 | ```cpp 461 | /* 产生式结构体,左部符号和右部符号串 */ 462 | struct Production { 463 | char left; 464 | vector rigths; 465 | }; 466 | 467 | /* LR0项目 */ 468 | struct LR0Item { 469 | Production p; 470 | /* 点的位置 */ 471 | int location; 472 | }; 473 | /* LR0项目集 */ 474 | struct LR0Items { 475 | vector items; 476 | }; 477 | /* LR0项目集规范族 */ 478 | struct CanonicalCollection { 479 | /* 项目集集合 */ 480 | vector items; 481 | /* 保存DFA的图,first为转移到的状态序号,second是经什么转移 */ 482 | vector< pair > g[100]; 483 | }CC; 484 | 485 | /* 文法结构体 */ 486 | struct Grammar { 487 | int num; // 产生式数量 488 | vector T; // 终结符 489 | vector N; // 非终结符 490 | vector prods; //产生式 491 | }grammar; 492 | 493 | /* FIRST集和FOLLOW集 */ 494 | map > first; 495 | map > follow; 496 | 497 | /* DFA队列, 用于存储待转移的有效项目集 */ 498 | queue< pair > Q; 499 | 500 | /* action表和goto表 */ 501 | pair action[100][100]; // first表示分析动作,0->ACC 1->S 2->R second表示转移状态或者产生式序号 502 | int goton[100][100]; 503 | 504 | /* 待分析串 */ 505 | string str; 506 | /* 分析栈 */ 507 | stack< pair > ST; // first是state,second 是symble 508 | ``` 509 | 510 | 511 | 512 | ### 辅助函数 513 | 514 | ```cpp 515 | /* 判断ch是否是非终结符, 若是返回其序号 */ 516 | int isInN(char ch); 517 | 518 | /* 判断ch是否是终结符, 若是返回其序号 */ 519 | int isInT(char ch); 520 | 521 | /* 求(T U N)的FIRST集 */ 522 | void getFirstSet(); 523 | 524 | /* 产找alpha串的FIRST集, 保存到FS集合中 */ 525 | void getFirstByAlphaSet(vector &alpha, set &FS); 526 | 527 | /* 求非终结符的FOLLOW集 */ 528 | void getFollowSet(); 529 | 530 | /* 判断是LR0项目t否在有效项目集I中 */ 531 | bool isInLR0Items(LR0Items &I, LR0Item &t); 532 | 533 | /* 打印某个项目集 */ 534 | void printLR0Items(LR0Items &I); 535 | 536 | /* 判断是否在项目集规范族中,若在返回序号 */ 537 | int isInCanonicalCollection(LR0Items &I); 538 | 539 | /* 读入并初始化语法 */ 540 | void initGrammar(); 541 | ``` 542 | 543 | 544 | 545 | ### 计算闭包 546 | 547 | ![image-20191126183442960](%E8%AF%AD%E6%B3%95%E5%88%86%E6%9E%90.assets/image-20191126183442960.png) 548 | 549 | ```cpp 550 | /* 求I的闭包 */ 551 | void closure(LR0Items &I) 552 | { 553 | bool change = true; 554 | while (change) { 555 | change = false; 556 | LR0Items J; 557 | /* 枚举每个项目 */ 558 | J.items.assign(I.items.begin(), I.items.end()); 559 | for (auto it = J.items.begin(); it != J.items.end(); it++) { 560 | LR0Item &L = *it; 561 | /* 非规约项目 */ 562 | if (L.location < L.p.rigths.size()) { 563 | char B = L.p.rigths[L.location]; 564 | if (isInN(B)) { 565 | /* 把符合条件的LR0项目加入闭包中 */ 566 | for (int i = 0; i < grammar.prods.size(); i++) { 567 | Production &P = grammar.prods[i]; 568 | if (P.left == B) { 569 | LR0Item t; 570 | t.location = 0; 571 | t.p.left = P.left; 572 | t.p.rigths.assign(P.rigths.begin(), P.rigths.end()); 573 | if (!isInLR0Items(I, t)) { 574 | /* 标记改变 */ 575 | change = true; 576 | I.items.push_back(t); 577 | } 578 | } 579 | } 580 | } 581 | } 582 | } 583 | } 584 | } 585 | ``` 586 | 587 | 588 | 589 | ### 计算转移 590 | 591 | ![image-20191126183810269](%E8%AF%AD%E6%B3%95%E5%88%86%E6%9E%90.assets/image-20191126183810269.png) 592 | 593 | ```cpp 594 | /* 转移函数,I为当前的项目集,J为转移后的项目集, 经X转移 */ 595 | void go(LR0Items &I, char X, LR0Items &J) 596 | { 597 | for (auto it = I.items.begin(); it != I.items.end(); it++) { 598 | LR0Item &L = *it; 599 | /* 非规约项目 */ 600 | if (L.location < L.p.rigths.size()) { 601 | char B = L.p.rigths[L.location]; 602 | /* 如果点后面是非终结符,且非终结符为X,点位置加1, 加入到转移项目集中*/ 603 | if (B == X) { 604 | LR0Item t; 605 | t.location = L.location + 1; 606 | t.p.left = L.p.left; 607 | t.p.rigths.assign(L.p.rigths.begin(), L.p.rigths.end()); 608 | J.items.push_back(t); 609 | } 610 | } 611 | } 612 | /* 若J中有项目,则求其闭包 */ 613 | if (J.items.size() > 0) { 614 | closure(J); 615 | } 616 | } 617 | ``` 618 | 619 | 620 | 621 | ### 构建有效项目集规范族和DFA 622 | 623 | ![image-20191126184218556](%E8%AF%AD%E6%B3%95%E5%88%86%E6%9E%90.assets/image-20191126184218556.png) 624 | 625 | ```cpp 626 | /* 构建DFA和项目集规范族 */ 627 | void DFA() 628 | { 629 | /* 构建初始项目集 */ 630 | LR0Item t; 631 | t.location = 0; 632 | t.p.left = grammar.prods[0].left; 633 | t.p.rigths.assign(grammar.prods[0].rigths.begin(), grammar.prods[0].rigths.end()); 634 | LR0Items I; 635 | I.items.push_back(t); 636 | closure(I); 637 | /* 加入初始有效项目集 */ 638 | CC.items.push_back(I); 639 | /* 把新加入的有效项目集加入待扩展队列中 */ 640 | Q.push(pair(I, 0)); 641 | while (!Q.empty()) { 642 | LR0Items &S = Q.front().first; 643 | int sidx = Q.front().second; 644 | /* 遍历每个终结符 */ 645 | for (int i = 0; i < grammar.T.size(); i++) { 646 | LR0Items D; 647 | go(S, grammar.T[i], D); 648 | int idx; 649 | /* 若不为空 */ 650 | if (D.items.size() > 0) { 651 | /* 查找是否已经在有效项目集族里 */ 652 | idx = isInCanonicalCollection(D); 653 | if (idx > 0) { 654 | idx = idx - 1; 655 | } else { 656 | idx = CC.items.size(); 657 | CC.items.push_back(D); 658 | /* 把新加入的有效项目集加入待扩展队列中 */ 659 | Q.push(pair(D, idx)); 660 | } 661 | /* 从原状态到转移状态加一条边,边上的值为转移符号 */ 662 | CC.g[sidx].push_back(pair(grammar.T[i], idx)); 663 | } 664 | } 665 | /* 遍历每个非终结符 */ 666 | for (int i = 0; i < grammar.N.size(); i++) { 667 | LR0Items D; 668 | go(S, grammar.N[i], D); 669 | int idx; 670 | if (D.items.size() > 0) { 671 | /* 查找是否已经在有效项目集族里 */ 672 | idx = isInCanonicalCollection(D); 673 | if (idx != 0) { 674 | idx = idx - 1; 675 | } else { 676 | idx = CC.items.size(); 677 | CC.items.push_back(D); 678 | /* 把新加入的有效项目集加入待扩展队列中 */ 679 | Q.push(pair(D, idx)); 680 | } 681 | /* 从原状态到转移状态加一条边,边上的值为转移符号 */ 682 | CC.g[sidx].push_back(pair(grammar.N[i], idx)); 683 | } 684 | } 685 | /* 当前状态扩展完毕,移除队列*/ 686 | Q.pop(); 687 | } 688 | } 689 | ``` 690 | 691 | 692 | 693 | ### 生成分析表(SLR(1)) 694 | 695 | ![image-20191126184647328](%E8%AF%AD%E6%B3%95%E5%88%86%E6%9E%90.assets/image-20191126184647328.png) 696 | 697 | ```cpp 698 | /* 生成SLR1分析表 */ 699 | void productSLR1AnalysisTabel() 700 | { 701 | for (int i = 0; i < CC.items.size(); i++) { 702 | LR0Items &LIt= CC.items[i]; 703 | /* 构建action表 */ 704 | for (auto it = LIt.items.begin(); it != LIt.items.end(); it++) { 705 | LR0Item &L = *it; 706 | /* 非规约项目 */ 707 | if (L.location < L.p.rigths.size()) { 708 | char a = L.p.rigths[L.location]; 709 | int j = isInT(a); 710 | /* a是终结符 */ 711 | if (j > 0) { 712 | j = j - 1; 713 | /* 找到对应a的出边,得到其转移到的状态 */ 714 | for (int k = 0; k < CC.g[i].size(); k++) { 715 | pair p = CC.g[i][k]; 716 | if (p.first == a) { 717 | action[i][j].first = 1; // 1->S 718 | action[i][j].second = p.second; //转移状态 719 | break; 720 | } 721 | } 722 | } 723 | } else { // 规约项目 724 | /* 接受项目 */ 725 | if (L.p.left == grammar.prods[0].left) { 726 | action[i][grammar.T.size() - 1].first = 3; 727 | } else { 728 | char A = L.p.left; 729 | for (auto a = follow[A].begin(); a != follow[A].end(); a++) { 730 | int j = isInT(*a); 731 | /* 终结符 */ 732 | if (j > 0) { 733 | j = j - 1; 734 | /* 找到产生式对应的序号 */ 735 | for (int k = 0; k < grammar.prods.size(); k++) { 736 | if (L.p == grammar.prods[k]) { 737 | action[i][j].first = 2; 738 | action[i][j].second = k; 739 | break; 740 | } 741 | } 742 | } 743 | } 744 | } 745 | } 746 | } 747 | /* 构建goto表 */ 748 | for (int k = 0; k < CC.g[i].size(); k++) { 749 | pair p = CC.g[i][k]; 750 | char A = p.first; 751 | int j = isInN(A); 752 | /* 终结符 */ 753 | if (j > 0) { 754 | j = j - 1; 755 | goton[i][j] = p.second; //转移状态 756 | } 757 | } 758 | } 759 | } 760 | ``` 761 | 762 | 763 | 764 | ### 分析程序 765 | 766 | ![image-20191126185427849](%E8%AF%AD%E6%B3%95%E5%88%86%E6%9E%90.assets/image-20191126185427849.png) 767 | 768 | ```cpp 769 | /* 分析程序 */ 770 | void process() 771 | { 772 | int ip = 0; 773 | printf("The ans:\n"); 774 | do { 775 | int s = ST.top().first; 776 | char a = str[ip]; 777 | int j = isInT(a) - 1; 778 | /* 移进 */ 779 | if (action[s][j].first == 1) { 780 | ST.push(pair(action[s][j].second, a)); 781 | ip = ip + 1; 782 | } else if (action[s][j].first == 2) { // 规约 783 | Production &P = grammar.prods[action[s][j].second]; 784 | /* 弹出并输出产生式 */ 785 | printf("%c->", P.left); 786 | for (int i = 0; i < P.rigths.size(); i++) { 787 | ST.pop(); 788 | printf("%c", P.rigths[i]); 789 | } 790 | printf("\n"); 791 | s = ST.top().first; 792 | char A = P.left; 793 | j = isInN(A) - 1; 794 | ST.push(pair(goton[s][j], A)); 795 | } else if (action[s][j].first == 3) { //接受 796 | printf("ACC\n"); 797 | return; 798 | } else { 799 | printf("error\n"); 800 | } 801 | } while(1); 802 | } 803 | ``` 804 | 805 | 806 | 807 | ### 测试 808 | 809 | #### 编译源程序 810 | 811 | ```shell 812 | g++ -o SLR1 SLR1.cpp 813 | ``` 814 | 815 | #### 执行SLR1分析程序 816 | 817 | ``` 818 | .\SLR1.exe 819 | ``` 820 | 821 | 输入以下内容 822 | 823 | ``` 824 | 9 825 | A->E 826 | E->E+T 827 | E->E-T 828 | E->T 829 | T->T*F 830 | T->T/F 831 | T->F 832 | F->(E) 833 | F->n 834 | A E T F # 835 | n + - * / ( ) # 836 | (n+n)*n-n/n 837 | ``` 838 | 839 | #### 查看输出结果 840 | 841 | ##### FIRST和FOLLOW集 842 | 843 | ``` 844 | FIRST: 845 | A: ( n 846 | E: ( n 847 | T: ( n 848 | F: ( n 849 | FOLLOW: 850 | A: $ 851 | E: $ ) + - 852 | T: $ ) * + - / 853 | F: $ ) * + - / 854 | ``` 855 | 856 | ##### 查看项目集规范族和DFA 857 | 858 | ``` 859 | CC size: 16 860 | LR0Items 0: 861 | A->.E E->.E+T E->.E-T E->.T T->.T*F T->.T/F T->.F F->.(E) F->.n 862 | to 1 using n 863 | to 2 using ( 864 | to 3 using E 865 | to 4 using T 866 | to 5 using F 867 | LR0Items 1: 868 | F->n. 869 | LR0Items 2: 870 | F->(.E) E->.E+T E->.E-T E->.T T->.T*F T->.T/F T->.F F->.(E) F->.n 871 | to 1 using n 872 | to 2 using ( 873 | to 6 using E 874 | to 4 using T 875 | to 5 using F 876 | LR0Items 3: 877 | A->E. E->E.+T E->E.-T 878 | to 7 using + 879 | to 8 using - 880 | LR0Items 4: 881 | E->T. T->T.*F T->T./F 882 | to 9 using * 883 | to 10 using / 884 | LR0Items 5: 885 | T->F. 886 | LR0Items 6: 887 | F->(E.) E->E.+T E->E.-T 888 | to 7 using + 889 | to 8 using - 890 | to 11 using ) 891 | LR0Items 7: 892 | E->E+.T T->.T*F T->.T/F T->.F F->.(E) F->.n 893 | to 1 using n 894 | to 2 using ( 895 | to 12 using T 896 | to 5 using F 897 | LR0Items 8: 898 | E->E-.T T->.T*F T->.T/F T->.F F->.(E) F->.n 899 | to 1 using n 900 | to 2 using ( 901 | to 13 using T 902 | to 5 using F 903 | LR0Items 9: 904 | T->T*.F F->.(E) F->.n 905 | to 1 using n 906 | to 2 using ( 907 | to 14 using F 908 | LR0Items 10: 909 | T->T/.F F->.(E) F->.n 910 | to 1 using n 911 | to 2 using ( 912 | to 15 using F 913 | LR0Items 11: 914 | F->(E). 915 | LR0Items 12: 916 | E->E+T. T->T.*F T->T./F 917 | to 9 using * 918 | to 10 using / 919 | LR0Items 13: 920 | E->E-T. T->T.*F T->T./F 921 | to 9 using * 922 | to 10 using / 923 | LR0Items 14: 924 | T->T*F. 925 | LR0Items 15: 926 | T->T/F. 927 | ``` 928 | 929 | ##### 查看分析表 930 | 931 | ![image-20191126190440849](%E8%AF%AD%E6%B3%95%E5%88%86%E6%9E%90.assets/image-20191126190440849.png) 932 | 933 | ##### 查看输出产生式 934 | 935 | ``` 936 | The ans: 937 | F->n 938 | T->F 939 | E->T 940 | F->n 941 | T->F 942 | E->E+T 943 | F->(E) 944 | T->F 945 | F->n 946 | T->T*F 947 | E->T 948 | F->n 949 | T->F 950 | F->n 951 | T->T/F 952 | E->E-T 953 | ACC 954 | ``` 955 | 956 | LR输出的产生式是最右推导的逆序列,下面验证其正确性。 957 | 958 | E=>E-T=>E-T/F=>E-T/n=>E-F/n=>E-n/n=>T-n/n=>T*F-n/n=>T\*n-n/n=>F\*n-n/n=>(E)\*n-n/n=>(E+T)\*n-n/n=>(E+F)\*n-n/n=>(E+n)\*n-n/n=>(T+n)\*n-n/n=>(F+n)\*n-n/n=>(n+n)\*n-n/n 959 | 960 | 可以看出,上述产生式的确是**最右推导**的逆序列,所以其是正确的。 961 | 962 | 经验证,程序自动构建的有效项目集规范族和DFA均正确,其分析表亦正确,对给定的输出串分析输出的产生式验证也正确。 963 | 964 | 965 | 966 | ## LR1语法分析程序 967 | 968 | 仅仅对上面的SLR1语法分析程序做出少量的修改即可实现LR1语法分析程序。 969 | 970 | ### 添加向前看符号 971 | 972 | ```cpp 973 | /* LR1项目 */ 974 | struct LR1Item { 975 | Production p; 976 | /* 点的位置 */ 977 | int location; 978 | /* 向前看符号 */ 979 | char next; 980 | }; 981 | ``` 982 | 983 | 984 | 985 | ### 修改相关函数 986 | 987 | #### 闭包 988 | 989 | ![image-20191223184130454](%E8%AF%AD%E6%B3%95%E5%88%86%E6%9E%90.assets/image-20191223184130454.png) 990 | 991 | #### 转移函数 992 | 993 | ![image-20191223184234241](%E8%AF%AD%E6%B3%95%E5%88%86%E6%9E%90.assets/image-20191223184234241.png) 994 | 995 | #### 构造分析表 996 | 997 | 主要改动如下 998 | 999 | ![image-20191223184521125](%E8%AF%AD%E6%B3%95%E5%88%86%E6%9E%90.assets/image-20191223184521125.png) 1000 | 1001 | 上述函数的实现见源代码,相对于SLR1的改动不多。 1002 | 1003 | 1004 | 1005 | ### 测试 1006 | 1007 | #### 编译源文件 1008 | 1009 | ```shell 1010 | g++ -o LR1 LR1.cpp 1011 | ``` 1012 | 1013 | #### 执行LR1分析 程序 1014 | 1015 | ``` 1016 | .\LR1.exe 1017 | ``` 1018 | 1019 | 输入一下内容(LR1有效项目集族状态 较多,此处给出一个状态相对较少的例子) 1020 | 1021 | ``` 1022 | 4 1023 | A->S 1024 | S->CC 1025 | C->cC 1026 | C->d 1027 | A S C # 1028 | c d # 1029 | cccdcd 1030 | ``` 1031 | 1032 | #### 查看输出结果 1033 | 1034 | ##### FIRST集 1035 | 1036 | ``` 1037 | FIRST: 1038 | A: c d 1039 | S: c d 1040 | C: c d 1041 | ``` 1042 | 1043 | ##### 查看项目集规范族和DFA 1044 | 1045 | ``` 1046 | CC size: 10 1047 | LR1Items 0: 1048 | A->.S,$ S->.CC,$ C->.cC,c C->.cC,d C->.d,c C->.d,d 1049 | to 1 using c 1050 | to 2 using d 1051 | to 3 using S 1052 | to 4 using C 1053 | LR1Items 1: 1054 | C->c.C,c C->c.C,d C->.cC,c C->.d,c C->.cC,d C->.d,d 1055 | to 1 using c 1056 | to 2 using d 1057 | to 5 using C 1058 | LR1Items 2: 1059 | C->d.,c C->d.,d 1060 | LR1Items 3: 1061 | A->S.,$ 1062 | LR1Items 4: 1063 | S->C.C,$ C->.cC,$ C->.d,$ 1064 | to 6 using c 1065 | to 7 using d 1066 | to 8 using C 1067 | LR1Items 5: 1068 | C->cC.,c C->cC.,d 1069 | LR1Items 6: 1070 | C->c.C,$ C->.cC,$ C->.d,$ 1071 | to 6 using c 1072 | to 7 using d 1073 | to 9 using C 1074 | LR1Items 7: 1075 | C->d.,$ 1076 | LR1Items 8: 1077 | S->CC.,$ 1078 | LR1Items 9: 1079 | C->cC.,$ 1080 | ``` 1081 | 1082 | ##### 查看分析表 1083 | 1084 | ``` 1085 | action goto 1086 | c d $ | S C 1087 | 0 S1 S2 | 3 4 1088 | 1 S1 S2 | 5 1089 | 2 R3 R3 | 1090 | 3 ACC | 1091 | 4 S6 S7 | 8 1092 | 5 R2 R2 | 1093 | 6 S6 S7 | 9 1094 | 7 R3 | 1095 | 8 R1 | 1096 | 9 R2 | 1097 | ``` 1098 | 1099 | ##### 查看输出产生式 1100 | 1101 | ``` 1102 | The ans: 1103 | C->d 1104 | C->cC 1105 | C->cC 1106 | C->cC 1107 | C->d 1108 | C->cC 1109 | S->CC 1110 | ACC 1111 | ``` 1112 | 1113 | LR输出的产生式是最右推导的逆序列,下面验证其正确性。 1114 | 1115 | S=>CC=>CcC=>Ccd=>cCcd=>ccCcd=>cccCcd=>cccdcd 1116 | 1117 | 可以看出,上述产生式的确是**最右推导**的逆序列,所以其是正确的。 1118 | 1119 | 经验证,程序自动构建的有效项目集规范族和DFA均正确,其分析表亦正确,对给定的输出串分析输出的产生式验证也正确。 --------------------------------------------------------------------------------