- 目次ページに戻る / 前 / 次
- 前回からの差分をまとめて見る
これは簡単なのでサラッとやります。
(18) ローカル変数の宣言と代入 / var, set文 のときにちょっと触れていた件です。 だいぶ枝葉な話ですね。
["var", "x"] , ["set", "x", 12]
このように2つの文に分けて書いていたのを、次のように 1つの文で書けるようにしたい。
["var", "x", 12]
アセンブリコードのレイヤーではこうですね。 var文と set文でそれぞれを出力していたのを、 var文だけで両方出力されるようにしたい。
sub_sp 1 # ローカル変数の宣言 cp 12 [bp-{N}] # ローカル変数に値をセット
動作確認用のコードを用意。
// 40_var_init.vgt.json ["stmts" , ["func", "main", [] , [ ["var", "a"] , ["var", "b", 12] ] ] ]
修正する箇所は codegen_func_def()
の var文の箇所。
def codegen_func_def(rest) # ... body = rest[2] # ... lvar_names = [] body.each {|stmt| stmt_head, *stmt_rest = stmt case stmt_head # ... when "var" lvar_names << stmt_rest[0] alines << " sub_sp 1" when "set" # ...
var文の引数(stmt_rest
)の数を見て、初期値が指定されていたら
cp {初期値} [bp-{N}]
を出力する、という修正で良さそうです。
それを愚直に書いてもいいのですが、
ここは横着して codegen_set()
がそのまま使えそうです。
横着というか意味的にもそうするのが適切なように思えます。
そうしましょう。
--- a/vgcg.rb +++ b/vgcg.rb @@ -390,6 +390,9 @@ def codegen_func_def(rest) when "var" lvar_names << stmt_rest[0] alines << " sub_sp 1" + if stmt_rest.size == 2 + alines += codegen_set(fn_arg_names, lvar_names, stmt_rest) + end when "set" alines += codegen_set(fn_arg_names, lvar_names, stmt_rest) when "eq"
できました。簡単〜。
動かして確認。
$ STEP= ./run.sh 40_var_init.vgt.json ... ================================ 6: reg_a(0) reg_b(0) reg_c(0) zf(0) ---- memory (main) ---- 00 ["call", 5] 02 ["exit"] 03 ["label", "main"] 05 ["push", "bp"] 07 ["cp", "sp", "bp"] 10 ["sub_sp", 1] 12 ["sub_sp", 1] ... ローカル変数 b の宣言 14 ["cp", 12, "[bp-2]"] ... ローカル変数 b に初期値をセット pc => 17 ["cp", "bp", "sp"] 20 ["pop", "bp"] 22 ["ret"] ---- memory (stack) ---- 37 0 38 0 39 0 40 0 41 0 42 0 43 0 44 0 sp => 45 12 ... ローカル変数 b 46 0 bp => 47 49 48 2 49 0
大丈夫そうですね。
ではライフゲームの方も書き換えます。
--- a/gol.vgt.json +++ b/gol.vgt.json @@ -63,8 +63,7 @@ , ["func", "calc_next_gen", ["current_val", "count"] , [ // 注目しているセルの次世代の生死 - ["var", "next_val"] - , ["set", "next_val", 0] + ["var", "next_val", 0] , ["case" , [["eq", "current_val", 0] @@ -88,8 +87,7 @@ , ["func", "count_alive", ["w", "h", "x", "y"] , [ - ["var", "count"] - , ["set", "count", 0] + ["var", "count", 0] , ["var", "xl"] , ["var", "xr"] @@ -161,11 +159,8 @@ , ["func", "make_next_gen", ["w", "h"] , [ - ["var", "x"] - , ["set", "x", 0] - - , ["var", "y"] - , ["set", "y", 0] + ["var", "x", 0] + , ["var", "y", 0] , ["var", "count"] // 注目しているセルの現世代の生死 @@ -203,8 +198,7 @@ , ["func", "replace_with_buf", [] , [ - ["var", "vi"] - , ["set", "vi", 0] + ["var", "vi", 0] , ["var", "vi_buf"] , ["var", "temp"] @@ -222,10 +216,8 @@ , ["func", "main", [] , [ - ["var", "w"] // 盤面の幅 - , ["set", "w", 5] - , ["var", "h"] // 盤面の高さ - , ["set", "h", 5] + ["var", "w", 5] // 盤面の幅 + , ["var", "h", 5] // 盤面の高さ // 初期状態の設定 , ["call", "vram_set", "w", 1, 0, 1]
codegen_set()
を流用したことにより、
["+", 1, 2]
のような二項の式も初期値として指定できるようになっています。
なので、次の箇所も書き換えられます。
--- a/gol.vgt.json +++ b/gol.vgt.json @@ -89,15 +89,10 @@ , [ ["var", "count", 0] - , ["var", "xl"] - , ["var", "xr"] - , ["var", "yt"] - , ["var", "yb"] - - , ["set", "xl", ["+", "x", -1]] - , ["set", "xr", ["+", "x", 1]] - , ["set", "yt", ["+", "y", -1]] - , ["set", "yb", ["+", "y", 1]] + , ["var", "xl", ["+", "x", -1]] + , ["var", "xr", ["+", "x", 1]] + , ["var", "yt", ["+", "y", -1]] + , ["var", "yb", ["+", "y", 1]] , ["_cmt", "★ xl の補正の直前"] , ["call_set", "xl", ["adjust_index", "w", "xl"]]
ライフゲームを実行すると……壊れていないようですね。OKです!
gol.vgt.json
は前回と比べて 13行減り、見た目がちょっとすっきりしました。
枝葉だけど微妙に気にはなっていたので、気分的にもまたちょっとすっきりです。