導航:首頁 > 源碼編譯 > 編譯原理LL1心得體會

編譯原理LL1心得體會

發布時間:2022-10-07 23:26:42

㈠ 為什麼要學習編譯原理(轉)

大學課程為什麼要開設編譯原理呢?這門課程關注的是編譯器方面的產生原理和技術問題,似乎和計算機的基礎領域不沾邊,可是編譯原理卻一直作為大學本科的必修課程,同時也成為了研究生入學考試的必考內容。編譯原理及技術從本質上來講就是一個演算法問題而已,當然由於這個問題十分復雜,其解決演算法也相對復雜。我們學的數據結構與演算法分析也是講演算法的,不過講的基礎演算法,換句話說講的是演算法導論,而編譯原理這門課程講的就是比較專註解決一種的演算法了。在20世紀50年代,編譯器的編寫一直被認為是十分困難的事情,第一Fortran的編譯器據說花了18年的時間才完成。在人們嘗試編寫編譯器的同時,誕生了許多跟編譯相關的理論和技術,而這些理論和技術比一個實際的編譯器本身價值更大。就猶如數學家們在解決著名的哥德巴赫猜想一樣,雖然沒有最終解決問題,但是其間誕生不少名著的相關數論。 推薦參考書 雖然編譯理論發展到今天,已經有了比較成熟的部分,但是作為一個大學生來說,要自己寫出一個像TurbocC,Java那樣的編譯器來說還是太難了。不僅寫編譯器困難,學習編譯原理這門課程也比較困難。 第一本書的原名叫《CompilersPrinciples,Techniques,andTools》,另外一個響亮的名字就是龍書。原因是這本書的封面上有條紅色的龍,也因為獗臼樵詒嘁朐?砘?嘴域確實?忻?所以很多國外的學者都直接取名為龍書。最近機械工業出版社已經出版了此書的中文版,名字就叫《編譯原理》。該書出的比較早,大概是在85或86年編寫完成的,作者之一還是著名的貝爾實驗室的科學家。裡面講解的核心編譯原理至今都沒有變過,所以一直到今天,它的價值都非凡。這本書最大的特點就是一開始就通過一個實際的小例子,把編譯原理的大致內容羅列出來,讓很多編譯原理的初學者很快心裡有了個底,也知道為什麼會有這些理論,怎麼運用這些理論。而這一點是我感覺國內的教材缺乏的東西,所以國內的教材都不是寫給願意自學的讀者,總之讓人看了半天,卻不知道裡面的東西有什麼用。 第二本書的原名叫《ModernCompilerDesign》,中文名字叫做《現代編譯程序設計》。該書由人民郵電出版社所出。此書比較關注的是編譯原理的實踐,書中給出了不少的實際程序代碼,還有很多實際的編譯技術問題等等。此書另外一個特點就是其現代而字。在傳統的編譯原理教材中,你是不可能看到如同Java中的垃圾回收等演算法的。因為Java這樣的解釋執行語言是在近幾年才流行起來的東西。如果你想深入學習編譯原理的理論知識,那麼你肯定得看前面那本龍書,如果你想自己動手做一個先進的編譯器,那麼你得看這本《現代編譯程序設計》。 第三本書就是很多國內的編譯原理學者都推薦的那本《編譯原理及實踐》。或許是這本書引入國內比較早吧,我記得我是在高中就買了這本書,不過也是在前段時間才把整本書看完。此書作為入門教程也的確是個不錯的選擇。書中給出的編譯原理講解也相當細致,雖然不如前面的龍書那麼深入,但是很多地方都是點到為止,作為大學本科教學已經是十分深入了。該書的特點就是注重實踐,不過感覺還不如前面那本《現代編譯程序設計》的實踐味道更重。此書的重點還是在原理上的實踐,而非前面那本那樣的技術實踐。《編譯原理及實踐》在講解編譯原理的各個部分的同時,也在逐步實踐一個現代的編譯器TinyC.等你把整本書看完,差不多自己也可以寫一個TinyC了。作者還對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)都作了十分詳細的說明。這些東西都是我們編寫平常程序的時候經常要做的事情,但是我們卻少去探求其內部是如何完成。 關於中間代碼生成,代碼生成,代碼優化部分的內容就實在不好說了。國內很多教材到了這部分都會很簡單地走馬觀花講過去,學生聽了也只是作為了解,不知道如何運用。不過這部分內容的東西如果要認真講,單獨開一學期的課程都講不完。在《編譯原理及實踐》的書上,對於這部分的講解就恰到好處。作者主要講解的還是一種以堆棧為基礎的指令代碼,十分通俗易懂,讓人看了後,很容易模仿,自己下來後就可以寫自己的代碼生成。當然,對於其它代碼生成技術,代碼優化技術的講解就十分簡單了。如果要仔細研究代碼生成技術,其實另外還有本叫做《》,那本書現在由機械工業出版社引進的,十分厚重,而且是英文原版。不過這本書我沒有把它列為推薦書給大家,畢竟能把龍書的內容搞清楚,在中國已經就算很不錯的高手了,到那個時候再看這本《》也不遲。代碼優化部分在大學本科教學中還是一個不太重要的部分,就是算是實踐過程中,相信大家也不太運用得到。畢竟,自己做的編譯器能正確生成執行代碼已經很不錯了,還談什麼優化呢? 編譯原理的課程畢竟還只是講解原理的課程,不是專門的編譯技術課程。這兩門課程是有很大的區別的。編譯技術更關注實際的編寫編譯器過程中運用到的技術,而原理的課

㈡ 編譯原理題,在建立LL(1)語法分析器時,提左因子和消除左遞歸的目的是什麼

消除左遞歸是因為LL文法不能處理含有左遞歸的文法。
提左因子只是推後產生式的選擇決定,等到獲取足夠多的輸入再作選擇。

㈢ LL(1)文法-------編譯原理

我正在寫一個編譯器,源代碼在這里:
http://code.google.com/p/bellman/source/browse
其中詞法規則在lex.l文件中,語法規則在grammer.y中,分別用flex和bison的輸入文件的格式寫的。我實現了一個類似C/C++的語法

地址如下:
http://code.google.com/p/bellman/source/browse/trunk/lib/bellman/lex.l
http://code.google.com/p/bellman/source/browse/trunk/lib/bellman/grammer.y
具體有什麼問題可以發郵件[email protected]

㈣ 編譯原理的LL(1)文法是什麼意思

第一個L表示從左向右讀取要判斷的字元(括弧內數字表示每次讀取的字元數),第二個L指最左推導。

㈤ 編譯原理語法分析LL(1)程序

推薦你找一下Lex和Yacc的教程。然後,下載一個bison 的windows版本,可以可以VC6集成在一起,自己寫一下Lex和Yacc文件。

你要做一個C語言的語法分析器么?太復雜了。
還是一個更簡單的語言?

分析出什麼結果呢?生成中間表示么?

如果不用Lex,Yacc的話,手寫就更難了。不過也能寫,只要你有時間,慢慢照著書上寫就行。呵呵。祝你好運!

㈥ 編譯原理的LL(1)文法是什麼意思

LL(1)的含義:第1個L表明自頂向下分析是從左向右掃描輸入串,第2個L表明分析過程中將用最左到推倒,1表明只需向右看一個符號便可決定如何推倒即選擇哪個產生式(規則)進行推導,類似也可以有LL(k)文法,也就是需要向前查看k個符號才能確定選用哪個產生式。
這是從我們編譯原理課本上抄來的,希望對你有幫助

㈦ 編譯原理的LL(1)文法是什麼意思

1.文法不含左遞歸,沒有公共左因子
2.對於文法中的每個非終結符A的產生式的候選首符集兩兩不相交。
3.對於文法中的每個非終結符A,它存在某個候選首符集包括ε,則FIRST(A)∩FOLLOW(A)=空
滿足以上條件的文法為LL(1)文法

㈧ 關於LL(1)文法

(1)first(E)={(,i},first(D)={+,-,ε},first(T)={(,i},first(S)={*,/,ε}
first(F)={(,i}
follow(E)={#,)},follow(D)={#,)},follow(T)={+,-,#,)} follow(S)={+,-,#,)} follow(F)={*,/,+,-,#,)}
(2)select(E->TD)=FIRST(TD)={(,i}
SELECT(E->+TD)={+}
SELECT(E->-TD)={-}
SELECT(E->ε)={#,)}
SELECT(T->FS)={(,i}
SELECT(S->*FS)={*}
SELECT(S->/FS)={/}
SELECT(S->ε)={+,-,#,)}
SELECT(F->(E))={(}
SELECT(F->i)={i}
預測分析表:
+ - * / ( ) i #
E ->+TD ->-TD ->TD ->ε ->TD ->ε
D
T ->FS ->FS
S ->ε ->ε ->*FS ->/FS ->(E) ->ε ->ε
F ->i

(3)i/i-i的分析過程:
步驟 輸入串 剩餘串 移進或規約
1 # i/i-i#
2 #i /i-i# E->TD
3 #DT ......
...
剩餘的只要按照書上的步驟填就行了。

㈨ 編譯原理-LL1文法詳細講解

我們知道2型文法( CFG ),它的每個產生式類型都是 α→β ,其中 α ∈ VN , β ∈ (VN∪VT)*。

例如, 一個表達式的文法:

最終推導出 id + (id + id) 的句子,那麼它的推導過程就會構成一顆樹,即 CFG 分析樹:

從分析樹可以看出,我們從文法開始符號起,不斷地利用產生式的右部替換產生式左部的非終結符,最終推導出我們想要的句子。這種方式我們稱為自頂向下分析法。

從文法開始符號起,不斷用非終結符的候選式(即產生式)替換當前句型中的非終結符,最終得到相應的句子。
在每一步推導過程中,我們需要做兩個選擇:

因為一個句型中,可能存在多個非終結符,我們就不確定選擇那一個非終結符進行替換。
對於這種情況,我們就需要做強制規定,每次都選擇句型中第一個非終結符進行替換(或者每次都選擇句型中最後一個非終結符進行替換)。

自頂向下的語法分析採用最左推導方式,即總是選擇每個句型的最左非終結符進行替換。

最終的結果是要推導出一個特定句子(例如 id + (id + id) )。
我們將特定句子看成一個輸入字元串,而每一個非終結符對應一個處理方法,這個處理方法用來匹配輸入字元串的部分,演算法如下:

方法解析:

這種方式稱為遞歸下降分析( Recursive-Descent Parsing ):

當選擇的候選式不正確,就需要回溯( backtracking ),重新選擇候選式,進行下一次嘗試匹配。因為要不斷的回溯,導致分析效率比較低。

這種方式叫做預測分析( Predictive Parsing ):

要實現預測分析,我們必須保證從文法開始符號起,每一個推導過程中,當前句型最左非終結符 A 對於當前輸入字元 a ,只能得到唯一的 A 候選式。

根據上面的解決方法,我們首先想到,如果非終結符 A 的候選式只有一個以終結符 a 開頭候選式不就行了么。
進而我們可以得出,如果一個非終結符 A ,它的候選式都是以終結符開頭,並且這些終結符都各不相同,那麼本身就符合預測分析了。

這就是S_文法,滿足下面兩個條件:

例子:

這就是一個典型的S_文法,它的每一個非終結符遇到任一終結符得到候選式是確定的。如 S -> aA | bAB , 只有遇到終結符 a 和 b 的時候,才能返回 S 的候選式,遇到其他終結符時,直接報錯,匹配不成功。

雖然S_文法可以實現預測分析,但是從它的定義上看,S_文法不支持空產生式(ε產生式),極大地限制了它的應用。

什麼是空產生式(ε產生式)?

例子

這里 A 有了空產生式,那麼 S 的產生式組 S -> aA | bAB ,就可以是 a | bB ,這樣 a , bb , bc 就變成這個文法 G 的新句子了。

根據預測分析的定義,非終結符對於任一終結符得到的產生式是確定的,要麼能獲取唯一的產生式,要麼不匹配直接報錯。

那麼空產生式何時被選擇呢?

由此可以引入非終結符 A 的後繼符號集的概念:
定義: 由文法 G 推導出來的所有句型,可以出現在非終結符 A 後邊的終結符 a 的集合,就是這個非終結符 A 的後繼符號集,記為 FOLLOW(A) 。

因此對於 A -> ε 空產生式,只要遇到非終結符 A 的後繼符號集中的字元,可以選擇這個空產生式。
那麼對於 A -> a 這樣的產生式,只要遇到終結符 a 就可以選擇了。

由此我們引入的產生式可選集概念:
定義: 在進行推導時,選用非終結符 A 一個產生式 A→β 對應的輸入符號的集合,記為 SELECT(A→β)

因為預測分析要求非終結符 A 對於輸入字元 a ,只能得到唯一的 A 候選式。
那麼對於一個文法 G 的所有產生式組,要求有相同左部的產生式,它們的可選集不相交。

在 S_文法基礎上,我們允許有空產生式,但是要做限制:

將上面例子中的文法改造:

但是q_文法的產生式不能是非終結符打頭,這就限制了其應用,因此引入LL(1)文法。

LL(1)文法允許產生式的右部首字元是非終結符,那麼怎麼得到這個產生式可選集。
我們知道對於產生式:

定義: 給定一個文法符號串 α , α 的 串首終結符集 FIRST(α) 被定義為可以從 α 推導出的所有串首終結符構成的集合。

定義已經了解清楚了,那麼該如何求呢?
例如一個文法符號串 BCDe , 其中 B C D 都是非終結符, e 是終結符。

因此對於一個文法符號串 X1X2 … Xn ,求解 串首終結符集 FIRST(X1X2 … Xn) 演算法:

但是這里有一個關鍵點,如何求非終結符的串首終結符集?

因此對於一個非終結符 A , 求解 串首終結符集 FIRST(A) 演算法:

這里大家可能有個疑惑,怎麼能將 FIRST(Bβ) 添加到 FIRST(A) 中,如果問文法符號串 Bβ 中包含非終結符 A ,就產生了循環調用的情況,該怎麼辦?

對於 串首終結符集 ,我想大家疑惑的點就是,串首終結符集到底是針對 文法符號串 的,還是針對 非終結符 的,這個容易弄混。
其實我們應該知道, 非終結符 本身就屬於一個特殊的 文法符號串
而求解 文法符號串 的串首終結符集,其實就是要知道文法符號串中每個字元的串首終結符集:

上面章節我們知道了,對於非終結符 A 的 後繼符號集 :
就是由文法 G 推導出來的所有句型,可以出現在非終結符 A 後邊的終結符的集合,記為 FOLLOW(A) 。

仔細想一下,什麼樣的終結符可以出現在非終結符 A 後面,應該是在產生式中就位於 A 後面的終結符。例如 S -> Aa ,那麼終結符 a 肯定屬於 FOLLOW(A) 。

因此求非終結符 A 的 後繼符號集 演算法:

如果非終結符 A 是產生式結尾,那麼說明這個產生式左部非終結符後面能出現的終結符,也都可以出現在非終結符 A 後面。

我們可以求出 LL(1) 文法中每個產生式可選集:

根據產生式可選集,我們可以構建一個預測分析表,表中的每一行都是一個非終結符,表中的每一列都是一個終結符,包括結束符號 $ ,而表中的值就是產生式。
這樣進行語法推導的時候,非終結符遇到當前輸入字元,就可以從預測分析表中獲取對應的產生式了。

有了預測分析表,我們就可以進行預測分析了,具體流程:

可以這么理解:

我們知道要實現預測分析,要求相同左部的產生式,它們的可選集是不相交。
但是有的文法結構不符合這個要求,要進行改造。

如果相同左部的多個產生式有共同前綴,那麼它們的可選集必然相交。
例如:

那麼如何進行改造呢?
其實很簡單,進行如下轉換:

如此文法的相同左部的產生式,它們的可選集是不相交,符合現預測分析。

這種改造方法稱為 提取公因子演算法

當我們自頂向下的語法分析時,就需要採用最左推導方式。
而這個時候,如果產生式左部和產生式右部首字元一樣(即A→Aα),那麼推導就可能陷入無限循環。
例如:

因此對於:

文法中不能包含這兩種形式,不然最左推導就沒辦法進行。

例如:

它能夠推導出如下:

你會驚奇的發現,它能推導出 b 和 (a)* (即由 0 個 a 或者無數個 a 生成的文法符號串)。其實就可以改造成:

因此消除 直接左遞歸 演算法的一般形式:

例如:

消除間接左遞歸的方法就是直接帶入消除,即

消除間接左遞歸演算法:

這個演算法看起來描述很多,其實理解起來很簡單:

思考 : 我們通過 Ai -> Ajβ 來判斷是不是間接左遞歸,那如果有產生式 Ai -> BAjβ 且 B -> ε ,那麼它是不是間接左遞歸呢?
間接地我們可以推出如果一個產生式 Ai -> αAjβ 且 FIRST(α) 包括空串ε,那麼這個產生式是不是間接左遞歸。

㈩ LL(1)分析法是什麼

LL(1)分析使用顯式棧而不是遞歸調用來完成分析。以標准方式表示這個棧非常有用,這樣LL(1)分析程序的動作就可以快捷地顯現出來。在這個介紹性的討論中,我們使用了生成成對括弧的串的簡單文法:
S →(S) S |
且將額外的棧項推向右邊。輸入符號由左列向右。美元符號標出了輸入的結束(它與由掃描程序生成的 EOF 記號相對應)。給出了由分析程序執行的動作的簡短描述,它將改變棧和(有可能)輸入。
LL(1)分析中的重復和選擇也存在著與在遞歸下降程序分析中遇到的類似問題,而且正是由於這個原因,還不能夠為的簡單演算法表達式文法給出一個LL(1)分析表

閱讀全文

與編譯原理LL1心得體會相關的資料

熱點內容
成都市區建成面積演算法 瀏覽:658
智能家居單片機 瀏覽:95
買男裝用什麼app好 瀏覽:853
文件夾合並了怎麼拆開 瀏覽:256
波段副圖源碼無未來函數 瀏覽:86
livecn伺服器地址 瀏覽:257
程序員這個工作真的很吃香嗎 瀏覽:844
程序員和數學分析師待遇 瀏覽:678
壓縮氣彈簧怎麼拆 瀏覽:321
華為公有雲伺服器添加虛擬ip 瀏覽:209
程序員和運營哪個累 瀏覽:24
抖音安卓信息提示音怎麼設置 瀏覽:454
光速虛擬機的共享文件夾 瀏覽:248
程序員培訓機構發的朋友圈真實性 瀏覽:742
天乾地支簡單演算法 瀏覽:299
下載個壓縮文件 瀏覽:300
普通人電腦關機vs程序員關機 瀏覽:628
米酷建站源碼 瀏覽:115
氫氣app怎麼搜搭配 瀏覽:619
pdf綠盟 瀏覽:506