標籤:

Lisp 解釋器?

我一直在用 JavaScript 寫一個 Lisp 的解釋器。但是長久以來一直有一個問題在困擾著我,那就是如果我寫解釋器的話需要不需要寫個虛擬機?是不是所有解釋性語言都有虛擬機?我直接parse完之後直接運行我的語言行不行,例如(+ 3 4)parse為 [+, 3 ,4]然後直接運行。 謝謝。 ;)


function $(C,E,K){if(!(C instanceof Array))return K("string"==typeof C?
E[C]:C);switch(C[0]){case"lambda":return K(function(K){return function(
){for(var e=Object.create(E),u=0;u&

有 call/cc 了,你們滿意了吧?!


如果你要完整的實現 Lisp,就必須要寫一個解釋器。

首先,對於「編譯」、「解釋」、「虛擬機」這些名詞我不做過多精確的討論。因為你我大概明白其中的意思。我只舉一個反例。如果你不寫虛擬機,你的 Lisp 的 runtime stack 就是 JavaScript 的 runtime stack。問題在於,JavaScript 沒有直接以 first-class 手段操縱 runtime stack 的能力,結果就是你無法實現 call/cc。

一般來說,一種高級語言翻譯成低級語言包括兩部分:低級語言可以直接支持的範式會被直接翻譯,而低級語言不支持的範式需要由一個虛擬機來完成。我們常說 Objective-C 沒有虛擬機,但是 Objective-C 的 message-passing 機制仍然需要一個 objc_msgSend() 來實現一個部分化的虛擬機。因為太過簡單,我們一般說 Objective-C 的虛擬機叫庫或者 runtime。而 Lisp 需要實現 first-class continuation,需要對棧進行操作,這就需要在直接翻譯和虛擬機之間做更靈活的劃分。一般來說需要 JIT 或者更複雜的 runtime 來完成。

更進一步說,什麼是虛擬機呢?其實虛擬機就是「固化的編譯器運行」。你當然可以寫一個完全沒有虛擬機的 Lisp 編譯器,結果就是每次編譯的時候都要生成一堆複雜的代碼,而且這些代碼中一大部分還大同小異。所以你不如把這些基本相同代碼事先寫好,每次編譯的時候只生成調用這些代碼的代碼。這也就是虛擬機和 bytecode 的劃分。


我直接parse完之後直接運行我的語言行不行,例如(+ 3 4)parse為 [+, 3 ,4]然後直接運行。

可以。

如果我寫解釋器的話需要不需要寫個虛擬機?

不需要。

是不是所有解釋性語言都有虛擬機?

不是。首先我們需要探討的是,不存在「解釋性語言」這個概念,編譯(compiled)還是解釋(interpreted)是一個關於「實現」的概念,理論上講任何語言都可以不同的實現。然後我們甚至需要探討的是,如果有虛擬機的話,該實現是否還屬於「解釋性實現」。我認為很難說。以Python舉例,CPython的實現是將源碼編譯(注意是編譯)成Python Bytecode, 然後在虛擬機里運行的(更甚者有些JIT技術還會直接編譯成機器碼以提高執行效率)。

我想我已經回答了問題。但是如果你說的「編譯」是指一定要編譯成機器碼來運行,那麼可能我需要重新定義一下什麼是「解釋」了。


推薦閱讀:

如何寫 Lisp 解釋器?
一個編程語言能否成功的關鍵之處?
Lisp可以完成哪些其它語言難以實現的功能?最好能夠舉一些例子
函數式語言中如何實現while true?
學習 LISP 有哪些網站或書籍推薦?

TAG:Lisp |