小白問,如何寫個編譯器,但是令我疑惑的是,為什麼都是用成熟的語言去寫編譯器呢?

時間 2021-05-08 15:38:51

1樓:avoidant

有點走都不會走,就想跑的意思。

想的很多,但似乎每樣東西又都含含糊糊。

忘了編譯器的事,多程式設計,這樣你距離寫編譯器還能近點。

2樓:ShTM

細節請自己上對應課程:Computer Architecture, Compilers, Models of Computing。有些部分為了方便入門者理解我沒有使用嚴謹和專業的表達(比如刪去Turing Machine, Computational States,Instruction等), 並且刪去了許多實際上非常重要的細節和東西,只是給乙個general picture提供乙個最最基本的認知而已。

什麼是計算機?(Models of Computing)

計算機是可以完成 general computation的機器。那什麼是general computation呢?實際上就是在有限步驟內store data 和 manipulate data,所以我們要製造乙個計算機,我們需要解決的就是如何store data和manipulate data。

比如如果我們用紙帶,那我們就把資料寫在紙帶上,用筆修改紙帶上的資料。

常見的計算機如何store data 和 manipulate data?(Computer Architecture)

用電路實現。要做到store data,實際上需要做到兩點:1.

這個模組裡電路的狀態不會輕易改變 2.在得到某些輸入的時候,我們可以根據輸入修改這個模組的狀態。manipulate data 更容易理解,你只要知道這個模組裡電路的狀態根據輸入如何改變就行了。

這樣一看,只要我們知道如何用電路的輸入改變電路的狀態和儲存電路的狀態(Don't worry about details!), 我們就可以構造出乙個計算機了。

為什麼需要程式語言呢?(Computer Architecture)

每次都用電路來操控太麻煩了..比如你知道11010對應了輸入的五條電路,前四個是資料流,代表了資料,最後乙個是控制流,代表是否根據輸入修改資料,那我們可以用乙個指令store A代表我們輸入的資料流是A,控制流是1(代表我們修改資料)。比如我們輸入store 2,那其實就是代表我們讓輸入電路是00101。

你可以規定乙個機器碼是abcde, 其中a代表控制電路的值,bcde代表資料電路的值,然後store x就對應了1bcde這個機器碼,其中bcde就是x的二進位制表達。這裡面有兩個部分,乙個是機器碼abcde, 乙個是程式語言(算是assembly吧),當然它現在只有一條指令store x。簡單來說,機器碼直接代表了輸入電路的值(包括了控制流和資料流),然後assembly的指令代表了有意義的機器碼,也就是真正實現的指令。

(這裡只是為了舉例子,實際上會有些區別,比如控制流實際上是decode出來的)

更高階的程式語言 (Compilers)

怎麼構造更高階的程式語言呢?我們只需要做到兩點就可以了:1.

把輸入的字串變成可以處理的指令 2.把指令翻譯成assembly。這樣,我們首先規定這個語言的syntax,然後就可以對輸入的字串進行分析了,把它表達成我們這個語言可以處理的結構,接下來就可以用別的語言根據semantics(比如assembly)進行evaluate了。

3樓:魔某人

第乙個問題,成熟的語言使它的使用者能更好地編制出程式。

第二個問題,計算機儲存器有其特殊性,不能隨意改變儲存單元的物理位置,通常只能改變其中的資料。

勤於思考,值得鼓勵。

4樓:Tracy Liang

你先了解計算機原理就不會問些不應該成為問題的問題了。

變長陣列,你可以一次分配很大的就夠你用了,而且很大的空間在作業系統的管理下也未必物理連續的。搞清楚位址空間,虛擬記憶體。插入資料,把後面的東西往後移動也可以,但是就要搬很多資料,跟實際生活一樣,對於有序的資料開銷很大啊,無序的資料你幹嘛不放在後面呢。

鍊錶就是對於經常插入資料設計的資料結構,實際上也是追加,只是標籤索引有序了。

編譯器自舉,只是高階語言可讀性更好,用起來方便,你用彙編寫也一樣。不僅僅是自舉,也可以新增新特性,創造新語言。對於寫編譯器,用if寫不了if,while更寫不了while,寫直譯器倒是可以。

去了解下編譯原理再說。

真的,想太多,做太少了。想東西存在的意義,而不是問為什麼不是你想的這樣。

5樓:navegador

我解釋一下放箱子那個:

程式設計時候很難有一種資料結構同時滿足

比如你的箱子A,B,C,D,E,

像下面這樣存: #sec1

【頭】->A->B->C->-D-E->【尾】

這樣的話,寫的快,比如你要新增乙個箱子O到 B 和 C 之間,只需要動前後3個資料

B->O-> C就好了

但是這種讀起來比較慢,比如我想知道 O 的序號,我得從【頭】開始數數到 2 .

假如像下面這樣存: #sec2

A[0] B[1] C[2] D[3] E[4]

這樣得話寫的比較慢 ,比如你要新增乙個箱子O到 B 和 C 之間,需要改 O,C,D,E四個資料

A[0] B[1] O[2] C[3] D[4] E[5]

但是讀起來很快,比如我想知道 O 的序號,直接讀就行,因為資料本身攜帶了額外資訊

究竟選擇#sec1 還是 #sec2 與具體情況有關,這個簡單得原理可以推廣到很多情況,資料庫,列資料庫,圖資料庫。。。。。就是說你設計首先要有乙個輸入條件限制,你究竟追求讀的快,還是寫的快。 然後再決定選擇什麼樣的結構。

總的來說:

攜帶的額外資訊(重在預先計算好,以空間換時間)越多的結構,讀的越快,寫的越慢。

靠延遲計算(只儲存必要邏輯,執行時再推演計算,以時間換空間),寫的越快,但是讀(搜尋查詢)的就會越慢。

置於邏輯轉換到機器是怎麼做,這個你得看書哦,都是細節,繁瑣且用處不大。

自舉不是那個意思,不是讓你用if 寫 if, while寫while, 乙個單詞(操作/指令)是沒法自舉的,如果乙個不可拆分的操作自己能實現自己那叫自我指涉,是病句。 但是一套單詞是可以的。

比如 可以實現 , 然後 又可以實現 這是自舉.

但是在的世界裡,come就是come,不需要come 再來實現come/解釋come, come就是come沒有道理的,它就在那裡,沒有緣由,沒有第一推動, 就要承認一些東西本來就在那裡。

就是你用一套世界 推出另一套等價世界 ,

世界 形成以後,可以把世界 銷毀,世界 已經不知道自己的創世者是世界 了。然後再用世界 造出世界 ,這是自舉。

在 這個世界裡,if就是if,不需要去實現。如果你想知道if怎麼來的,那你在這個 的世界是沒法知道的, 要跳到另乙個實現 的世界比如 中去。

就比如 在的世界,是 的世界不可見的, 但是 的世界有可能自舉再造乙個 在的世界, 只要上帝和神能幹的操作,你全部實現了就OK了。

6樓:wangzaixiang

我的感覺是沒有人能解決你的問題,因為你想的東西很多很多很多,而書又讀得很少很少很少。

所以,如果你願意的話,先學習一下《計算機組成原理》,理解一下記憶體、數字、計算之後,能完成基本的作業題之後,再去問這些又抽象又哲學的問題。

如何開發編譯器?

gitlab.gnome.org GNOME vala issues?milestone title 1.0 發展中的編譯器,正好可以做學習和研究。 Anges 說一下做過的編譯器前端部分 動態生成語法樹,詞法解析,主要利用狀態機,更高階點nfa轉行dfa,其實解析起來也沒有大家說的那麼難,會基本的...

編譯能過,但是編譯器好像還是報錯?

異常是說 ch附近的棧空間被破壞。ch是棧上的乙個char變數,你在它及後續空間寫入了東西。這是非法訪問,而且破壞了棧空間內容。 你的字串越界啦,朋友,你應該用 calloc 動態分配記憶體 include include intmain int argc char argv char Str ch...

編譯器是如何編譯自己的?

何源 比如你是馬雲,沒身份證 編譯器 之前怎麼證明自己是馬雲。那你得弄來一張名為馬雲的身份證 編譯器 問題來了,這張身份證怎麼來呢?你去找你爸要了戶口本 其他語言的編譯器 去派出所填寫了自己的資料 自己編譯器原始碼 辦理身份證,因為戶口本上你的名字是馬雲,派出所給了一張名為馬雲的身份證。從此,你不用...