標籤:

給Lice寫了倆工具

最近在折騰我的Lice,由於暫時告一段落了(暫時想不到什麼必須寫的東西),星期一作業比較少,於是就在那天拿了兩節晚自習的時間給它造了倆工具。

靈感來源於豐愷同學@lfkdsk 給他的HobbyScript寫的解析器的一個彩蛋, 就是在Parse代碼拿到AST之後把它顯示為(非常友好,顯示了很多元數據的)韋恩圖, 不過他這個是調用了一個Python庫的Java API。

我發現Java的Swing框架是有一個JTree的,可以顯示樹形結構。 JetBrains系列IDE用於顯示文件樹的控制項應該就是魔改過後的JTree。

所以我就直接選擇了它。

我在寫這個東西之前對於JTree的了解僅限於它是一個Swing控制項。 但是我卻成功地拿它做出了可以用的東西。 這雖然大部分歸功於Swing的封裝很簡單,但是我認為這也是一種平常情況下不會自動產生、 需要學習的一種非常重要的技能。我決定之後再找時間寫一篇教程, 教你怎麼在沒有文檔沒有網路只有IDE的情況下使用一些庫。

詞法樹閱讀器

我不知道這門翻譯對不對,反正原意是「Syntax Tree Viewer」。 它的功能就是讀取一個Lice代碼文件並進行詞法分析,然後把AST通過swing的JTree顯示出來。

大概效果是這樣的,對應這樣的一個Lice代碼(SICP第一章那個費馬檢查的代碼):

; SICP 1.2.6nn(def exp-mod a b m (|>n (-> ret 1)n (while (!= 0 b) (|>n (if (!= 0 (& b 1))n (-> ret (% (* a ret) m)))n (-> b (/ b 2))n (-> a (% (* a a) m))))n ret))n(def try-it a n (== (exp-mod a n n) a))n(def fermat-test nn (try-it (+ 1 (rand (- n 1))) n))n(def say nn (println n " => " (fermat-test n)))n(|>n (say 101)n (say 233)n (say 777)n (say 666)n ()n)n

以上代碼精簡了注釋,原文在GitHub上。

使用該工具顯示出來的語法樹是這樣的:

有點大,分成兩張圖算了:

這是字元級別的語法樹,相當於是只進行了Syntax級別的Parse。

Lice語言的Syntax級別的Parse和Semantic級別的Parse是分開的, 首先使用循環+棧(指數據結構)進行一次Syntax級別的Parse, 然後再遞歸遍歷這棵樹,建立一顆等同的Semantic分析過後的樹。

上面的工具就是把Syntax分析過後的樹給map了一遍之後代理給 JTree所需要的DefaultMutableTreeNode。

既然如此,我們還可以把Semantic級別的語法樹拿來Parse。

我為此給那些Node分別添加了一個toString用來顯示內容。 這是Parse之後的樣子。

還是有點大,分成兩張圖片:

還是不錯的對吧?字面量顯示出了類型,函數調用顯示出了參數數量。

注意def不是保留字而是一個內置的函數。 因此「函數定義」這一過程其實也算是一種函數調用。

按理說你們是可以在GitHub的release界面看到這倆工具的下載的, 打開jar之後會先彈出一個文件選擇框,選擇一個擴展名為lice的文件, 打開就可以看到語法樹辣。

當然,這個和豐愷的輸出圖片也是有很多不同之處的。比如圖片就只能是圖片, 我這個可以展開、關閉一些語法樹節點。

目前兩個小工具代碼都非常少。

甚至還可以做到:

  • 對現有AST節點進行編輯
  • 根據編輯後的AST,導出Lice代碼
  • 合併、添加、刪除等複雜操作
  • AST節點的複製粘貼

以上內容目前還只是YY,不知道我這二倍根號二腳貓水平能不能做出來。

—— 2017/3/7

辣雞知乎編輯器,粘貼的圖片編輯的時候還在,發出來就沒了


推薦閱讀:

SICP第二章里的「圖形語言」在DrRacket 或者MIT Scheme上有沒有辦法實現啊?
如何評價 Racket 這門編程語言?
根據遞推關係,如何編程計算這個數列的前10項?
clojure中 x x #x 他們之間的關係一直很暈 能給一些應用場景例子嗎?

TAG:Lisp | Kotlin | 编程 |