做 C 語言編譯器前端的難度如何?

想嘗試做一下,但是不知道難度如何。


先來看看 C 標準是怎麼規定一個 C Compiler 在翻譯過程中應該完成哪些步驟的(主要參考自ISO/IEC 9899(俗稱C99)標準 "5.1.1.2 Translation phases")

第一階段:對字符集進行轉換;三並字(Trigraph sequences)被替換為單個字元。

第二階段:行末的反斜杠 被刪除,實現行連接。

第三階段:整個源文件被識別為一系列的預處理記號(preprocessing tokens)和空白字元(含注釋);一塊注釋替換為一個空格;換行符被保留。

第四階段:預處理指令被執行,宏調用展開,_Pragma 一元運算符表達式執行;#include 預處理指令所涉及的文件,也被按照當前所描述的階段一至階段四進行處理,且處理過程是遞歸的;以上完畢後,預處理指令被刪除。

第五階段:字元常量(character constants)和字元串字面量(string literals)中的字符集成員和轉義序列被轉換。

第六階段:連接毗鄰的字元串字面量記號。

第七階段:預處理記號(preprocessing tokens)轉換為一般記號(token);並對轉換後的一般記號進行語法及語義上的分析,然後轉換為翻譯單元(translation unit)。

第八階段:解析對外部對象和函數的引用;鏈接庫組件(library components),獲得可執行的程序映像文件(program image)。

上面八個階段中,前六個階段至第七階段的前半部分,大體上對應了大多數程序員熟知的「預處理過程」,而第七個階段的後半部分則是「編譯過程」(實則涵蓋了文法分析、語義分析、等許多細分階段),最後的第八階段則是「鏈接過程」。

上述八個階段的描述並不是對原文的直接翻譯,為了簡明扼要和重點突出,做了修改和總結。並不能替代標準中的描述。想要獲得精確的信息,請一定參考原文。

可以看到,要實現工業級的 C 編譯器其實是個苦力活。有許多細節需要處理。

但是大多數人想做 C 編譯器初衷只是實驗和學習。對編碼轉換、三並字處理、轉義序列處理之類的問題其實並無興趣。更大的興趣其實是如何實現(手工)文法分析。為此,我介紹一些「特(gui)別(chu)的技巧」,那麼事情的難度就會大大降低。

----------------------------------------------------------------------------

10 月 20 日更新 —— 了解「粘連」與 SSF 化

----------------------------------------------------------------------------

因為樓主很忙(借口,其實是拖延症+懶癌),所以會逐步更新。

在 C 語言里(其實很多語言都這樣,但是這裡就不贅述了,大家自行根據經驗腦補),代碼的格式是很「自由化」的。

第一個顯著的特點就是,空白字元的數量很自由,例如下述三行都是等價的

if (a&>b)

if ( a &> b )

if ( a &> b )

這使得 C 程序的格式排版更加自由。但是也使得 tokenize 過程中必須考慮到這一因素,增加了一定的複雜度。

第二個顯著的特點是,有些 token 之間必須存在至少一個空白字元作為分隔,但另外一些 token 則允許「粘連」在一起,例如下面的例子

int main() { ... } // 不能寫成 intmain() { ... }

a ++ + b // 可以「粘連」寫成 a+++b

「粘連」的存在使得 tokenize 演算法寫起來變得頗為羅嗦。因為可能會有「粘連」,我們不能簡單的按照某種「單一」標準去搜尋 token。

為了解決這一問題,有很多種策略。你如果翻閱解析器方面的參考資料,大致上會找到不少。不過我今天先介紹一種比較簡單粗暴又有趣的方法,稱之為 SSF 化。

SSF 是 Space Spliting Format (空格分隔形式)的縮寫。簡單來說 SSF 化,就是將原本「粘連」的代碼「展開」的過程。下面舉幾個例子

int a=b+c-d; // SSF 化之後變為 int a = b + c - d ;

a+++b; // SSF 化之後變為 a ++ + b ;

如果一個代碼的形式是 SSF 化的,那麼,我們其實就可以直接以空格(space)為特徵對其進行分詞。

後續我們會介紹 SSF 化的實現。但是在接下來的部分,我們會先介紹另外一項重要的概念,「Reduce」


做一個玩具不難

做好了還是有一些難度的,做到讓大家都來用,難度就很大了,整個編譯行業c前端那麼少是有原因的


一個ebnf的事。

最多一小時吧,不能再多了。

以及畢業設計做這種不懂計算機的人都能做的事情是不是有點過分?


編譯器前端已經相當成熟 有很多現成的輪子

lex + yacc

flex + bison

antlr

或者手寫遞歸下降分析器

做這個很酷 但其實後端才是重點


前端到語法分析結束嗎?用不用前端工具?c語法是現成的,用工具(如lexyacc 或 antlr)直接生成了詞法語法分析器,easy,都是現成的。

不用前端工具?自己寫詞法語法分析器,做c--可行,但是要支持完整的c語言就比較困難和繁瑣了。

anyway,自己寫詞法和語法分析器固然好,但是不如做後面的程序分析(數據流分析)意義大。可以用前端工具快速生成詞法語法分析器,抽象語法樹,然後進行數據流分析,個人覺得這樣更好。


除非你準備不用flex-bison這類語法解析框架擼一個難度是NORMAL模式之外,用框架都是EASY模式

當然,工業級的東西擼出來大概是HARD模式,也沒到NIGHTMARE就是了


拿YACC和FLEX套一下大四生還是可以完成的.後端用LLVM


不難,有現成的,需要聯繫


做個實驗用的簡單,計算機專業本科生的水平。做個商業級,具有良好擴展性和健壯性的難。


推薦閱讀:

開發效率與執行效率,我們應該怎樣斟酌?
為什麼大部分碼農做不了軟體架構師?
大學可以逃課自主學習嗎?
求解一個C語言問題?

TAG:編程 | C編程語言 | 畢業設計 | 編譯器 |