- 目次ページに戻る / 前 / 次
- 前回からの差分をまとめて見る
前回の座標補正の続き……の前に、 先に引っかかるところを潰しておきます。
codegen_return()
でローカル変数を返そうとすると
参照の解決ができずにエラーになるので、修正。
--- a/vgcg.rb +++ b/vgcg.rb @@ -307,8 +307,8 @@ def codegen_return(lvar_names, stmt_rest) when Integer alines << " set_reg_a #{retval}" when String - case retval - when /^vram\[([a-z0-9_]+)\]$/ + case + when /^vram\[([a-z0-9_]+)\]$/ =~ retval var_name = $1 case when lvar_names.include?(var_name) @@ -317,6 +317,9 @@ def codegen_return(lvar_names, stmt_rest) else raise not_yet_impl("retval", retval) end + when lvar_names.include?(retval) + lvar_addr = to_lvar_addr(lvar_names, retval) + alines << " cp #{lvar_addr} reg_a" else raise not_yet_impl("retval", retval) end
はい、では本題に戻りましょう。
前回は左端を超えてしまった場合の処理を作りました。
今回は同じように、右端・上端・下端を超えてしまった場合の処理を追加します。
前回の vgtコードをコピーして、
cp 32_adjust_index.vgt.json 33_adjust_index_2.vgt.json
コメントをちょっと修正して、
--- a/33_adjust_index_2.vgt.json +++ b/33_adjust_index_2.vgt.json @@ -39,14 +39,14 @@ , ["set", "yt", ["+", "y", -1]] , ["set", "yb", ["+", "y", 1]] - , ["_cmt", "★ 補正の直前"] + , ["_cmt", "★ xl の補正の直前"] , ["case" , [["eq", "xl", -1] - , ["_cmt", "★ -1 だった場合"] + , ["_cmt", "★ 左端を超えた場合"] , ["set", "xl", ["+", "w", -1]] ] ] - , ["_cmt", "★ 補正の直後"] + , ["_cmt", "★ xl の補正の直後"] , ["var", "tmp"]
まず右端から。
--- a/33_adjust_index_2.vgt.json +++ b/33_adjust_index_2.vgt.json @@ -48,6 +48,15 @@ ] , ["_cmt", "★ xl の補正の直後"] + , ["_cmt", "★ xr の補正の直前"] + , ["case" + , [["eq", "xr", "w"] + , ["_cmt", "★ 右端を超えた場合"] + , ["set", "xr", 0] + ] + ] + , ["_cmt", "★ xr の補正の直後"] + , ["var", "tmp"] , ["_cmt", "左上"] @@ -99,7 +108,7 @@ , ["var", "y"] , ["set", "y", 0] - , ["call", "count_alive", "w", 0, 2] + , ["call", "count_alive", "w", 4, 2] ] ]
動作の確認のため、注目するセルを (4, 2) として、
xr == 5
だったら xr = 0
に補正されることを期待して、実行。
================================ 52: reg_a(0) reg_b(1) reg_c(0) zf(0) ---- memory (main) ---- 142 ["set_reg_a", 1] 144 ["label", "end_eq_2"] 146 ["set_reg_b", 1] 148 ["compare"] 149 ["jump_eq", 155] 151 ["jump", 169] 153 ["label", "when_1_0"] 155 ["_cmt", "★~左端を超えた場合"] 157 ["set_reg_a", "[bp+2]"] 159 ["set_reg_b", -1] 161 ["add_ab"] 162 ["cp", "reg_a", "[bp-2]"] 165 ["jump", 169] 167 ["label", "end_case_1"] 169 ["_cmt", "★~xl~の補正の直後"] pc => 171 ["_cmt", "★~xr~の補正の直前"] 173 ["set_reg_a", "[bp-3]"] 175 ["set_reg_b", "[bp+2]"] 177 ["compare"] 178 ["jump_eq", 186] 180 ["set_reg_a", 0] 182 ["jump", 190] 184 ["label", "then_4"] 186 ["set_reg_a", 1] 188 ["label", "end_eq_4"] 190 ["set_reg_b", 1] 192 ["compare"] 193 ["jump_eq", 199] 195 ["jump", 208] 197 ["label", "when_3_0"] 199 ["_cmt", "★~右端を超えた場合"] 201 ["cp", 0, "[bp-3]"] ---- memory (stack) ---- 25 0 26 0 27 0 28 0 29 0 30 0 31 0 32 0 sp => 33 3 34 1 35 5 ... xr 36 3 37 0 bp => 38 47 39 457 40 5 41 4
補正前に 5 になっていた xr
が……
(step=62) 171 ["_cmt", "★~xr~の補正の直前"] 173 ["set_reg_a", "[bp-3]"] 175 ["set_reg_b", "[bp+2]"] 177 ["compare"] 178 ["jump_eq", 186] 180 ["set_reg_a", 0] 182 ["jump", 190] 184 ["label", "then_4"] 186 ["set_reg_a", 1] 188 ["label", "end_eq_4"] 190 ["set_reg_b", 1] 192 ["compare"] 193 ["jump_eq", 199] 195 ["jump", 208] 197 ["label", "when_3_0"] pc => 199 ["_cmt", "★~右端を超えた場合"] 201 ["cp", 0, "[bp-3]"] 204 ["jump", 208] 206 ["label", "end_case_3"] 208 ["_cmt", "★~xr~の補正の直後"]
「右端を超えた場合」の分岐に入って
================================ 65: reg_a(1) reg_b(1) reg_c(0) zf(1) ---- memory (main) ---- 178 ["jump_eq", 186] 180 ["set_reg_a", 0] 182 ["jump", 190] 184 ["label", "then_4"] 186 ["set_reg_a", 1] 188 ["label", "end_eq_4"] 190 ["set_reg_b", 1] 192 ["compare"] 193 ["jump_eq", 199] 195 ["jump", 208] 197 ["label", "when_3_0"] 199 ["_cmt", "★~右端を超えた場合"] 201 ["cp", 0, "[bp-3]"] 204 ["jump", 208] 206 ["label", "end_case_3"] pc => 208 ["_cmt", "★~xr~の補正の直後"] 210 ["sub_sp", 1] 212 ["_cmt", "左上"] 214 ["push", "[bp-4]"] 216 ["push", "[bp-2]"] 218 ["push", "[bp+2]"] 220 ["_cmt", "call_set~~vram_get"] 222 ["call", 41] 224 ["add_sp", 3] 226 ["cp", "reg_a", "[bp-6]"] 229 ["set_reg_a", "[bp-1]"] 231 ["set_reg_b", "[bp-6]"] 233 ["add_ab"] 234 ["cp", "reg_a", "[bp-1]"] 237 ["_cmt", "上"] ---- memory (stack) ---- 25 0 26 0 27 0 28 0 29 0 30 0 31 0 32 0 sp => 33 3 34 1 35 0 ... xr 36 3 37 0 bp => 38 47 39 457 40 5 41 4
0 になりました! いいですね。
同様に、上端を超えた場合の補正を追加:
--- a/33_adjust_index_2.vgt.json +++ b/33_adjust_index_2.vgt.json @@ -24,7 +24,7 @@ ] ] -, ["func", "count_alive", ["w", "x", "y"] +, ["func", "count_alive", ["w", "h", "x", "y"] , [ ["var", "count"] , ["set", "count", 0] @@ -57,6 +57,15 @@ ] , ["_cmt", "★ xr の補正の直後"] + , ["_cmt", "★ yt の補正の直前"] + , ["case" + , [["eq", "yt", -1] + , ["_cmt", "★ 上端を超えた場合"] + , ["set", "yt", ["+", "h", -1]] + ] + ] + , ["_cmt", "★ yt の補正の直後"] + , ["var", "tmp"] , ["_cmt", "左上"] @@ -108,7 +117,7 @@ , ["var", "y"] , ["set", "y", 0] - , ["call", "count_alive", "w", 4, 2] + , ["call", "count_alive", "w", "h", 2, 0] ] ]
上端・下端の場合は幅の代わりに高さ h
が必要なので
count_alive()
の引数として渡すようにしました。
右端、左端のときと同じ要領なので動作確認の結果は省略します。
最後に下端。
--- a/33_adjust_index_2.vgt.json +++ b/33_adjust_index_2.vgt.json @@ -66,6 +66,15 @@ ] , ["_cmt", "★ yt の補正の直後"] + , ["_cmt", "★ yb の補正の直前"] + , ["case" + , [["eq", "yb", "h"] + , ["_cmt", "★ 下端を超えた場合"] + , ["set", "yb", 0] + ] + ] + , ["_cmt", "★ yb の補正の直後"] + , ["var", "tmp"] , ["_cmt", "左上"] @@ -117,7 +126,7 @@ , ["var", "y"] , ["set", "y", 0] - , ["call", "count_alive", "w", "h", 2, 0] + , ["call", "count_alive", "w", "h", 2, 4] ] ]
四隅の各セルに注目している場合も確認しておきましょう。
左上 (0, 0) に注目している場合:
================================ 98: reg_a(0) reg_b(1) reg_c(0) zf(0) ---- memory (main) ---- (略) 284 ["cp", 0, "[bp-5]"] 287 ["jump", 291] 289 ["label", "end_case_7"] pc => 291 ["_cmt", "★~yb~の補正の直後"] 293 ["sub_sp", 1] 295 ["_cmt", "左上"] 297 ["push", "[bp-4]"] (略) ---- memory (stack) ---- 24 0 25 0 26 0 27 0 28 0 29 0 30 0 31 0 sp => 32 1 ... yb: 0 + 1 33 4 ... yt: 0 - 1 => 4 に補正 34 1 ... xr: 0 + 1 35 4 ... xl: 0 - 1 => 4 に補正 36 0 bp => 37 47 38 542 39 5 40 5
期待どおりの動きです。
右上 (4, 0) に注目している場合
(以下、同様なので yb
の補正の直後の時点でのスタック領域の一部だけ示します):
(step=95) sp => 32 1 ... yb: 0 + 1 33 4 ... yt: 0 - 1 => 4 に補正 34 0 ... xr: 4 + 1 => 0 に補正 35 3 ... xl: 4 - 1 36 0 bp => 37 47
左下 (0, 4) に注目している場合:
(step=95) sp => 32 0 ... yb: 4 + 1 => 0 に補正 33 3 ... yt: 4 - 1 34 1 ... xr: 0 + 1 35 4 ... xl: 0 - 1 => 4 に補正 36 0 bp => 37 47
右下 (4, 4) に注目している場合:
(step=92) sp => 32 0 ... yb: 4 + 1 => 0 に補正 33 3 ... yt: 4 - 1 34 0 ... xr: 4 + 1 => 0 に補正 35 3 ... xl: 4 - 1 36 0 bp => 37 47
(2, 2) に注目している場合(補正が発生しない場合)も念のため再度確認しておきましょうか。
(step=88) sp => 32 3 ... yb: 2 + 1 33 1 ... yt: 2 - 1 34 3 ... xr: 2 + 1 35 1 ... xl: 2 - 1 36 0 bp => 37 47
問題ないようです!
さて、 右端、左端、上端、下端のそれぞれについて case文を追加することで補正をしましたが、 似た処理なのでこれは共通化しておくと良さそうです。
関数にしてみました:
--- a/33_adjust_index_2.vgt.json +++ b/33_adjust_index_2.vgt.json @@ -24,6 +24,27 @@ ] ] +, ["func", "adjust_index", ["width", "i"] + , [ + ["var", "adjusted"] + , ["var", "max_i"] + , ["set", "max_i", ["+", "width", -1]] + + , ["case" + , [["eq", "i", -1] + , ["_cmt", "下限を超えた場合"] + , ["set", "adjusted", "max_i"]] + , [["eq", "i", "width"] + , ["_cmt", "上限を超えた場合"] + , ["set", "adjusted", 0]] + , [["eq", 1, 1] + , ["_cmt", "補正が不要な場合"] + , ["set", "adjusted", "i"]] + ] + , ["return", "adjusted"] + ] + ] + , ["func", "count_alive", ["w", "h", "x", "y"] , [ ["var", "count"]
たとえば xl
の場合は「右端を超えたか」のチェックは不要なので、
「下限の補正」「上限の補正」に分けてもいいかなという気もしましたが、
とりあえずはこれでいいんじゃないでしょうか。
気になるようであればライフゲームが動いてから好きなだけいじりましょう。
main()
の先頭に適当に確認用コードを追加して、
簡単に動作確認してみます。
, ["func", "main", [] , [ ["var", "tmp"] , ["call_set", "tmp", ["adjust_index", 5, -1]] , ["_cmt", "★ 座標補正の確認 下端: 4 になるべき"] , ["call_set", "tmp", ["adjust_index", 5, 5]] , ["_cmt", "★ 座標補正の確認 上端: 0 になるべき"] , ["call_set", "tmp", ["adjust_index", 5, 1]] , ["_cmt", "★ 座標補正の確認 補正なし: 1 になるべき"] // 略
期待通り(上記のコメントで書いてある通り)に動いていることを確認できたので、
確認用コードをコメントアウトしてから、
補正処理の箇所を adjust_index()
を使うように置き換えていきます。
まずは左端を超えた場合の xl
の補正だけ。
--- a/33_adjust_index_2.vgt.json +++ b/33_adjust_index_2.vgt.json @@ -61,12 +61,7 @@ , ["set", "yb", ["+", "y", 1]] , ["_cmt", "★ xl の補正の直前"] - , ["case" - , [["eq", "xl", -1] - , ["_cmt", "★ 左端を超えた場合"] - , ["set", "xl", ["+", "w", -1]] - ] - ] + , ["call_set", "xl", ["adjust_index", "w", "xl"]] , ["_cmt", "★ xl の補正の直後"] , ["_cmt", "★ xr の補正の直前"] @@ -96,6 +91,8 @@ ] , ["_cmt", "★ yb の補正の直後"] + , ["_cmt", "★ 座標補正の直後"] + , ["var", "tmp"] , ["_cmt", "左上"] @@ -160,7 +157,7 @@ , ["var", "y"] , ["set", "y", 0] - , ["call", "count_alive", "w", "h", 2, 4] + , ["call", "count_alive", "w", "h", 0, 2] ] ]
ついでに、4つの補正が全部終わったところに
★ 座標補正の直後
というコメントも追加しました。
================================ 72: reg_a(4) reg_b(1) reg_c(0) zf(1) ---- memory (main) ---- 238 ["set_reg_b", -1] 240 ["add_ab"] 241 ["cp", "reg_a", "[bp-4]"] 244 ["set_reg_a", "[bp+5]"] 246 ["set_reg_b", 1] 248 ["add_ab"] 249 ["cp", "reg_a", "[bp-5]"] 252 ["_cmt", "★~xl~の補正の直前"] 254 ["push", "[bp-2]"] 256 ["push", "[bp+2]"] 258 ["_cmt", "call_set~~adjust_index"] 260 ["call", 77] 262 ["add_sp", 2] 264 ["cp", "reg_a", "[bp-2]"] pc => 267 ["_cmt", "★~xl~の補正の直後"] 269 ["_cmt", "★~xr~の補正の直前"] 271 ["set_reg_a", "[bp-3]"] 273 ["set_reg_b", "[bp+2]"] 275 ["compare"] 276 ["jump_eq", 284] 278 ["set_reg_a", 0] 280 ["jump", 288] 282 ["label", "then_6"] 284 ["set_reg_a", 1] 286 ["label", "end_eq_6"] 288 ["set_reg_b", 1] 290 ["compare"] 291 ["jump_eq", 297] 293 ["jump", 306] 295 ["label", "when_5_0"] 297 ["_cmt", "★~右端を超えた場合"] ---- memory (stack) ---- 24 0 25 0 26 4 27 4 28 37 29 262 30 5 31 -1 sp => 32 3 33 1 34 1 35 4 ... xl 36 0 bp => 37 47 38 642 39 5 40 5
問題ないようです。
xl
以外も同じように動作確認しつつ置き換えていきましょう。
--- a/33_adjust_index_2.vgt.json +++ b/33_adjust_index_2.vgt.json @@ -65,12 +65,7 @@ , ["_cmt", "★ xl の補正の直後"] , ["_cmt", "★ xr の補正の直前"] - , ["case" - , [["eq", "xr", "w"] - , ["_cmt", "★ 右端を超えた場合"] - , ["set", "xr", 0] - ] - ] + , ["call_set", "xr", ["adjust_index", "w", "xr"]] , ["_cmt", "★ xr の補正の直後"] , ["_cmt", "★ yt の補正の直前"] @@ -157,7 +152,7 @@ , ["var", "y"] , ["set", "y", 0] - , ["call", "count_alive", "w", "h", 0, 2] + , ["call", "count_alive", "w", "h", 4, 2] ] ]
--- a/33_adjust_index_2.vgt.json +++ b/33_adjust_index_2.vgt.json @@ -69,12 +69,7 @@ , ["_cmt", "★ xr の補正の直後"] , ["_cmt", "★ yt の補正の直前"] - , ["case" - , [["eq", "yt", -1] - , ["_cmt", "★ 上端を超えた場合"] - , ["set", "yt", ["+", "h", -1]] - ] - ] + , ["call_set", "yt", ["adjust_index", "h", "yt"]] , ["_cmt", "★ yt の補正の直後"] , ["_cmt", "★ yb の補正の直前"] @@ -152,7 +147,7 @@ , ["var", "y"] , ["set", "y", 0] - , ["call", "count_alive", "w", "h", 4, 2] + , ["call", "count_alive", "w", "h", 2, 0] ] ]
--- a/33_adjust_index_2.vgt.json +++ b/33_adjust_index_2.vgt.json @@ -73,12 +73,7 @@ , ["_cmt", "★ yt の補正の直後"] , ["_cmt", "★ yb の補正の直前"] - , ["case" - , [["eq", "yb", "h"] - , ["_cmt", "★ 下端を超えた場合"] - , ["set", "yb", 0] - ] - ] + , ["call_set", "yb", ["adjust_index", "h", "yb"]] , ["_cmt", "★ yb の補正の直後"] , ["_cmt", "★ 座標補正の直後"] @@ -147,7 +142,7 @@ , ["var", "y"] , ["set", "y", 0] - , ["call", "count_alive", "w", "h", 2, 0] + , ["call", "count_alive", "w", "h", 2, 4] ] ]
というわけで、座標補正処理、完成です!