-
Notifications
You must be signed in to change notification settings - Fork 0
期中報告
由C語言寫出的編譯器,包含以下功能
- 整數,代號,以及虛數。
- 全域變數(C語言)
- 局部變數
- 匿名函式
- if 條件句
- 原始函數
- 自訂函數
- 巨集系統
- 垃圾回收
$ make
Minilisp 已經在 Linux x86/x86-64 和 64 位 Mac OS 上進行了測試。它並不是建構於體系結構上,因此可以在大部分類Unix操作系統上進行編譯和運行。
MiniLisp 帶有一個全面的測試套件。為了運行測試,給 make 提供“test”參數。
$ make test
MiniLisp 是一個傳統的 Lisp 解釋器。它一次從標準輸入中讀取一個表達式,對其求值,然後打印出表達式的返回值。這是有效輸入的示例。
(+ 1 2)
結果為3
MiniLisp 支援整數定數, (), t, 符號, 串列定數
- Integer literals are positive or negative integers.
- () 是唯一假值. 也代表空值.
- t是對自身求值的預定變義量。這是表示真值的首選方式,而任何非()值都被認為是真值。
- 符號是有獨立名字的物件. 他們通常代表識別字,由於 MiniLisp 沒有字串類別,所以符號有時候被當字串使用
- 串列定數是構造函數. 它的cdr元素會是ˋ()ˋ,或是一個點狀列表沒有任何ˋ()ˋ值,一個點狀列表會這樣表示 (a . b)
cons
接受兩個參數並返回一個新的 cons 單元格,使第一個參數為car,第二個參數為 cdr
(cons 'a '(b)) ; -> (a b)
car
和cdr
是 cons
單元的訪問器。car
歸還car
且cdr
歸還cdr
(car '(a . b)) ; -> a
(cdr '(a . b)) ; -> b
setcar
突變一個 cons 單元格。setcar
接受兩個參數,假設第一個參數是一個 cons 單元格。它將第二個參數的值設置為 cons 單元的car。
(define cell (cons 'a 'b))
cell ; -> (a . b)
(setcar cell 'x)
cell ; -> (x . b)
+
操作域裡的總和 (+ 1) ; -> 1 (+ 1 2) ; -> 3 (+ 1 2 3) ; -> 6
-
如果操作域裡只有一個參數則否定操作域裡的參數 (- 3) ; -> -3 (- -5) ; -> 5
如果操作域裡不只一個參數,則由第一個參數減去後面的參數
(- 5 2) ; -> 3
(- 5 2 7) ; -> -4
=
接受兩個參數,如果兩者是相同的整數則輸出 t ,不是則輸出()。
(= 11 11) ; -> t
(= 11 6) ; -> ()
<
接受兩個參數,如果第一個參數小於第二個參數,則輸出 t
(< 2 3) ; -> t
(< 3 3) ; -> ()
(< 4 3) ; -> ()
(if cond then else)
是語言中唯一的條件。首先執行cond。如果結果為真值,執行then不然就是執行else
(while cond expr ...)
執行 expr ...
直到 cond
得出為()
這是 MiniLisp 唯一支持的循環
如果您熟悉 Scheme,您可能想知道是否可以在 MiniLisp 中通過尾呼叫編寫循環。答案是不。尾呼叫會消耗 MiniLisp 中的堆疊空間,因此將會因為內存耗盡錯誤而失敗。
eq
執行兩格參數如果兩個參數一樣則輸出 t 。 而 eq比較的是地址,用它對symbols(符號)快速地比較,測試兩個cons cells是否物理上是同一個對象
println
將指定對象輸出
(println 3) ; prints "3"
(println '(hello world)) ; prints "(hello world)"
MiniLisps支持變量跟函數 可以用 define
來定義
(define a (+ 1 2))
(+ a a) ; -> 6
定義函數有兩種方式。一種方法是使用特殊形式 lambda。(lambda (args ...) expr ... 輸出得函數可以使用ˊdefineˊ指定變數
(define double (lambda (x) (+ x x)))
(double 6) ; -> 12
((lambda (x) (+ x x)) 6) ; 沒有指定也是同樣的結果
另一個則是 defun
(defun fn (args ...) expr ...)
比起(define fn (lambda (args ...) expr ...)
比較短
;; Define "double" using defun
(defun double (x) (+ x x))
(defun fn (expr . rest) rest)
(fn 1) ; -> ()
(fn 1 2 3) ; -> (2 3)
變量是詞法範圍的並且具有不確定的範圍。即使在創建變量的函數返回後,對“外部”變量的引用仍然有效。
;; A countup function. We use lambda to introduce local variables because we
;; do not have "let" and the like.
(define counter
((lambda (count)
(lambda ()
(setq count (+ count 1))
count))
0))
(counter) ; -> 1
(counter) ; -> 2
;; This will not return 12345 but 3. Variable "count" in counter function
;; is resolved based on its lexical context rather than dynamic context.
((lambda (count) (counter)) 12345) ; -> 3
setq為現有變量設置新值。如果未定義變量,則為錯誤。
(define val (+ 3 5))
(setq val (+ val 1)) ; increment "val"
巨集看起來類似於函數,但它們的不同之處在於Macro將表達式作為輸入並返回一個新的表達式作為輸出。(defmacro macro-name (args ...) body ...)
定義一個Macro。
(defmacro unless (condition expr)
(list 'if condition () expr))
上面defmacro
定義了一個新的巨集。除非unless是一個新的條件,它評估expr,除非條件是一個真值。您不能對函數做同樣的事情,因為所有參數都將在控件傳遞給函數之前進行評估。
(define x 0)
(unless (= x 0) '(x is not 0)) ; -> ()
(unless (= x 1) '(x is not 1)) ; -> (x is not 1)
macroexpand
是一種方便的特殊形式,可以查看巨集的擴展形式。
(macroexpand (unless (= x 1) '(x is not 1)))
;; -> (if (= x 1) () (quote (x is not 1)))
gensym
創建一個新符號,它永遠不會出現eq
在除自身之外的任何其他符號上。對於編寫引入新標識符的巨集很有用。
(gensym) ; -> a new symbol
與傳統的 Lisp 語法一樣, ;
(分號)開始單行註釋。持續到行尾。