2015讀書進度-《自制程式語言》[漆楚衡]
筆記:《自制程式語言》
這本書在我這已經沉睡了快一年了。一直以自己能力不夠為藉口。不過這個學期開了編譯原理課程,想著順帶著就把這本書看看。
現在編譯原理也上了一個月了,各方面也都瞭解了一些,發現這本書其實跟編譯原理的教科書的側重點完全不一樣,相互之間算是互補。
教科書主要教了一些演算法和概念,而這本書的主要路線就是實戰,兩門語言,涵蓋了目前的主流語言的諸多特性,都是通過實現來講。
基於lex/yacc的語言開發在本書中所表現出來的路線是
- 詞法分析,此處lex將一個正規表示式對映為一個語句塊,可以直接在語句塊裡對token實現解釋。
- 語法分析,此處直接利用上一步驟的token串,根據語法定義(同lex,此處有產生式到語句塊的對映)生成相應的語法分析樹。
- 值得注意的是上面兩步中的token和語法法分析樹中的非終結符似乎都是有型別的。這一塊型別對映沒有深究。
- 接下來
- crowbar的語法樹生成後就可以開始解釋執行了。
- Diskam則有語法樹修正,編譯為虛擬機器位元組碼,執行等過程。
這是利用到了工具(lex/yacc)的部分,實際上,這只是整個編譯工作中的一小部分 ,lex/yacc的作用其實十分有限。
現在稱所設計的語言為目標語言,而實現目標語言的語言為底層語言。
設計語言(的執行系統)的主要工作是設計底層語言對目標語言中各種結構(值,表示式,控制結構)的表示,以及如何將這些結構轉化為底層語言的計算過程。
lex/yacc所完成的只不過是自動化的結構搭建工作。
學習 Diksam
從crowbar到Diksam,難度跨度有點大,而作者對內容的講述卻越來越簡練。
不過也不能怪作者,這本書進行到Diksam,在很大程度上要靠讀者自己去讀原始碼,而我現在耐心不足,貪心有餘。
昨天耐下心來,將前半本書又看了一遍,熟悉作者在Diksam部分幾乎不再提的那些基礎部分。
Diksam0.1
這裡一切還都不難理解(吹牛了,看了半天才看懂)。
比較有難度的有
- 派生型別:這是處理陣列和函式的型別的機制,乍看一眼難倒我了。
- 函式呼叫機制:這一部分感覺作者說了幾次都沒有說透。
這一部分的主要流程
- 分析原始碼,生成語法樹
- 修正語法樹,在應該插入型別轉換的地方插入型別轉換,表示式的型別資訊在此時新增
- 生成位元組碼,此處產生的是一個DVM_Executable
- 將DVM_Executable繫結到已給DVM_VirtualMachine
- 執行
值得注意的是此處有三個在後來十分重要的結構(以下列出的只是主要成員):
- DVM_Compiler:分類儲存分析結果
- 變數宣告的集合
- 函式定義的集合
- 頂層語句序列
- DVM_Executable:儲存Compiler的編譯結果(位元組碼),一個檔案對應一個Executable
- 常量池
- 全域性變數(只是形式)
- 函式集合(包括位元組碼)
- 頂層語句的位元組碼
- DVM_VirtualMachine:Executable儲存的是“程式”(位元組碼等)的不變部分,要執行一個“程式”,還要給它提供一套可變部分的系統
- 全域性變數的實際儲存空間
- 執行時棧
- 函式登記表
這裡最繞的部分就是函式集合(DVM_Function *function
)和函式登記表(Function *function
)了。
在生成位元組碼的時候,push_function的引數是DVM_Function表的引數,DVM_Function存放了檔案中出現的所有函式(本地宣告的和原生函式)。
掛載到VirtualMachine後,會用Function的對應索引替換DVM_Function索引,在Function中實現對原生函式的登記。
所以Function的內容有兩種
- 指回DVM_Function
- 指向原生函式
這幾個結構的成員的功能一定要記好, 它們三個的成員之間的相互聯絡(特別是與函式有關的部分)也一定要記好,否則後面的連結機制很難看懂。
Diksam0.2
這裡沒遇見特別難以理解的部分,
Diksam0.3 require
我覺得這一部分可以分成兩部分,因為包引入機制是我認為這本書裡最難理解的部分,這裡沒有細講,讓對整體認識把握不足的讀者(我)完全摸不著頭腦。
這一部分的困難在於
- 相對於0.1版,各結構的功能有變化
- 各結構的內容有變化
- 所有這些變化都是相關聯的
VM(VirtualMachine)和Exe(Executable)的關係
0.1版中VM和Exe是一一對應的,VM管理了Exe所需的“記憶體”(棧,堆,靜態區)
現在VM和多個Exe對應了,多個Exe公用一個棧,一個堆。
不過Exe們要各自私有一個靜態區。所以通過一個ExecutableEntry結構將靜態區附加到Exe上, 而VM的管理單位從Exe變成了ExecutableEntry。
函式,函式登記表,函式關聯
對於Exe中的DVM_Function,它有兩個作用
- 記錄本地函式的內容(位元組碼等),有一個is_implemented的欄位,為真時表示當前項具有這一功能。
- 記錄本檔案對所有函式的使用,原因是當要生成位元組碼的時候(此時還未載入到VM,對外界一無所知),我們依然要給每一個被呼叫的函式分配編號。
對於VM中的Function
- 全域性的函式登記:所有VM中被使用的Exe的函式都會登記在此(原生函式也登記在此)。
- 動態載入:這個功能要求登記表中的具體連結可以為空,所有一個is_implemented欄位。
- 因為動態載入是按函式名稱來的,所以Function要儲存函式的名稱。
核心問題是多個檔案的函式如何關聯彼此,這一部分我感覺極其雜亂,還未能完全理解。
大體思路是從一個檔案開始,會遞迴編譯檔案和它的require(.dkh),組成一組Exe,將這一組Exe逐個加入VM,就可以執行了,
執行時會發生dkh要求載入dkm,發生動態載入,動態載入就是跟據需要編譯對應dkm,然後重新整理Function。
應用篇
異常處理
實現異常的核心(與其他控制結構,比如if-else的不同)就是對棧的非常規操作,所以如果是自己完全實現了目標語言的棧,則比較方便的寫出異常。
而crowbar中的直譯器依賴於宿主語言C的遞迴執行,所以之前在實現基本的crowbar時break等流程跳轉需要一些輔助的控制(返回執行狀態標誌)。
到了要實現異常了,作者祭出了殺手鐗:setjump/long_jmp,這兩個函式雖然是標準的,不過我之前也從來沒見過有誰用它們。這次也算是開眼了。
總結
首先吐槽一下這本書的翻譯,感覺用詞跟我之前習慣的用詞不太一樣,不知道是不是日文原文就是這樣。
這本書在crowbar部分還是很耐心的講解各個部分的,到了diksam部分感覺作者是假定讀者以原始碼閱讀為主,當你不懂得時候,來看書,提點一下。
幾點收穫:
先有宿主語言,在宿主語言中實現目標語言的控制結構和基本型別。
表示式與語句的不同
- 邏輯目標:表示式是與運算相關的,而語句是與流程控制相關的
- 函式呼叫是表示式,不是顯式的流程控制對應
- 層次關係:表示式可以構成語句,而語句不能構成表示式
型別是一個語言的高層邏輯,(這個不太好表達),型別不是執行的特徵,而是面向編譯器的輔助檢查手段。
異常是一種控制結構(跟if-else同級),特點是具有對棧的讀取能力。
虛擬機器提供的是面向目標語言的最小基本操作集
- 對各種基本型別的操作
- 棧模型
- 幾個“記憶體空間”,棧,堆,靜態區(全域性變數)之間的相互傳遞,
- 流程控制:順序,goto
最痛苦的就是Diksam中包引入的部分。說實話我現在也沒有特別透徹的理解,只是把幾個影響閱讀的地方搞懂了。
- 個人認為這裡的幾個核心結構(DVM_Function, Function, DVM_Exectuable)都承擔了多重功能,之間的關係和通訊手段感覺比較雜亂。
- 不過收穫也蠻大的,之前都沒有思考過多個檔案的整合到底要怎麼來,瞭解了作者的一個VM對應多個Exe(共用一個棧,堆)之後感覺這樣挺好。
類的處理其實比較簡單,屬性就是一組變數,而函式不過是普通函式附加一個this引數。
類相關的概念中比較複雜的是(介面)多繼承。不過這也只是需要一個比較強大的上/下轉型時虛表替換而已。
教訓:要提升自己的程式碼閱讀能力
相關文章
- 2015讀書進度[漆楚衡]-《Write Yourself a Scheme in 48 Hours》Scheme
- 2015讀書進度[fairjm]AI
- 兩週自制指令碼語言 - 讀後心得指令碼
- 【自制程式語言】1 - 基本語句(1)
- C語言+圖形程式設計——自制象棋C語言程式設計
- 自制程式語言有什麼好處?
- 為什麼自制指令碼語言是程式語言的最高境界?指令碼
- 《Go 語言程式設計》讀書筆記(四)介面Go程式設計筆記
- 《Go 語言程式設計》 讀書筆記 (八) 包Go程式設計筆記
- 《Go 語言程式設計》讀書筆記(十)反射Go程式設計筆記反射
- 《Go 語言程式設計》讀書筆記 (三) 方法Go程式設計筆記
- C語言程式設計讀書筆記:結構C語言程式設計筆記
- 用msys2編譯《自制程式語言》程式碼編譯
- 《自制程式語言》封面設計方案徵集意見
- 《Go 語言程式設計》讀書筆記 (二)函式Go程式設計筆記函式
- C語言程式設計師必讀的5本書C語言程式設計師
- C語言深度剖析——讀書筆記C語言筆記
- 《Go 語言程式設計》讀書筆記 (九) 命令工具集Go程式設計筆記
- 程式設計師最全必讀書單(包含各種語言)程式設計師
- 《Go 語言程式設計》讀書筆記(十一)底層程式設計Go程式設計筆記
- TIOBE 2015年9月程式語言排行榜:時髦語言Rust進前50Rust
- 讀書寫筆記-王爽《組合語言》筆記組合語言
- 程式語言的可讀性
- 《Go 語言程式設計》讀書筆記 (五) 協程與通道Go程式設計筆記
- 《Java8函數語言程式設計》讀書筆記---類庫Java函數程式設計筆記
- C語言程式書寫規範 (轉)C語言
- 程式語言特色:系統說明書
- 兒童程式語言的進化史
- 《Java8函數語言程式設計》讀書筆記---收集器Java函數程式設計筆記
- C程式設計語言讀書筆記:型別運算子與表示式C程式程式設計筆記型別
- 讀書筆記:組合語言(王爽)實驗七筆記組合語言
- 蘋果新的程式語言 Swift 語言進階(十二)--選項鍊蘋果Swift
- 《Java8函數語言程式設計》讀書筆記---常用的流操作Java函數程式設計筆記
- 天書夜讀:從組合語言到Windows核心程式設計筆記(2)組合語言Windows程式設計筆記
- 2015年程式語言“錢途”盤點
- 好語言,就該善用它——《C++語言的設計與演化》讀書筆記C++筆記
- 2015讀書總結
- 入門,進階go語言優秀書籍推薦Go