編譯原理學習--詞法分析(1)

詞法分析的任務:

  首先,從階段上來看,編譯器可分爲若干個中間階段:前端

    

  典型的,能夠包含爲一個前端,一個後端。前端接收源程序產生一箇中間表示,後端接收中間表示繼續生成一個目標程序。因此,前端處理的是跟源語言有關的屬性,後端處理跟目標機器有關的屬性。程序員

  更細節的,前端能夠劃分爲若干個階段:正則表達式

    

  下面咱們看看詞法分析器的任務:
算法

    

  詞法分析器讀入程序員寫的程序,而後對字符流作切分紅記號流。舉個例子:後端

    這是一個程序員看到的字符流數據結構

  詞法分析器將字符流讀入,根據關鍵字、標識符、標點、字符串、整形數等進行劃分,造成記號流(單詞):閉包

    

  那麼就會有兩個問題:1.記號的數據結構如何定義? 2.如何實現從字符流到記號流轉換的算法?
工具

  首先看第一個問題,如何定義記號的數據結構,假如用C語言實現數據結構的定義,能夠這樣實現:flex

    

  舉個例子:假如源語句if(x>5),則詞法分析器返回token{k=IF,lexeme=0};token{k=IPAREN,lexeme=0};token{k=ID,lexeme="X"};……編碼

 

  【此處小結】:詞法分析器的任務:字符流到記號流。

       字符流:和被編譯語言密切相關(ASCII,Unicode,or……)

       記號流:編譯器內部定義的數據結構,編碼所識別出的詞法單元

 

  再看第二個問題,詞法分析器怎麼實現呢?目前來講通常有兩種方案:

    1.手工編碼實現法。這種方法相對複雜,容易出錯,可是很是流行的方法,如GCC,LLVM等。

    2.詞法分析器的生成器。這種方法可快速原型,代碼量少,但較難控制細節。

  (1)咱們先看第一種方案,手工編碼法。如何識別語言中的各類符號呢?假設咱們分析一種語言,包含如下關係運算符:<=、>=、<>、=、>、<,咱們能夠用轉移圖對其進行識別,轉移圖以下所示:

       

   那麼怎麼用算法實現這個轉移圖呢?以下所示:

     

  同理,語言中其餘標識符的識別也相似實現:

    

  實際上這兩張轉移圖(包括代碼)是結合在一塊兒的。

  那麼問題來了,如何區別關鍵字標識符呢?由於在不少語言中關鍵字和標識符是有交集的,但從詞法分析上看,關鍵字是標識符的一部分。以C語言爲例,標識符是:以字母或下劃線開頭,後跟0個或多個字母、下劃線或數字。關鍵字:if、while、else……

  怎麼識別關鍵字呢?這裏介紹兩種方法。

  先看第一種,咱們須要將上面的轉移圖稍加修改:(以識別if爲例)

    此處還應注意一個問題,假如輸入ifxy呢?並非關鍵字,所以這裏還需判斷。

    

  再看第二種,使用關鍵字表,即Hash表。對語言中全部的關鍵字構建哈希表,對全部的關鍵字和標識符,先統一按標識符的轉移表進行識別,識別完成後,再查哈希表看是否爲關鍵字。經過構造合理的哈希表,能夠再O(1)時間內完成。

 

  (2)再看第二種方案,詞法分析器的生成器。那麼怎樣自動生成呢?

    

  這種方案不須要像第一種方案那麼繁瑣,只須要用正則表達式寫出程序語言中的詞法規則,而後經過自動生成工具lex,flex,jlex等,自動產生出詞法分析器,生成的詞法分析器跟第一種方案的圖轉移算法是相似的,可是,程序員只須要寫一個聲明式規範,工做量就顯著減少了。

  如何寫這種聲明式規範呢?首先咱們要先學正則表達式。什麼是正則表達式,其定義以下:

    

   舉個例子,對於字符集Σ={a,b},能夠寫出哪些正則表達式? ε、a、b、ε|a,ε|b……εε、εa、εb、ab、a(ε|a)……ε*、a(ε|a)*……

  知道正則表達式了,那麼如何用正則表達式表示程序語言的詞法規則呢?再看個例子:C語言中的關鍵字if如何用正則表達式表示?if中i∈Σ,f∈Σ,根據定義則if∈Σ。再看個複雜點的,如何用正則表達式表示C語言的標識符?可將標識符寫成兩部分,第一部分只能以字母或下劃線開頭,後鏈接零個或多個字母、下劃線、數字(閉包),則正則表達式爲(a|b|c……A|B|C……|_)(a|b|c……A|B|C……|0|1|2……|_)*。可是這樣表達顯然比較繁瑣,能夠引入更多的語法糖來構造正則表達式,來簡化構造:

    

相關文章
相關標籤/搜索