鸚鵡虛擬機器/編譯器構建
現在我們已經瞭解了NQP和PGE,我們有了開始編寫我們最喜歡的語言編譯器的工具。讓我們回顧一下建立編譯器的步驟
- 使用PGE編寫語法
- 使用NQP編寫動作
- 動作建立PAST樹
- PCT將PAST轉換為PIR
- 鸚鵡將PIR轉換為位元組碼。
在步驟5之後,如果我們一切都做對了,我們應該有一個可以工作的編譯器。當然,在我們到達步驟5之前還有很多工作要做。幸運的是,步驟4和5由構建過程自動完成,因此我們只需要關注1、2和3。在教程部分,我們將提供一些語言構建教程,你可以參考。
PAST節點是你的NQP動作方法必須建立的物件。PCT會在你建立這些節點後自動將它們插入到樹中。PAST節點是具有陣列和雜湊元件的複雜物件。陣列儲存對子節點引用的列表,而雜湊儲存有關節點本身的資訊。建立PAST樹意味著我們建立低層規則的節點,並將它們插入到高層規則的陣列中。在建立過程中,我們為每個規則設定必要的選項,以便PCT可以生成相應的程式碼。
附錄中提供了有關各種PAST節點型別的參考。
PAST::Node是其他PAST節點型別派生的基類。其他型別是PAST::Stmts、PAST::Val、PAST::Var、PAST::Op和PAST::Block。
PAST::Op
- PAST::Op節點是需要執行的操作。
PAST::Val
- PAST::VAL節點是常量值,如整數或字串
PAST::Var
- PAST::Var節點是變數
PAST::Block
- PAST::Block節點用於詞法作用域變數和定義子例程。它們將其他節點放在一起。
PAST::Stmts
- PAST::Stmts節點只是其他節點的組,除了基本的組織之外不執行任何任務。
建立好必要的節點後,可以使用關鍵字make將它插入到解析樹中。
匹配物件是一個包含雜湊的特殊物件。匹配物件雜湊包含有關匹配規則的資訊。雜湊中的每個元素都以規則中的一個子規則命名。例如,如果我們有以下規則
rule sentence {
<adjective> <noun> <adverb> <verb>
}
那麼匹配規則將包含條目“形容詞”、“名詞”、“副詞”和“動詞”。這些鍵的雜湊值是使用make命令從子規則返回的值(如果有)。所以,我們將有以下欄位
$<adjective> $<noun> $<adverb> $<verb>
然後,我們將使用這些欄位的值來為sentence規則生成和make一個節點。如果這些欄位中的每一個都返回它們自己的PAST節點,我們應該將它們推入
我們將在這裡展示一些非常小的示例,以演示基本的編譯器構建方法。教程部分提供了更高階的教程。
- 問題
我們想建立一個基本的計算器程式,它可以對整數執行加法和減法。計算器應將結果列印到螢幕上。
- 解決方案
- 我們首先執行
mk_language_shell.pl來建立一個基本的語言框架。這還會生成一個名為say的內建函式。我們將使用say函式將結果列印到螢幕上。我們將使用基本的自頂向下解析器,我們不會使用操作表。
我們為我們的計算器建立一個基本語法
rule TOP {
<expression>
{*}
}
rule expression {
<term> <operation> <term>
{*}
}
token operation { '+' | '-' }
token term { \d+ }
現在我們需要建立兩個動作,一個用於TOP,另一個用於表示式。TOP方法應該獲取解析表示式的值並將其傳遞給say函式。表示式函式應該生成必要的PIR操作,並將term值插入這些操作中。這是一個基本的動作檔案來完成這項工作
method TOP($/) {
my $past := PAST::Op.new(:pasttype('inline'));
my $expr := $( $<expression> );
$past.inline('say(%0)');
$past.unshift($expr);
make $past;
}
method expression($/) {
my $left := $( $<term>[0] );
my $right := $( $<term>[1] );
my $op := $( $<operation> );
my $pirop := "sub_n";
if $op eq "+" {
my $pirop := "add_n";
}
my $past := PAST::Op.new(:pasttype('pirop'), :pirop($pirop));
$past.unshift($left);
$past.unshift($right);
make $past;
}