我寫了一門編程語言,你也可以!

在過去六個月,我一直在致力于開發一門叫 Pinecone 的編程語言。我還不能說它已經成熟了,但是它在使用中已經擁有足夠多(編程語言)的特征,例如:

- 變量

- 函數

- 用戶定義的結構體

如果你有興趣,可以看看 Pinecone 的引導頁(landing page)或者它的GitHub

我不是一個專家。當我開始這個工程的時候,我對我所做的事情還沒有方向,但我還是沒有放棄。我在語言創建上的級別為0,只是讀了一點點在線的資料,也沒有遵循我給出的那些建議。

不過,我還是制造了一個完整的新語言。并且它能工作。所以我一定做了正確的事情。

在這篇文章中,我將深入展示管線?Pinecone (以及其他編程語言)把源碼變成魔法。

我也會談談我已經做出的一些權衡,以及為什么我會做出那些決定。

這絕對不是制作編程語言的完整教程,但是如果你對語言開發感到好奇,那么這是一個好的開始。

入門

“我都不知道我該從哪里開始”,當我告訴其他開發人員我在寫一門語言時,我通常會得到這樣的回應。如果聽后的反應也是這樣,我現在將通過一些已經嘗試過的決定和步驟,來告訴你如何開始一門新語言。

編譯型 vs 解釋型

語言主要有兩種類型:編譯型和解釋型:

編譯器會計算出一個程序將執行的操作,將其轉換為“機器代碼”(計算機可以運行的格式,非常快),然后保存以便稍后執行。

一個解釋器逐行逐步執行源代碼,弄清楚它在做什么。

技術上,任何語言都可以被編譯或解釋,但是一種或另一種語言通常對于特定語言更有意義。一般來說,解釋往往更加靈活,而編譯往往具有更高的性能。但這只是解決復雜問題前的預熱。

我高度重視性能,我看到缺乏高性能和簡單性的編程語言,所以我去編譯了 Pinecone。

這是需要今早確定的重要決定,因為很多語言設計決策受到它影響(例如,靜態類型對于編譯型語言來說是一個很大的好處,但對于解釋型語言而言并不是那么重要)。

盡管 Pinecone 是按照編譯型設計,但它也有唯一一個可運行的,功能完整的解釋器。原因我稍后會解釋。

選擇一門語言

我知道這有點像是一個元數據,但編程語言本身就是一個程序,因此你需要用一種語言編寫它。 我選擇了 C++ ,因為它的性能和龐大的功能集。此外,我其實很喜歡使用 C ++ 工作。

如果你正在編寫一種解釋性語言,那么在編譯語言(如 C、C ++ 或 Swift )中編寫將是非常有意義的,因為你的解釋型語言中的性能損失及其對應的解釋器將會更加復雜。

如果你打算編譯,較慢的語言(如 Python 或 JavaScript )是更為可接受的。編譯時間可能很糟糕,但在我看來,運行時間差別不大。

高級設計

一門編程語言通常被構造為一類管線。也就是說,它通常擁有幾個階段。每個階段的數據都會以明確的方式被格式化。還具有將數據從這一階段轉換到下一個階段的功能。

第一個階段是一串包含了整個輸入源文件的字符串。最終階段是可以被運行的東西。我們逐步完成?Pinecone 管線的時候,這一切就會變得清晰起來。

Lexing 詞法

大多數編程語言的第一步是詞法分析或分詞。 “Lex” 是詞法分析的縮寫,這是一個非常棒的詞,是將一大堆文本分解成多個符號。 “tokenizer” 這個詞更有意義,但是,“詞法分析”說起來很有趣,因此我經常使用它。

標記

標記或記號是語言的一個單元。標記可能是一個變量或函數名(也叫標識符),也可能是一個操作符或數字。

詞法分析器的任務

詞法分析器將包含源碼的文件作為輸入字符串,輸出包含標記符號的列表。

流水線(就是編譯過程)后面的階段將不再參考這些字符串源代碼,所以詞法分析器必須產生所有后面各階段需要的信息。之所以會有這樣相對嚴格的格式設計,是因為這個階段詞法分析器可以做一些工作,比如移除注釋或檢測標識符或數字等。如果你將這些邏輯規則放在詞法分析器里,那么在構造語言的其它部分時就不必再考慮這些規則了,而且你可以方便地在同一個地方集中修改這些語法規則。

Flex

我開始開發這個語言,第一件事情就是寫了一個簡單的詞法。不久之后,我開始學習可以讓詞法更簡單正確的工具。

這個小工具就是 Flex ,一個生成詞法的程序。你傳入一個具有特定格式來描述語言語法的文件。它會生成一個 C 語言語法的程序代碼。

我的決定

我選擇暫時保留最初寫的詞法分類器。因為到最后我沒有看到 Flex 的明顯優勢,至少不能達到添加依賴和完成復雜構建。

我的詞法分類器只有幾百行代碼,幾乎沒有什么問題。迭代我的詞法分類器也給了更多的靈活性。例如在不編輯多個文件的情況下向語言添加操作符。

語法分析

管線流程的第二階段就是語法分析器。語法分析器把標識符列表解析為一個帶結點的樹。用于存儲這種數據的樹稱為抽象語法樹,即 AST 。?最后在 Pinecone 的抽象語法樹中不會包含任何標識符類型信息,它就是一個簡單的結構化的標識符。

解析器的作用

解析器將結構添加到詞法分析器產生有序列表中的令牌。 為了阻止歧義,解析器必須考慮括號和操作順序。 簡單的解析運算符并不怎么困難,但隨著更多的語言結構的添加,解析變得非常復雜。

Bison

再次,有一個決定涉及第三方庫。 主要的解析庫是 Bison。 Bison 的作品很像 Flex。 你使用存儲語法信息的自定義格式編寫文件,然后 Bison 使用該文件生成將執行解析的 C 程序。 但我沒有選擇使用?Bison。

為什么自定義更好

在詞法分析器中,使用我自己的代碼這是相當明顯的決定。詞法分析器是一個這樣一個小程序,我自己不寫,感覺就像不會寫我自己的“left-pad”一樣愚蠢。

解析器是另一回事。我的Pinecone解析器目前是750線長,我寫了三個,因為前兩個都是垃圾。

我做出這樣的決定原因有很多,雖然不算順利,但大部分都是正確的。主要內容如下:

最小化工作流中的上下文切換:C ++和Pinecone之間的上下文切換是不夠的,而不會拋出Bison的語法

保持構建簡單:每次語法改變Bison必須在構建之前運行。這可以是自動化的,但是在構建系統之間切換時會變得很痛苦。

我喜歡構建很酷玩意:我沒有做Pinecone,因為我認為這很容易,所以為什么我自己決定一個中心角色?自定義解析器可能不是微不足道的,但它是完全可行的。

一開始我并不完全確定這是否可行,但是我對Walter Bright(C ++的早期版本的開發人員,D語言的創造者)不得不說的是:

有一點更有爭議的是,我不會因為詞法分析器或解析器生成器和其他所謂的”編譯器的編譯器“浪費時間,這些太浪費時間。編寫詞法分析器和解析器是編寫編譯器的一小部分工作。使用一個生成器將花費與編寫一個手工一樣多的時間,它將把您與生成器(在將編譯器移植到一個新平臺上非常重要)相結合。生成器也有時候會發出糟糕的錯誤信息和不幸的聲音。

行為樹(Action Tree)

我們現在已經離開了有共同術語或者通用術語的領域,至少這些術語我不認識。從我的理解,我所謂的‘行動樹' 是最類似于 LLVM 的 IR(中間表示)。

我花了相當長的一段時間弄清楚,行為樹和抽象語法樹之間有一個細微但非常重要的區別,我們應該區別對待(這促成了解析器的改寫)。

行為樹 vs AST

簡單來說,行為樹是帶有上下文的 AST。上下文是一個函數返回的類型的信息,或者兩個地方使用的變量實際上是相同的變量。 因為它需要弄清楚并記住所有這些上下文,生成行為樹的代碼需要大量的命名空間查找表和其他的東西。

運行行為樹

一旦我們有了行為樹,運行代碼就很容易了。 每個行為節點都有一個函數“execute”,它接受一些輸入,不管行為應該如何(包括可能調用子行為),返回行為的輸出。 這是行為中的解釋器。

編譯的選擇

等等,Pinocone 不是應該先編譯嗎?是的,但是編譯起來要比解釋復雜的多,有幾種解決方案:

新開發一個編譯器

聽起來是個好辦法,我喜歡創造東西,早就想好好研究下編譯領域了。

但是,寫一個編譯器并不是將語言的每個元素翻譯成機器代碼這么簡單,因為有很多不同的架構和操作系統,個人想要編寫一個跨平臺的編譯器不切實際。

即使是 Swift 團隊的 Rust 和 Clang 也不想從頭開始編寫,他們的辦法是...

LLVM

LLVM 是一個編譯工具集,基本上就是一個庫,可以把你的編程語言編譯成可執行文件,看似是完美的選擇,所以我馬上使用了它,但不幸的是當時并未意識到水有多深。

LLVM 即使沒有匯編語言那么難,也是一個異常龐大的庫,幾乎沒法使用。即使他們有很好的幫助文檔,但是我覺得在完全使用 LLVM 實現 Pinecone 之前,我還要多積累些經驗。

轉譯

我想快速編譯?Pinecone,所以我轉向了一種可行的方法:轉譯。

我寫了一個 Pinecone 到 C ++ 轉譯器,并添加了使用 GCC 自動編譯輸出源碼的功能。 這個目前適用于幾乎所有 Pinecone 程序(但也有例外)。 它不是一個特別便攜或可擴展的解決方案,但是個可用的臨時解決方案。

未來

假設我繼續開發 Pinecone,它遲早將得到 LLVM 的編譯支持。 懷疑無論我做了多少工作,轉譯器永遠不會完全穩定工作,LLVM 的好處則很多。 問題是什么時候我才能有時間在 LLVM 中做一些示例項目,并掌握它。

在此之前,解釋器對于微不足道的程序是非常好的,并且 C ++ 轉譯適用于大多數需要更多性能的時候。

結論

我希望我所編寫的編程語言對你來說簡單明了。如果你想自己做一個,我強烈推薦它。還有很多實現細節需要弄清楚,這里的大綱應該對你有所幫助。

這是我給出的入門建議(記住,我真的不知道我做的什么,所以僅舉個例子):

- 如有疑問,請選擇解釋型的。解釋型語言通常更易于設計、構建和學習。如果你確定你想要做的是編譯型語言,我不會阻止你嘗試編寫一個,但持觀望態度。

- 當談到詞法分析器和解析器,選擇任何你想要的。這里有很多自己編寫和反方的有效論據。最后,如果你給出了你的設計,并以合理的方式實現了一切,這并不重要。

- 從本文結束部分中的管道中學到一些技巧。我在設計管道時有很多嘗試和錯誤。我試圖消除AST,將AST變成action樹,以及其他糟糕的想法。這個管道可以工作了,所以不需要改動它,除非你有一個很好的主意。

- 如果你沒有時間或動機來實施復雜的通用語言,請嘗試像Brainfuck一樣實現一個深奧的語言。這些解釋器可以短至幾百行。

很抱歉我在Pinecone的實現過程中做了一些糟糕的決定,但是我已經重寫了大部分受這種錯誤影響的代碼。

現在,Pinecone已經足夠好了,特別是它的功能,可以接受改進。編寫Pinecone對我而言是一項非常受益和愉快的經歷,它才剛剛開始。

編譯自:I wrote a programming language. Here’s how you can, too.

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,797評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,179評論 3 414
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,628評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,642評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,444評論 6 405
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,948評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,040評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,185評論 0 287
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,717評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,602評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,794評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,316評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,045評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,418評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,671評論 1 281
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,414評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,750評論 2 370

推薦閱讀更多精彩內容