- 目次ページに戻る / 前 / 次
- 前回からの差分をまとめて見る
はい、前回でとうとう 1回のターンが動くように……なってないんですねこれが。 1回のターンに必要な処理がもう1つ残ってます。 VRAM のバッファ領域に書き込んだ次世代の状態をメイン領域に戻す処理です。
やりましょう!
まずは、二重ループの部分が大きくなってきたので 別の関数に分けます。
分かりやすい diff にならなかったので 修正後のものを貼ります。
変数宣言と、 x
, y
の初期化と
二重ループの部分を
make_next_gen()
に抽出しました。
, ["func", "make_next_gen", ["w", "h"] , [ ["var", "x"] , ["set", "x", 0] , ["var", "y"] , ["set", "y", 0] , ["var", "count"] // 注目しているセルの現世代の生死 , ["var", "current_val"] // 注目しているセルの次世代の生死 , ["var", "next_val"] , ["while", ["neq", "y", "h"] , [ ["set", "x", 0] , ["while", ["neq", "x", "w"] , [ ["call_set", "count", ["count_alive", "w", "h", "x", "y"]] , ["_cmt", "★ count_alive から戻った直後"] , ["_cmt", "★次世代の生死決定の直前"] , ["call_set", "current_val", ["vram_get", "w", "x", "y"]] , ["call_set", "next_val", ["calc_next_gen", "current_val", "count"]] , ["_cmt", "★次世代の生死決定の直後"] , ["call", "vram_set_buf", "w", "x", "y", "next_val"] , ["_cmt", "★ vram_set_buf から戻った直後"] , ["set", "x", ["+", "x", 1]] ] ] , ["set", "y", ["+", "y", 1]] ] ] ] ] , ["func", "main", [] , [ // ... ["var", "w"] // 盤面の幅 , ["set", "w", 5] , ["var", "h"] // 盤面の高さ , ["set", "h", 5] // 初期状態の設定 , ["call", "vram_set", "w", 1, 0, 1] , ["call", "vram_set", "w", 2, 1, 1] , ["call", "vram_set", "w", 0, 2, 1] , ["call", "vram_set", "w", 1, 2, 1] , ["call", "vram_set", "w", 2, 2, 1] , ["call", "make_next_gen", "w", "h"] ] ]
実行。
$ ./run.sh gol.vgt.json vgcg.rb:208:in `block in codegen_call': Not yet implemented ("w") (RuntimeError) from vgcg.rb:198:in `each' from vgcg.rb:198:in `codegen_call' from vgcg.rb:400:in `block in codegen_stmts' from vgcg.rb:394:in `each' from vgcg.rb:394:in `codegen_stmts' from vgcg.rb:93:in `codegen_while' from vgcg.rb:408:in `block in codegen_stmts' from vgcg.rb:394:in `each' from vgcg.rb:394:in `codegen_stmts' from vgcg.rb:93:in `codegen_while' from vgcg.rb:375:in `block in codegen_func_def' from vgcg.rb:356:in `each' from vgcg.rb:356:in `codegen_func_def' from vgcg.rb:398:in `block in codegen_stmts' from vgcg.rb:394:in `each' from vgcg.rb:394:in `codegen_stmts' from vgcg.rb:427:in `codegen' from vgcg.rb:439:in `<main>'
うーむ、この期に及んでまだ出ますね……。
call
のときに関数の引数の参照が解決できてないようです。
修正します。
--- a/vgcg.rb +++ b/vgcg.rb @@ -191,7 +191,7 @@ def codegen_exp(fn_arg_names, lvar_names, exp) alines end -def codegen_call(lvar_names, stmt_rest) +def codegen_call(fn_arg_names, lvar_names, stmt_rest) alines = [] fn_name, *fn_args = stmt_rest @@ -201,6 +201,9 @@ def codegen_call(lvar_names, stmt_rest) alines << " push #{fn_arg}" when String case + when fn_arg_names.include?(fn_arg) + fn_arg_addr = to_fn_arg_addr(fn_arg_names, fn_arg) + alines << " push #{fn_arg_addr}" when lvar_names.include?(fn_arg) lvar_addr = to_lvar_addr(lvar_names, fn_arg) alines << " push #{lvar_addr}" @@ -357,7 +360,7 @@ def codegen_func_def(rest) stmt_head, *stmt_rest = stmt case stmt_head when "call" - alines += codegen_call(lvar_names, stmt_rest) + alines += codegen_call(fn_arg_names, lvar_names, stmt_rest) when "call_set" alines += codegen_call_set(fn_arg_names, lvar_names, stmt_rest) when "var" @@ -397,7 +400,7 @@ def codegen_stmts(fn_arg_names, lvar_names, rest) when "func" alines += codegen_func_def(stmt_rest) when "call" - alines += codegen_call(lvar_names, stmt_rest) + alines += codegen_call(fn_arg_names, lvar_names, stmt_rest) when "call_set" alines += codegen_call_set(fn_arg_names, lvar_names, stmt_rest) when "set"
一度動かして、問題なさそうなので、
replace_with_buf()
を追加して、
make_next_gen()
の次に呼び出します。
VRAM のメイン領域をバッファ領域の内容で置き換える処理です。これは割と簡単。
--- a/gol.vgt.json +++ b/gol.vgt.json @@ -268,6 +268,25 @@ ] ] +, ["func", "replace_with_buf", [] + , [ + ["var", "vi"] + , ["set", "vi", 0] + + , ["var", "vi_buf"] + , ["var", "temp"] + + , ["while", ["neq", "vi", 25] + , [ + ["set", "vi_buf", ["+", "vi", 25]] + , ["set", "temp", "vram[vi_buf]"] + , ["set", "vram[vi]", "temp"] + , ["set", "vi", ["+", "vi", 1]] + ] + ] + ] + ] + , ["func", "main", [] , [ // ["var", "tmp"] @@ -300,6 +319,7 @@ , ["call", "vram_set", "w", 2, 2, 1] , ["call", "make_next_gen", "w", "h"] + , ["call", "replace_with_buf"] ] ]
実行!
vgvm.rb:293:in `block in start': Not yet implemented ("arg1") ("vi_buf") (RuntimeError) from vgvm.rb:152:in `loop' from vgvm.rb:152:in `start' from vgvm.rb:470:in `<main>'
修正!!
--- a/vgcg.rb +++ b/vgcg.rb @@ -273,10 +273,20 @@ def codegen_set(fn_arg_names, lvar_names, rest) to_fn_arg_addr(fn_arg_names, rest[1]) when lvar_names.include?(rest[1]) to_lvar_addr(lvar_names, rest[1]) - when /^vram\[(.+)\]$/ =~ rest[1] + when /^vram\[(\d+)\]$/ =~ rest[1] vram_addr = $1 alines << " get_vram #{vram_addr} reg_a" "reg_a" + when /^vram\[([a-z_][a-z0-9_]*)\]$/ =~ rest[1] + dest = $1 + case + when lvar_names.include?(dest) + lvar_addr = to_lvar_addr(lvar_names, dest) + alines << " get_vram #{ lvar_addr } reg_a" + else + raise not_yet_impl("rest", rest) + end + "reg_a" else raise not_yet_impl("set src_val", rest) end
場当たり的な感じがしますがもうちょっとなので逃げ切りたい!
vgvm.rb:264:in `block in start': Not yet implemented ("set_vram") ("[bp-3]") (RuntimeError) from vgvm.rb:152:in `loop' from vgvm.rb:152:in `start' from vgvm.rb:470:in `<main>'
修正!!
--- a/vgvm.rb +++ b/vgvm.rb @@ -260,6 +260,9 @@ class Vm when /^\[bp\+(\d+)\]$/ stack_addr = @bp + $1.to_i @mem.stack[stack_addr] + when /^\[bp-(\d+)\]$/ + stack_addr = @bp - $1.to_i + @mem.stack[stack_addr] else raise not_yet_impl("set_vram", arg2) end
実行!!
================================ 19517: reg_a(0) reg_b(1) reg_c(0) zf(0) ---- memory (main) ---- 00 ["call", 1374] pc => 02 ["exit"] 03 ["label", "to_vi"] 05 ["push", "bp"] 07 ["cp", "sp", "bp"] 10 ["sub_sp", 1] 12 ["set_reg_a", "[bp+4]"] 14 ["set_reg_b", "[bp+2]"] 16 ["mult_ab"] 17 ["cp", "reg_a", "[bp-1]"] 20 ["sub_sp", 1] 22 ["set_reg_a", "[bp-1]"] 24 ["set_reg_b", "[bp+3]"] 26 ["add_ab"] 27 ["cp", "reg_a", "[bp-2]"] 30 ["set_reg_a", "[bp-2]"] 32 ["set_reg_b", "[bp+5]"] ---- memory (stack) ---- 41 0 42 25 43 47 44 1473 45 5 46 5 47 49 48 2 sp bp => 49 0 ---- memory (vram) ---- ..... ..... ..... @.@.. ..... .@@.. ..... .@... ..... ..... exit
グェーッッ! 全部死んだッ!!!
デバッグ! 修正!!
--- a/vgcg.rb +++ b/vgcg.rb @@ -278,10 +278,10 @@ def codegen_set(fn_arg_names, lvar_names, rest) alines << " get_vram #{vram_addr} reg_a" "reg_a" when /^vram\[([a-z_][a-z0-9_]*)\]$/ =~ rest[1] - dest = $1 + var_name = $1 case - when lvar_names.include?(dest) - lvar_addr = to_lvar_addr(lvar_names, dest) + when lvar_names.include?(var_name) + lvar_addr = to_lvar_addr(lvar_names, var_name) alines << " get_vram #{ lvar_addr } reg_a" else raise not_yet_impl("rest", rest)
ここの前後ですでに dest
という名前の変数を使っていて、
ここで dest
に別の値を入れてしまうとまずいのでした
*1。
実行!!!
================================ 19517: reg_a(0) reg_b(1) reg_c(0) zf(0) ---- memory (main) ---- 00 ["call", 1374] pc => 02 ["exit"] 03 ["label", "to_vi"] 05 ["push", "bp"] 07 ["cp", "sp", "bp"] 10 ["sub_sp", 1] 12 ["set_reg_a", "[bp+4]"] 14 ["set_reg_b", "[bp+2]"] 16 ["mult_ab"] 17 ["cp", "reg_a", "[bp-1]"] 20 ["sub_sp", 1] 22 ["set_reg_a", "[bp-1]"] 24 ["set_reg_b", "[bp+3]"] 26 ["add_ab"] 27 ["cp", "reg_a", "[bp-2]"] 30 ["set_reg_a", "[bp-2]"] 32 ["set_reg_b", "[bp+5]"] ---- memory (stack) ---- 41 49 42 25 43 47 44 1473 45 5 46 5 47 49 48 2 sp bp => 49 0 ---- memory (vram) ---- ..... ..... @.@.. @.@.. .@@.. .@@.. .@... .@... ..... ..... exit
よっしゃ!!!!
このままゴールまでいきましょう!!!!!!!!!!
--- a/gol.vgt.json +++ b/gol.vgt.json @@ -318,8 +318,12 @@ , ["call", "vram_set", "w", 1, 2, 1] , ["call", "vram_set", "w", 2, 2, 1] - , ["call", "make_next_gen", "w", "h"] - , ["call", "replace_with_buf"] + , ["while", ["eq", 0, 0] + , [ + ["call", "make_next_gen", "w", "h"] + , ["call", "replace_with_buf"] + ] + ] ] ]
グワーッッッ!! 動いた!!! 動きました!!!!!! (めちゃくちゃ遅いけど!!!!)
いやー、できるかどうかよく分からないとこから始めて とうとうここまで辿り着きましたね……感無量……。
とりあえずここでゴールです! 目標は達成しました。
Mission accomplished. (TODO ランボー/怒りの脱出 のキャプチャ画像を貼る*2)
次回、いくつか落ち穂拾い的な修正をやって いったん終わりにしようと思います。