鸚鵡虛擬機器/Squaak教程/簡介
第一集: 簡介
第二集: 深入編譯器內部
第三集: Squaak細節和第一步
第四集: PAST節點和更多語句
第五集: 變數宣告和作用域
第六集: 作用域和子程式
第七集: 運算子和優先順序
第八集: 雜湊表和陣列
第九集: 總結和結論
這是關於使用鸚鵡編譯器工具構建編譯器的教程系列的第一集。如果您對虛擬機器感興趣,您可能聽說過鸚鵡虛擬機器。鸚鵡是一個通用的虛擬機器,專為動態語言而設計。這與 Java 虛擬機器 (JVM) 和微軟的公共語言執行時 (CLR) 相反,它們都是為執行靜態語言而設計的。JVM 和微軟(透過動態語言執行時 - DLR)都在新增對動態語言的支援,但他們的主要關注點仍然是靜態語言。
虛擬機器的主要目的是執行程式。這些程式通常是用某種高階語言 (HLL) 編寫的。一些眾所周知的動態語言(有時稱為指令碼語言)包括 Lua、Perl、PHP、Python、Ruby 和 Tcl。鸚鵡被設計為能夠執行所有這些語言。鸚鵡託管的每種語言都需要一個編譯器來解析語言的語法並生成鸚鵡指令。
如果您從未實現過程式語言(即使您可能實現過一種語言),您可能會認為編寫編譯器有點像黑魔法。我知道我以前就是這麼想的。你知道嗎?事實的確如此。編譯器是複雜的程式,實現一種語言可能非常困難。
事實:1) 鸚鵡適合執行幾乎所有已知的動態語言,但在此之前,必須編寫編譯器,2) 編寫編譯器相當困難。
這就是鸚鵡編譯器工具包 (PCT) 的用武之地。為了使鸚鵡成為語言開發者的一個有趣目標,構建編譯器的過程應該得到合適工具的支援。正如任何一項建築工作,如果你擁有合適的工具,就會變得容易得多(你不會只用雙手來建造一座房子,對吧?),對於構建編譯器來說也是如此。PCT 的設計就是為了做到這一點:提供強大的工具,使為鸚鵡編寫編譯器變得輕而易舉。
本教程將透過演示使用 PCT 以多麼容易的方式為鸚鵡實現一種(簡單)語言來介紹 PCT。該案例研究語言並不像現實世界中的語言那樣複雜,但本教程旨在激發您的興趣,並展示 PCT 的強大功能。本教程還將介紹一些您可以探索的練習,以便學習本教程中未涵蓋的 PCT 的更多細節。
我們將要在鸚鵡上實現的案例研究語言名為 Squaak,它將是一個功能齊全的編譯器,可以將程式從原始碼編譯成鸚鵡中間表示 (PIR)(或立即執行 PIR)。它也可以用作命令列直譯器。Squaak 演示了一些常見的語言結構,但同時也缺少一些其他看似簡單的功能。例如,我們的語言將沒有 return、break 或 continue 語句(或您最喜歡的語法中的等效項)。
Squaak 將具有以下功能
- 全域性變數和區域性變數
- 基本型別:整數、浮點數和字串
- 聚合型別:陣列和雜湊表
- 運算子:+、-、/、*、%、<、<=、>、>=、==、!=、..、and、or、not
- 子程式和引數
- 賦值和各種控制語句,如“if”和“while”
如您所見,缺少一些常見的(更高階的)功能。最值得注意的是
- 類和物件
- 異常控制語句,如 break 和 return
- 高階控制語句,如 switch
- 閉包(巢狀子程式和訪問外部作用域中的區域性變數)
我們將用來實現 Squaak 的鸚鵡編譯器工具包括以下部分
- 鸚鵡語法引擎 (PGE)。PGE 是一個用於正則表示式的先進引擎。除了 Perl 5 中的正則表示式之外,它還可以用於定義語言語法,使用 Perl 6 語法。(檢視參考資料瞭解規範。)
- 鸚鵡抽象語法樹 (PAST)。PAST 節點是一組類,用於定義表示常見語言結構的通用抽象語法樹節點。
- HLLCompiler 類。此類是所有基於 PCT 的編譯器的編譯器驅動程式。
- 幾乎不是 Perl (6) (NQP)。NQP 是一種受 Perl 6 啟發的輕量級語言,可以用來編寫解析階段必須執行的方法,就像您可以在 Yacc/Bison 輸入檔案中編寫操作一樣。
在本教程中,假設您已經成功編譯了鸚鵡(也許還運行了測試套件)。如果您瀏覽鸚鵡原始碼樹中的 languages 目錄,您會發現許多語言實現。其中大多數尚未完成;有些正在積極維護,而另一些則沒有。如果您在閱讀完本教程後想為這些語言中的任何一種做出貢獻,您可以檢視郵件列表或加入 IRC(有關詳細資訊,請參見參考資料部分)。
languages 子目錄是放置我們語言實現的合適位置。鸚鵡帶有一個特殊的 Perl5 指令碼,用於生成語言實現所需的必要檔案。在執行它之前,必須安裝鸚鵡以進行開發。從鸚鵡的根目錄開始,輸入
$ make install-dev
為了生成一個包含我們語言檔案的目錄,輸入(假設您在鸚鵡的根目錄中)
$ perl tools/dev/mk_language_shell.pl Squaak
(注意:如果您在 Windows 上,則應使用反斜槓。) 這將在一個名為“squaak”的目錄中生成檔案,並將“Squaak”用作語言的名稱。之後,轉到此目錄並輸入
$ parrot setup.pir test
這將編譯生成的檔案並執行測試套件。如果您想了解更多關於生成哪些檔案的資訊,請檢視本集末尾的參考資料。
請注意,我們沒有編寫一行程式碼,但是已經有了基本的架構來幫助我們開始。當然,生成的編譯器甚至不像我們將要實現的語言,但現在沒關係。稍後我們將調整語法以接受我們的語言。
現在,您可能想用這個編譯器實際執行一個簡單的指令碼。啟動您最喜歡的編輯器,並輸入以下語句
say "Squaak!";
儲存檔案(例如儲存為 test.sq),然後鍵入
$ parrot squaak.pbc test.sq
這將執行 Parrot,指定 squaak.pbc 為 Parrot 要執行的檔案,該檔案接受一個引數:檔案 test.sq。如果一切順利,您應該看到以下輸出
$ parrot squaak.pbc test.sq Squaak!
除了執行指令碼檔案之外,您還可以以互動式直譯器的形式執行 Squaak 編譯器。在不指定指令碼檔案的情況下執行 Squaak 編譯器,並輸入與您在檔案中編寫的相同語句
$ parrot squaak.pbc say "Squaak!";
它將列印
Squaak!
本教程的第一部分主要是對即將發生的事情的概述。希望您現在已經對 Parrot 編譯器工具是什麼以及如何使用它們構建針對 Parrot 的編譯器有了全域性的瞭解。如果您想檢視 PCT 的一些實際應用,請檢視 Rakudo(Parrot 上的 Perl 6)或 Pynie(Parrot 上的 Python)。
接下來的部分將重點介紹我們語言的逐步實現,包括以下主題
- 基於 PCT 的編譯器的結構
- 使用 PGE 規則定義語言語法
- 使用運算子優先順序表實現運算子優先順序
- 使用 NQP 編寫嵌入式解析操作
- 實現語言庫例程
在此期間,請自行嘗試。歡迎您加入我們 IRC 頻道(有關詳細資訊,請參閱參考部分)。感謝您對本教程的任何反饋。
練習在本文件的每一部分末尾提供。為了使本教程的長度在可接受的範圍內,並非所有內容都能得到詳細討論。這些練習的答案或解決方案將在該部分發布後幾天內釋出。
- 問題 1 高階互動模式
啟動您最喜歡的編輯器,檢視檔案 src/Squaak/Compiler.pm,該檔案仍位於目錄 squaak 中。此檔案是用 Not Quite Perl(“NQP”)編寫的,當您執行 parrot setup.pir test 時,它會被編譯為 src/gen_compiler.pir。它包含編譯器的設定。類 HLL::Compiler 定義了用於在編譯器以互動模式執行時設定命令列橫幅和提示的方法。例如,當您以互動模式執行 Python 時,您將看到
Python 2.6.5 (r265:79063, Apr 1 2010, 05:28:39) [GCC 4.4.3 20100316 (prerelease)] on linux2 Type "help", "copyright", "credits" or "license" for more information.
或類似的東西(取決於您的 Python 安裝和版本)。此文字稱為命令列橫幅。在互動模式下執行時,每一行將以
>>>
開頭,這稱為提示。對於 Squaak,我們希望在互動模式下執行時看到以下內容(當然,您可以根據自己的喜好更改它)
$ ../../parrot squaak.pbc Squaak for Parrot VM. >
在檔案 Compiler.pm 中新增程式碼以實現此功能。
- 提示:請注意,NQP 中只有雙引號字串可以解釋跳脫字元,如 '\n'。
- 答案
鑑於提供的提示,找到解決方案可能並不困難,該解決方案如下所示。此程式碼可以在檔案 Compiler.pm 中找到。相關行以粗體顯示。
INIT {
Squaak::Compiler.language('Squaak');
Squaak::Compiler.parsegrammar(Squaak::Grammar);
Squaak::Compiler.parseactions(Squaak::Actions);
Squaak::Compiler.commandline_banner("Squaak for Parrot VM.\n");
Squaak::Compiler.commandline_prompt('> ');
}
HLL::Compiler 類提供了更多您可以設定的選項,您應該探索所有選項。
- Parrot 郵件列表:parrot-dev@lists.parrot.org
- IRC:加入 irc.perl.org 上的 #parrot 頻道
- PCT 入門:docs/pct/gettingstarted.pod
- Parrot 抽象語法樹 (PAST):docs/pct/past_building_blocks.pod
- 使用 PCT 進行運算子優先順序解析:docs/pct/pct_optable_guide.pod
- Perl 6/PGE 規則語法:Synopsis 5