ãããã¤ã©ãï¼æ¨æ¶ï¼ãé»åã®æµ·ã«æ¼ãã¯ããªã泡沫ï¼ããããï¼ãã¯ãããã¾ã§ãã
ã¿ãªãããæ¸ç±ãRubyã§ã¤ããRubyãããåç¥ã§ããï¼Rubyã使ã£ã¦Rubyã®ãµãã»ãããMinRubyãã®ã¤ã³ã¿ããªã¿ãä½ããã¨ã§è¨èªå¦çç³»ä½æã®ã¨ãã»ã³ã¹ãå¦ã¼ãï¼ã¨ããæ¬ã§ãã
- Rubyã§ã¤ããRuby
ä»åã¯ããã®æ¬ã®MinRubyãé¡æã«ãç°¡æãªMinRubyã³ã³ãã¤ã©ãRubyã§ä½æãã¦ã¿ããã¨æãã¾ãã
ï¼ãã®è¨äºã¯ ESM Advent Calendar 2023 ã®4æ¥ç®ã®è¨äºã«ãªãã¾ãï¼
Gitãªãã¸ããª
ä»åä½æããã³ã³ãã¤ã©ã®ã½ã¼ã¹ã¯ãã¡ãã®gitãªãã¸ããªã«ç½®ãã¦ã¾ãã
https://github.com/thata/minrubyc-m1
è¨èªä»æ§ã¨ã¿ã¼ã²ããç°å¢
- è¨èªä»æ§
- MinRubyã®ãµãã»ãã
- ãã¼ã¿åã¯Intï¼æ´æ°ï¼ã®ã¿
- Arrayã¨Hashã¯å®è£ ããªã
- é¢æ°ã®å¼æ°ã¯8ã¤ã¾ã§
- ï¼ãã以å¤ã«ã足ãã¦ãªãæ©è½ãå±±ã»ã©ãããï¼
- MinRubyã®ãµãã»ãã
- ã¿ã¼ã²ããç°å¢
- ã¿ã¼ã²ããOS
- macOS
- ã¿ã¼ã²ããCPU
- Apple Mã·ãªã¼ãºï¼M1, M2 ãªã©ï¼
- ã¿ã¼ã²ããOS
ã¤ã³ãã«ã®CPUã§åãããã®ï¼
ä»åä½æããã³ã³ãã¤ã©ã¯Apple M1åãã®ã³ã¼ããçæãããããã¤ã³ãã«CPUã®ãã·ã³ã§ã¯åä½ããããã¨ãã§ãã¾ããã代ããã«ãä»åã®ã³ã³ãã¤ã©ãã¤ã³ãã«CPUã¸ç§»æ¤ãããã®ãããã®ã§ãã¡ããè¦ã¦ã¿ã¦ãã ããã
- thata/minruby_x86-64
- x86_64移æ¤æã®ã¡ã¢
åå¥è§£æå¨ã¨æ§æ解æå¨
ã³ã³ãã¤ã©ã«æ¬ ãããã¨ã®ã§ããªããåå¥è§£æãã¨ãæ§æ解æãã¨å¼ã°ããå¦çãããã¾ãã
- åå¥è§£æ
- ããã°ã©ã ããåèªãããè¨å·ããªã©ã®ããã¼ã¯ã³ãã¨å¼ã°ããããã°ã©ã ã®æå°åä½ã«åå²ããå¦ç
- æ§æ解æ
- ææ³ãå ã«ãã¼ã¯ã³ãçµã¿åããã¦æ§ææ¨ãæ§ç¯ããå¦ç
é常ã®ã³ã³ãã¤ã©ã§ã¯åå¥è§£æãè¡ãåå¥è§£æå¨ã¨æ§æ解æãè¡ãæ§æ解æå¨ãèªåã§å®è£ ããå¿ è¦ãããã¾ãããä»åä½æããã³ã³ãã¤ã©ã§ã¯ãRubyã§ã¤ããRubyã使ããã¦ããMinRubyã®ãã¼ãµããã®ã¾ã¾å©ç¨ãã¾ãã
MinRubyã®ãã¼ãµã¯RubyGemsã¨ãã¦æä¾ããã¦ããã®ã§ãäºåã«ä»¥ä¸ã®ã³ãã³ããå®è¡ã㦠minruby
gemãã¤ã³ã¹ãã¼ã«ãã¦ããã¦ãã ããã
gem install minruby
MinRubyãã¼ãµã®ä½¿ãæ¹
MinRubyã®ãã¼ãµã®ä½¿ãæ¹ã¯ãããªæãã渡ãããã½ã¼ã¹ã³ã¼ããæ§ææ¨ã®å½¢å¼ã«å¤æãã¦è¿ãã¾ãã
irb(main):001:0> require 'minruby' => true irb(main):002:0> minruby_parse "10" => ["lit", 10] irb(main):003:0> minruby_parse "10 + 20" => ["+", ["lit", 10], ["lit", 20]]
MinRubyãã¼ãµãè¿ãæ§ææ¨ã®ãã¼ãã«ã¯ä¸»ã«ä»¥ä¸ã®ãããªãã®ãããã¾ãã
- ãªãã©ã«ãã¼ã
["lit", 10]
- ååæ¼ç®ãã¼ãï¼
+
-
*
/
ï¼["+", ["lit", 10], ["lit", 20]]
["-", ["lit", 10], ["lit", 20]]
- å¤æ°ä»£å
¥ãã¼ã
["var_assign", "a", ["lit", 10]]
- å¤æ°åç
§ãã¼ã
["var_ref", "a"]
- ã¹ãã¼ãã¡ã³ãï¼è¤æï¼ãã¼ã
["stmts", ["var_assign", "a", ["lit", 10]], ["func_call", "p", ["var_ref", "a"]]]
- æ¯è¼æ¼ç®åãã¼ãï¼
>
<
>=
<=
==
!=
ï¼["==", ["lit", 1], ["lit", 1]]
- if ãã¼ã
["if", ["==", ["lit", 1], ["lit", 1]], ["stmts", ["lit", nil], ["lit", "foo"]], ["stmts", ["lit", nil], ["lit", "bar"]]]
- é¢æ°å®ç¾©ãã¼ã
["func_def", "foo", [], ["lit", 0]]
- é¢æ°ã³ã¼ã«ãã¼ã
["func_call", "p", ["lit", 10]]
ã³ã³ãã¤ã©ã®ã¯ããã®ä¸æ©
ã§ã¯ãã³ã³ãã¤ã©ãä½ã£ã¦ããã¾ããã¾ãã¯æ´æ°ãªãã©ã«ã表示ããã ãã®ã³ã³ãã¤ã©ãä½æãã¾ãã
æ´æ°ãªãã©ã«ã表示ããã ãã®ã³ã³ãã¤ã©ã¯ãããªæãã§ããæ´æ°ãªãã©ã«ãã¼ãã渡ããããããªãã©ã«ã®å¤ãã¬ã¸ã¹ã¿ x0
ã¸æ ¼ç´ããããªã³ãé¢æ° p
ãå¼ã³åºãã¦ç»é¢ã¸åºåãã¾ãã
# minrubyc.rb require "minruby" tree = minruby_parse(ARGF.read) puts "\t.text" puts "\t.align 2" puts "\t.globl _main" puts "_main:" # lr ã¬ã¸ã¹ã¿ã¨ fp ã¬ã¸ã¹ã¿ãã¹ã¿ãã¯ã¸éé¿ puts "\tsub sp, sp, #16" puts "\tstp fp, lr, [sp, #0]" if tree[0] == "lit" # æ´æ°ãªãã©ã«ã®å¤ã x0 ã¬ã¸ã¹ã¿ã¸æ ¼ç´ puts "\tmov x0, ##{tree[1]}" else raise "invalid AST: #{tree}" end # çµäºããåã« x0 ã¬ã¸ã¹ã¿ã®å¤ãåºåãããããp é¢æ°ãå¼ã³åºã puts "\tbl _p" # lr ã¬ã¸ã¹ã¿ã¨ fp ã¬ã¸ã¹ã¿ãã¹ã¿ãã¯ãã復å puts "\tldp fp, lr, [sp, #0]" puts "\tadd sp, sp, #16" # çµäºã¹ãã¼ã¿ã¹ã« 0 ãè¿ã puts "\tmov x0, #0" puts "\tret"
ããªã³ãé¢æ° p
㯠libminruby.c
ã¸å®ç¾©ãã¦ããã¾ãã
// libminruby.c #include <stdio.h> long p(long n) { printf("%ld\n", n); return n; }
æ©éã³ã³ãã¤ã«ãã¦ã¿ã¾ãããï¼ã³ã³ãã¤ã«æé ã¯å¾è¿°ï¼ã4649
ãåºåãããã°OKã§ãã
ãã¡ãã£ã¨è£è¶³ãã³ã³ãã¤ã«æé
MinRubyã³ã³ãã¤ã©ã®ã³ã³ãã¤ã«ã¯ä»¥ä¸ã®æµãã§è¡ããã¾ãã
# MinRubyã®ã½ã¼ã¹ãã³ã³ãã¤ã«ã㦠foo.s ã¸åºå ruby minrubyc.rb foo.rb > foo.s # foo.s 㨠libminruby.c ãã³ã³ãã¤ã« gcc foo.s libminruby.c -o a.out # å®è¡ ./a.out
ã³ã³ãã¤ã©ã¸ã®MinRubyã®ã½ã¼ã¹ã®æ¸¡ãæ¹ã¯ããã¡ã¤ã«ã§æ¸¡ãã¦ãè¯ãããæ¨æºå ¥åãã渡ãã¦ãOKã§ãã
ååæ¼ç®ã®å°å ¥
æ´æ°ãªãã©ã«ã®è¡¨ç¤ºãã§ããã®ã§ã次ã¯ååæ¼ç®ãå°å ¥ãã¾ãã
以ä¸ãååæ¼ç®ãå°å ¥ããã³ã³ãã¤ã©ã®ã³ã¼ãã§ãã
å³è¾ºã¨å·¦è¾ºãè©ä¾¡ããçµæãããããã¬ã¸ã¹ã¿ x0
ã¸æ ¼ç´ãããã®ã§ãå³è¾ºã¨å·¦è¾ºã®å¤ãè¨ç®ããã®ã¡ã¬ã¸ã¹ã¿ x0
ã¸æ ¼ç´ãã¾ãã
# minrubyc.rb require "minruby" def gen(tree) if tree[0] == "lit" puts "\tmov x0, ##{tree[1]}" elsif %w(+ - * /).include?(tree[0]) # ååæ¼ç® op = tree[0] expr1 = tree[1] expr2 = tree[2] # è©ä¾¡çµæä¸æä¿æç¨ã®ã¹ã¿ãã¯é åãç¢ºä¿ puts "\tsub sp, sp, #16" # x0 ã¸æ ¼ç´ããã左辺è©ä¾¡çµæãã¹ã¿ãã¯ã¸ç©ã gen(expr1) puts "\tstr x0, [sp, #0]" # x0 ã¸æ ¼ç´ãããå³è¾ºè©ä¾¡çµæãã¹ã¿ãã¯ã¸ç©ã gen(expr2) puts "\tstr x0, [sp, #8]" # ã¹ã¿ãã¯ã¸ç©ãã è©ä¾¡çµæã x1 ã¬ã¸ã¹ã¿ã¨ x0 ã¬ã¸ã¹ã¿ã¸ãã¼ã puts "\tldr x1, [sp, #8]" puts "\tldr x0, [sp, #0]" # æ¼ç®çµæã x0 ã¸æ ¼ç´ case op when "+" puts "\tadd x0, x0, x1" when "-" puts "\tsub x0, x0, x1" when "*" puts "\tmul x0, x0, x1" when "/" puts "\tsdiv x0, x0, x1" else raise "invalid operator: #{op}" end # ã¹ã¿ãã¯ãç ´æ£ puts "\tadd sp, sp, #16" else raise "invalid AST: #{tree}" end end tree = minruby_parse(ARGF.read) puts "\t.text" puts "\t.align 2" puts "\t.globl _main" puts "_main:" # lr ã¬ã¸ã¹ã¿ã¨ fp ã¬ã¸ã¹ã¿ãã¹ã¿ãã¯ã«éé¿ puts "\tsub sp, sp, #16" puts "\tstp fp, lr, [sp, #0]" gen(tree) # çµäºããåã« x0 ã¬ã¸ã¹ã¿ã®å¤ãåºåãããããp é¢æ°ãå¼ã³åºã puts "\tbl _p" # lr ã¬ã¸ã¹ã¿ã¨ fp ã¬ã¸ã¹ã¿ãã¹ã¿ãã¯ãã復å puts "\tldp fp, lr, [sp, #0]" puts "\tadd sp, sp, #16" # çµäºã¹ãã¼ã¿ã¹ã« 0 ãè¿ã puts "\tmov w0, #10" puts "\tret"
10 + 20
ãã³ã³ãã¤ã«ãã¦ã¿ã¾ãã30
ã表示ãããã°OKã§ãã
ãã¡ãã£ã¨è£è¶³ãã¬ã¸ã¹ã¿ã®ä½¿ãæ¹ã®ã«ã¼ã«
64ãããARMã§ã¯ x0
ãã x30
ã¾ã§ã®31åã®æ´æ°ã¬ã¸ã¹ã¿ãããã¾ãï¼ãã®ä»ãæµ®åå°æ°ç¹ã¬ã¸ã¹ã¿ãªã©ãããã¾ãï¼ã
ã¬ã¸ã¹ã¿ã«ã¯å©ç¨æã®ã«ã¼ã«ãããããããã¾ããä¾ãã°é¢æ°ã®å¼æ°ã¨æ»ãå¤ã«é¢ãã¦ã¯ä»¥ä¸ã®ãããªã«ã¼ã«ãããã¾ãã
- é¢æ°ã®å¼æ°ã¯
x0
ããx7
ã¸ã»ãããã- 1çªç®ã®å¼æ°ã¯
x0
ã¸ã2çªç®ã®å¼æ°ã¯x1
ã¸ãã¿ãããªæã㧠- ï¼8å以ä¸ã»ãããããå ´åã®ã«ã¼ã«ã¯å²æï¼
- 1çªç®ã®å¼æ°ã¯
- é¢æ°ã®æ»ãå¤ã¯
x0
ã¸ã»ãããã
MinCamlã³ã³ãã¤ã©ã§ã¯ããã«ãªãã£ã¦ãæ§ææ¨ã®åãã¼ããå¤ãè¿ãæã¯ã¬ã¸ã¹ã¿ x0
ã¸å¤ãã»ããããããã«ãªã£ã¦ãã¾ããã¾ããçµã¿è¾¼ã¿é¢æ°ãã¦ã¼ã¶ã¼å®ç¾©é¢æ°ãå¼ã³åºãæã®å¼æ°ã¯ã¬ã¸ã¹ã¿ x0
ãã x7
ã¸ã»ããããé¢æ°ã®æ»ãå¤ã¯ x0
ã¸ã»ããããããã«ãªã£ã¦ãã¾ãã
åèè³æ
ARM64: ABI è¦å
https://zenn.dev/hidenori3/articles/c9053a76be641c
ããªã³ãé¢æ° p
ã®å°å
¥
次ã¯ãæ´æ°ãããªã³ããã p
é¢æ°ãå°å
¥ãã¾ãã
macOSã§ã¯Cã§å®ç¾©ããé¢æ°åã®ããªãã£ãã¯ã¹ã« _
ãã¤ãããã¦ãã¾ããããã¢ã»ã³ããªãã p
é¢æ°ãå¼ã³åºãé㯠bl _p
ã®ããã«ã¢ã³ãã¼ã¹ã³ã¢ãã¤ãã¦å¼ã³åºãã¾ãã
diff --git a/minrubyc.rb b/minrubyc.rb index 780f97e..268a901 100644 --- a/minrubyc.rb +++ b/minrubyc.rb @@ -40,6 +40,11 @@ def gen(tree) # ã¹ã¿ãã¯ãç ´æ£ puts "\tadd sp, sp, #16" + elsif tree[0] == "func_call" && tree[1] == "p" + # p é¢æ°ãå¼ã³åºã + expr = tree[2] + gen(expr) + puts "\tbl _p" else raise "invalid AST: #{tree}" end @@ -57,9 +62,6 @@ puts "\tstp fp, lr, [sp, #0]" gen(tree) -# çµäºããåã« x0 ã¬ã¸ã¹ã¿ã®å¤ãåºåãããããp é¢æ°ãå¼ã³åºã -puts "\tbl _p" - # lr ã¬ã¸ã¹ã¿ã¨ fp ã¬ã¸ã¹ã¿ãã¹ã¿ãã¯ãã復å puts "\tldp fp, lr, [sp, #0]" puts "\tadd sp, sp, #16"
p 5963
ãã³ã³ãã¤ã«ã㦠5963
ãåºåãããã°OKã§ãã
è¤æï¼statementsï¼ã®å°å ¥
次ã¯ä»¥ä¸ã®ããã«è¤æ°ã®ã¹ãã¼ãã¡ã³ããè©ä¾¡ã§ããããã«ãã¾ãã
p 123 p 456 p 789
è¤æã®å¯¾å¿ã¯ä»¥ä¸ã®ã¨ãããstmts
ã®ä¸ã®è¤æ°ã®ãã¼ããããããåãã¦ã³ã¼ããçæããã ãã§OKã§ãã
diff --git a/minrubyc.rb b/minrubyc.rb index 268a901..b08b705 100644 --- a/minrubyc.rb +++ b/minrubyc.rb @@ -45,6 +45,10 @@ def gen(tree) expr = tree[2] gen(expr) puts "\tbl _p" + elsif tree[0] == "stmts" + tree[1..].each do |stmt| + gen(stmt) + end else raise "invalid AST: #{tree}" end
ã³ã³ãã¤ã« & å®è¡ãã¦ã¿ã¾ãã4649
㨠5963
ãåºåãããã°OKã§ãã
å¤æ°ã®å°å ¥
次ã¯å¤æ°ãå°å ¥ãã¾ãã
å¤æ°ã«ã»ããããå¤ã¯ã¹ã¿ãã¯ä¸ã«æ ¼ç´ããããããå®ç¾©ãããå¤æ°ã®æ°ï¼ var_assign
ã®æ°ï¼ãæ°ãã¦ããã®åã ãã¹ã¿ãã¯ä¸ã«é åã確ä¿ãã¾ãã
å¤æ°ã¯å®£è¨ãããé çªã§ã¹ã¿ãã¯ä¸ã«ä¸¦ã¶ã®ã§ãããå¤æ°ãä½çªç®ã«å®£è¨ãããããåããã°ããã®å¤æ°ãã¹ã¿ãã¯ä¸ã®ã©ãã®ã¢ãã¬ã¹ã«æ ¼ç´ãããã®ããåããã¾ãã
var_assign
ãæ¥ããã¹ã¿ãã¯ä¸ã®æ±ºããããã¢ãã¬ã¹ã¸å¤ãæ ¼ç´ããvar_ref
ãæ¥ããã¹ã¿ãã¯ä¸ã®æ±ºããããã¢ãã¬ã¹ããå¤ãåå¾ãã¦è¿ãã¾ãã
diff --git a/minrubyc.rb b/minrubyc.rb index b08b705..2bbdefa 100644 --- a/minrubyc.rb +++ b/minrubyc.rb @@ -1,7 +1,33 @@ # minrubyc.rb require "minruby" -def gen(tree) +# tree å ã«å«ã¾ãããvar_assign ã§å®ç¾©ãããå¤æ°åã®ä¸è¦§ +def var_names(tree) + if tree[0] == "var_assign" + [tree[1]] + elsif tree[0] == "stmts" + arr = [] + tree[1..].each do |statement| + arr += var_names(statement) + end + arr + else + [] + end +end + +# ã¹ã¿ãã¯ãã¬ã¼ã ä¸ã®å¤æ°ã®ã¢ãã¬ã¹ããã¬ã¼ã ãã¤ã³ã¿(fp)ããã®ãªãã»ããã¨ãã¦è¿ã +# ä¾ï¼ +# ã²ã¨ã¤ç®ã®å¤æ°ã®ã¢ãã¬ã¹ = ãã¬ã¼ã ãã¤ã³ã¿(fp) + 16 +# ãµãã¤ç®ã®å¤æ°ã®ã¢ãã¬ã¹ = ãã¬ã¼ã ãã¤ã³ã¿(fp) + 24 +# ãµãã¤ç®ã®å¤æ°ã®ã¢ãã¬ã¹ = ãã¬ã¼ã ãã¤ã³ã¿(fp) + 32 +# ... +def var_offset(var, env) + # å¤æ°1ã¤ã«ã¤ã8ãã¤ãã®é åãå¿ è¦ + env.index(var) * 8 + 16 +end + +def gen(tree, env) if tree[0] == "lit" puts "\tmov x0, ##{tree[1]}" elsif %w(+ - * /).include?(tree[0]) @@ -13,11 +39,11 @@ def gen(tree) puts "\tsub sp, sp, #16" # x0 ã¸æ ¼ç´ããã左辺è©ä¾¡çµæãã¹ã¿ãã¯ã¸ç©ã - gen(expr1) + gen(expr1, env) puts "\tstr x0, [sp, #0]" # x0 ã¸æ ¼ç´ãããå³è¾ºè©ä¾¡çµæãã¹ã¿ãã¯ã¸ç©ã - gen(expr2) + gen(expr2, env) puts "\tstr x0, [sp, #8]" # ã¹ã¿ãã¯ã¸ç©ãã è©ä¾¡çµæã x1 ã¬ã¸ã¹ã¿ã¨ x0 ã¬ã¸ã¹ã¿ã¸ãã¼ã @@ -43,32 +69,53 @@ def gen(tree) elsif tree[0] == "func_call" && tree[1] == "p" # p é¢æ°ãå¼ã³åºã expr = tree[2] - gen(expr) + gen(expr, env) puts "\tbl _p" elsif tree[0] == "stmts" tree[1..].each do |stmt| - gen(stmt) + gen(stmt, env) end + elsif tree[0] == "var_assign" + name, expr = tree[1], tree[2] + + # è©ä¾¡ããå¤ãã¹ã¿ãã¯ä¸ã®ãã¼ã«ã«å¤æ°é åã¸æ ¼ç´ + gen(expr, env) + puts "\tstr x0, [fp, ##{var_offset(name, env)}]" + elsif tree[0] == "var_ref" + name = tree[1] + + # ãã¼ã«ã«å¤æ°é åããx0ã¸å¤ããã¼ã + puts "\tldr x0, [fp, ##{var_offset(name, env)}]" else raise "invalid AST: #{tree}" end end tree = minruby_parse(ARGF.read) +env = var_names(tree) +lvar_size = env.size * 8 puts "\t.text" puts "\t.align 2" puts "\t.globl _main" puts "_main:" + +# ã¹ã¿ãã¯ãã¬ã¼ã ãç¢ºä¿ +# NOTE: ã¹ã¿ãã¯ã®ãµã¤ãºã¯16ã®åæ°ã§ãªããã°ãªããªã +puts "\tsub sp, sp, ##{16 + (lvar_size % 16 == 0 ? lvar_size : lvar_size + 8)}" + # lr ã¬ã¸ã¹ã¿ã¨ fp ã¬ã¸ã¹ã¿ãã¹ã¿ãã¯ã«éé¿ -puts "\tsub sp, sp, #16" puts "\tstp fp, lr, [sp, #0]" +puts "\tmov fp, sp" -gen(tree) +gen(tree, env) # lr ã¬ã¸ã¹ã¿ã¨ fp ã¬ã¸ã¹ã¿ãã¹ã¿ãã¯ãã復å puts "\tldp fp, lr, [sp, #0]" -puts "\tadd sp, sp, #16" + +# ã¹ã¿ãã¯ãã¬ã¼ã ãç ´æ£ +# NOTE: ã¹ã¿ãã¯ã®ãµã¤ãºã¯16ã®åæ°ã§ãªããã°ãªããªã +puts "\tadd sp, sp, ##{16 + (lvar_size % 16 == 0 ? lvar_size : lvar_size + 8)}" # çµäºã¹ãã¼ã¿ã¹ã« 0 ãè¿ã puts "\tmov w0, #10"
以ä¸ã®ã³ã¼ããå®è¡ãã¦ã¿ã¾ãã
a = 10 b = 20 c = 30 p a p b p c
ããæãã«åãã¦ããããã§ãã
æ¯è¼æ¼ç®åã®å°å ¥
æ¯è¼æ¼ç®åï¼ ==
!=
>
<
>=
<=
ï¼ãå°å
¥ãã¾ããMinCamlã³ã³ãã¤ã©ã«ã¯ bool åããªããããæ¯è¼æ¼ç®ã®çµæãçã®æã¯æ´æ°ã® 1
ããå½ã®æã¯æ´æ°ã® 0
ãè¿ãã¾ãã
diff --git a/minrubyc.rb b/minrubyc.rb index 2bbdefa..a7bbb06 100644 --- a/minrubyc.rb +++ b/minrubyc.rb @@ -30,7 +30,7 @@ end def gen(tree, env) if tree[0] == "lit" puts "\tmov x0, ##{tree[1]}" - elsif %w(+ - * /).include?(tree[0]) + elsif %w(+ - * / == != < <= > >=).include?(tree[0]) op = tree[0] expr1 = tree[1] expr2 = tree[2] @@ -60,6 +60,24 @@ def gen(tree, env) puts "\tmul x0, x0, x1" when "/" puts "\tsdiv x0, x0, x1" + when "==" + puts "\tcmp x0, x1" + puts "\tcset x0, eq" + when "!=" + puts "\tcmp x0, x1" + puts "\tcset x0, ne" + when "<" + puts "\tcmp x0, x1" + puts "\tcset x0, lt" + when "<=" + puts "\tcmp x0, x1" + puts "\tcset x0, le" + when ">" + puts "\tcmp x0, x1" + puts "\tcset x0, gt" + when ">=" + puts "\tcmp x0, x1" + puts "\tcset x0, ge" else raise "invalid operator: #{op}" end
ããæãã«åãã¦ããããã§ãã
æ¡ä»¶åå²ã®å°å ¥
次ã¯æ¡ä»¶åå²ãå°å ¥ãã¾ãããããã if æã§ããifæã®æ§ææ¨ã¯ãããªæããæ¡ä»¶å¼ãçã®å ´åã¯THENå¥ãè©ä¾¡ãããå½ã®å ´åã¯ELSEå¥ãè©ä¾¡ããã¾ãã
irb(main):003:0> minruby_parse "if 0 == 1; p 123; else p 345; end" => ["if", ["==", ["lit", 0], ["lit", 1]], ["func_call", "p", ["lit", 123]], # THENå¥ ["func_call", "p", ["lit", 345]]] # ELSEå¥
以ä¸ã¯ã³ã³ãã¤ã©ã®ã³ã¼ãã§ãã
æ¡ä»¶å¼ãè©ä¾¡ããçã®å ´åã¯THENå¥ã¸è©ä¾¡ããå½ã®å ´åã¯ELSEå¥ãè©ä¾¡ãã¾ãã
åå²å
ã®ã©ãã«åãããã°ã©ã ä¸ã§ä¸æã«ãããããã©ãã«åã« tree.object_id
ãä»ä¸ãã¦ãã¾ãã
diff --git a/minrubyc.rb b/minrubyc.rb index a7bbb06..fba72e9 100644 --- a/minrubyc.rb +++ b/minrubyc.rb @@ -11,6 +11,13 @@ def var_names(tree) arr += var_names(statement) end arr + elsif tree[0] == "if" + # ifæã®ä¸ã®å¤æ°ãåç §ã§ãããããifã®ä¸ã®ãããã¯ã«ã var_assign ãæ¢ãã«è¡ã + arr = [] + arr += var_names(tree[2]) + if tree[3] + arr += var_names(tree[3]) + end + arr else [] end @@ -104,6 +111,24 @@ def gen(tree, env) # ãã¼ã«ã«å¤æ°é åããx0ã¸å¤ããã¼ã puts "\tldr x0, [fp, ##{var_offset(name, env)}]" + elsif tree[0] == "if" + cond, texpr, fexpr = tree[1], tree[2], tree[3] + # æ¡ä»¶å¼ãè©ä¾¡ + puts "\t// æ¡ä»¶å¼ãè©ä¾¡" + gen(cond, env) + puts "\tcmp x0, #0" + + puts "\tbeq .Lelse#{tree.object_id}" + + # çã®å ´åã¯texprãè©ä¾¡ + puts "\t// çã®å ´å" + gen(texpr, env) + puts "\tb .Lendif#{tree.object_id}" + puts ".Lelse#{tree.object_id}:" + # å½ã®å ´åã¯fexprãè©ä¾¡ + puts "\t// å½ã®å ´å" + gen(fexpr, env) if fexpr + puts ".Lendif#{tree.object_id}:" else raise "invalid AST: #{tree}" end @@ -126,6 +151,12 @@ puts "\tsub sp, sp, ##{16 + (lvar_size % 16 == 0 ? lvar_size : lvar_size + 8)}" puts "\tstp fp, lr, [sp, #0]" puts "\tmov fp, sp" +# ãã¼ã«ã«å¤æ°ã0ã§åæå +env.each do |var| + puts "\tmov x0, #0" + puts "\tstr x0, [fp, ##{var_offset(var, env)}]" +end + gen(tree, env) # lr ã¬ã¸ã¹ã¿ã¨ fp ã¬ã¸ã¹ã¿ãã¹ã¿ãã¯ãã復å
ã³ã³ãã¤ã«ãã¦ã¿ã¾ãã 123
ãåºåãããã°OKã§ãã
ãã®ã¾ã¾å¢ã㧠while æãå°å ¥ãã¡ããã¾ãã
diff --git a/minrubyc.rb b/minrubyc.rb index fba72e9..3840382 100644 --- a/minrubyc.rb +++ b/minrubyc.rb @@ -18,6 +18,9 @@ def var_names(tree) arr += var_names(tree[3]) end arr + elsif tree[0] == "while" + puts "\t// while: #{tree}" + var_names(tree[2]) else [] end @@ -129,6 +132,15 @@ def gen(tree, env) puts "\t// å½ã®å ´å" gen(fexpr, env) if fexpr puts ".Lendif#{tree.object_id}:" + elsif tree[0] == "while" + cond, body = tree[1], tree[2] + puts ".Lwhile#{tree.object_id}:" + gen(cond, env) + puts "\tcmp x0, #0" + puts "\tbeq .Lendwhile#{tree.object_id}" + gen(body, env) + puts "\tb .Lwhile#{tree.object_id}" + puts ".Lendwhile#{tree.object_id}:" else raise "invalid AST: #{tree}" end
ãããããæãã«åãã¦ããããã§ãã
çµã¿è¾¼ã¿é¢æ°ã®å¼ã³åºã
次ã¯libminruby.c
ã§å®ç¾©ããçµã¿è¾¼ã¿é¢æ°ãå¼ã³åºããããã«ãã¾ãã func_call
ãè¿ãæ§ææ¨ã¯ãããªæãã
irb(main):001:0> minruby_parse "p my_add(10, 20)" => ["func_call", "p", ["func_call", "my_add", ["lit", 10], ["lit", 20]]]
libminruby.c
ã¸é¢æ° my_add
ã追å ãã
// libminruby.c #include <stdio.h> long p(long n) { printf("%ld\n", n); return n; } // çµã¿è¾¼ã¿é¢æ°ãã¹ãç¨ long my_add(long a, long b) { return a + b; }
ã³ã³ãã¤ã©ã以ä¸ã®ããã«ä¿®æ£ãã¾ãã
ä¸è¿°ããéããé¢æ°ãå¼ã³åºãæã®å¼æ°ã¯ã¬ã¸ã¹ã¿ x0
ãã x7
ã«ã»ãããã¾ãã func_call
ã®å¼æ°ã«æ¸¡ã£ã¦ãããã¼ããè©ä¾¡ã㦠x0
ãã x7
ã¸é çªã«æ¸¡ãã¾ããé常8ã¤ãè¶
ããå¼æ°ãåãæ±ãå ´åã¯ã¹ã¿ãã¯ãéããå¼æ°ã®åã渡ããè¡ãã®ã§ãããä»åã¯8ã¤ãè¶
ããå¼æ°ã¯ãµãã¼ãããã«ã¨ã©ã¼ãè¿ãããã«ãã¾ããã
diff --git a/minrubyc.rb b/minrubyc.rb index 3840382..94f1769 100644 --- a/minrubyc.rb +++ b/minrubyc.rb @@ -1,6 +1,9 @@ # minrubyc.rb require "minruby" +# å¼æ°ç¨ã¬ã¸ã¹ã¿ã®ä¸è¦§ +PARAM_REGISTERS = %w(x0 x1 x2 x3 x4 x5 x6 x7) + # tree å ã«å«ã¾ãããvar_assign ã§å®ç¾©ãããå¤æ°åã®ä¸è¦§ def var_names(tree) if tree[0] == "var_assign" @@ -94,11 +97,27 @@ def gen(tree, env) # ã¹ã¿ãã¯ãç ´æ£ puts "\tadd sp, sp, #16" - elsif tree[0] == "func_call" && tree[1] == "p" - # p é¢æ°ãå¼ã³åºã - expr = tree[2] - gen(expr, env) - puts "\tbl _p" + elsif tree[0] == "func_call" + name, *args = tree[1..] + + # å¼æ°ç¨ã®ã¬ã¸ã¹ã¿ã¯8ã¤ãããªãã®ã§ãå¼æ°ã8å以ä¸ã®å ´åã¯ã¨ã©ã¼ + raise "too many arguments (given #{args.size}, expected 8)" if args.size > 8 + + # å¼æ°ãè©ä¾¡ãã¦ã¹ã¿ãã¯ã¸ç©ã + args.reverse.each do |arg| + gen(arg, env) + puts "\tsub sp, sp, #16" + puts "\tstr x0, [sp, #0]" + end + + # ã¹ã¿ãã¯ã¸è©°ãã å¼æ°ã®å¤ããå¼æ°ç¨ã¬ã¸ã¹ã¿ã¸ã»ãã + args.each_with_index do |arg, i| + puts "\tldr #{PARAM_REGISTERS[i]}, [sp, #0]" + puts "\tadd sp, sp, #16" + end + + # é¢æ°å¼ã³åºã + puts "\tbl _#{name}" elsif tree[0] == "stmts" tree[1..].each do |stmt| gen(stmt, env)
ã³ã³ãã¤ã«ãã¦åããã¦ã¿ã¾ããããæãã«åãã¦ããã§ãã
ã¦ã¼ã¶ã¼å®ç¾©é¢æ°ã®å°å ¥
æå¾ã«ãã¦ã¼ã¶ã¼å®ç¾©é¢æ°ãå°å ¥ãã¾ãã以ä¸ã®ããã«ãã¦ã¼ã¶ã¼ãé¢æ°ãå®ç¾©ãããããå¼ã³åºããããã«ãã¾ãã
def hello() 860 # ããã¼ end p hello() #=> 860
ä¸è¨ã®ã³ã¼ãããã¼ãµã«ãããã¨ä»¥ä¸ã®ãããªæ§ææ¨ãè¿ãã¾ãã
irb(main):002:0> minruby_parse "def hello() 860; end; p hello()" => ["stmts", ["func_def", "hello", [], ["lit", 860]], ãããããããããã["func_call", "p", ["func_call", "hello"]]]
ã³ã³ãã¤ã©ã¯ãfunc_def
ã§å®ç¾©ãããé¨åãã¢ã»ã³ããªã³ã¼ãã¨ãã¦åºåãã func_call
ã§ãããå¼ã³åºãã¾ããä¸è¨ã®æ§ææ¨ãã¢ã»ã³ããªã³ã¼ãã¨ãã¦åºåããã¨ä»¥ä¸ã®ããã«ãªãã¾ããã¦ã¼ã¶ã¼å®ç¾©é¢æ°ã®ååãä»ã®ã©ã¤ãã©ãªé¢æ°ã®ååã¨è¡çªããªããããé¢æ°åã®å
é ã« _minruby_
ã¨ããããªãã£ãã¯ã¹ãã¤ãã¦ãã¾ããä¾ãã°é¢æ° hello
ã¯ã¢ã»ã³ããªã³ã¼ãä¸ã§ã¯ _minruby_hello
ã¨ããã©ãã«ãä»ãããã¾ãã
.text .align 2 ;; func_def ã§å®ç¾©ãããã¦ã¼ã¶ã¼å®ç¾©é¢æ° .globl _minruby_hello _minruby_hello: sub sp, sp, #16 stp fp, lr, [sp, #0] mov fp, sp mov x0, #860 ldp fp, lr, [sp, #0] add sp, sp, #16 ret .globl _main _main: sub sp, sp, #16 stp fp, lr, [sp, #0] mov fp, sp ;; ã¦ã¼ã¶ã¼å®ç¾©é¢æ° hello ãå¼ã³åºã bl _minruby_hello sub sp, sp, #16 str x0, [sp, #0] ldr x0, [sp, #0] add sp, sp, #16 bl _minruby_p ldp fp, lr, [sp, #0] add sp, sp, #16 mov w0, #10 ret
以ä¸ãã¦ã¼ã¶ã¼å®ç¾©é¢æ°ãå®è£ ããã³ã³ãã¤ã©ã®ã³ã¼ãã§ãã主ã«ä»¥ä¸ã®ãã¨ãè¡ãªã£ã¦ãã¾ãã
libminrby.c
ã®é¢æ°ãã¡ã«minruby_
ã®ããªãã£ãã¯ã¹ãã¤ãã- æ§ææ¨ããé¢æ°å®ç¾©
func_defs
ãæ½åºããé¢æ°func_defs
ã追å - æ½åºããé¢æ°å®ç¾©ãã¢ã»ã³ããªã³ã¼ãã¨ãã¦åºå
diff --git a/libminruby.c b/libminruby.c index a581930..2ff715c 100644 --- a/libminruby.c +++ b/libminruby.c @@ -1,12 +1,12 @@ // libminruby.c #include <stdio.h> -long p(long n) { +long minruby_p(long n) { printf("%ld\n", n); return n; } // çµã¿è¾¼ã¿é¢æ°ãã¹ãç¨ -long my_add(long a, long b) { +long minruby_my_add(long a, long b) { return a + b; } diff --git a/minrubyc.rb b/minrubyc.rb index 94f1769..6c309d8 100644 --- a/minrubyc.rb +++ b/minrubyc.rb @@ -40,6 +40,25 @@ def var_offset(var, env) env.index(var) * 8 + 16 end +# ã¦ã¼ã¶ã¼å®ç¾©é¢æ°ãæ§ææ¨ããæ½åº +def func_defs(tree) + if tree[0] == "func_def" + { + # é¢æ°åããã¼ã«ã㦠[é¢æ°å, å¼æ°, é¢æ°æ¬ä½] ãæ ¼ç´ + tree[1] => tree[1..] + } + elsif tree[0] == "stmts" + tmp_hash = {} + tree[1..].each do |stmt| + tmp_hash.merge!(func_defs(stmt)) + end + tmp_hash + else + {} + end +end + +# æ§ææ¨ãã¢ã»ã³ããªã³ã¼ãã¨ãã¦åºå def gen(tree, env) if tree[0] == "lit" puts "\tmov x0, ##{tree[1]}" @@ -97,6 +116,8 @@ def gen(tree, env) # ã¹ã¿ãã¯ãç ´æ£ puts "\tadd sp, sp, #16" + elsif tree[0] == "func_def" + # é¢æ°ã®å®ç¾©ã¯ã³ã³ãã¤ã«æã«ã³ã¼ãã¨ãã¦åºåããããããå®è¡æã«ã¯ä½ãè¡ããªãã¦è¯ã elsif tree[0] == "func_call" name, *args = tree[1..] @@ -117,7 +138,7 @@ def gen(tree, env) end # é¢æ°å¼ã³åºã - puts "\tbl _#{name}" + puts "\tbl _minruby_#{name}" elsif tree[0] == "stmts" tree[1..].each do |stmt| gen(stmt, env) @@ -165,12 +186,55 @@ def gen(tree, env) end end +# é¢æ°å®ç¾©ãã¢ã»ã³ããªã³ã¼ãã¨ãã¦åºå +def gen_func_def(func_def) + name, params, body = func_def + lenv = var_names(body) + env = params + lenv + + # ååãè¡çªããªãããã«ãé¢æ°åã®å é ã« _minruby_ ãä»ä¸ + puts "\t.globl _minruby_#{name}" + puts "_minruby_#{name}:" + + # é¢æ°ãããã¼ã° + lvar_size = env.size * 8 + puts "\tsub sp, sp, ##{16 + (lvar_size % 16 == 0 ? lvar_size : lvar_size + 8)}" # NOTE: ã¹ã¿ãã¯ã®ãµã¤ãºã¯16ã®åæ°ã§ãªããã°ãªããªã + puts "\tstp fp, lr, [sp, #0]" + puts "\tmov fp, sp" + # ã¹ã¿ãã¯ä¸ã®ãã©ã¡ã¼ã¿é åãåæå + params.each_with_index do |param, i| + puts "\tstr #{PARAM_REGISTERS[i]}, [fp, ##{var_offset(param, env)}]" + end + # ãã¼ã«ã«å¤æ°ãåæå + lenv.each do |var| + puts "\tmov x0, #0" + puts "\tstr x0, [fp, ##{var_offset(var, env)}]" + end + + gen(body, env) + + # é¢æ°ã¨ããã¼ã° + puts "\tldp fp, lr, [sp, #0]" + puts "\tadd sp, sp, ##{16 + (lvar_size % 16 == 0 ? lvar_size : lvar_size + 8)}" # NOTE: ã¹ã¿ãã¯ã®ãµã¤ãºã¯16ã®åæ°ã§ãªããã°ãªããªã + puts "\tret" +end + tree = minruby_parse(ARGF.read) env = var_names(tree) lvar_size = env.size * 8 +# ã¦ã¼ã¶ã¼å®ç¾©é¢æ°ãæ§ææ¨ããæ½åº +func_defs = func_defs(tree) + puts "\t.text" puts "\t.align 2" + +# ã¦ã¼ã¶ã¼å®ç¾©é¢æ°ãã¢ã»ã³ããªã³ã¼ãã¨ãã¦åºå +func_defs.values.each do |func_def| + gen_func_def(func_def) +end + +# ã¡ã¤ã³é¢æ° puts "\t.globl _main" puts "_main:"
ã³ã³ãã¤ã«ãã¦åããã¦ã¿ã¾ãã 860 (ããã¼)
ã表示ãããã°OKã§ãã
ãµã³ãã«ããã°ã©ã ãåããã¦ã¿ã
MinCaml ã³ã³ãã¤ã©ã¯ããã§å®æã§ããæå¾ã«ãµã³ãã«ããã°ã©ã ã¨ãã¦10çªç®ã®ãã£ããããæ°ãè¨ç®ãã以ä¸ã®ããã°ã©ã ãåããã¦ã¿ã¾ãã
# fib.rb def fib(n) if n < 2 n else fib(n - 1) + fib(n - 2) end end p fib(10)
ã³ã³ãã¤ã«ãã¦å®è¡ãã¦ã¿ã¾ãã10çªç®ã®ãã£ããããæ°ã§ãã 55
ã表示ãããã°OKã§ãã
çµããã«
以ä¸ãç°¡æãªã³ã³ãã¤ã©ã®ä½ãæ¹ã®ãç´¹ä»ã§ãããã¯ãªã¹ãã¹ã®å¤ãã°ã©ã¹çæã«ãã³ã³ãã¼ã¤ï¼Compileï¼ããªãã¦ãããã§ããï¼
ã¾ãããã®è¨äºãèªãã§ããã£ã¨è¨èªå¦çç³»ã«ã¤ãã¦ç¥ãããï¼ãã¨ãªã£ãæ¹ã¯ä»¥ä¸ãèªãã§ã¿ãã¨è¯ãããã
- Rubyã§ã¤ããRuby
- ä½ã¬ã¤ã¤ãç¥ããã人ã®ããã®Cã³ã³ãã¤ã©ä½æå ¥é
- ã¤ã³ã¿ããªã¿ã®ä½ãæ¹ï¼Crafting Interpretersï¼
- ææ°ã³ã³ãã¤ã©æ§æææ³
ã§ã¯ãã³ã³ãã¤ãã¤ãã