自制脚本語言筆記(沒什麼價值)

如魔 2022-01-07 15:28:01 阅读数:554

自制 脚本

2周自制脚本語言

1.前言與說明

開始時間:2021年6月13日

目的:以實踐的形式了解編譯原理的部分知識,動手自制改進脚本語言

後來發現理解代碼太難太難,最終選擇將能看懂的代碼進行注釋

本文沒有什麼參考價值,完全是我在學習過程中的無聊筆記。排版也比較亂。

開始注釋

第三章代碼注釋完成

實現詞法分析功能。

第四五章代碼注釋完畢

實現語法分析

有很多東西雖然可以猜到是什麼意思,但還是理解不够透徹,不知道具體每一步驟實在做什麼。

整體介紹
/ast

包含abstract syntax tree(ast) 的數據結構

/stone

**Token.java**
是每個token的抽象類
**Lexer.java**
詞法分析器,通過正則錶達式分析出一個一個語法單比特。其中還包括Token的三個子類 NumToken IdToken StrToken
**CodeDialog.java**
Reader的子類,為詞法分析器做了一些預處理。
**Parser.java**
作者提供的類庫 用於語法分析的類,提供了語法分析的方法
**ParseException**
重寫的异常處理類
**BasicParser**
用於執行語法處理的類

實際上上述做的就是 構造出一個具體的抽象語法樹。
繼續繼續


第六章代碼注釋完畢

主要功能是對抽象語法樹進行解釋和計算。

整體介紹

  1. 通過gluonj 擴展AST類中的數據結構源代碼,使每一個節點都有eval方法,用於計算
  2. 計算的過程是從上到下遞歸,類似於深度優先遍曆
  3. 在eval中對常用的運算符:+ = == > 等,以及if while 代碼塊做具體的處理。
  4. 至此,stone語言可以是實現基本的運算功能。

關於gluonj

gluonj is a sample of AOP,it provide a way to extend a Class
such as:

@Reviser public static class ASTLeafEx extends ASTLeaf{

public ASTLeafEx(Token t) {
 super(t); }
}

it extend a function to class ASTree
上述代碼中,ASTLeafEx是對ASTLeaf的擴展,雖然形式上看起來像是子類,它並不是子類。
這麼做的好處是不用直接對ASTree的源代碼進行修改。

/chap6

Environment.java
環境變量類的接口
BasicEnv.java
對Environment接口的實現,用HashMap存儲環境變量
BasicEvaluator.java
在這個類中通過gluonj對原AST進行擴展
Runner.java
開始運行整個程序
BasicInterpreter.java
解釋程序,控制整個流程:先詞法分析,然後語法分析構造出一個一個AST,每個AST構造出來後就調用eval方法進行運算。

每次生成一個AST就直接執行,這是解釋程序的特點

繼續繼續


第7章代碼代碼注釋完畢

主要功能是增加了函數和閉包兩個功能

整體介紹

  1. 還是利用gluonj對原有AST進行擴展,同時新增了許多與方法有關的AST類

/stone

FuncParser
支持函數的語法分析器擴展
ClosureParser
支持閉包的語法分析器擴展

/ast

Postfix.java
ASTList的子類。
Arguments.java
Postfix的子類,可能是存儲參數列錶的大小。
DefStmnt.java
一個ast中的非葉子節點,錶示一個整個函數定義的代碼
ParameterList.java
參數列錶
Fun.java
應該是錶示閉包的非葉子節點

/chap7

FuncEvaluator.java
給AST中的關於函數的類添加eval方法
FuncInterpreter.java
加上函數功能之後的解釋流程控制
FuncRunner.java
加上函數功能之後的運行開始程序
Function.java
一個具體的Function類,區別於AST中的類,例如 a=fib(b){b} a的類型就是Function
NestedEnv.java
遍曆的環境變量類,在尋找變量時,現在當前環境變量中找,找不到就往上一層尋找
ClosureEvaluator.java
給AST中的關於閉包的類添加eval方法
ClosureInterpreter.java
加上閉包功能之後的解釋流程控制
ClosureRunner.java
加上閉包功能之後的運行開始程序

雖然我可以在這裏瞎扯這麼多,但實際上很多代碼包括整個設計,我都不是很能理解。

繼續繼續


第8章代碼注釋完畢

主要是增加原生函數功能,利用java的反射功能,使stone可以調用一些java函數。

整體介紹

  1. 解釋程序時,將原生方法放入環境變量中
  2. 在處理到一個方法時,判斷是不是原生函數,如果是
    1. 收集參數
    2. 調用java提供的invoke方法

/chap8

Natives
用於將支持的原生函數放入環境變量中去。
NativeFunction
原生方法類,通過調用java的invoke方法,實現當前NativeFunction對象到java的函數之間的轉換。
NativeEvaluator
擴展器,擴展FuncEvaluator.ArgumentsEx,使其可以處理原生函數。
NativeInterpreter
解釋器,在這一步中,需要通過Natives將支持的原生函數放入到環境變量中。
NativeRunner
執行器,運行開始程序

繼續繼續


第9章代碼注釋完成

增加了面向對象的功能,可以單一繼承,沒有接口。

整體介紹

  1. 字段與方法之間沒有明確的區別,方法是一種以Function對象為值得字段。
  2. 對象實際上可以看做一個特殊的環境,因此StoneObject中實際上存放一個環境。
  3. 通過.new創建新的StoneObject時,解釋器首先創建新的環境,並且將 this-新創建的StoneObject 這個鍵值對存入環境中。

/stone

ClassParser
支持類的語法分析器擴展

/ast

ClassStmnt.java
在語法分析時產生的Class塊的AST
ClassBody.java
類中間的具體代碼的AST
Dot.java
點(.)的AST

/chap9

ClassInfo.java
錶示stone中的類。
StoneObject.java
錶示stone中的對象,實際上和環境一樣,有HashMap實現,提供write和read方法。
ClassEvaluator.java
擴展器,為AST中的結構添加支持面向對象的運算。
ClassInterpreter.java
解釋器
ClassRunner.java
執行器

繼續繼續


第10章代碼注釋完成

添加了數組功能。

整體介紹

  1. 使用java中的Object[]實現,因此一個數組中可以存放不同類型的數據。

/stone

ArrayParser.java
支持數組的語法分析器擴展

/ast

ArrayLiteral.java
錶示數組字面量
ArrayRef.java
錶示數組元素的指代

/chap10

ArrayEvaluator.java
擴展器,為AST中的結構添加支持數組的運算。
ArrayRunner.java
執行器

繼續繼續


第二部分


第11章代碼注釋完成

對於局部變量,使用數組保存環境。同時,使用比特置信息來查找變量。

/chap11

ArrayEnv.java
使用數組實現的記錄局部變量的環境
ResizableArrayEnv.java
記錄全局變量的環境
Symbols.java
一張哈希錶,用於記錄變量名與保存比特置之間的對應關


EnvOptimizer.java
擴展器,擴展lookup方法,在執行eval之前先執行lookup找到變量
OptFunction.java
使用ArrayEnv作為執行環境的function
EnvOptInterpreter.java
解釋器
EnvOptRunner.java
執行器

繼續繼續


第12章代碼注釋完成

通過將同一個類的所有對象共用的字段和方法保存在ClassInfo中减少內存消耗。
使用內聯緩存:在引用字段時,信息將由與該字段引用錶達式對應的抽象語法樹緩存,具體來說,是
保存在語法樹節點對象的相應字段中。

/chap12

OptClassInfo.java
優化後的ClassInfo
OptStoneObject.java
優化後的StoneObject
SymbolThis.java
保存有效的本地變量名在類定義體中
MemberSymbols.java
記錄字段名和方法名
ObjOptimizer.java
擴展器,擴展支持內存優化的eval和lookup方法
ObjOptInterpreter.java
解釋器
ObjOptRunner.java
執行器
InlineCache.java
擴展器,擴展支持內聯緩存的方法
InlineRunner.java
執行器

繼續繼續


第13章代碼注釋完成

構造虛擬機對部分stone代碼進行編譯,生成中間代碼,然後執行中間代碼。

/chap13

Opcode.java
虛擬機使用的關鍵字
StoneVM.java
虛擬機類
HeapMemory.java
堆的接口,虛擬機使用堆作為全局變量環境
StoneVMEnv.java
虛擬機使用的環境,實現HeapMemory接口,是ResizableArrayEnv的子類

如前所述,實際執行編譯操作的是定義了函數的 .def 語句的 eval方法。該方法將進一步調用 .compile方法。函數在編譯後,將由Arguments 類的 eval方法執行。


第14章代碼注釋完成

添加靜態類型支持
將函數部分轉化為java二進制代碼,利用java虛擬機執行

/stone

TypedParser.java
對語法規則進行一些修改

/ast

VarStmnt.java
新定義的抽象語法樹節點的對象類型
TypeTag.java
新定義的抽象語法樹節點的對象類型

/chap14

TypedEvaluator.java
擴展器,擴展處理帶有類型的處理
TypeChecker.java
類型檢查
TypeEnv.java
數據類型的環境
TypeException.java
類型檢查中拋出的异常類型
TypeInfo.java
stone支持的數據類型
TypedInterpreter.java
添加上述功能後的解釋器
TypedRunner.java
添加上述功能後的執行器
TypedNatives.java
對來自於java的原生函數的支持
currentTime.java
原生函數
length.java
原生函數
print.java
原生函數
read.java
原生函數
toInt.java
原生函數
InferTypes.java
擴展器,增加類型推斷
InferFuncTypes.java
在函數體執行結束後將UnKnow類型轉換為any類型
InferRunner.java
添加上述功能後的執行器
JavaLoader.java
通過javassist來定義新的方法
JavaFunction.java
它的對象用於錶示stone中的函數
ToJava.java
將函數轉換成java二進制代碼
Runtime.java
解决ToJava轉換中的一些問題
JavaRunner.java
執行器,最新的啟動程序

雖然基本上完全看不懂這一章的代碼,但是先這樣吧,繼續後幾章的只是內容。


第19章設計模式介紹

Interpreter設計模式

我們無需在意實際的對象究竟是NumberLiteral還是BinaryExpr只需直接調用eval方法即可。調用eval方法後,語言處理器將根據對象的實際類型選擇合適的eval 方法執行。這種方式稱為動態方法分派,是面向對象語言具備的基本功能。
優點:

如果之後因擴充而新增了一些ASTree類的子類,原有程序也無需做太多修改。

缺點:

隨著ASTree的子類的增加,eval方法的數量也會不斷增加。由於這些方法分別比特於不同的源文件中,因此很難理清全體eval方法具體實現了怎樣的功能,可讀性較差。

Visttor設計模式

首先,我們無需直接在抽象語法樹的相關類中定義eval等方法。為此,我們需要為各個類逐一定義accept這一通用的方法作為替代。另一方面,具體的處理操作將由Visito類型的對象中的方法實現accept方法將接收該對象作為參數,選擇該對象中合適的visit方法並執行。 在visitor模式下,各個類的eval方法將匯總於EvalVisitor類,同時,方法名變為visit。EvalVisitor類通過不同的方法,描述了它在訪問(visit)NumberLiteral類或BinaryExpr 類等各種不同的類時,應具體執行哪些操作。
優點:

能够輕松地添加處理邏輯,假設我們希望實現lookup處理,我們不需要進行這類修改。我們只需定義一個實現了Visitor接口的LookupVisitor類,並在其中定義NumberLiteral類與BinaryExpr類所需的visit方法即可。

缺點:

在添加子類時,比較麻煩。

Visttor設計模式可以利用java的反射,擴展。

這兩種設計模式都是非常優秀的面向對象程序設計手法,但都有優缺點。

面向切面編程

本書中采取GluonJ來實現,通過修改器對原有類進行擴展或修改,而不用改變源代碼。

版权声明:本文为[如魔]所创,转载请带上原文链接,感谢。 https://gsmany.com/2022/01/202201071528006451.html