如何自己創建一種編程語言? | 知乎問答精選

 

A-A+

如何自己創建一種編程語言?

2019年02月24日 知乎問答精選 暫無評論 閱讀 6 ℃ 次

【Belleve的回答(86票)】:

你要做的事情有三步:

  1. 語義設計
  2. 語法設計
  3. 實現一個編譯器

實際上,最難的往往是第一步,也就是語義設計,因為它決定了你的語言的最終形態。「語義」的內容會很寬泛,下面這些都是語義的範疇:

  1. 類型系統:是強類型還是弱類型?靜態類型還是動態類型?是否有類型推導?如果有,基於哪種形式系統?是否允許子類型?是否允許遞歸類型?類型轉換的機制如何?等等。
  2. 編程範式:你的語言是過程式(Imperative)還是聲明式(Declarative)還是兩者結合?對於「聲明式」,是函數式(Functional)還是邏輯式(Logical)?是否允許元編程?等等。
  3. 存儲:你的語言是否允許用戶干預存儲細節?是否允許指針算數?是否允許手動內存管理?變量(符號)的作用域規則如何?是詞法作用域(Lexical Scoping)還是動態作用域(Dynamic Scoping)還是兩者結合?
  4. 子程序:你的語言是否有子程序?如果有,他們是否是第一態(First Class)的?參數傳遞是按值傳遞還是按名傳遞?是否允許按引用傳遞?求值策略是急迫求值還是懶惰求值?參數之間的求值順序是怎樣?
  5. 流程控制:你的語言是否允許非結構跳轉?是否有內建的異常處理機制?是否有連續體(Continuation)或協程(Coroutine)機制?

在語義設計完成之後就要設計與之對應的語法(Grammar)。幾乎所有的編譯原理教程都是從語法開始,這在實現編譯器的時候是這樣,然而設計語言時,語義是比語法先完成的。一套核心語義可以有多種語法與之對應,當然這些語法裡肯定有最合適的。像 Lisp 裡無比強大的宏就更喜歡簡單的語法。(等等……Lisp 這貨有語法?)

在語法設計完成之後,你就可以著手實現編譯器/解釋器了。現在成熟的後端非常多,即使你想直接編譯成 x86 機器代碼,使用現有庫的話也沒有很高的難度。不過對於初學者,把編譯器的目標平台定到一些虛擬機——如 JVM 或者 CLI 上會容易的多。在實現編譯器的時候你要做的事情包括:

  1. 語法分析。這一塊庫相當豐富(畢竟還有一堆程序要讀文本文件),從老牌的 yacc 到現在流行的 Parser Combinator 隨你挑。這一步完成時你會得到一個語法樹(Parse Tree)。
  2. 類型檢查與類型推導。對於那些靜態類型的語言,你要在這一步完成類型檢查/類型推導。這一塊沒有通用的庫,你得自己查閱相關算法(比如 Hindley-Milner 推導算法)。
  3. 語言相關優化。這一步是針對語言的優化。尤其是對那些使用大量函數式特性的語言,這一步尤其重要。優化的好,編譯出的程序性能可提升數倍。當然,傳統的平台無關優化,如子表達式消除、複製傳播等也不能忽略。
  4. 中間代碼生成。絕大多數後端都是線性的簡單指令,此時你就要想辦法把樹狀的語法樹變成線性的指令列表。你可以用三地址(3-address)或者靜態單賦值形式(SSA)。如果你使用 LLVM、JVM 這類的後端,你的編譯器在這裡就可以宣告完工了。
  5. 代碼生成。如果你想編譯成機器代碼而不想用現成後端的話,這是最後一步。在這一步裡你還要進行平台相關優化,把你的程序調教成最適合目標平台的形式。
  6. 標準庫的編寫。這個嚴格意義上不算編譯器的內容,但是誰的語言是裸語言呢?編寫一套好的標準庫比你想像的困難,看看 nodejs 所用 libuv 的規模就知道了。

編譯器的調試和測試是非常困難的:一方面它不允許任何錯誤,另一方面編譯器的測試用例也非常難寫。所以在優化這一步上,寧可保守一些也不要引入錯誤。同時在編程時,請寫「明顯正確」的程序:結構清楚,一看便明的程序。

——————————————————————————————————————————

補充:

  1. 有人提及 OOP。喂,OOP 不就是結構類型 + 子類型披了層皮嗎?
  2. 「語法設計」我提得少,因為它相比語義設計和編譯器作成來看,重要性最低。但是它的工作十分瑣碎,而且對於語言用家的最終體驗也有巨大影響,所以還是認真點好。真的不想設計語法,就 lisp 好了……

【vczh的回答(4票)】:

@Belleve 基本上已經把該說的都說完了。但是想讓自己用的爽,還得給這門語言開發一個帶intellisense的編輯器。這是對水平的挑戰,啊哈哈哈

【彭勇誠的回答(8票)】:

參考

@vczh 的如何設計一門語言(九)——類型

【張辛宇的回答(0票)】:

設計一種規則,用來實現某種或某些功能,並且有一個程序能把這個規則轉變成期望的結果,這樣一種語言就誕生了。語言可複雜可簡單,完全取決於你的需求。

【changcheng的回答(0票)】:

llvm

【XiYang的回答(0票)】:

第一名的答案說得很明確了,補充一些具體工具。

yacc、bison是一個解析器生成器。

優化與目標代碼生成可以用llvm,它是前後端分離的,相當於你只需要弄個前端。

【知乎用戶的回答(0票)】:

寫一堆 define 哦耶,第二個中文編程語言誕生了

【知乎用戶的回答(2票)】:

買本《編譯原理》的書看看就明白了~~~姆哇咪哇~~~

【知乎用戶的回答(0票)】:

.net的DLR能幫助你更快創建一種語言。你只需要定義好語義和語法,編譯和運行的事交給DLR就行了,你的語言可以完美的運行在.net平台下,像微軟自己做的似的

【俞志強的回答(0票)】:

《圖靈程序設計叢書:自製編程語言》

標籤:-編程 -編程語言 -編譯器 -編譯原理


相關資源:





給我留言