學習較底層編程:動手寫一個C語言編譯器

動手編寫一個編譯器,學習一下較為底層的編程方式,是一種學習計算機到底是如何工作的非常有效方法。

編譯器通常被看作是十分復雜的工程。事實上,編寫一個產品級的編譯器也確實是一個龐大的任務。但是寫一個小巧可用的編譯器卻不是這么困難。

秘訣就是首先去找到一個最小的可用工程,然后把你想要的特性添加進去。這個方法也是Abdulaziz Ghuloum在他那篇著名的論文“一種構造編譯器的捷徑”里所提到的辦法。不過這個辦法確實可行。你只需要按照這篇論文中的第一步來操作,就可以得到一個真正可用的編譯器!當然,它只能編譯程序語言中的非常小的子集,但是它確實是一個真實可用的編譯器。你可以隨意的擴展這個編譯器,然后從中學到更多更深的知識。

受到這篇文章的鼓舞,我就寫了一個C編譯器。從某種意義上來說這比寫一個scheme的編譯器要困難一些(因為你必須去解析C那復雜的語法),但是在某些方面又很便利(你不需要去處理運行時類型)。要寫這樣一個編譯器,你只需要從你那個可用的最小的編譯器開始。

對于我寫的編譯器來說,我把它叫 babyc,我選了這段代碼來作為我需要運行的第一個程序:

1
2
3
int main() {
????return 2;
}

沒有變量,沒有函數調用,沒有額外的依賴,甚至連if語句,循環語句都沒有,一切看起來是那么簡單。

我們首先需要解析這段代碼。我們將使用 Flex 和 Bison 來做到這點。這里有怎么用的例子可以參考,幸好我們的語法是如此簡單,下面就是詞法分析器:

1
2
3
4
5
6
7
8
9
"{" { return '{'; }
"}" { return '}'; }
"(" { return '('; }
")" { return ')'; }
";" { return ';'; }
[0-9]+ { return NUMBER; }
"return" { return RETURN; }
"int" { return TYPE; }
"main" { return IDENTIFIER; }

這里是語法分析器:

1
2
3
4
5
6
7
function:
????TYPE IDENTIFIER '(' ')' '{' expression '}'
????;
expression:
????RETURN NUMBER ';'
????;

最終,我們需要生成一些匯編代碼。我們將使用32位的X86匯編,因為它非常的通用而且可以很容易的運行在你的機器上。這里有X86匯編的相關網站。

下面就是我們需要生成的匯編代碼:

1
2
3
4
5
6
7
.text
????????.global _start # Tell the loader we want to start at _start.
_start:
????????movl??? $2,%ebx # The argument to our system call.
????????movl??? $1,%eax # The system call number of sys_exit is 1.
????????int???? $0x80 # Send an interrupt

然后加上上面的詞法語法分析代碼,把這段匯編代碼寫進一個文件里。恭喜你!你已經是一個編譯器的編寫者了!

Babyc 就是這樣誕生的,你可以在這里看到它最開始的樣子。

當然,如果匯編代碼沒辦法運行也是枉然。讓我們來用編譯器生成我們所希望的真正的匯編代碼。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# Here's the file we want to compile.
$ cat return_two.c
#include <stdio.h>
int main() {
????return 2;
}
# Run the compiler with this file.
$ ./babyc return_two.c
Written out.s.
# Check the output looks sensible.
$ cat out.s
.text
????.global _start
_start:
????movl??? $2, %ebx
????movl??? $1, %eax
????int???? $0x80

非常棒!接著讓我們來真正的運行一下編譯之后代碼來確保它能得到我們所想的結果。

1
2
3
4
5
6
7
8
9
10
11
12
13
# Assemble the file. We explicitly assemble as 32-bit
# to avoid confusion on x86_64 machines.
$ as out.s -o out.o --32
# Link the file, again specifying 32-bit.
$ ld -m elf_i386 -s -o out out.o
# Run it!
$ ./out
# What was the return code?
$ echo $?
2 # Woohoo!

我們踏出了第一步,接下去怎么做就全看你了。你可以按照那篇文章所指導的全部做一遍,然后制作一個更加復雜的編譯器。你需要去寫一個更加精巧的語法樹來生成匯編代碼。接下去的幾步分別是:(1)允許返回任意的值(比如,return 3; 一些可執行代碼);(2)添加對“非”的支持(比如,return ~1; 一些可執行代碼)。每一個額外的特性都可以教你關于C語言的更多知識,編譯器到底是怎么執行的,以及世界上其他編寫編譯器的人是如何想的。

這是構建 babyc 的方法。Babyc 現在已經擁有了if語句,循環,變量以及最基礎的數據結構。歡迎你來check out它的代碼,但是我希望看完我的文章你能夠自己動手寫一個。

不要害怕底層的一些事情。這是一個非常奇妙的世界。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/447322.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/447322.shtml
英文地址,請注明出處:http://en.pswp.cn/news/447322.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Arrays.deepToString() 方法同時適用于基元數組和對象數組

Arrays.deepToString() 方法同時適用于基元數組和對象數組&#xff1a; import java.util.*;public class MultiDimWrapperArray {public static void main(String[] args) {Integer[][] a1 { // Autoboxing{ 1, 2, 3, },{ 4, 5, 6, },};Double[][][] a2 { // Autoboxing{ {…

高效程序員的7個共同特征

要想成為高效的程序員&#xff0c;你需要具備一定的綜合素質才能夠讓你用你所掌握的技能、經驗和知識編寫出有效的代碼。有一些開發人員在技術方面具備一定的技巧&#xff0c;但他們永遠無法成為高效的程序員&#xff0c;就是因為他們缺乏所需的其它幾項特質。本文將給出成為一…

java.util.Array中的方法

概述 asList(): 獲取任何序列或數組&#xff0c;并將其轉換為一個 列表集合 &#xff08;集合章節介紹了此方法&#xff09;。 copyOf()&#xff1a;以新的長度創建現有數組的新副本。 copyOfRange()&#xff1a;創建現有數組的一部分的新副本。 equals()&#xff1a;比較兩…

有關編程的12個猜想

摘要&#xff1a;編程世界的將來如何目前仍難預料&#xff0c;但可以肯定的一點是技術一直在加速發展。本文搜羅出12個獨特的編程視角猜想&#xff0c;一起來看看有哪些猜想在不久的將來就能變為現實。 編程世界的將來如何目前仍難預料&#xff0c;但可以肯定的一點是技術一直…

面試中如何剔除“魚目混珠”程序員?

公司招聘面試事宜是一個耗時耗錢的項目&#xff0c;從挑選簡歷開始&#xff0c;還要花更多的時間面試候選人。有的時候這些人才機構會向你保證這些人都是Java天才、SQL專家、堆棧開發者等等&#xff0c;但實際上真實情況遠不及你想想的。對于一個公司來說&#xff0c;執行招聘面…

InputStream 類型

輸入流類型 I/O-1 類功能構造器參數如何使用ByteArrayInputStream允許將內存的緩沖區當做 InputStream 使用緩沖區&#xff0c;字節將從中取出作為一種數據源&#xff1a;將其與 FilterInputStream 對象相連以提供有用接口StringBufferInputStream將 String 轉換成 InputStr…

java容器相關問題

同步類容器 1&#xff0c;這些復合操作在多線程并發地修改容器時&#xff0c;可能會表現出意外的行為&#xff0c;最經典的便是ConcurrentModificationException&#xff0c;原因是當容器迭代的過程中&#xff0c;被并發的修改了內容&#xff0c;這是由于早期迭代器設計的時候…

趣文:如果編程語言是車

C語言是全能手&#xff0c;小巧&#xff0c;強大&#xff0c;所向披靡&#xff0c;可靠&#xff0c;任何事情都能對付。 C是新的C&#xff0c;雙倍的能力&#xff0c;雙倍的尺寸&#xff0c;適應險惡的環境&#xff0c;但是你如果沒練好就去駕駛&#xff0c;很可能會撞車。 C#是…

Java 線程安全

線程安全 線程安全概念&#xff1a;當多個線程訪問某一個類&#xff08;對象或方法&#xff09;時&#xff0c;這個類始終都能表現出正確的行為&#xff0c;那么這個類&#xff08;對象或方法&#xff09;就是線程安全的。synchronized&#xff1a;可以在任意對象及方法上加鎖…

開發者應該了解的API技術清單!

摘要&#xff1a;有人說&#xff0c;有API的地方就有App&#xff0c;借助這些API開發者輕松構建出一款應用&#xff0c;極大地提高開發效率和開發質量。文中整理了一份API服務清單&#xff0c;內容涵蓋&#xff1a;監控/調試、 CDN 、數據庫、儀表盤、支付、通信等方面&#xf…

提高程序員職場價值的10大技巧

如果你已經是個很牛叉的程序員&#xff0c;但是依然覺得覺得還不夠的話&#xff0c;歡迎閱讀此文。本文旨在幫助各位更上一層樓。 你是不是覺得自己已經掌握了所有的編程技巧&#xff1f;別太自以為是了&#xff01; 會寫代碼的確很重要&#xff0c;但是要拿到更好薪水&#…

google python的風格規范

點擊鏈接&#xff0c;查看內容

IT人應當知道的10個行業小內幕

如果你打算從事IT行業或剛進入這個行業&#xff0c;也許本文下面的小內幕會嚇到你&#xff0c;因為這些事平常都不會公開討論的。如果你是IT資深人士&#xff0c;或許你已經遇到其中的大部分了。如果你愿意&#xff0c;請一起來參與討論吧。 這些內幕大多數是針對網絡管理員、…

Volatile原子性一致性JVM指令重排

概念 Volatile概念&#xff1a;Volatile關鍵字的主要作用是使變量在多個線程間可見。作用&#xff1a; 在多線程間可以進行變量的變更&#xff0c;使得線程間進行數據的共享可見 阻止指令重排序&#xff0c;happens-before package com.example.core.cas;import com.example.c…

python修改文件內容,不需要read,write多個動作。

python 要修改文件內容&#xff0c;常用 是先read&#xff0c;后write &#xff0c; 再 rename&#xff0c;很不爽。 比如&#xff1a;需要 把 yuv_dir "../HD/" # "H:/HD_Master/1080i25/" 改為 yuv_dir "C:/HD/" # "H:…

Atomic系列類

Atomic系列類別 Atomic系列類封裝了一系列的基礎類型和對象操作&#xff0c;其主要目的就是為了實現原子性&#xff0c;主要核心類如下 AtomicIntegerAtomicLongAtomicBooleanAtomicIntegerArrayAtomicLongArrayAtomicReference 原子性的引用對象在對Atomic類操作的時候&…

python 系統學習筆記(十二)---os os.path os.walk

得到當前工作目錄&#xff0c;即當前 Python腳本工作的目錄路徑: os.getcwd() 返回指定目錄下的所有文件和目錄名:os.listdir()函數用來刪除一個文件:os.remove()刪除多個目錄&#xff1a;os.removedirs&#xff08;r“c&#xff1a;\python”&#xff09;檢驗給出的路徑是否是…

Java JUC工具類--CountDownLatch

CountDownLatch&#xff1a;用于監聽某些初始化操作&#xff0c;并且線程進行阻塞&#xff0c;等初始化執行完畢后&#xff0c;通知主線程繼續工作執行 package com.example.core.juc;import java.util.concurrent.CountDownLatch;public class UseCountDownLatch {public stat…

Java JUC工具類--CyclicBarrier

CyclicBarrier&#xff1a;柵欄的概念&#xff0c;多線程的進行阻塞&#xff0c;等待某一個臨界值條件滿足后&#xff0c;同時執行 類比&#xff1a;每個線程代表一個跑步運動員&#xff0c;當運動員都準備好后&#xff0c;才一起出發&#xff0c;只要有一個人沒有準備好&#…