用Scheme寫乙個Scheme編譯器(一)

2021-06-29 04:37:30 字數 2539 閱讀 9348

在博主的大學生涯中,感覺最頭痛的一門課程就是編譯原理了,學習完這門課程之後,雖然知道了ll,lr演算法,和一系列與編譯原理相關的術語,可是對它的了解一直停留在做題上,雖然博主一直希望能夠通過自己寫乙個編譯器來加深對編譯原理的理解,可是用c語言寫編譯器真的是一場噩夢,每天大把的時間都花在了除錯bug上,更沒有時間和精力去思考有關編譯原理的東西@~@。

int scheme_entry();

int main(int argc, char** argv)

2 scheme編譯程式

(define (compile-program x)

(emit " .text")

(emit " .global_scheme_entry")

(emit " .def_scheme_entry; .scl 2; .type 32; .endef")

(emit "_scheme_entry:")

(emit "lfb0:")

(emit " .cfi_startproc")

(emit " pushl %ebp")

(emit " .cfi_def_cfa_offset 8")

(emit " .cfi_offset 5,-8")

(emit " movl %esp,%ebp")

(emit " .cfi_def_cfa_register 5")

(emit " movl $~a,%eax" x)

(emit " popl %ebp")

(emit " .cfi_restore5")

(emit " .cfi_def_cfa 4,4")

(emit " ret")

(emit " .cfi_endproc")

(emit "lfe0:"))

這是編譯器的主程式,emit函式就是把字串輸出到我們規定的output-port裡面,這個程式的字串由彙編構成,不熟悉組合語言的朋友看起來會感覺比較奇怪,其中大部分我們都不需要了解,我們需要注意的是(emit "    movl $~a,%eax" x),x就是我們的立即數,這裡把它放入eax暫存器中,因為計算機在執行完乙個函式後會把結果放入eax暫存器中。

(define (emit . args)

(newline (compile-port)))

這是emit函式的定義,將結果顯示入我們規定的埠。

(define compile-port

(make-parameter

(current-output-port)

(lambda (p)

(unless (output-port? p)

(error 'compile-port (format "not an output port ~s" p)))

p)))

current-output-port在rnrs/io/ports-6模組中定義,我們需要(require rnrs/io/ports-6)。

(define (compile expr)

(run-compile expr)

(build)

(execute))

這個函式幫我們執行函式的編譯,鏈結,執行。

(define (run-compile expr)

(let((p (open-output-file "program.s" #:exists 'replace)))

(parameterize ((compile-port p))

(compile-program expr))

(close-output-portp)))

我們將輸出埠規定為program.s。

(define (build)

(unless (not (false? (system (format "gcc -m32 -wall -o program ~a program.s"

(runtime-file)

))) )

(error 'make"could not build target")))

連線我們使用gcc與我們前面準備的c執行時程式連線。

(define (execute)

(unless (not (false? (system "./stst > stst.out")))

(error 'make"produced program exited abnormally")))

執行程式。

好了,執行完以上步驟後,你就得到了乙個能編譯數字的編譯器了,雖然很簡單,但是這個編譯器是我們以後構造更複雜的編譯器的基礎,希望感興趣的朋友認真對待它。

最後,我們先休息一下,希望大家玩的開心

自己寫乙個scheme測試工具

端午在家休息了好幾天,基本上就是帶孩子和睡覺了。荒廢了好幾天之後,今天重操舊業。the little scheme看到第99頁了。要寫乙個函式numbered?來判斷乙個表示式是否是數字表示式。上 define atom?lambda a not or null?a pair?a define op...

用golang寫乙個proxy

我複雜的網路環境中,proxy是個很有用的工具,我們可以通過proxy 幫我們完成網路流量的 這個proxy得先能接收請求,所以這裡先啟動乙個tcp的監聽,獲取請求 func s server start glog.infof proxy listen in s,waiting for connec...

用python寫乙個restful API

coding utf 8 package.module python實現的圖書的乙個restful api.restful api 一般模式 get select 從伺服器取出資源 一項或多項 post create 在伺服器新建乙個資源。put update 在伺服器更新資源 客戶端提供改變後的完...