minrubyコンパイラ / 変数を導入する
minrubyコンパイラに変数を導入した。
tree 上の var_assign を走査して以下を算出する。
変数の定義される順番に応じて、スタックポインタ(spレジスタ)からのオフセット位置を計算する(1番目に定義される変数のオフセット = 16、2番目に定義される変数のオフセット = 24、みたいな感じ)
スタックフレームのサイズ算出のため、変数の個数を数える
var_assign でスタックフレーム上へローカル変数を格納し、var_ref でスタックフレーム上のローカル変数を取得する。
code:diff
diff --git a/minrubyc.rb b/minrubyc.rb
index aa7a93c..06269df 100644
--- a/minrubyc.rb
+++ b/minrubyc.rb
@@ -1,6 +1,32 @@
require "minruby"
-def gen(tree)
+# tree 内の変数名一覧
+def var_names(arr, tree)
+ if tree0 == "var_assign" + arr.include?(tree1) ? arr : arr + [tree1] + tmp_arr = arr
+ tree1...each do |statement| + tmp_arr = tmp_arr + var_names(tmp_arr, statement)
+ end
+ tmp_arr
+ else
+ arr
+ end
+end
+
+# スタックフレーム上の変数のアドレスをスタックポインタ(sp)からのオフセットとして返す
+# 例:
+# ひとつ目の変数のアドレス = スタックポインタ + 16
+# ふたつ目の変数のアドレス = スタックポインタ + 24
+# ふたつ目の変数のアドレス = スタックポインタ + 32
+# ...
+def var_offset(var, env)
+ # 変数1つにつき8バイトの領域が必要
+ env.index(var) * 8 + 16
+end
+
+def gen(tree, env)
elsif %w(+ - * /).include?(tree0) @@ -12,11 +38,11 @@ def gen(tree)
# 左辺を評価した結果をスタックへ積む
- gen(expr1)
+ gen(expr1, env)
# 右辺を評価した結果をスタックへ積む
- gen(expr2)
+ gen(expr2, env)
# 演算
@@ -40,29 +66,41 @@ def gen(tree)
elsif tree0 == "func_call" && tree1 == "p" - gen(expr)
+ gen(expr, env)
puts "\tbl _p"
- gen(stmt)
+ gen(stmt, env)
end
+ elsif tree0 == "var_assign" + name, expr = tree1, tree2 +
+ # 評価した値をスタック上のローカル変数領域へ格納
+ gen(expr, env)
+ elsif tree0 == "var_ref" +
+ # ローカル変数領域からx0へ値をロード
else
end
end
tree = minruby_parse(ARGF.read)
+env = var_names([], tree)
puts "\t.text"
puts "\t.align 2"
puts "\t.globl _main"
puts "_main:"
-puts "\tsub sp, sp, #16" +puts "\tsub sp, sp, ##{16 + env.size * 8}" -gen(tree)
+gen(tree, env)
-puts "\tadd sp, sp, #16" +puts "\tadd sp, sp, ##{16 + env.size * 8}" puts "\tret"
diff --git a/test.sh b/test.sh
index 204047b..084c486 100755
--- a/test.sh
+++ b/test.sh
@@ -1,7 +1,5 @@
-#!/bin/bash
-
assert() {
# expected の "\n" を改行コードをとして解釈させる
expected=echo -e "$1"
@@ -20,12 +18,20 @@ assert() {
fi
}
+# 変数
+assert "10\n20\n30\n" "a = 10; b = 20; c = 30; p a; p b; p c"
+
+# 複文
assert "10\n20\n" "p 10; p 20"
+
+# 四則演算
assert "305" "p((10+20*30)/2)"
assert "5" "p 30/6"
assert "72" "p 8*9"
assert "20" "p 30-10"
assert "30" "p 10+20"
+
+# 整数リテラル
assert "-10" "p(-10)"
assert "4649" "p 4649"
いい感じに動いてそう。
https://gyazo.com/4081d1ac190d8937ab0bd83587c3e1f6