RubyでオレオレVMとアセンブラとコード生成器を2週間で作ってライフゲームを動かした話 の製作過程を雑にダラダラ書きます。
- 下書きっぽいものは用意しているので、打ち切りにならずに完走はできると思います(2019-10-05 完走しました!)
- 予定では全38回
- 時間や気力不足などで 1ヶ月更新が止まるとかはあるかもしれません
- 教科書的な正しさは保証できませんし、自分用のふりかえりメモみたいな体でやります
- なので、文体は丁寧でも説明は全然足りてないと思います
- 最初に作ったもの(v1)と全く同じではなく、微妙に違うものになります
- 試行錯誤した過程を全部そのまま書くとさすがに退屈・煩雑になるので多少整理したり
- あと、作って時間が経ってるので細かいところは覚えてない
- あまり大きく変えない程度に改良したり(2周目なので)
- 試行錯誤した過程を全部そのまま書くとさすがに退屈・煩雑になるので多少整理したり
- 私はあれこれ悩みながら2週間かけて作りましたが、
単純に書き写すだけなら1週間もかからないんじゃないかと思います
- なので、「コンパイラ作ってみたいけど何ヶ月もかかるような本格的なのはちょっと無理そう……」 と思っていたり、実際やってみて挫折した、というような昔の自分みたいな人の役に立てたらいいなあ、という気持ちがあります
リポジトリ
目次
VM・アセンブラは飛ばしてコンパイラっぽい部分から見たいという場合は「16. 簡単なコード生成」あたりから見てください。
VM
- 1. 最初のVM
- 2. プログラムカウンタとVMの骨組み
- 3. regチカ(jump)
- 4. カウンタ / プログラムをファイルに
- 5. 条件分岐(compare, jump_eq)
- 6. if文っぽい条件分岐
アセンブラ
- 7. ラベルとアセンブラ
- 8. サブルーチンの呼び出し(call, ret)
- 9. 2段以上のサブルーチン呼び出し / スタック領域とスタックポインタ
- 10. ステップ実行 / ダンプ表示の改善
Vm.num_args_for
- 11. 引数渡しの準備 / bp, push, pop
- 12. リファクタリング / cp
- 13. サブルーチンに引数を1個渡す / add_sp
- 14. 複数の引数を渡す / スタックオーバーフロー対策 / 返り値
- 15. ローカル変数 / sub_sp
コード生成
- 16. 簡単なコード生成
- 17. main から別の関数を呼ぶ / call文
- 18. ローカル変数の宣言と代入 / var, set
- 19. 関数に引数を渡す
- 20. 値を返却してローカル変数に代入 / return, call_set
- 21. case文
- 22. 組み込みの足し算
- 23. 組み込みの eq / while文
- 24. 入れ子の式
- 25. 配列とVRAM / set_vram, get_vram
- 26. 配列とVRAM その2 / ダンプ表示の改良
このあたりで最低限必要なものは大体出揃っていて、以降は肉付けやバグ修正をしながらライフゲームを書いていく作業になります。
ライフゲームの実装開始
- 27. ライフゲームの実装開始 / 組み込みの掛け算
- 28. リファクタリング / ダンプ表示の改良
- 29. 盤面のスキャン / 組み込みの neq
- 30. 生存カウント / VRAM から値を取得 / ステップ数を表示
- 31. 生存カウント (2) / _cmt
- 32. 座標の補正
- case文の処理を修正
- 33. 座標の補正 (2)
- 34. 次世代の生死を決定
- 35. 次世代の生死をバッファ領域に書き込み
- 36. すべてのセルで繰り返し
- 37. 完成!
ここまでできた時点で RubyでオレオレVMとアセンブラとコード生成器を2週間で作ってライフゲームを動かした話 を書きました。
ライフゲームが動いた後の修正
以下は完成後の追加の修正。おまけコーナーです。
さらにその後
ここから先はちびちびとリファクタリングしたりフォーマットをいじってみたり。増えてきたのでページを分けました。