1. 程式人生 > >不羈的風的專欄--逆水行舟 不進則退

不羈的風的專欄--逆水行舟 不進則退

學課程為什麼要開設編譯原理呢?這門課程關注的是編譯器方面的產生原理和技術問題,似乎和計算機的基礎領域不沾邊,可是編譯原理卻一直作為大學本科的必修課程,同時也成為了研究生入學考試的必考內容。編譯原理及技術從本質上來講就是一個演算法問題而已,當然由於這個問題十分複雜,其解決演算法也相對複雜。我們學的資料結構與演算法分析也是講演算法的,不過講的基礎演算法,換句話說講的是演算法導論,而編譯原理這門課程講的就是比較專注解決一種的演算法了。在20世紀50年代,編譯器的編寫一直被認為是十分困難的事情,第一Fortran的編譯器據說花了18年的時間才完成。在人們嘗試編寫編譯器的同時,誕生了許多跟編譯相關的理論和技術,而這些理論和技術比一個實際的編譯器本身價值更大。就猶如數學家們在解決著名的哥德巴赫猜想一樣,雖然沒有最終解決問題,但是其間誕生不少名著的相關數論。 

推薦參考書 

雖然編譯理論發展到今天,已經有了比較成熟的部分,但是作為一個大學生來說,要自己寫出一個像Turboc C,Java那樣的編譯器來說還是太難了。不僅寫編譯器困難,學習編譯原理這門課程也比較困難。 

正是因為編譯原理學習相對困難,那麼就要求有好的教師和好的教材。教師方面不是我們能自己更改的,而在教材方面我們卻可以按自己的意願來閱讀。我下面推薦幾本好的編譯原理的教材。我推薦的書籍都是國外的經典教材,因為在國內的教材中,確實還沒發現什麼讓人滿意的。 

第一本書的原名叫《Compilers Principles,Techniques,and Tools》,另外一個響亮的名字就是龍書。原因是這本書的封面上有條紅色的龍,也因為獗臼樵詒嘁朐砘×煊蛉肥堤忻?所以很多國外的學者都直接取名為龍書。最近機械工業出版社已經出版了此書的中文版,名字就叫《編譯原理》。該書出的比較早,大概是在85或86年編寫完成的,作者之一還是著名的貝爾實驗室的科學家。裡面講解的核心編譯原理至今都沒有變過,所以一直到今天,它的價值都非凡。這本書最大的特點就是一開始就通過一個實際的小例子,把編譯原理的大致內容羅列出來,讓很多編譯原理的初學者很快心裡有了個底,也知道為什麼會有這些理論,怎麼運用這些理論。而這一點是我感覺國內的教材缺乏的東西,所以國內的教材都不是寫給願意自學的讀者,總之讓人看了半天,卻不知道里面的東西有什麼用。 

第二本書的原名叫《Modern Compiler Design》,中文名字叫做《現代編譯程式設計》。該書由人民郵電出版社所出。此書比較關注的是編譯原理的實踐,書中給出了不少的實際程式程式碼,還有很多實際的編譯技術問題等等。此書另外一個特點就是其“現代”而字。在傳統的編譯原理教材中,你是不可能看到如同Java中的“垃圾回收”等演算法的。因為Java這樣的解釋執行語言是在近幾年才流行起來的東西。如果你想深入學習編譯原理的理論知識,那麼你肯定得看前面那本龍書,如果你想自己動手做一個先進的編譯器,那麼你得看這本《現代編譯程式設計》。 

第三本書就是很多國內的編譯原理學者都推薦的那本《編譯原理及實踐》。或許是這本書引入國內比較早吧,我記得我是在高中就買了這本書,不過也是在前段時間才把整本書看完。此書作為入門教程也的確是個不錯的選擇。書中給出的編譯原理講解也相當細緻,雖然不如前面的龍書那麼深入,但是很多地方都是點到為止,作為大學本科教學已經是十分深入了。該書的特點就是注重實踐,不過感覺還不如前面那本《現代編譯程式設計》的實踐味道更重。此書的重點還是在原理上的實踐,而非前面那本那樣的技術實踐。《編譯原理及實踐》在講解編譯原理的各個部分的同時,也在逐步實踐一個現代的編譯器Tiny C.等你把整本書看完,差不多自己也可以寫一個Tiny C了。作者還對Lex和Yacc這兩個常用的編譯相關的工具進行了很詳細的說明,這一點也是很難在國內的教材中看到的。 

推薦了這三本教材,都有英文版和中文版的。很多英文好的同學只喜歡看原版的書,不我的感覺是這三本書的翻譯都很不錯,沒有必要特別去買英文版的。理解理論的實質比理解表面的文字更為重要。 

編譯原理的實質 

前面已經說過,學習編譯原理其實也就是學習演算法而已,沒什麼特別的。只不過這些演算法的產生已經形成了一套理論。下面我來看看編譯原理裡面到底有什麼高深的理論吧。 

幾乎每本編譯原理的教材都是分成詞法分析,語法分析(LL演算法,遞迴下降演算法,LR演算法),語義分析,執行時環境,中間程式碼,程式碼生成,程式碼優化這些部分。其實現在很多編譯原理的教材都是按照85,86出版的那本龍書來安排教學內容的,所以那本龍書的內容格式幾乎成了現在編譯原理教材的定式,包括國內的教材也是如此。一般來說,大學裡面的本科教學是不可能把上面的所有部分都認真講完的,而是比較偏重於前面幾個部分。像程式碼優化那部分東西,就像個無底洞一樣,如果要認真講,就是單獨開一個學期的課也不可能講得清楚。所以,一般對於本科生,對詞法分析和語法分析掌握要求就相對要高一點了。 

詞法分析相對來說比較簡單。可能是詞法分析程式本身實現起來很簡單吧,很多沒有學過編譯原理的人也同樣可以寫出各種各樣的詞法分析程式。不過編譯原理在講解詞法分析的時候,重點把正則表示式和自動機原理加了進來,然後以一種十分標準的方式來講解詞法分析程式的產生。這樣的做法道理很明顯,就是要讓詞法分析從程式上升到理論的地步。 

語法分析部分就比較麻煩一點了。現在一般有兩種語法分析演算法,LL自頂向下演算法和LR自底向上演算法。LL演算法還好說,到了LR演算法的時候,困難就來了。很多自學編譯原理的都是遇到LR演算法的理解成問題後就放棄了自學。其實這些東西都是隻要大家理解就可以了,又不是像詞法分析那樣非得自己寫出來才算真正的會。像LR演算法的語法分析器,一般都是用工具Yacc來生成,實踐中完全沒有比較自己來實現。對於LL演算法中特殊的遞迴下降演算法,因為其實踐十分簡單,那麼就應該要求每個學生都能自己寫。當然,現在也有不少好的LL演算法的語法分析器,不過要是換在非C平臺,比如Java,Delphi,你不能運用YACC工具了,那麼你就只有自己來寫語法分析器。 

等學到詞法分析和語法分析時候,你可能會出現這樣的疑問:“詞法分析和語法分析到底有什麼?”就從編譯器的角度來講,編譯器需要把程式設計師寫的源程式轉換成一種方便處理的資料結構(抽象語法樹或語法樹),那麼這個轉換的過程就是通過詞法分析和語法分析的。其實詞法分析並非一開始就被列入編譯器的必備部分,只是我們為了簡化語法分析的過程,就把詞法分析這種繁瑣的工作單獨提取出來,就成了現在的詞法分析部分。除了編譯器部分,在其它地方,詞法分析和語法分析也是有用的。比如我們在DOS,Unix,Linux下輸入命令的時候,程式如何分析你輸入的命令形式,這也是簡單的應用。總之,這兩部分的工作就是把不“規則”的文字資訊轉換成一種比較好分析好處理的資料結構。那麼為什麼編譯原理的教程都最終把要分析的源分析轉換成“樹”這種資料結構呢?資料結構中有Stack, Line,List…這麼多資料結構,各自都有各自的特點。但是Tree這種結構有很強的遞迴性,也就是說我們可以把Tree的任何結點Node提取出來後,它依舊是一顆完整的Tree。這一點符合我們現在編譯原理分析的形式語言,比如我們在函式裡面使用函樹,迴圈中使用迴圈,條件中使用條件等等,那麼就可以很直觀地表示在Tree這種資料結構上。同樣,我們在執行形式語言的程式的時候也是如此的遞迴性。在編譯原理後面的程式碼生成的部分,就會介紹一種堆疊式的中間程式碼,我們可以根據分析出來的抽象語法樹,很容易,很機械地運用遞迴遍歷抽象語法樹就可以生成這種指令程式碼。而這種程式碼其實也被廣泛運用在其它的解釋型語言中。像現在流行的Java,.NET,其底層的位元組碼bytecode,可以說就是這中基於堆疊的指令程式碼的。 

關於語義分析,語法制導翻譯,型別檢查等等部分,其實都是一種完善前面得到的抽象語法樹的過程。比如說,我們寫C語言程式的時候,都知道,如果把一個浮點數直接賦值給一個整數,就會出現型別不匹配,那麼C語言的編譯器是怎麼知道的呢?就是通過這一步的型別檢查。像C++語言這中支援多型函式的語言,這部分要處理的問題就更多更復雜了。大部編譯原理的教材在這部分都是講解一些比較好的處理策略而已。因為新的問題總是在發生,舊的辦法不見得足夠解決。 

本來說,作為一個編譯器,起作用的部分就是使用者輸入的源程式到最終的程式碼生成。但是在講解最終程式碼生成的時候,又不得不講解機器執行環境等內容。因為如果你不知道機器是怎麼執行最終程式碼的,那麼你當然無法知道如何生成合適的最終程式碼。這部分內容我自我感覺其意義甚至超過了編譯原理本身。因為它會把一個計算機的程式的執行過程都通通排在你面前,你將來可能不會從事編譯器的開發工作,但是隻要是和計算機軟體開發相關的領域,都會涉及到程式的執行過程。執行時環境的講解會讓你更清楚一個計算機程式是怎麼儲存,怎麼裝載,怎麼執行的。關於部分的內容,我強烈建議大家看看龍書上的講解,作者從最基本的儲存組織,儲存分配策略,非區域性名字的訪問,引數傳遞,符號表到動態儲存分配(malloc,new)都作了十分詳細的說明。這些東西都是我們編寫平常程式的時候經常要做的事情,但是我們卻少去探求其內部是如何完成。 

關於中間程式碼生成,程式碼生成,程式碼優化部分的內容就實在不好說了。國內很多教材到了這部分都會很簡單地走馬觀花講過去,學生聽了也只是作為了解,不知道如何運用。不過這部分內容的東西如果要認真講,單獨開一學期的課程都講不完。在《編譯原理及實踐》的書上,對於這部分的講解就恰到好處。作者主要講解的還是一種以堆疊為基礎的指令程式碼,十分通俗易懂,讓人看了後,很容易模仿,自己下來後就可以寫自己的程式碼生成。當然,對於其它程式碼生成技術,程式碼優化技術的講解就十分簡單了。如果要仔細研究程式碼生成技術,其實另外還有本叫做《Advance Compiler Desgin and Implement》,那本書現在由機械工業出版社引進的,十分厚重,而且是英文原版。不過這本書我沒有把它列為推薦書給大家,畢竟能把龍書的內容搞清楚,在中國已經就算很不錯的高手了,到那個時候再看這本《Advance Compiler Desgin and Implement》也不遲。程式碼優化部分在大學本科教學中還是一個不太重要的部分,就是算是實踐過程中,相信大家也不太運用得到。畢竟,自己做的編譯器能正確生成執行程式碼已經很不錯了,還談什麼優化呢? 

關於實踐 

編譯原理的課程畢竟還只是講解原理的課程,不是專門的編譯技術課程。這兩門課程是有很大的區別的。編譯技術更關注實際的編寫編譯器過程中運用到的技術,而原理的課關注講解其基本理論。但是電腦科學本身就是一門實踐性很強的課程,如果能夠學以致用,那才叫真正的學會。李陽在講解瘋狂英語的時候就說到,只要當你會實際中運用一個單詞一個片語的時候你才能叫學會了這個單詞或者片語,而不是隻是知道了它的拼寫和意思。其實任何學習都是一樣的,如果缺少了實踐的結合,你不能算學會。 

編譯原理的課程主要就是講解編譯器產生的理論和原理,那麼很簡單,自己寫個編譯器就是最好的實踐過程了。不過你得小心,編譯系統可能是所有軟體系統中最複雜的系統之一,不然為什麼大學裡面還會把編譯器的編寫開成一門叫做編譯原理的課程來講?我很佩服那些學了作業系統原理就開始自己寫作業系統,學了編譯原理就開始自己寫編譯器的人們,確實,在中國,敢這麼做的學生太少了。且不管你這樣做能不能做成功,至少有了這個嘗試,會讓你的程式設計,系統規劃安排的功底增進不少。我下面給出一些關於實踐過程中可能會遇到的困難,希望能夠在你陷入困境的前幫你一把。 

1. Lex和Yacc. 這兩工具是作為詞法分析很語法分析的工具。如果你自己寫一個編譯器,我十分不建議你連詞法分析這種事情都親手來寫。Lex和Yacc應該是作為每本編譯原理的教材的必備內容,可是在國內的教材中缺很少看到。這兩個工具是Unix系統下的小東西,如果你要在Windows中運用,那麼你最好去下在cygwin這個軟體。它是個在Windows下模擬Unix的東東,裡面就包含了flex.exe和bison.exe(yacc)這兩個工具.這兩個工具使用起來還挺麻煩的(其實unix 下的很多十分有用的工具都是這樣), 不過在《編譯原理與實踐》這本書上對於這兩個工具的講解十分詳細,還列舉了不少實際的例子。 

2. 做解釋型語言比做生成機器程式碼的編譯器簡單。雖然說,做解釋型的編譯器,像Java那樣的,你還得自己去寫直譯器,不過這樣你就不必去查詢機器程式碼的資料了。如果你做生成的最終機器程式碼編譯器可能會遇到問題還有就是暫存器為基礎的程式碼生成方法。前面說過,如果你生成的是以堆疊為基礎的程式碼,那麼其程式碼生成過程十分簡單,需要考慮的東西也不多,如果你考慮最終的機器程式碼生成的話,你必須考慮機器的暫存器如何分配等麻煩的問題。 

3. 考慮用別人已經生成的語法檔案,儘量不要自己動手寫詞法檔案和語法檔案.以前一個朋友曾經說過,寫出一個好的程式語言的語法定義,就幾乎完成了一個編譯器的一半.確實是這樣,語法檔案的編寫是個很難的事情.現在網上到處都可以找到比如C語言,C++,Java, Tiny C,Minus C等語言的詞法檔案和語法檔案,你完全可以自己下下來來用. 

在《編譯原理及實踐》的書中,作者給出了一個Tiny C的全部程式碼.我自我感覺作者的這個編譯器做得很不錯,相對於其它php,perl等語言的原始碼來說,簡單得多,容易看懂,而且很清晰地展現了一個完成的編譯系統的實現過程.其原始碼可以在作者的網站上下載. 

後話 

編譯原理的學習可能算是一個困難的歷程,特別是對於那些不對編譯系統感興趣的同學來說.既然它已經作為了大學本科的必修課程,那麼就說明的它引申出來的一套理論在整個電腦科學領域還是佔有相對重要的地位. 

如果我們考究一下歷史,就會發現很多被稱為程式設計大師的人都是編譯領域的高手.寫出第一個微型機上執行的Basic語言的比爾蓋茨,設計出Delphi的Borland的”世界上最厲害的程式設計師”, Sun的JAVA之父, 貝爾實驗室的C++之父…

相關推薦

不羈專欄--逆水行舟 不進則退

學課程為什麼要開設編譯原理呢?這門課程關注的是編譯器方面的產生原理和技術問題,似乎和計算機的基礎領域不沾邊,可是編譯原理卻一直作為大學本科的必修課程,同時也成為了研究生入學考試的必考內容。編譯原理及技術從本質上來講就是一個演算法問題而已,當然由於這個問題十分複雜,其解決演算法

讀左耳聽專欄:09渴望、熱情與選擇

渴望、熱情與選擇 這裡是我看了耗子叔專欄後的摘抄,加上自己的思考或總結。 加班太嚴重完全沒時間學習怎麼辦? 一方面:現在社會有些公司工作壓力大,經常加班,可以理解。 另一方面:我們在通宵打遊戲,追美劇,泡妞的時候,從來不會給自己找藉口說時間不夠。我們總是

做站如逆水行舟不進則退

放了個假回來,網站資料狂降,原因肯定是國慶7天內沒有任何新文章,不過好的是最近很多人的pr和百度索引都在降,而我的沒變化,還是老樣子。站長是個很辛苦的職業,每天都起早貪黑的看資料,想方設法地往前走,我不完全算一個站長,因為我的部落格純粹是興趣,或者說是為了有一個寫東西的地方而已,我是業餘的。連我這樣業餘的博主

逆水行舟不進則退

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>逆水行舟不進則退</title> <

學如逆水行舟不進則退;心似平原走馬,易放難收

在呼叫一個函式的過程中又出現直接或間接地呼叫該函式本身,稱為函式的遞迴(recursive)呼叫。C++允許函式的遞迴呼叫,例如: int f(int x) { int y, z; z = f(y); //在呼叫函式f的過程中,又要呼叫f函式 return (2 *

吹夏天的專欄

我個人一向對磨皮類演算法不抱有興趣,初衷還是美化自然場景,所以看官若是對人像美化感興趣的,可以看人在旅途的部落格。 先前對磨皮印象不過是用一種保邊濾波器平滑處理一下,但見旅途這段時間做的工作都是磨皮,索性看一下。方法也很簡單,就一個公式,我用matlab測試了

guisu,程式人生。 逆水行舟不進則退

     Spring 框架作為目前非常流行的一個 Java 應用開發框架,它所包含的內容是非常繁多的。Spring 框架包含幾十個不同的子專案,涵蓋應用開發的不同方面。要在這些子專案之間進行選擇,並快速搭建一個可以執行的應用是比較困難的事情。Spring Boot

探梅的專欄

參考資料: 《OpenCV 2 Computer Vision Application Programming Cookbook》《The OpenCV Reference Manual》 讀取視訊 123456789

起何緣的專欄

6、null(沒有值 空值) 零和null 是不一樣的null表示空值沒有值,零表示一個確定的值null 不參與<> 、!=、= 運算但可以參與is 或is not運算任何數字與null參與數學運算結果為null任何型別的資料都可以為null。如: cr

專欄--Oracle/ClearCase管理員日記

     在一個ORACLE資料庫執行過程中,有時候會遇到要批量刪除資料的情況,如一個儲存歷史資料的表中有大量的資料已經不需要保留,要將這部分資料刪除。以下就這種情況可以採取的方法進行討論。 1、使用TRUNCATE命令進行刪除。 如果是整個表的資料都要刪除的話,使用TRU

左耳朵耗子-左耳聽-技術專欄

陳皓通過一篇篇觀點鮮明、文風犀利的文章吸引了大量 IT 從業人員的關注,影響了成千上萬程式設計師在技術選型、求職就業、個人成長等方面的思考和發展。 在過去這 20 年中,作者意識到,很多人都非常在意自己的成長。所以,在專欄中會結合他的親身經歷的,撰寫一系列與個人發展相關的文

樸(guofengpu)的Android影音專欄

別能讓不好意思,成為人生的絆腳石,缺的還是勇氣,   1.乞丐不好意思要飯,結果餓死了;    2.商戶不好意思要賬,結果自己門店關了;     3.不好意思向心儀的人表白,結果她跟別人走了;    4.不好意思讓客戶簽單,結果客戶在別人那裡成交

學如逆水行舟不進則退

在上面向物件課程的時候,老師出了一個題目,讓通過程式輸出一個回型矩陣。 n=1的回型矩陣 1 n=2的回型矩陣 1     2 4     3 n=3的回型矩陣 1    2    3 8    9    4 7    6    5 n=4的回型矩陣 1       2  

crystal521(雲淡輕)的專欄

1、資源中加入對話方塊背景圖片,命名為IDB_BK;2、dlg類標頭檔案中定義 private: CBitmap m_bitmap; CBrush  m_brush; 3、在OnInitDialog中加入BOOL CDlg::OnInitDialog(){ ... m_bit

學如逆水行舟不進則退

   距離上一次寫部落格已經差不多有四十多天的時間了,工作很緊張也很忙碌,但是思考的東西卻更多了。從研究生畢業算起,自己工作也差不多四年半了。和剛畢業的學生不同,我現在思考的不僅僅是工作、知識和生活,更多的還有自己的發展軌跡。當然,偶爾也會發呆,生活中自己需要的究竟是什麼

愛留圖 - 一個定期開設專欄活動的圖片收集網站誕生。

數據庫 解決方案 sql 本章和大家分享的是一個自制的圖片收集網站:愛留圖;本章不打算分享什麽技術知識點,而分享的主要內容有網站的創立的需求,現階段采用的技術架構,服務器配置等信息;在站點服務構建時用到的部分技術,知識點,以及遇到的問題會在後面分不同的章節+不同的小節來講解,樂於和大家分享自己的經

命運 曾經 清晰 讓我 寂寞 時間 我們 愛的 想象 起風了。 “我似乎不比普通人幸福,也並非不幸。那種人們所謂的幸福,曾經讓我們那樣焦慮,現在卻能隨時忘掉。或許我現在的狀態更接近幸福,卻又比幸福多一點悲傷,但也並非不快樂... ...我能現在這樣若無其事地活著,或許是因為

樹秀於林必摧之——線段樹

線段 strong pda -1 自己的 我們 不重復 ebe wid 關於線段樹,其實我一開始也是很懵的,但看久了也就習慣了。   以下是我對線段樹的一點理解,寫得不好,也請各位看官見諒。   搜狗定義:線段樹(Segment Tree)是一種二叉搜索樹,它將一個區間劃分

九萬裏鵬正舉,揚帆起航,踏上新征程

machine 搭建 了解 小程序 機器學習 起航 knn rnn 萬裏 畢業後就從事了現在這份工作,算一算已經10多年了。日常工作內容包括軟件開發、系統維護、網絡搭建、軟件平臺應用等,算是專業對口,平時空閑時間也比較多。人已近中年,卻還有一顆躁動不安的心,始終想在技術上再

往事隨明今朝

loser 朋友 做人做事 愛人 報紙 知識通過學習就可以提升,而做人做事卻不是僅靠學習就能夠成為自己的一部分。起初丈二和尚——摸不著頭腦,可能難免走邯鄲學步的彎路,但無論如何,經歷過都會成長,區別就在於向好的一方面發展,還是不好的一方面。抱怨是最無能的表現,因為充實的人生沒有心思去抱怨。