天天看點

怎麼用我寫的scf編譯代碼

#頭條創作挑戰賽#

我寫的scf編譯器,并沒有嚴格按照C語言的文法來寫。

我寫scf的目标是:

1,在C語言的基礎上,做一門更完善的、文法好看的程式設計語言。

文法不能像go語言那麼難看[捂臉]

2,給出一套完全自主知識産權的編譯器架構,

這個架構要盡可能簡單,并且可以作為開發其他程式設計語言的基礎架構。

類似llvm那樣,隻是我懶得去看llvm的文檔,我嫌它太麻煩了。

是以,scf前端的文法跟C語言幾乎一樣,但有點差别:

1,我還沒給它支援switch case語句[呲牙]

因為if else的使用範圍更廣,是以我就先支援了if else,把switch case暫時放到以後了。

2,支援while,但不支援do while。

因為根據我寫C代碼的經驗,do while用到的特别少。

3,for循環是肯定支援的。

4,編譯器不再區分頭檔案和源檔案,而是隻有一種檔案。

可以使用include關鍵字包含其他的代碼檔案。

可以把類型定義和函數聲明都寫在一個檔案裡,把它當作頭檔案去包含。

代碼在檔案裡怎麼分布,完全交給了程式員。

5,不需要考慮檔案的重複包含問題。

我在文法分析時做了去重處理,不需要像C語言那樣使用ifndef去防止重複包含。

6,沒有支援宏,

宏的展開還是比較麻煩的,不想把文法分析做得太複雜。

7,沒有格式限制,

回車、換行、Tab都一律當空格。

語句的結束以分号為标志,語句塊的結束以(右邊的)大括号為标志。

對于scf編譯器來說,換行符的作用隻是在debug資訊裡記錄行号[捂臉]

8,源檔案的擴充名暫時設定為.c,在scf的main()函數的第65行可以修改。

怎麼用我寫的scf編譯代碼

之是以設定為.c,是因為大多數的文本編輯器都對C語言有文法高亮功能,例如vim。

除了這裡之外,其他子產品都不會檢查擴充名,而是一律當成文本檔案處理。

編譯時輸入的檔案擴充名隻能是這4種:

.c表示源檔案,

.o表示目标檔案,

.a表示靜态庫,

.so表示動态庫,

隻會編譯源檔案.c,其他3種在連接配接時處理。

怎麼用我寫的scf編譯代碼

預設連接配接的庫檔案

預設連接配接的“庫檔案”如上圖:

1)_start.o,啟動main()函數用的,也是程式的真正入口。

2)scf_object.o,自動記憶體管理用的,

scf_atomic.o,自動記憶體管理用的,引用計數的原子操作。

3)最後那2個so庫,都是C語言的動态庫。

下面的3個例子都在scf/examples目錄:

1,hello.c,

它列印hello world。

怎麼用我寫的scf編譯代碼

hello world

因為要使用C标準庫的printf()函數,可以直接把它聲明在檔案的開頭。

沒有支援宏,沒法包含C語言的stdio.h,把用到的函數聲明一下就行了。

也可以把C庫的常用函數(例如printf, malloc, free)都聲明到一個檔案裡,以後隻包含那個檔案就行。

假設目前目錄是scf/parse,那麼編譯指令是:./scf ../examples/hello.c

2,qsort.c,

怎麼用我寫的scf編譯代碼

快速排序

因為最後要用printf()列印結果,是以也把它聲明在開頭。

快速排序的sort()函數有2層循環+2個遞歸,并且還有指針和數組的使用。

大多數情況下,我都是拿它來檢測scf編譯的代碼對不對。

怎麼用我寫的scf編譯代碼

編譯和運作結果

3,mat.c,

一個簡單的矩陣類。

怎麼用我寫的scf編譯代碼

mat類

因為使用了自動記憶體管理,先包含../lib/scf_capi.c,這個檔案裡有幾個自動記憶體管理的函數聲明,如下圖:

怎麼用我寫的scf編譯代碼

lib/scf_capi.c

include在scf裡作為關鍵字之一,用來包含其他的檔案。

然後聲明mat類,并且聲明它的成員變量。

scf對類的成員沒有權限控制,在類内和類外都可以通路。

怎麼用我寫的scf編譯代碼

構造函數__init()

構造函數:名字是__init(),傳回值是int,第一個參數是this指針,明确地寫在第一個位置。

構造函數的傳回值可以傳回錯誤碼,成功傳回0。

怎麼用我寫的scf編譯代碼

加号+的重載函數

加号的重載operator+()函數:

operator也是關鍵字,跟C++一樣。

它的2個參數都明确地寫出來:

第一個是this,位于加号左邊的操作數,

第2個是that,加号右邊的操作數。

傳回值有2個,mat*是計算結果,int是錯誤碼(成功為0)。

怎麼用我寫的scf編譯代碼

加号+的重載函數2

析構函數:名字是__release(),隻有1個參數this,明确地寫出來。

怎麼用我寫的scf編譯代碼

析構函數__release()

mat類的成員變量裡隻有uint8_t* data是指針,需要申請記憶體,是以在析構函數裡隻釋放它就可以。

它是需要自動記憶體管理的,使用scf__auto_freep()釋放:這樣如果它指向的記憶體被其他指針引用了的話,不會出現錯誤釋放。

例如這樣的代碼:

mat* a = create mat(); // 這時a->data的記憶體引用計數是1,

uint8_t* p = a->data; // 這時a->data的記憶體引用計數是2,因為指針p也指向了同一塊記憶體,

釋放a之後,p指向的記憶體應該還能用:這時a->data的引用計數隻是減1,并沒有真正free記憶體。

釋放p之後,這塊記憶體才被真正釋放,因為沒有指針指向它了。

自動記憶體管理的代碼都在scf/lib/scf_object.c裡,連接配接scf_object.o就行。

怎麼用我寫的scf編譯代碼

main()函數

最後是main()函數:

用3個double數組作為參數,建立了3個mat矩陣的對象。

然後進行了一個加法運算。

最後列印結果:

我沒有關閉自動記憶體管理子產品的日志,是以連記憶體申請和釋放的過程都打出來了。

紅框裡才是main()函數列印的運算結果。

怎麼用我寫的scf編譯代碼

編譯運作的結果