Tiny語言編譯器:Tiny詞法分析器模組

來源:互聯網
上載者:User

這是《編譯原理》課程的一個作業,要求為Tiny語言的拓展Tiny+編寫一個編譯器,第一階段要實現的是對Tiny+語言的詞法分析。首先,簡單的解釋下Tiny+語言的構成: 

TINY+     We define here a programming language called TINY+, which is a superset of TINY in that it includes declarations, if statement, do-while statement, string type and so on.The following consists of:1     Lexical conventions of the language, including a description of the tokens of the language2     EBNF description of each language construct3     An description of the main semantics4     Sample programs in TINY+Part 1 Lexical Conventions of TINY+1.     The keywords of the language are the following:true         false     or         and      not         int         bool     string     while     do     if         then     else     end         repeat     until     read     write      All keywords are reserved and must be written in lowcase2.     Special symbols are the following:     >         <=         >=         ,     '  {     }     ;     :=     +     -     *     /     (     )     <     =3.     Other tokens are ID, NUM and STRING which are defined by the following regular expressions:ID=letter (letter | digit)*     Identifier is letter followed by letters and digitsNUM=digit digit*STRING=' any character except ' 'A STRING is enclosed in brackets '…', any character except ' can appear in a STRING. A STRING can’t be defined more than a lineletter=a|…|z|A|…|Zdigit=0|…|9Lower and uppercase letters are distinct4.     White space consists of blanks, newlines and tabs. White space is ignored except that it must separate IDs, NUMs, and keywords5.     Comments are enclosed in curly brackets {…} and cannot be nested. Comments can include more than one line. Part 2 Syntax of TINY+An EBNF grammar for TINY+ is as follows:1     program         ->     declarations stmt-sequence2     declarations     -> decl ; declarations |ε3     decl         -> type-specifier varlist4     type-specifier     -> int | bool | string5     varlist     -> identifier { , identifier }6     stmt-sequence     -> statement { ; statement }7     statement     -> if-stmt | repeat-stmt | assign-stmt | read-stmt | write-stmt | while-stmt8     while-stmt -> while bool-exp do stmt-sequence end9     if-stmt     -> if   bool-exp then stmt-sequence [else stmt-sequence] end10     repeat-stmt     -> repeat stmt-sequence until bool-exp11     assign-stmt     -> identifier:=exp12     read-stmt     -> read identifier13     write-stmt     -> write exp14     exp     -> arithmetic-exp | bool-exp | string-exp| comparison-exp15     comparison-exp -> arithmetic-exp comparison-op arithmetic-exp16     comparison-op     -> < | = | > | >= | <= 17     arithmetic-exp     -> term { addop term } 18     addop     -> + | -19     term     -> factor { mulop factor }20     mulop     -> * | /21     factor     -> (arithmetic-exp) | number | identifier22     bool-exp     -> bterm { or bterm }23     bterm     -> bfactor { and   bfactor}24     bfactor     -> true | false | identifier | (bool-exp) | not bfactor | (comparison-exp)25     string-exp         -> string | identifier26     Part 3 Main semantics description of TINY+     A program consists of variable declarations and a sequence of statements. Variable declarations may be empty but there must be at least one statement.     All variables must be declared before they are used, and each variable name can be declared only once     The type of variables and expressions may be int, bool or string, type checking must be done on themPart 4 Sample programs in TINY+string str;int x, fact;str:= 'sample program in TINY+ language- computes factorial' ;read x;if x>0 and x<100 then {don’t compute if x<=0}     fact:=1;     while x>0 do         fact:=fact*x;         x:=x-1     end;     write factend
從上面我們可以看到有關Tiny+的關鍵字,資料定義,詞法定義以及文法定義等等。最後記錄下自己的學習過程:

Tiny+開發環境:
Intel處理器
Microsoft Windows 7 作業系統 
Visual Studio 2010 與業版  .Net 4 版本

本Tiny+編譯器採用圖形操作視窗,而丌是基於命令控制項台輸入輸出方式,這樣更友好的與使用者進行互動,編譯器提供了下面功能: 
      詞法分析功能模組; 
      文法分析功能模組; 
      詞/文法分析結果儲存模組; 
      文本編輯模組; 
      進階功能模組; 
      代碼輸入模組; 
      分析結果輸出模組; 

TINY+編譯器核心演算法 

Scanner :這部分的功能的核心函數是 getToken()函數。該函數中,它首先通過使用一個迴圈不斷地調用 getNextchar()(還有相對應的 getNextcharT()函數)來判斷擷取 tiny+的原始碼的字元(每次一個字元),然後根據狀態轉換表中“目前狀態 – 輸入字元“ 來轉換到新的狀態,然後再根據 advance 表中的”當前狀體 –當前輸入字元“ 來判斷是否接受新的字元,如果接受那麼就接受新字元,否則,判斷目前狀態變數 state,看是否為不可接受並丏是丌是錯誤狀態。如果目前狀態可以接受,標明當前 tokenString 已經是一個 token,那麼就可以退出迴圈,或者目前狀態是錯誤,那麼也可以退出迴圈。如果 state 是不可以接受並且 state 不是錯誤的,那麼就可以繼續接受字元。

代碼如下:

 while(!acceptlist[state]&& state!=MERROR )                            {                   ch = getNextCharT(c);                           newState = (SateType)(translateTable[(int)state])[ch] ;                               if( tokenStringIndex < MAXTOKENLENTH && //當前的字元是否要儲存到當前的                                                                                                      //tokenString  中                            newState        != START    &&                              newState        != INCOMENT )                            tokenString[tokenStringIndex++] = c ;                   if((advanceTable[int(state)])[ch] == 1)                          //是否可以接受下一個字元                                          c    =    getNextChar();                   oldState = state ;                   state = newState;          }  

退出迴圈之後,就可以判斷目前狀態是否是可以接受狀態,如果可以接受,那麼判斷目前狀態 state是 rolldone,還是 notrolldone 
1).如果是 rolldone : 那麼就復原一個字元。即不儲存讀到的最後一個字元。 
2).如果是 notrolldone: 那麼就不用復原一個字元。 
接著根據 state 在沒有轉換到 done(rolldone 戒者 notrolldone)狀態之前的狀態來判斷當前 token 的類型

 if(acceptlist[state])            {                   if(state == ROLLDONE){                            tokenString[tokenStringIndex -1] = '\0';                            ungetNextChar();                   }                   else{                            tokenString[tokenStringIndex ++] = '\0';                   }                   switch (oldState){                                case START :                                     {                                              if( *tokenString == -1){                                                       currentToken = ENDFILE; //      華南理工大學軟體學院  08 級  陳俊邊    李本卿                                                       return currentToken      ;                                              }                                              else                                                         currentToken =    symbolLookup(tokenString);                                     }break ;                            case INNUM : currentToken =    NUM ;break ;                            case INID    : currentToken =    reservedLookup(tokenString)    ;break ;                            case INSTRING :currentToken =    STRINGS ;break ;                            default:currentToken = symbolLookup(tokenString);break ;                   }                             }          else{                   currentToken =    EORROR;          }          if(TranceScan){                   fprintf(listing,"%d ",lineno);                   printToken(currentToken,tokenString,listing);                   fprintf(listingDetails,"\t%d ",lineno);                   printToken(currentToken,tokenString,listingDetails);          }                   return currentToken; 

 

最後,如上面代碼最後 7 行,把當前的 tokenString 輸入到儲存檔案中,接著返回當前 token 的類型。 其中,提供給外界調用的介面是:int scan(); 

一點小總結:

簡單而言,編譯器就是將“進階語言”翻譯為“機器語言(低級語言)”的程式。一個現代編譯器的主要工作流程:原始碼 (source code) → 前置處理器 (preprocessor) → 編譯器 (compiler) → 組譯工具 (assembler) → 目標代碼 (object code) → 連結器 (Linker) → 可執行程式 (executables)。 從上面可以看出,在實現一個編譯器的過程中涉及了很多編程技術,一個真正的技術人員應該對這些編程技術都非常的熟悉,並且,在實現一個編譯器的過程中需要的不單是相關的編程技術,也需要編程人員擁有良好的開發態度和軟體開發思想,所以通過這次實驗不僅能學到有關編譯原理的知識,還能真正應用到自己的編程實踐中去。其實,課本裡的這些知識丌單可以應用到編寫編譯器上去,在我們平時的軟體開發實踐中也經常會用到,像Regex的應用,還有對 XML 檔案的操作等等。

在做詞法掃描器中,遇到的最大的問題,莫過於對狀態轉換表的設計由於狀態轉換表是整個程式的核心,通過狀態裝換表,程式才能夠實現通過接受每個字元,識別每個 token,最終把整個 tiny+的來源程式掃描處來。因此,我們花了較多的時間來討論表的設計,通過跟其他同學討論,和自己思考,最後把一個狀態轉換表設計出來。 

由於時間和能力的限制,整個表還是存在著一些問題,對以某些錯誤還是不能夠很好的識別,例如出現 112ab 這樣的情況,程式會任務 112a 是錯誤的 token ,而 b 是 ID ,而這很明顯是有問題的。正確的分析結果應該是 112ab 都是錯的。有鑒於此,為了能有讓程式有更好的可修改性,方便於以後修改,我把狀態轉換表寫到一個 XML 設定檔中,然後程式每次要運行才從中讀取,這樣以後如果發現狀態轉換表中的轉換邏輯出錯,只需要修改設定檔就可以了。 

第二個問題就是程式出現了一些問題,例如字元編碼的問題等等。 這次實現使得我們意識到在編程的前期,確實應該要注意些不同開發環境下編程的相容問題。要麼或者在早期就應該確定要用相同的環境。這樣才可以避免像我們這次程式所遇到的問題。還有確實表驅動的方法對於初學者來說,真的是一個不錯的方法,利用該方法可以減少代碼量和減低程式的複雜度,程式更容易理解和更容易完成。 
2010-10-26 20:31:42 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.