小記:
其實這個程序是編譯原理這門課的綜合實驗,前段時間我申請免試又失敗了,原因是有缺課,平時分不夠,早上賴床現在嘗到苦果我也是醉了……沒辦法,逼上梁山,只好攻克這個大boss以拿下免試資格。
選了一個最簡單的文法,分析了1個多星期,終於決定開始要寫的時候時間已經很緊了。
去實驗室通宵了一晚,在宿舍熬了一晚,睡了3個小時就起來去驗收了。還好是通過了,沒白費勁。
不得不說,編譯原理就是燒腦,知識點都比較抽象,如果數據結構和算法的基礎打得不牢的話,實現起來會感到吃力。
再次感覺到了基礎的重要性,這也是一個收獲吧。
總的來說,相比較之前實現形式化的des加密算法,抽象的編譯器更有難度,寫完也更能讓你感覺到提高。
ps:程序僅供參考,時間有限,沒做太多測試。
功能:
給定一個簡單語言的文法描述,本程序是該語言的編譯器前端。
輸入一個符合該文法規則的源文件,輸出三地址形式的中間代碼。
具體功能有詞法分析,語法分析,分析流程顯示,錯誤提示等。
程序運行結果:
源程序:
分析過程:
生成中間代碼(三地址形式):
分析過程:
文法:
文法(消除左遞歸后) Program->BEGIN Stmt-List END Stmt-List->Stmt Stmt-List' Stmt-List'->Stmt Stmt-List' | . Stmt->Assign-stmt Assign-stmt->ID = Expr Expr->Term Expr' Expr'->Add-Op Term Expr' | . Term->Factor Term' Term'->Multiple-Op Factor Term' | . Factor->( Expr ) | ID | NUM Add-Op->+ | - Multiple-Op->* | /
FIRST集 First(Program)={BEGIN} First(Stmt-List)={ID} First(Stmt-List')={ ID,ε}
First(Stmt)={ ID} First(Assign-stmt)={ ID} First(Expr)={(,ID,NUM} First(Expr')={+,-,ε}
First(Term)={(,ID,NUM} First(Term')={*,/,ε}
First(Factor)={(,ID,NUM} First(Add-Op)={+,-} First(Multiple-Op)={*,/}
FOLLOW集 Follow(Program)={$} Follow(Stmt-List)={END} Follow(Stmt-List')={ END}
Follow(Stmt)={ ID,END} Follow(Assign-stmt)={ ID,END } Follow(Expr)={ ID,END ,)} Follow(Expr')={ ID,END , )}
Follow(Term)={+,-, ID,END , )} Follow(Term')={ +,-, ID,END , )}
Follow(Factor)={ *,/,+,-, ID,END , )} Follow(Add-Op)={(,ID,NUM} Follow(Multiple-Op)={ (,ID,NUM }
預測分析表:
代碼:
1 //詞法分析中' '代表空白字符,包括換行符,空格,制表符 2 //源程序格式:1、一行只能有一條語句;2、程序中可以有注釋
3 #include <iostream>
4 #include <string.h>
5 #include <stdio.h>
6 #include <stack>
7 #include <stdlib.h>
8 using namespace std; 9
10 char src[1000010]; //存儲源代碼
11 char TokenList_kind[1010][100]; //詞法單元流 之 類別
12 int TokenList_value[1010]; //詞法單元流 之 值
13 char WordList[1010][100]; //符號表 -- 由token_value指向
14 int LineList[1010]; //記錄每一個token對應的行數 -- 由token_value指向
15 int TokenListPoint; //詞法單元流指針
16 int WordListPoint; //符號表指針
17
18 int WordsPoint; //語法分析時的詞法單元流指針
19
20 int tmpcnt; //三地址語句中寄存器的編號
21
22 int ExpTable[11][8] = { //用 表驅動法 讀取表達式 ,狀態轉換表
23 2, -1, 1, -1, -1, -1, -1, 9, 24 2, -1, -1, -1, -1, -1, -1, 9, 25 2, -1, -1, 3, -1, -1, -1, 9, 26 4, 5, -1, -1, -1, -1, -1, 9, 27 4, -1, 8, -1, 6, -1, 10, 9, 28 -1, 5, 8, -1, 6, -1, 10, 9, 29 4, 5, -1, -1, -1, 7, -1, 9, 30 4, 5, -1, -1, -1, -1, -1, 9, 31 -1, -1, -1, -1, -1, -1, -1, -1, 32 -1, -1, -1, -1, -1, -1, -1, -1, 33 -1, -1, 8, -1, 6, -1, 10, 9
34 }; 35
36 /*
37 文法 38 1 Program->BEGIN Stmt-List END 39 2 Stmt-List->Stmt Stmt-List' 40 3 Stmt-List'->Stmt Stmt-List' | . 41 4 Stmt->Assign-stmt 42 5 Assign-stmt->ID = Expr 43 6 Expr->Term Expr' 44 7 Expr'->Add-Op Term Expr' | . 45 8 Term->Factor Term' 46 9 Term'->Multiple-Op Factor Term' | . 47 10 Factor->( Expr ) | ID | NUM 48 11 Add-Op->+ | - 49 12 Multiple-Op->* | / 50
51 預測分析表 52 非終結符號 輸入符號 53 BEGIN ‘+’ ‘-’ ‘*’ ‘/’ ( ) ‘=’ ID NUM END $ 54 Program 1 55 Stmt-List 2 56 Stmt-List' 3 . 57 Stmt 4 58 Assign-stmt 5 59 Expr 6 6 6 60 Expr' 7 7 . . . 61 Term 8 8 8 62 Term' . . 9 9 . . . 63 Factor 10_1 10_210_3 64 Add-Op 11_1 11_2 65 Multiple-Op 12_1 12_2 66 */
67
68 char PreTab[12][12][100]={ //存儲預測分析表
69 {"BEGIN Stmt-List END","","","","","","","","","","",""}, 70 {"","","","","","","","","Stmt Stmt-List'","","",""}, 71 {"","","","","","","","","Stmt Stmt-List'","",".",""}, 72 {"","","","","","","","","Assign-stmt","","",""}, 73 {"","","","","","","","","ID = Expr","","",""}, 74 {"","","","","","Term Expr'","","","Term Expr'","Term Expr'","",""}, 75 {"","Add-Op Term Expr'","Add-Op Term Expr'","","","",".","",".","",".",""}, 76 {"","","","","","Factor Term'","","","Factor Term'","Factor Term'","",""}, 77 {"",".",".","Multiple-Op Factor Term'","Multiple-Op Factor Term'","",".","",".","",".",""}, 78 {"","","","","","( Expr )","","","ID","NUM","",""}, 79 {"","+","-","","","","","","","","",""}, 80 {"","","","*","/","","","","","","",""} 81 }; 82
83 char Product[23][50]={ //記錄產生式出現的字符串
84 "Program", //0
85 "Stmt-List", //1
86 "Stmt-List'", //2
87 "Stmt", //3
88 "Assign-stmt", //4
89 "Expr", //5
90 "Expr'", //6
91 "Term", //7
92 "Term'", //8
93 "Factor", //9
94 "Add-Op", //10
95 "Multiple-Op", //11
96
97 "BEGIN", //12
98 "+", //13
99 "-", //14
100 "*", //15
101 "/", //16
102 "(", //17
103 ")", //18
104 "=", //19
105 "ID", //20
106 "NUM", //21
107 "END" //22
108 }; 109
110
111 //語法樹節點
112 struct Node{ 113 Node(char na[]){ //構造函數
114 strcpy(name,na); 115 wp = 0; 116 brother = NULL; 117 next = NULL; 118 } 119 char name[50]; 120 int wp; //終結符在token流中的位置
121 Node* brother; //指向下一個兄弟節點
122 Node* next; //指向當前節點的孩子節點
123 }*root,*now,*p; 124
125 void Init() 126 { 127 memset(src,0,sizeof(src)); //初始化源代碼字符數組
128 memset(TokenList_kind,0,sizeof(TokenList_kind)); //初始化詞法單元流
129 memset(TokenList_value,0,sizeof(TokenList_value)); //初始化詞法單元流
130 memset(WordList,0,sizeof(WordList)); //初始化符號表
131 TokenListPoint = 1; 132 WordListPoint = 1; 133
134 WordsPoint = 1; 135
136 //初始化指針
137 root = NULL; 138 now = NULL; 139 p = NULL; 140 tmpcnt = 1; 141 } 142
143 //--------------- 詞法分析 start ---------------
144 void AddToken(char kind[],char value[],int line) //將<類別,值>放入token流中
145 { 146 strcpy(TokenList_kind[TokenListPoint],kind); 147 TokenList_value[TokenListPoint++] = WordListPoint; 148
149 strcpy(WordList[WordListPoint],value); 150 LineList[WordListPoint++] = line; 151 } 152
153 void strsub(char str1[],int start,int len,char str2[]) //截取str1的子字符串給str2
154 { 155 int i=0,j; 156 for(j=0;j<len;j++){ 157 str2[i++] = str1[start+j]; 158 } 159 str2[i] = '\0'; 160 } 161
162 void InputString() //從文件中讀取源代碼,同時過濾注釋,一行只能放置一條語句
163 { 164 //文件讀入
165 FILE* fs = fopen(".\\src.txt","rb"); //源代碼
166 if(fs==NULL){ 167 printf("源代碼文件 src.txt 不存在\n"); 168 return ; 169 } 170
171 char s[10010]={0}; 172 //fscanf(fs,"%s",src);
173 while(fgets(s,10010,fs)){ 174 if(sscanf(s,"%s",s)==-1){ //沒有讀到字符串,將s清空
175 s[0]='\0'; 176 continue; 177 } 178 //過濾注釋
179 if(s[0]=='/' && s[1]=='/') 180 continue; 181 int i; 182 for(i=0;s[i];i++) 183 if(s[i]=='/' && s[i+1]=='/') 184 break; 185 s[i]='\0'; 186
187 strcat(src,s); //連接到源代碼字符串后
188 strcat(src," "); //連接一個空白符
189 } 190
191 int len = strlen(src); 192 len--; 193 src[len] = '\0'; 194 } 195
196 bool getBEGIN(int &i,int &line) //讀取“BEGIN”
197 { 198 char tmp[6]; 199 strsub(src,i,5,tmp); 200 if(strcmp(tmp,"BEGIN")==0){ 201 i = i+5; 202 AddToken("BEGIN","BEGIN",line); //添加token,<類別,值>
203 return true; 204 } 205 else
206 return false; 207 } 208 bool getBLANK(int &i) //讀取“空白符”==>' '
209 { 210 if(src[i]==' '){ 211 i++; 212 return true; 213 } 214 else
215 return false; 216 } 217 bool getEND(int &i,int &line) //讀取“END”
218 { 219 char tmp[4]; 220 strsub(src,i,3,tmp); 221 if(strcmp(tmp,"END")==0){ 222 i = i+3; 223 AddToken("END","END",line); //添加token,<類別,值>
224 return true; 225 } 226 else
227 return false; 228 } 229 bool getExp(int &i,int &line) //讀取表達式,遇到' '結束
230 { 231 int status=0; 232 char tmp[10010]={0}; 233 char t[2]={0}; 234 int j=0; 235 stack <char> ss; 236 while(status!=8){ 237 if(status==-1) //跳到錯誤的狀態號,返回false
238 return false; 239 if(status==9) //跳到了錯誤狀態,返回false
240 return false; 241
242 //根據src[i]確定下一個狀態,直到抵達結束狀態 8
243 if( ('a'<=src[i] && src[i]<='z') || ('A'<=src[i] && src[i]<='Z') ){ 244 //讀取到字母
245 status = ExpTable[status][0]; 246 tmp[j++] = src[i++]; 247 } 248 else if('0'<=src[i] && src[i]<='9'){ 249 //讀取到數字
250 status = ExpTable[status][1]; 251 tmp[j++] = src[i++]; 252 } 253 else{ 254 switch(src[i]){ 255 case ' ': //空白符
256 status = ExpTable[status][2]; 257 if(tmp[0]!='\0'){ 258 //如果是后來讀到空白符,說明表達式該結束了 259 //將讀取的最后一個單詞放入token
260 if(j!=0){ //說明之前是一個單詞或數字,否則是一個),)已經將最后一個單詞放入token流中了,所以不需要處理它
261 if( ('a'<=tmp[0] && tmp[0]<='z') || ('A'<=tmp[0] && tmp[0]<='Z') ) 262 AddToken("ID",tmp,line); //將這個字符代表的單詞放入token流中
263 else if( '0'<=tmp[0] && tmp[0]<='9' ) 264 AddToken("NUM",tmp,line); //將這個字符代表的單詞放入token流中
265 j=0; 266 } 267 } 268 line++; 269 i++; 270 break; 271 case '=': // =
272 status = ExpTable[status][3]; 273
274 tmp[j] = '\0'; 275 AddToken("ID",tmp,line); //=前面一定是標識符,放入token流
276 j=0; 277 AddToken("=","=",line); //將當前的=也放入token流
278
279 i++; 280 break; 281 case '+': //OP
282 case '-': 283 case '*': 284 case '/': 285 status = ExpTable[status][4]; 286
287 tmp[j] = '\0'; 288 if( ('a'<=tmp[0] && tmp[0]<='z') || ('A'<=tmp[0] && tmp[0]<='Z') ) //如果運算符前是字母,則說明是標識符
289 AddToken("ID",tmp,line); 290 else if( '0'<=tmp[0] && tmp[0]<='9' ) 291 AddToken("NUM",tmp,line); 292 j=0; 293 t[0] = src[i]; 294 t[1] = '\0'; 295 AddToken(t,t,line); //將運算符放入token流
296
297 i++; 298 break; 299 case '(': // (
300 status = ExpTable[status][5]; 301
302 AddToken("(","(",line); //將(放入token流
303 ss.push('('); 304
305 i++; 306 break; 307 case ')': // )
308 status = ExpTable[status][6]; 309
310 tmp[j] = '\0'; 311 if( ('a'<=tmp[0] && tmp[0]<='z') || ('A'<=tmp[0] && tmp[0]<='Z') ) //如果)前是字母,則說明是標識符,即ID
312 AddToken("ID",tmp,line); 313 else if( '0'<=tmp[0] && tmp[0]<='9' ) 314 AddToken("NUM",tmp,line); 315 j=0; 316
317 AddToken(")",")",line); //將(放入token流
318
319 if(ss.empty()) //括號不匹配
320 return false; 321 else
322 ss.pop(); 323
324 i++; 325 break; 326 default: //其它
327 status = ExpTable[status][7]; 328 i++; 329 break; 330 } 331 } 332 } 333
334 if(status==8){ //正確跳出
335 /*
336 if(ss.empty()) //括號匹配 337 return true; 338 else 339 return false; 340 */
341 return true; 342 } 343 else
344 return false; 345 } 346
347 bool Lex() //進行詞法分析
348 { 349 printf("詞法分析......\n"); 350 int i=0; 351 int line = 1; 352 InputString(); 353 try{ 354 getBEGIN(i,line)?1:throw 1; 355 getBLANK(i)?line++:throw 2; 356 while(1){ //讀取表達式
357 if(src[i]=='\0') //還沒檢測到END,程序就結束了
358 throw 3; 359 char tmp[4]; 360 strsub(src,i,3,tmp); //截取字符串
361 if(strcmp(tmp,"END")==0){ 362 //如果檢測到END,跳出循環
363 break; 364 } 365
366 //讀取表達式
367 getExp(i,line)?1:throw 4; 368 } 369 getEND(i,line)?1:throw 3; 370 if(src[i]!='\0') //如果END結束標志之后還有輸入符號,說明出錯誤了
371 throw 5; 372 } 373 catch(int err){ 374 printf("【詞法錯誤】\n"); 375 //計算行號
376 int errline = 1; 377 int j; 378 for(j=0;j<=i;j++) 379 if(src[j]==' ') 380 errline++; 381
382 switch(err){ 383 case 1: 384 printf("ERROR 1 (第%d行) : 沒有讀取到開始標識 BEGIN!\n",errline); 385 printf("具體位置:\t%s%s\n",WordList[WordListPoint-2],WordList[WordListPoint-1]); 386 printf("\t\t"); 387 for(j=0;j<strlen(WordList[WordListPoint-2]);j++) 388 printf(" "); 389 printf("^\n"); 390 printf("\n"); 391 return false; 392 case 2: 393 printf("ERROR 2 (第%d行) : 沒有讀取到空白符!\n",errline); 394 printf("具體位置:\t%s%s\n",WordList[WordListPoint-2],WordList[WordListPoint-1]); 395 printf("\t\t"); 396 for(j=0;j<strlen(WordList[WordListPoint-2]);j++) 397 printf(" "); 398 printf("^\n"); 399 printf("\n"); 400 return false; 401 case 3: 402 printf("ERROR 3 (第%d行) : 沒有讀取到結束標識 END!\n",errline); 403 printf("具體位置:\t%s%s\n",WordList[WordListPoint-2],WordList[WordListPoint-1]); 404 printf("\t\t"); 405 for(j=0;j<strlen(WordList[WordListPoint-2]);j++) 406 printf(" "); 407 printf("^\n"); 408 printf("\n"); 409 printf("\n"); 410 return false; 411 case 4: 412 printf("ERROR 4 (第%d行) : 表達式錯誤。例如:標識符有誤!\n",errline); 413 printf("具體位置:\t%s%s\n",WordList[WordListPoint-2],WordList[WordListPoint-1]); 414 printf("\t\t"); 415 for(j=0;j<strlen(WordList[WordListPoint-2]);j++) 416 printf(" "); 417 printf("^\n"); 418 printf("\n"); 419 return false; 420 case 5: 421 printf("ERROR 5 (第%d行) : BEGIN...END 代碼段格式錯誤!\n",errline); 422 printf("具體位置:\t%s%s\n",WordList[WordListPoint-2],WordList[WordListPoint-1]); 423 printf("\t\t"); 424 for(j=0;j<strlen(WordList[WordListPoint-2]);j++) 425 printf(" "); 426 printf("^\n"); 427 printf("\n"); 428 return false; 429 default:break; 430 } 431 } 432 printf("沒有詞法錯誤\n"); 433 printf("\n"); 434 return true; 435 } 436
437 void printTokenList() //輸出token流
438 { 439 int i=1; 440 printf("單詞流:\n"); 441 printf("<\t類別\t,值\t>\n"); 442 for(;i<TokenListPoint;i++){ 443 printf("<\t%s\t,%s\t>\n",TokenList_kind[i],WordList[TokenList_value[i]]); 444 } 445 printf("\n"); 446 } 447 //--------------- 詞法分析 end --------------- 448
449
450 //--------------- 語法分析 start --------------- 451 //生成語法分析樹
452
453 void OutStack(stack <char*> z) //輸出棧中內容的前兩個
454 { 455 char t[200]={0}; 456 int j=0; 457 while(!z.empty()){ 458 if(j==2) 459 break; 460 if(j==1) 461 strcat(t,","); 462 strcat(t,z.top()); 463 z.pop(); 464 j++; 465 } 466 strcat(t,"$"); 467 printf("%23s",t); 468 } 469
470 void OutRightStr() //輸出當前token流中前兩個
471 { 472 char t[200]={0}; 473 int i,j=0; 474 for(i = WordsPoint;i<WordListPoint;i++){ 475 if(j==2) 476 break; 477 char tt[200]={0}; 478 sprintf(tt,"<%s,%s>",TokenList_kind[i],WordList[TokenList_value[i]]); 479 strcat(t,tt); 480 j++; 481 } 482 printf("%23s$",t); 483 } 484
485 void OutAction(char action[]) //輸出動作
486 { 487 printf(" %s\n",action); 488 } 489
490 bool seltab(int row,char f[]) 491 { 492 if(strcmp(TokenList_kind[WordsPoint],"BEGIN")==0){ 493 strcpy(f,PreTab[row][0]); 494 } 495 else if(strcmp(TokenList_kind[WordsPoint],"+")==0){ 496 strcpy(f,PreTab[row][1]); 497 } 498 else if(strcmp(TokenList_kind[WordsPoint],"-")==0){ 499 strcpy(f,PreTab[row][2]); 500 } 501 else if(strcmp(TokenList_kind[WordsPoint],"*")==0){ 502 strcpy(f,PreTab[row][3]); 503 } 504 else if(strcmp(TokenList_kind[WordsPoint],"/")==0){ 505 strcpy(f,PreTab[row][4]); 506 } 507 else if(strcmp(TokenList_kind[WordsPoint],"(")==0){ 508 strcpy(f,PreTab[row][5]); 509 } 510 else if(strcmp(TokenList_kind[WordsPoint],")")==0){ 511 strcpy(f,PreTab[row][6]); 512 } 513 else if(strcmp(TokenList_kind[WordsPoint],"=")==0){ 514 strcpy(f,PreTab[row][7]); 515 } 516 else if(strcmp(TokenList_kind[WordsPoint],"ID")==0){ 517 strcpy(f,PreTab[row][8]); 518 } 519 else if(strcmp(TokenList_kind[WordsPoint],"NUM")==0){ 520 strcpy(f,PreTab[row][9]); 521 } 522 else if(strcmp(TokenList_kind[WordsPoint],"END")==0){ 523 strcpy(f,PreTab[row][10]); 524 } 525 else if(strcmp(TokenList_kind[WordsPoint],"$")==0){ 526 strcpy(f,PreTab[row][11]); 527 } 528 else{ 529 return false; 530 } 531 if(f[0]=='\0') //確定的表位置為空
532 return false; 533 return true; 534 } 535
536 bool Parse() //語法分析階段。輸入是token流,輸出分析結果
537 { 538 stack <char*> z; 539 stack <Node*> nz; 540 z.push(*Product); 541
542 root = new Node("Program"); 543 now = root; 544
545 printf("詞法分析......\n"); 546 printf("【分析流程】\n"); 547 printf("%22s%24s%22s\n","棧","輸入","動作"); 548 char action[100]={0}; 549 try{ 550 while(!z.empty() || WordsPoint<WordListPoint){ //棧和輸入串中只剩結束符號(棧空 or 指向'\0')時退出循環 551
552 //輸出當前分析結果
553 OutStack(z); //輸出棧中內容
554 OutRightStr(); //輸出剩余輸入字符串
555 OutAction(action); //輸出動作
556
557 memset(action,0,sizeof(action)); 558
559 //預處理。例:匹配e。預處理:將e出棧,輸入指針后移。 560
561 //還沒結束棧就空了
562 if(z.empty()) 563 throw 1; //非法跳出
564
565 if(strcmp(z.top(),TokenList_kind[WordsPoint])==0){ //棧頂元素==指針指向字符,匹配成功 566 //語義動作 - 構造語法樹
567 while(!now->brother){ //回到有下一個兄弟節點的節點為止
568 if(nz.empty()){ 569 if(now==root) //如果回到了根節點
570 goto label; 571 else
572 throw 1; 573 } 574 now = nz.top(); 575 nz.pop(); 576 } 577 now = now->brother; 578
579 label: 580 //准備輸出字符串 action
581 strcat(action,"匹配"); 582 strcat(action,z.top()); 583
584 //出棧、指針后移
585 if(!z.empty()) 586 z.pop(); 587 if(WordsPoint<WordListPoint) 588 WordsPoint++; 589 } 590 else{ //不相等,輸出推導 591 //確定推導
592 char f[200]={0}; 593 if(strcmp(z.top(),"Program")==0){ 594 if(!seltab(0,f)) //從表中確定推導串
595 throw 2; //沒有找到對應的推導
596 } 597 else if(strcmp(z.top(),"Stmt-List")==0){ 598 if(!seltab(1,f)) //從表中確定推導串
599 throw 2; //沒有找到對應的推導
600 } 601 else if(strcmp(z.top(),"Stmt-List'")==0){ 602 if(!seltab(2,f)) //從表中確定推導串
603 throw 2; //沒有找到對應的推導
604 } 605 else if(strcmp(z.top(),"Stmt")==0){ 606 if(!seltab(3,f)) //從表中確定推導串
607 throw 2; //沒有找到對應的推導
608 } 609 else if(strcmp(z.top(),"Assign-stmt")==0){ 610 if(!seltab(4,f)) //從表中確定推導串
611 throw 2; //沒有找到對應的推導
612 } 613 else if(strcmp(z.top(),"Expr")==0){ 614 if(!seltab(5,f)) //從表中確定推導串
615 throw 2; 616 } 617 else if(strcmp(z.top(),"Expr'")==0){ 618 if(!seltab(6,f)) //從表中確定推導串
619 throw 2; 620 } 621 else if(strcmp(z.top(),"Term")==0){ 622 if(!seltab(7,f)) //從表中確定推導串
623 throw 2; 624 } 625 else if(strcmp(z.top(),"Term'")==0){ 626 if(!seltab(8,f)) //從表中確定推導串
627 throw 2; 628 } 629 else if(strcmp(z.top(),"Factor")==0){ 630 if(!seltab(9,f)) //從表中確定推導串
631 throw 2; 632 } 633 else if(strcmp(z.top(),"Add-Op")==0){ 634 if(!seltab(10,f)) //從表中確定推導串
635 throw 2; 636 } 637 else if(strcmp(z.top(),"Multiple-Op")==0){ 638 if(!seltab(11,f)) //從表中確定推導串
639 throw 2; 640 } 641 else{ 642 throw 2; 643 } 644 //准備輸出字符串 action
645 strcat(action,"輸出"); 646 strcat(action,z.top()); 647 strcat(action,"->"); 648 strcat(action,f); 649
650 //將棧頂字符串記錄下來后用
651 char proleft[50]; 652 //將棧頂元素出棧並將推導入棧
653 if(!z.empty()){ 654 strcpy(proleft,z.top()); 655 z.pop(); 656 } 657 else
658 throw 1; 659
660 char tmp[100]; 661
662 //如果推導出來的是空,即f->.,不作處理
663 if(f[0]=='.'){ 664 nz.push(now); 665
666 now->next = new Node("."); 667 now = now->next; //now指向當前產生式右邊的第一個字符串
668
669 while(!now->brother){ //回到有下一個兄弟節點的節點為止
670 if(nz.empty()){ 671 if(now==root) //如果回到了根節點
672 goto label; 673 else
674 throw 1; 675 } 676 now = nz.top(); 677 nz.pop(); 678 } 679 now = now->brother; 680
681 continue; 682 } 683 stack <char*> tz; //臨時的棧 684
685 //正向輸入到臨時棧中
686 while(sscanf(f,"%s",tmp)!=-1){ 687 //語義動作 - 創建語法樹
688 if(strcmp(proleft,now->name)==0){ 689 nz.push(now); //將當前節點記錄下來
690
691 now->next = new Node(tmp); 692 now = now->next; //now指向當前產生式右邊的第一個字符串
693 p = now; 694 } 695 else{ 696 p->brother = new Node(tmp); 697 p = p->brother; 698 } 699
700 char* pos = strstr(f,tmp); 701 strcpy(f,pos+strlen(tmp)); 702 if(strcmp(tmp,"Program")==0){ 703 tz.push(*(Product)); 704 } 705 else if(strcmp(tmp,"Stmt-List")==0){ 706 tz.push(*(Product+1)); 707 } 708 else if(strcmp(tmp,"Stmt-List'")==0){ 709 tz.push(*(Product+2)); 710 } 711 else if(strcmp(tmp,"Stmt")==0){ 712 tz.push(*(Product+3)); 713 } 714 else if(strcmp(tmp,"Assign-stmt")==0){ 715 tz.push(*(Product+4)); 716 } 717 else if(strcmp(tmp,"Expr")==0){ 718 tz.push(*(Product+5)); 719 } 720 else if(strcmp(tmp,"Expr'")==0){ 721 tz.push(*(Product+6)); 722 } 723 else if(strcmp(tmp,"Term")==0){ 724 tz.push(*(Product+7)); 725 } 726 else if(strcmp(tmp,"Term'")==0){ 727 tz.push(*(Product+8)); 728 } 729 else if(strcmp(tmp,"Factor")==0){ 730 tz.push(*(Product+9)); 731 } 732 else if(strcmp(tmp,"Add-Op")==0){ 733 tz.push(*(Product+10)); 734 } 735 else if(strcmp(tmp,"Multiple-Op")==0){ 736 tz.push(*(Product+11)); 737 } 738 else if(strcmp(tmp,"BEGIN")==0){ 739 tz.push(*(Product+12)); 740 } 741 else if(strcmp(tmp,"+")==0){ 742 tz.push(*(Product+13)); 743 } 744 else if(strcmp(tmp,"-")==0){ 745 tz.push(*(Product+14)); 746 } 747 else if(strcmp(tmp,"*")==0){ 748 tz.push(*(Product+15)); 749 } 750 else if(strcmp(tmp,"/")==0){ 751 tz.push(*(Product+16)); 752 } 753 else if(strcmp(tmp,"(")==0){ 754 tz.push(*(Product+17)); 755 } 756 else if(strcmp(tmp,")")==0){ 757 tz.push(*(Product+18)); 758 } 759 else if(strcmp(tmp,"=")==0){ 760 tz.push(*(Product+19)); 761 } 762 else if(strcmp(tmp,"ID")==0){ 763 tz.push(*(Product+20)); 764 } 765 else if(strcmp(tmp,"NUM")==0){ 766 tz.push(*(Product+21)); 767 } 768 else if(strcmp(tmp,"END")==0){ 769 tz.push(*(Product+22)); 770 } 771 else{ 772 throw 1; 773 } 774
775 } 776
777 //反向輸出到真正的棧中
778 while(!tz.empty()){ 779 if(strcmp(tz.top(),"Program")==0){ 780 z.push(*(Product)); 781 } 782 else if(strcmp(tz.top(),"Stmt-List")==0){ 783 z.push(*(Product+1)); 784 } 785 else if(strcmp(tz.top(),"Stmt-List'")==0){ 786 z.push(*(Product+2)); 787 } 788 else if(strcmp(tz.top(),"Stmt")==0){ 789 z.push(*(Product+3)); 790 } 791 else if(strcmp(tz.top(),"Assign-stmt")==0){ 792 z.push(*(Product+4)); 793 } 794 else if(strcmp(tz.top(),"Expr")==0){ 795 z.push(*(Product+5)); 796 } 797 else if(strcmp(tz.top(),"Expr'")==0){ 798 z.push(*(Product+6)); 799 } 800 else if(strcmp(tz.top(),"Term")==0){ 801 z.push(*(Product+7)); 802 } 803 else if(strcmp(tz.top(),"Term'")==0){ 804 z.push(*(Product+8)); 805 } 806 else if(strcmp(tz.top(),"Factor")==0){ 807 z.push(*(Product+9)); 808 } 809 else if(strcmp(tz.top(),"Add-Op")==0){ 810 z.push(*(Product+10)); 811 } 812 else if(strcmp(tz.top(),"Multiple-Op")==0){ 813 z.push(*(Product+11)); 814 } 815 else if(strcmp(tz.top(),"BEGIN")==0){ 816 z.push(*(Product+12)); 817 } 818 else if(strcmp(tz.top(),"+")==0){ 819 z.push(*(Product+13)); 820 } 821 else if(strcmp(tz.top(),"-")==0){ 822 z.push(*(Product+14)); 823 } 824 else if(strcmp(tz.top(),"*")==0){ 825 z.push(*(Product+15)); 826 } 827 else if(strcmp(tz.top(),"/")==0){ 828 z.push(*(Product+16)); 829 } 830 else if(strcmp(tz.top(),"(")==0){ 831 z.push(*(Product+17)); 832 } 833 else if(strcmp(tz.top(),")")==0){ 834 z.push(*(Product+18)); 835 } 836 else if(strcmp(tz.top(),"=")==0){ 837 z.push(*(Product+19)); 838 } 839 else if(strcmp(tz.top(),"ID")==0){ 840 z.push(*(Product+20)); 841 } 842 else if(strcmp(tz.top(),"NUM")==0){ 843 z.push(*(Product+21)); 844 } 845 else if(strcmp(tz.top(),"END")==0){ 846 z.push(*(Product+22)); 847 } 848 else{ 849 throw 1; 850 } 851 tz.pop(); 852 } 853 } 854
855 } 856 if(z.empty() && WordsPoint >= WordListPoint){ //正常退出循環 857 //輸出最后一行分析結果
858 OutStack(z); //輸出棧中內容
859 OutRightStr(); //輸出剩余輸入字符串
860 OutAction(action); //輸出動作
861 } 862 else{ //非正常情況
863 throw 1; 864 } 865 } 866 catch(int err){ 867 printf("\n"); 868 printf("【語法錯誤】\n"); 869
870 switch(err){ 871 case 1: 872 printf("ERROR 1 (第%d行) : 非法跳出!\n",LineList[WordsPoint]); 873 printf("\n"); 874 return false; 875 case 2: 876 printf("ERROR 2 (第%d行) : 沒有找到 %s 對應的推導!\n",LineList[WordsPoint],z.top()); 877 printf("\n"); 878 return false; 879 default: 880 break; 881 } 882 } 883 printf("沒有語法錯誤\n"); 884 printf("\n"); 885 return true; 886 } 887 //--------------- 語法分析 end --------------- 888
889 //--------------- 生成三地址代碼 start --------------- 890 //對語法分析樹進行后序遍歷,執行語義規則,一遍掃描之后,樹根的code即為三地址代碼
891
892
893 void setWP(Node* cur) //設置每一個葉子節點的wp指針
894 { 895 if(!cur->next){ 896 if(cur->name[0]=='.') 897 return ; 898 cur->wp = WordsPoint++; 899 return ; 900 } 901 Node* p = cur->next; 902 while(p){ 903 setWP(p); 904 p = p->brother; 905 } 906 } 907
908 char* getNext(Node* cur,FILE* fo) 909 { 910 //遞歸出口
911 if(!cur->next){ 912 if(cur->name[0]=='.'
913 || cur->name[0]=='('
914 || cur->name[0]==')'){ //忽略空. 和 ( 和 )
915 char* t = new char[2]; 916 t[0]='\0'; 917 return t; 918 } 919 return WordList[TokenList_value[cur->wp]]; 920 } 921 if(strcmp(cur->name,"Program")==0){ 922 fprintf(fo,"%s\r\n",getNext(cur->next,fo)); 923 getNext(cur->next->brother,fo); 924 fprintf(fo,"%s\r\n",getNext(cur->next->brother->brother,fo)); 925 char* tmp = new char[2]; 926 tmp[0] = '\0'; 927 return tmp; 928 } 929 else if(strcmp(cur->name,"Assign-stmt")==0){ 930 char* tmp = new char[2]; 931 tmp[0] = '\0'; 932 fprintf(fo,"%s=%s\r\n",getNext(cur->next,fo),getNext(cur->next->brother->brother,fo)); 933 return tmp; 934 } 935 else if(strcmp(cur->name,"Term")==0){ 936 char* tmp = new char[150]; 937 tmp = getNext(cur->next->brother,fo); 938 if(tmp[0]=='*' || tmp[0]=='/'){ 939 fprintf(fo,"t%d=%s%s\r\n",tmpcnt,getNext(cur->next,fo),tmp); 940 sprintf(tmp,"t%d",tmpcnt++); 941 return tmp; 942 } 943 } 944 else if(strcmp(cur->name,"Expr")==0){ 945 char* tmp = new char[150]; 946 tmp = getNext(cur->next->brother,fo); 947 if(tmp[0]=='+' || tmp[0]=='-'){ 948 fprintf(fo,"t%d=%s%s\r\n",tmpcnt,getNext(cur->next,fo),tmp); 949 sprintf(tmp,"t%d",tmpcnt++); 950 return tmp; 951 } 952 } 953 else if(strcmp(cur->name,"Term'")==0){ 954 char* tmp = new char[150]; 955 if(cur->next->brother!=NULL){ 956 p = cur->next->brother->brother; 957 if(p->next->brother!=NULL){ 958 tmp = getNext(cur->next->brother->brother,fo); 959 if(tmp[0]=='*' || tmp[0]=='/'){ 960 if(*getNext(cur->next,fo)=='/'){ //如果最前面的是‘-’,后面的運算符應該是反的
961 if(tmp[0]=='/') 962 tmp[0]='*'; 963 else
964 tmp[0]='/'; 965 } 966 fprintf(fo,"t%d=%s%s\r\n",tmpcnt,getNext(cur->next->brother,fo),tmp); 967 sprintf(tmp,"%st%d",getNext(cur->next,fo),tmpcnt++); 968 return tmp; 969 } 970 } 971 } 972 } 973 else if(strcmp(cur->name,"Expr'")==0){ 974 char* tmp = new char[150]; 975 if(cur->next->brother!=NULL){ 976 p = cur->next->brother->brother; 977 if(p->next->brother!=NULL){ 978 tmp = getNext(cur->next->brother->brother,fo); 979 if(tmp[0]=='+' || tmp[0]=='-'){ 980 if(*getNext(cur->next,fo)=='-'){ //如果最前面的是‘-’,后面的運算符應該是反的
981 if(tmp[0]=='-') 982 tmp[0]='+'; 983 else
984 tmp[0]='-'; 985 } 986 fprintf(fo,"t%d=%s%s\r\n",tmpcnt,getNext(cur->next->brother,fo),tmp); 987 sprintf(tmp,"%st%d",getNext(cur->next,fo),tmpcnt++); 988 return tmp; 989 } 990 } 991 } 992 } 993
994 char * s = new char[150]; //new一個字符串,存儲這個節點的結果
995 memset(s,0,sizeof(s)); 996
997 Node* p = cur->next; 998 while(p){ 999 strcat(s,getNext(p,fo)); 1000 p = p->brother; 1001 } 1002 return s; 1003 } 1004
1005 void get3AddrCode() 1006 { 1007 WordsPoint = 1; 1008 FILE* fo = fopen(".\\out.txt","wb"); 1009 if(fo==NULL){ 1010 printf("三地址代碼生成文件 out.txt 打開失敗!\n"); 1011 return ; 1012 } 1013
1014 setWP(root); 1015 printf("生成三地址語句......\n"); 1016 getNext(root,fo); 1017 } 1018 //--------------- 生成三地址代碼 end ---------------
1019
1020 int main() 1021 { 1022 bool f=true; 1023 Init(); 1024 if(!Lex()) //詞法分析
1025 f=false; 1026 //printTokenList();
1027 if(!Parse()) //語法分析
1028 f=false; 1029 if(f) //都通過了才能生成三地址代碼
1030 get3AddrCode(); //生成三地址代碼
1031 return 0; 1032 }
Freecode : www.cnblogs.com/yym2013