隨著接觸過的語言越來越多,心中想自造門語言的想法,就越發強烈,然而,打造出更好的語言,並不是我的目的。

在打造過程中,能否將過往的設計經驗加以運用,是原因之一,不過,能否進一步跳脫語言的框架、從這課題上學習更多先驅者的想法,或許才是好奇心的根本來源。

拼圖裡缺少的部份

想想從第一門學習的語言開始,從C語言、Java,一直到lambda演算、圖靈機,中間也探索過一、二十種語言了,每次探索新語言的動機,都是基於好奇。

像是:對動態定型語言的好奇,對函數式的好奇,對函數式結合物件導向、基於原型的繼承、建構DSL的能力、圖像語言、3D程式建模等的好奇,甚至,只是單純地好奇,想知道語言倡議者是不是在胡說八道,都可能是學習語言的動機之一。

多年來,接觸語言的經驗告訴我,語言代表著語言創建者或是社群,在對待問題時所採取的不同角度或想法。

世界上沒什麼最好用的語言,因為,在面對真實問題,用語言的角度來解決之前,語言什麼都不是。當然,如果願意,只用一種想法來解決全部的問題,也並非不行,但是,我的個性就是偏愛從不同的角度來看待問題,若還有語言存在著吸引我的不同想法,我就會樂此不疲地接觸下去。

在不持偏見下,只要接觸的語言夠多,就越能跳脫語言的框架來看待一門語言,這始終是我心中一貫的態度。然而,即便如此,心裡亦存在著另一種聲音:「跳脫語言框架?但是,你連一門語言都沒實現過啊!」這聲音的另一面就是,渴望著知道如何創造語言,甚至,是更進一步地實現心中想要的語言。

渴望歸渴望,拼圖裡總是覺得少了那麼幾塊,所以,想法一直沒有實現,直到接觸了lambda演算,才對語言有了更深一層的認識:語言是運算式的規則,程式是一串龐大的運算式。

探索圖靈機時,則得到了不同的啟發:不同的機器,有不同的運算能力,而不同的機器,代表著運算能力各不相同的語言;語言中的符號,對應著一個運算規則,而連續的符號編寫,就是連續的運算規則。在簡單的情況下(像是Brainfuck),符號與規則都會是線性的,而在複雜的情況下,連續符號的實現上,可分解為一棵樹,因而運算規則也會是一棵樹。

從經驗中開始拼湊

在接觸lambda演算、圖靈機之後,感覺就像找到了拼圖中缺少的那幾塊。

既然,學習程式語言的第一個範例是Hello World,我就試著從簡單的print 'Hello World'開始打造語言吧!然後,試著加入數值、重複語句、變數、運算式,接著就停手了,我自問:「一門語言真的是這樣打造的嗎?」

聽說關於自造程式語言的基礎是編譯原理,如果是資訊相關科系的話,在大二之後的程式語言或編譯器課程就會談到,可惜的是,在學校沒有接觸過這類課程。

或許,也沒什麼可惜的,畢竟求學時代對程式語言也沒什麼深入認識,當時,若修習編譯原理之類的課程,大概也只是鴨子聽雷沒有感覺。

我看了幾篇關於自造語言的文件,想試著比較先前停手時所留下的東西(https://goo.gl/XR7JN5),然而,通常在談過詞法分析、語法分析等概念之後,為了簡化範例,就會使用剖析器程式庫,但這對我而言,根本就是隔靴搔癢,因為剖析器的設計,也是我想知道的啊!

不過,看過這些文件還是有好處的,至少我知道了,詞法分析、語法分析通常會設計為各自獨立,於是,絕對會基於這個原則。因此,我再度從經驗中開始拼湊,想知道剖析器設計、抽象語法樹組織,各會遇上什麼問題,而目前的能力又能想出什麼樣的解決方式,最後,又能將這土炮式的語言,實作到哪種程度。

基於經驗思考、動手實作、遇上問題,再基於經驗思考如何解決問題,接下來,看看別人如何思考、解決問題,有時這是個必要的過程。

當然,前人已經留下了不少方案,只不過往往在沒有經歷這個過程的情況下,會覺得這些方案過於抽象,或者體會不出箇中奧妙,所以,有些事還是要動手才會知道。

重構治百病

就結論而言,我打造出的第一個玩具語言,像是Java、JavaScript、Python、Ruby的綜合體,畢竟是生手,這語言沒有解決現有語言問題的偉大夢想,首要想法是剖析器易於處理的語法就拿來用,至於次要的想法就是,抽象語法樹在處理時具有一致性,儘量可以重用既有的樹節點設計。

就目標來說,這玩具語言會是個命令式語言,可以有判斷式、迴圈、函式、類別等近代高階語言的基本元素,然而語法沒有目標,往往是打算加入下個語法元素前,想想現有的設計下怎麼安插進去,過程中,往往就是重構、重構、不斷地重構,而重構的對象,包含了抽象語法樹、剖析器,甚至是規則表示式。

當不知道手中打造的東西,應當往哪個方向發展時,重構就是引導方向的工具,就算只是單純地檢視程式碼中重複的部份,想辦法加以消弭或者是重用,有時也會意外地找到思路。

不!應該說,它一直在那邊,只不過被混亂的程式碼掩蓋了!

如果慣於重構,而在重構過程中找到臭蟲,應該是太常發生的事情了,至於在設計語言這方面,還有個意外收穫——雖然重構時,面對的是程式碼,然而,也重構出你想要打造的語言當中的不足、矛盾等文法錯誤,接著,就會開始體會到,以前學習過的語言會有那些文法存在的原因。

抽象語法樹的重構過程,也是如此。函式呼叫是什麼?一級函式是什麼?變數範圍?類別定義?物件初始化?this?方法呼叫與函式的差別?雖說程式語言相關文件或書籍,多少會談及這些概念,然而,若能將這些概念實現,依需求重構與結合,這些概念就不再只是概念了。

值得一提的是,重構的好幫手是函數式典範,不可變動的特性,可以引導出更好的設計,這也就是為何,我打造的玩具語言雖然是命令式,然而,在原始碼的實現上,卻是函數式的原因。

別人是怎麼做的?

想想我一個打造語言的生手,利用工作的空檔,以手中的玩具語言約莫打造了一個月,就達到了一開始設定的目標,若是熟手應該更快吧!這就令我想到Brendan Eich,他曾說在十天內建立JavaScript,這完全是有可能的,也就是說,土炮打造出第一個玩具語言並不難。

然而,這只是一個過程,中間累積了不少的想法,一如學習各種程式語言,是為了獲取各種解決問題的方式,在首個語言打造之後,接下來,就是學習別人是怎麼做,應該是要好好找些編譯原理、程式語言實現的書來看了。

整體而言,只要是能從不同的角度來看待問題,就會引發我的好奇心,而這才是我真正樂此不疲的動力來源。

專欄作者

熱門新聞

Advertisement