一個簡單編譯器前端的實現


小記:

  其實這個程序是編譯原理這門課的綜合實驗,前段時間我申請免試又失敗了,原因是有缺課,平時分不夠,早上賴床現在嘗到苦果我也是醉了……沒辦法,逼上梁山,只好攻克這個大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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM