前些天寫了個小語言的詞法分析程序,因為前些天在VC知識庫看到一個pascal詞法分析的程序,覺得寫得挺復雜的。其實詞法分析程序的原理都是一樣的,所以我想只要搞明白了簡單的詞法分析程序,再寫復雜的就不難了,無非是多加幾個關鍵字,多寫幾個條件判斷語句而已。詞法分析是編譯程序的基礎,也是最簡單的。好,現在讓我們看程序吧。
先讓我們看看這個小語言的文法吧。
G[<程序>]:
<程序>∷=<程序首部>;<分程序>.
<程序首部>∷=program<標識符>
<分程序>∷=<復合語句>
<復合語句>∷=begin<語句序列>end
<語句序列>∷=<語句>{;<語句>}
<語句>∷=<賦值語句>|<復合語句>|<條件語句>
<賦值語句>∷=<標識符>:=<表達式>
<條件語句>∷=if <布爾表達式> then <語句> else <語句>
<表達式>∷=<項>{(+|-)<項>}
<項>∷=<因式>{(*|/)<因式>}
<因式>∷=<標識符>|<無正負號常量>|’(’<表達式>’)’
<布爾表達式>∷=<表達式><關系運算符><表達式>
<關系運算符>∷= =|<|<=|>|>=|<>
<標識符>∷=<字母>{<字母>|<數字>}
<無正負號常量>∷=<數字>{<數字>}[.<數字>{<數字>}]
<字母>∷=a|b|c|d|e|f|g|……|u|v|w|x|y|z
<數字>∷=0|1|2|3|4|5|6|7|8|9
根據此文法,構造一詞法分析程序。輸入以“#”為結束符
按照這個文法,找出該語言的關鍵字,如program,begin,end ,if,then,else,以及其他一些特殊符號,然後再構造一個分析表,如下表: 單詞符號 類別編號 標識符 1 常數 2 if 3 then 4 else 5 program 6 begin 7 end 8 + 9 - 10 * 11 / 12 ( 13 ) 14 > 15 >= 16 < 17 <= 18 <> 19 := 20 ; 21 . 22 , 23
根據這個表來構造程序,程序的核心是下面的這個函數,
/******************************************************************** 以下為主分析函數 從輸入文件裡面讀,把分析結果寫到輸出文件中 參數:fpin :輸入文件指針 fpout: 輸出文件指針 ********************************************************************/ void parse(FILE* fpin,FILE* fpout) { char arr[MAXBUF];//讀出的最長的字符串不超過MAXBUF,MAXBUF定義為255,夠長了我想 int i=0;//分析含字母的字符串用 int j=0;//分析純數字的字符串用 while(1) { fscanf(fpin,"%c",&ch);//從輸入文件中讀入一個字符 if( ch=='' ''|| ch ==''\t'')//過濾掉空格和tab ; else if( ch==''\n'')//回車換行符,為下面進行錯誤判斷 lineno++; else if( IsDigit(ch))//讀入的是數字 { while(IsDigit(ch)) { arr[j] = ch; j++; fscanf(fpin,"%c",&ch); } fseek(fpin,-1L,SEEK_CUR);//文件指針後退一個字節 char* temp1 =(char*)malloc(j+1);/ memcpy(temp1,arr,j); temp1[j] =''\0'';//把數組裡面的內容拷貝到連外一個數組裡面,因為我定義的 //arr為255個字節,實際上寫不到那麼多,所以只拷貝實際上有數據的 j=0;//恢復初始狀態,以備下次使用 fprintf(fpout,"%s\t\t%d\n",temp1,2);//常數 free(temp1);//釋放內存 } else if(IsAlpha(ch))//是字母開頭的 { while(IsAlpha(ch) || IsDigit(ch)) { arr[i] =ch; i++; fscanf(fpin,"%c",&ch); } fseek(fpin,-1L,SEEK_CUR); char* temp = (char*)malloc(i+1) ; memcpy(temp,arr,i); temp[i] =''\0''; i=0; /*基本思想同處理數字的*/ if(FindOK(temp))//FindOK函數在關鍵字表中查找和temp字符串相同的,找到就返回類別編號 { fprintf(fpout,"%s\t\t%d \n",temp,FindOK(temp)); } else { fprintf(fpout,"%s\t\t%d\n",temp,1);//標示符號 } free(temp); } //以下為2字節的運算符號 else if( ch=='':'')//符號“:=” { fscanf(fpin,"%c",&ch); if(ch==''='') fprintf(fpout,"%s\t\t%d\n",":=",20); else fprintf(fpout,"error in compileing %d lines unknown character %c \n",lineno,ch);//出錯了 } else if(ch==''>'')//符號 “> “ 和”>=” { fscanf(fpin,"%c",&ch); if(ch==''='') fprintf(fpout,"%s\t\t%d\n",">=",16); else fprintf(fpout,">\t\t15\n"); } else if( ch==''<'') //符號 “< “ 和”<=” { fscanf(fpin,"%c",&ch); if(ch==''='') {fprintf(fpout,"<=\t\t18\n");} else if( ch==''>'') {fprintf(fpout,"<>\t\t19");} else {fprintf(fpout,"<\t\t19\n");} } else { //以下為一個字節的運算符號 if(ch==''-'') {fprintf(fpout,"%s\t\t%d\n",''-'',10);continue;}//在文件中輸出為“- 10” if(ch=='';'') {fprintf(fpout,";\t\t21\n");continue;} if(ch==''+'') {fprintf(fpout,"+\t\t9\n");continue;} if(ch==''*'') {fprintf(fpout,"*\t\t11\n");continue;} if(ch==''/'') {fprintf(fpout,"/ \t\t12\n");continue;} if(ch==''('') {fprintf(fpout,"(\t\t13\n");continue;} if(ch=='')'') {fprintf(fpout,")\t\t14\n");continue;} if(ch==''.'') {fprintf(fpout,".\t\t22\n");continue;} if(ch=='','') {fprintf(fpout,",\t\t23\n");continue;} if(ch==''#'') break;//分析結束 else fprintf(fpout,"error in compileing %d lines unknown character %c \n",lineno,ch);//出錯了,輸出出錯信息 } } }
其他請看源代碼,注釋很詳細,但是肯定有不足的地方,請大家吝賜教。有什麼問題,可以給我發郵件。這是我第一次向VC知識庫投稿,以後將會陸續寫一些VC方面的程序來和大家共享。我的email:[email protected],QQ:110902663, 謝謝大家。
本文配套源碼