かんたんな自作言語のコンパイラをいろんな言語で書いてみるシリーズ 15番目の言語は Rust です。
理解は後回しにしてとにかく動くものを作るぞ、という方向性で書いたもの。
できたもの
移植元
ベースになっているバージョン: tag:56 のあたり
動かし方の例
$ echo ' func add(a, b) { return a + b; } func main() { call add(1, 2); } ' | cargo run lex | cargo run parse | cargo run codegen # ↓アセンブリが出力される call main exit label add push bp cp sp bp cp [bp:2] reg_a push reg_a cp [bp:3] reg_a push reg_a pop reg_b pop reg_a add_ab cp bp sp pop bp ret label main push bp cp sp bp cp 2 reg_a push reg_a cp 1 reg_a push reg_a _cmt call~~add call add add_sp 2 cp bp sp pop bp ret (snip)
メモ
- 理解は後回しにして、かっこ悪い書き方でもいいのでとにかく完成まで持って行く……といういつも通りの方針で、時間をかけすぎないように。理解は後でゆっくり。まずは手を動かして慣れる。
- Tour of Rust
- 情報量が多すぎずよく整理されていて、一番最初にこれを読めばよかった
- 借用とかムーブとか
- このくらいのプログラムを書いて動かせる程度には分かってきた、はず。 でもけっこう怪しい。
- ライフタイム
- まだよく分かっていなくて、コンパイルが通らなかったらライフタイムが絡まない書き方にして回避したりしている
- 連結リストが難しそうだったので
Vec<NodeId>
で管理する方式にしてとりあえず回避 - レキサの入力文字列は最初に
Vec<char>
にして使い回し
TODO
気が向いたらあとで
- List にノードID ではなくノードを直接持たせる
- List のイテレータ対応