柯里化的前生今世(四):编译器与解释器
關(guān)于
在上一篇中,我們提到了形式語言與文法,S表達(dá)式與M表達(dá)式,同像性。
本文將開始寫一個簡單的解釋器,
通過具體實現(xiàn),我們來理解求值環(huán)境,動態(tài)作用域和靜態(tài)作用域,還有閉包等概念。
當(dāng)然,一篇文章來寫完這些肯定是不夠的,我們可以慢慢來,循序漸進(jìn)。
寫完了這個解釋器之后,我們會增加一些新的功能。
編譯器與解釋器
編譯器會將源代碼轉(zhuǎn)換成另一種語言的代碼,然后在支持后一種語言的機(jī)器上執(zhí)行。
而解釋器則不同,它會逐行分析源代碼,直接執(zhí)行分析結(jié)果。
值得一提的是,編譯和解釋是執(zhí)行代碼的兩種手段,
具體的語言實現(xiàn)很可能采用兩者的混合形式。
例如,一段Java程序,會首先經(jīng)過javac編譯為字節(jié)碼,
字節(jié)碼再交由Java虛擬機(jī)來解釋執(zhí)行。(JIT和RTSJ,略。。
編譯器包含以下三個部分,
編譯器前端:詞法分析,語法分析,最終生成抽象語法樹這種中間代碼。
編譯器優(yōu)化:中間代碼多次轉(zhuǎn)換,多種優(yōu)化,
編譯器后端:目標(biāo)代碼生成,優(yōu)化目標(biāo)代碼。
解釋器不包含目標(biāo)代碼生成階段,將優(yōu)化結(jié)果直接執(zhí)行。
前端和優(yōu)化,是編譯器和解釋器共有的。
抽象語法樹
編譯器前端會分析源代碼文本,生成一棵抽象語法樹。
假如,我們有如下源代碼,(1+2*3)*(4-5)。
使用ANTLR,我們得到了(具體)語法樹,
語法文件如下:
grammar Expr;expr: expr ('*'|'/') expr| expr ('+'|'-') expr| INT| '(' expr ')';INT: [0-9]+ ; WS: [ \t]+ -> skip ;我們看到語法樹包含了產(chǎn)生式的名稱,這在后續(xù)處理過程中是不需要的,
因此,編譯器前端會將具體語法樹轉(zhuǎn)換成一種中間形式——抽象語法樹。
這不就是S表達(dá)式嗎?
對的,編譯器前端會將任何語言的源代碼轉(zhuǎn)換成與具體語法無關(guān)的抽象語法樹,
而S表達(dá)式正是這種抽象語法樹的線性編碼。
(因此,你寫任何語言,本質(zhì)上都是在寫Lisp。。
格林斯潘第十定律:
任何C或Fortran程序復(fù)雜到一定程度之后,都會包含一個臨時開發(fā)的、不合規(guī)范的、充滿程序錯誤的、運行速度很慢的、只有一半功能的Common Lisp實現(xiàn)。
簡化解釋器的實現(xiàn)
為了簡化解釋器的實現(xiàn),我們會直接分析S表達(dá)式(抽象語法樹),并且略過優(yōu)化環(huán)節(jié)。我們也不解釋四則運算表達(dá)式,因為這涉及到了操作符的定義問題。
我們將直接實現(xiàn)lambda表達(dá)式和函數(shù)的調(diào)用。
和其他解釋器的教材不同的是,我沒有寫那么多的if-else,
而是把決策模式提取出來了,這樣會更清晰一些。
eval-exp會根據(jù)exp的具體形式,尋找相應(yīng)的處理方式,
而各個處理方式中,還有可能再用到eval-exp來處理子表達(dá)式。
因此,這是一個遞歸執(zhí)行的過程。
下文,我們會剖析這個簡單的解釋器,
把每個處理分支都實現(xiàn)一下。
關(guān)于寫作意圖
本系列文章的寫作目的是想借著柯里化這個概念,
把函數(shù)式編程相關(guān)的知識點串聯(lián)起來。
為什么選擇柯里化呢,因為柯里化首先和高階函數(shù)相關(guān),
我可以借此來引入作用域的概念,
continuation本身就是一個單參函數(shù),順便就可以介紹了,
hygienic macro也涉及到了標(biāo)識符的查找,學(xué)了求值環(huán)境也容易理解了。
其次,帶參數(shù)的類型,可以類比函數(shù)的柯里化來理解,
要想理解帶參數(shù)的類型,我們就得學(xué)習(xí)類型,以及代數(shù)數(shù)據(jù)類型,
從而繼續(xù)深入下去,學(xué)習(xí)Functor,Applicative,Monad這些類型類。
這樣類型系統(tǒng)就揭開了神秘的面紗。
當(dāng)然,這些都是偏工業(yè)應(yīng)用的,并沒有涉及理論基礎(chǔ),
自動機(jī)理論,可計算性理論,形式語義,也不適合在本系列中提及,
寫完本系列后,我會嘗試寫其他系列,希望能覆蓋掉某些點,
以此來督促自己努力學(xué)習(xí),小心求證。
參考
程序設(shè)計語言:實踐之路
編程語言實現(xiàn)模式
The Definitive ANTLR 4 Reference
Lisp in Small Pieces
Java 是編譯型語言還是解釋型語言?
Abstract vs. Concrete Syntax Trees
總結(jié)
以上是生活随笔為你收集整理的柯里化的前生今世(四):编译器与解释器的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Linux 双网卡绑定
- 下一篇: Widget开发中遇到的坑