Slide 1

Slide 1 text

アセンブリ言語のみで 言語処理系を作った話 (原題: ブートストラッピングで言語処理系を作った話) 第11回 カーネル/VM探検隊 中村 晃一

Slide 2

Slide 2 text

本日の資料・コード •https://speakerdeck.com/nineties/bootstrap •https://github.com/nineties/amber

Slide 3

Slide 3 text

自己紹介 • 中村晃一(@9_ties) • IoTデバイスを作っています • idein.jp • 課外活動 • 圏論勉強会、パターン認識・機械学習勉強会などの講師

Slide 4

Slide 4 text

処理系作りが趣味でした • 学生実験でコンパイラ係に • O’CamlでminCamlコンパイラを作ったり • Haskellでも作りました github.com/nineties/Choco • 大学院では最適化コンパイラの研究をしました • 特殊なプロセッサの為のコンパイラを書いたり • 型推論器を書いたり

Slide 5

Slide 5 text

自分の言語を作ろうと思いました • 言語名: 最初はrowl ⇒ 後にamber • ただ作るだけでなくその過程を楽しみたい • どうやったら楽しめるだろうか?

Slide 6

Slide 6 text

縛りを入れて作ろう • ルール 1. 実装言語はアセンブリ言語のみ 2. 既存ライブラリは使ってはならない 3. コード生成ツールは使ってはならない libcなど Cなどの高級言語 flex/bisonなど

Slide 7

Slide 7 text

作戦:ブートストラッピング アセンブリ言語でちょっと高級な言語1の処理系を書く 言語1でもうちょっと高級な言語2の処理系を書く 言語kでamberの処理系を書く amberでamberの処理系を書く 今ココ(暫らく放置中)

Slide 8

Slide 8 text

何の意味があるの? • 純粋に楽しみとして • 知識・技術・ノウハウを磨くのに役に立つかも • 効率の良い学習方法ではありませんが・・・ • ツール群を作った先人への尊敬と感謝が芽生える

Slide 9

Slide 9 text

以下ダイジェストでお見せします

Slide 10

Slide 10 text

1.アセンブリで言語「rowl0」を実装

Slide 11

Slide 11 text

アセンブリより少し高級な言語を作ります • 言語名: rowl0 • コンパイラ名: rlc

Slide 12

Slide 12 text

トークンの正規表現から

Slide 13

Slide 13 text

状態遷移図を書いて

Slide 14

Slide 14 text

状態遷移表にして

Slide 15

Slide 15 text

レキサを作ります

Slide 16

Slide 16 text

文法をBNFで書いたら

Slide 17

Slide 17 text

再帰降下法でパーサを作ります

Slide 18

Slide 18 text

コード生成はパースと同時にやりました • この時点でメモリ管理を実装 するのは面倒 ⇒ 構文木作るの面倒 コード生成

Slide 19

Slide 19 text

最初の言語「rowl0」が完成! • 変数管理が出来ない • 関数引数はp0,p1,p2,... • ローカル変数はallocate(n)でスタックメモ リを確保し x0,x1,x2,...で参照

Slide 20

Slide 20 text

2.「rowl0」でLISP系言語「rowl-core」を実装

Slide 21

Slide 21 text

一旦LISPを作る事にしました • 言語名: rowl-core • インタプリタ名: rlci • 実装が容易 • メタプログラミングによる生産性向上

Slide 22

Slide 22 text

さっきと同じ感じでレキサ・パーサを作る

Slide 23

Slide 23 text

アセンブリよりかなり記述が楽

Slide 24

Slide 24 text

evalも作っていきます。

Slide 25

Slide 25 text

メモリ管理はまだしません • mmapしか使えないので負担が大きい 1. 不要になったメモリは回収しない 2. 足りなくなったら新たに確保 3. 動かし続けるといつか死ぬ • 次の世代のコンパイルだけ出来ればあと不要なので良しとした malloc, free

Slide 26

Slide 26 text

LISP系言語「rowl-core」が完成! • lambdaやmapが使えたり • マクロが使える!

Slide 27

Slide 27 text

3.「rowl-core」で「VM記述言語」を作る

Slide 28

Slide 28 text

次の世代では仮想マシンを導入します。 • その為の「VM記述用言語」を作成。 • LISPの強みを生かして、言語内DSLとして作成 • レキサ・パーサの実装は不要!

Slide 29

Slide 29 text

こんな感じでVM用コンパイラを書きます

Slide 30

Slide 30 text

今回は高階関数とかも使えます • 生産性がぐっと向上!

Slide 31

Slide 31 text

4.「VM記述言語」で仮想マシン「rlvm」を実装

Slide 32

Slide 32 text

言語内DSLでVMのコードを書いていきます

Slide 33

Slide 33 text

ガベコレもようやく実装します • コピーGCにしました

Slide 34

Slide 34 text

組み込み関数も作っていきます

Slide 35

Slide 35 text

ここでメタプログラミングの活用例を紹介します • 以下は、VMの命令セットのテーブル

Slide 36

Slide 36 text

命令テーブルから色々自動生成します • 命令の追加・削除を自 動的に反映 • LISPだとこういう仕組み 作るのが楽な気がする vm_instructions VMのevalループ リンカ ディスアセンブラ アセンブラ amber内部で使うアセンブラ

Slide 37

Slide 37 text

命令セットを作っていきます

Slide 38

Slide 38 text

浮動小数点数演算や

Slide 39

Slide 39 text

多倍長整数演算なども用意しました

Slide 40

Slide 40 text

例外機構なども作ります

Slide 41

Slide 41 text

継続も作ってみました

Slide 42

Slide 42 text

仮想マシン「rlvm」が完成! • 186命令 • スタックマシン • コピーGC • 例外機構 • shift/reset限定継続 • 浮動小数点数演算、多倍長整数演算

Slide 43

Slide 43 text

5.VM用ツールチェインを作る

Slide 44

Slide 44 text

VMは出来たがプログラミング環境がない • VM上のツールチェインを作る • VM用中級言語「rowl1」 • アセンブラ • コンパイラ • リンカ • ディスアセンブラ

Slide 45

Slide 45 text

言語・アセンブラ・コンパイラを作ります • これらは次世代で捨てるので「rowl-core」の言語内DSLにします

Slide 46

Slide 46 text

リンカ、ディスアセンブラを作ります • 「rowl1」で記述し、これら自身もVM上で動くように実装 • リンカはメモリを食うのでGCのある環境でやりたかった

Slide 47

Slide 47 text

ディスアセンブラの出力はこんな感じ

Slide 48

Slide 48 text

VM上でプログラミングが可能に! • 分割コンパイルが出来る • デバッグもしやすい • メモリも潤沢に使える • 例外とかも使える • 普通の事が出来るようになっただけ・・・でも達成感がとても大きい!

Slide 49

Slide 49 text

6.「rowl1」で「amber」を実装

Slide 50

Slide 50 text

いよいよamberの実装に入ります • 動的スクリプティング言語として作る • インスタンスベースオブジェクト指向 • 先ほど作った「rlvm」上で動作

Slide 51

Slide 51 text

アセンブラを作ります • さっき作ったアセンブラは プログラム実行前にコンパイル • これは、プログラム実行時に その場でコンパイル • アドレスはバックパッチ

Slide 52

Slide 52 text

オブジェクトシステムを作ります • スロット、メッセージ、 ペアレントへの委譲

Slide 53

Slide 53 text

オブジェクトシステム上に中核機能を作っていきます • 動的パターンマッチングエンジンと • 部分関数関数の融合メカニズム

Slide 54

Slide 54 text

この上にコンパイラを作ります • コンパイラ自体を通常のオブジェクトとして実装 VM オブジェクトシステム パターンマッチングエンジン コンパイラ amberのコアシステム 構文木のマッチング リソース管理

Slide 55

Slide 55 text

クロージャ変換も実装しました

Slide 56

Slide 56 text

この上にパーサを作ります • 実行時にパーサをコンパイル • 各パーサは通常のオブジェクト(クロージャ) VM オブジェクトシステム パターンマッチングエンジン コンパイラ amberのコアシステム コンパイル パーサ

Slide 57

Slide 57 text

とてもシンプルな文法 1. リテラルは式である 2. hがシンボル、e1,..,en (n>=0) が式の時h{e1, ..., en}も式である 3. 以上で定まるもののみがamberの式である • これと、あるトリックを後で組み合わせる

Slide 58

Slide 58 text

Packrat法で実装します • 後のトリックのため • 従ってレキサ不要

Slide 59

Slide 59 text

浮動小数点数のエンコード・デコードは苦労します • libcが無いので自分で作ります • 先ほど作った多倍長整数演算が必要になります “3.14” 0x40091eb851eb851f stortod, sprintf

Slide 60

Slide 60 text

amberが完成! • 動的スクリプティング言語 • VM上で動作 • インスタンスベースオブジェクト指向 • 動的パターンマッチングエンジンと部分関数融合が中核機能 • レキシカルクロージャ • すごく高級になってきた!

Slide 61

Slide 61 text

7. 「amber」の標準ライブラリを作る

Slide 62

Slide 62 text

amberのテーマは自己拡張性 • amberの文法は標準ライブラリで定義されている • amber/lib/syntax/parse.ab • 起動時に自身の文法を構築する

Slide 63

Slide 63 text

起動時はリテラルとh{e1,..,en}という文法だけ

Slide 64

Slide 64 text

amberの文法を定義する為の文法を定義する

Slide 65

Slide 65 text

今定義された文法でamberの文法を定義する

Slide 66

Slide 66 text

続いてマクロシステムを作る

Slide 67

Slide 67 text

マクロで更に文法を増強

Slide 68

Slide 68 text

リッチな構文が使えるようになりました

Slide 69

Slide 69 text

オブジェクトシステムも増強します

Slide 70

Slide 70 text

継承などが使えるようになりました

Slide 71

Slide 71 text

ここで開発停止です • 更新予定はありません • 以下でインタプリタが起動(Linuxのみ) • makeのログで以上のブートストラッピングの過程を見てみましょう % git clone https://github.com/nineties/amber.git % cd amber % make; sudo make install % amber

Slide 72

Slide 72 text

まとめ rowl0 rlc rlci rowl-core as VM記述言語 rlvm rowl1 リンカ ディスアセン ブラ コンパイラ コンパイラ amber インタプリタ 実装 実装 実行 言語 ツール • 大分高級な所まで到達出来たので満足

Slide 73

Slide 73 text

No content