设计一种面向对象脚本语言
有沒有感覺設計一門語言實在是太有意思了,可以自定義語法規則,我的“地盤聽我的”。
腳本語言的功能
本書設計一門純粹的面向對象腳本語言,任何語言都有個名詞,這里給這個語言起個名字——sparrow(麻雀)。它支持的功能如下。
1 變量
支持局部變量和局部變量的定義。
變量可引用、賦值。
內部復合數據類型以大寫字符開頭,如System.print()
2 基本數據類型
數值:包括整數和浮點數。
字符串:包括普通字符和unicode。
list:列表,如Python中的list。
支持字面量創建,如['a', 'b']和new方法創建。
元素通過下標list'[索引]'獲得。
map:哈希數組,如Python中的字典。支持字面量創建和new創建。字面量創建如:
{
'k1':v1
"k2":v2
}
key可以是任何數據類型。同樣支持new方法創建。
value通過下標map'[key]'獲得。
range:用以確定一段整數范圍,用符號..表示。range包括from和to兩個成員,分別表示這段范圍的起和始,用區間表示[from, to],即包括from和to。如range“2..6”,2就是from,6就是to,“2..6”表示2、3、4、5、6?!?.”類似于Python中的分片操作符“:”,只不過我們包括了結尾的to,而Python不包括,若用區間表示則to后面的是右小括號“)”。
3 運算
數值:+、?、*、/、%。
邏輯:>、<、==、!=、||、&&、?:、|、&等。
位運算:>>、<<。
方法調用:.。
索引:[]。
字符串:+、%(字符串內的表達式)
4 控制結構
支持if-else選擇。
支持while循環。
支持for循環。
支持break退出循環。
支持continue,跳過本次循環體后面的部分,繼續下一輪循環。
支持return返回。
5 函數
盡管這是一門面向對象語言,但也支持傳統意義上的函數,用關鍵字fun實現函數定義。
函數也是用類實現。
支持函數重載。
6 類
就是傳統意義上的class,包括類定義和類實例,靜態類。
實現繼承,所有類都是object類的子類。
類成員(也稱域,或字段)必須先聲明再引用。
方法包括method、getter、setter、subscript、subscriptSetter和構造函數。支持塊參數,塊參數的參數是用“||”括起來的參數列表,以逗號分隔。
支持靜態方法。
7 線程
支持線程創建及調度。
8 模塊
支持執行模塊和模塊內模塊變量的單獨導入。
9 注釋
行注釋://
塊注釋:/* 塊注釋 */
以上列舉若有遺漏則以實際代碼為主。
關鍵字
有以下關鍵字被提前征用了。
var:用于變量定義。
fun:用于函數定義。
if:用于條件判斷。
else:用于條件判斷的else分支。
true:bool值真。
false:bool值假。
while:用于while循環。
for:用于for循環。
break:用于退出循環。
continue:用于結束本次循環并進入下一輪循環。
return:用于從函數返回。
null:空值。
class:用于類定義。
is:用于判斷類是否為某類的子類,即“is a”。
static:用于設置靜態文法。
this:用于指向本實例。
super:用于指向父類。
import:用于導入模塊。
腳本的執行方式
我們采用傳統的虛擬機作為執行方式,即要實現一個虛擬機。編譯器先把源碼編譯為opcode,再讓虛擬機執行opcode。
opcode即操作碼,是自定義的一套專供虛擬機執行的指令,后面我們在實現虛擬機時會詳細介紹。
“純手工”的開發環境
既然本著教學的目的我覺得應該拿出教學的誠意,因此這里所說的“純手工”是指編碼中不想借助STL或其他類似的泛型語言,沒有第三方庫,一切以最基礎最原始的形式展現語言的奧秘,因此選擇了C語言,確定地說是C89,并不是較新的C99標準,誠意滿滿,讓我們純手工去編碼吧。
基礎開發環境是:
宿主系統是Linux,采用CentOS release 6.8 (Final);
編譯器是gcc,版本是gcc version 4.4.7 20120313 (Red Hat 4.4.7-17) (GCC)。
定義sparrow語言的文法
在之前介紹的文法中,我們采用的是大寫字母表示非終結符,小寫字母表示終結符,然而我們也說過了,在現實中為了便于編程,一般都用正規文法來定義語言,正規文法說白了就是用正則表達式定義的文法,因此本小節的基礎是正則表達式,為保證容易看懂,我會用最簡單的方式書寫正則表達式。
值得注意的是,正規文法與第0章中介紹的文法有很大的差別,主要是涉及終結符是用''表示,原因是正規文法中會涉及()、[]和{},這些在正規文法中都是元字符,有其特殊含義:()表示成為一組,[]表示范圍,{}表示重復。
但在實際語言它們只是字符串字面量(即終結符),比如在語言中()表示函數名后面的括號,也可表示表達式中的小括號,[]表示下標索引,因此為避免沖突,正規文法中用單引號括起的是終結符。
其實語法和傳統語言差不多,只是用文法來描述就顯得生澀了。注意,正規文法中的[]與EBNF中的意義不同,在此表示范圍,其中可以用-表示一段連續的范圍,比如0-9就表示0至9之間(包括0和9)的任何數;a-z同理,表示字母a到字母z之間的任何字母。[]后面一般會接量詞,當然量詞不一定只用在[]之后,但它一定是用在某個字符之后以表示該字符的數量,其前不能沒有字符。
按照數量級別劃分有3種量詞,+表示重復出現1次以上,*表示重復出現0次以上,?表示出現0次或1次,比如可用[\t]*表示0個或多個空白字符,其中\t是tab。
注意此處[]中的空白是空格,為了突顯這里有個空格就寫了兩個。.表示任意字符,包括控制字符比如回車等,|表示或者、任意其一,比如a|b,表示a和b兩者取其一,注意,|是對兩邊的整體有效,并不是只對緊鄰|的有效。
比如對于ab|cd的意思是ab或者cd,如果想表達abd或acd,可以用分組符號(),就是小括號對兒。()表示作為一組考慮,使相應的正則符號應用于整個組成員。
初次接觸文法的讀者可能對遞歸定義感到“消化不良”,比如非終結符exp是用于定義表達式,exp是由infixExp等非終結符組成,而infixExp又是由exp組成,看上去有點死循環出不來了,但你不要忘了,infixExp只是exp的其中一個組成部分,exp還可以由num、id等指代,num和id下面再無遞歸定義,這就是遞歸終止的條件。因此infixExp的組成部分exp也會是num或id等。
下面是具體的樣本。
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??
以下是上述文件的執行結果,其中的spr是最終的腳本解釋器(包括編譯器及虛擬機),spr是sparrow的縮寫。
? ? ? ? ? ? ? ? ? ? ?
?
以上./spr manager.sp就是執行腳本文件manager.sp,這與任何腳本語言的運行方法都是一致的,執行過就是腳本的輸出,大家有興趣可以核對一下結果,除了System.clock返回的時間戳是動態變化的外,其他不變。
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??
《自制編程語言》
鄭鋼 著
本書全面從腳本語言和虛擬機介紹開始,講解了詞法分析的實現、一些底層數據結構的實現、符號表及類的結構符號表,常量存儲,局部變量,模塊變量,方法存儲、虛擬機原理、運行時棧實現、編譯的實現、語法分析和語法制導自頂向下算符優先構造規則、調試、查看指令流、查看運行時棧、給類添加更多的方法、垃圾回收實現、添加命令行支持命令行接口。
小福利
你認為程序員存在的最大價值是什么,參與話題有機會獲獎哦。截止時間9月7日17時,留言+轉發本活動到朋友圈,小編將抽獎選出3名讀者贈送紙書1本。
掃碼關注我們
點擊閱讀原文,直接購買《自制編程語言》
閱讀原文????
總結
以上是生活随笔為你收集整理的设计一种面向对象脚本语言的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: GMQ集团推出全球创新型金融衍生品交易平
- 下一篇: node安装和使用redis