简单的Ruby直接到机器码的生成器(X86) RPGMaker兼容
2016 年 5 月 7 日
毕竟Bellard大牛的OTCC里面就是到处飞机器码,并且,他是一边解析词法符号一边就直接产生了,真是棒棒的不按套路却又无比正经的写法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 | =begin Author: 晴兰@66RPG UID=131313 LICENSE: CC-BY-SA 3.0 [url]http://creativecommons.org/licenses/by-sa/3.0/deed.zh[/url] Purpose: Simple Machine Code Generator. Limited operation supported =end CallWindowProc = Win32API.new 'user32', 'CallWindowProcW', 'pLLLL', 'L' def prolog(num_of_var = nil) [0x55, 0x8b, 0xec].pack("C*") + (num_of_var ? [0x83, 0354, num_of_var * 4].pack("C*") : "") end def epilog [0xc9, 0xc2, 0x10].pack("CCS") end def render(list, num_of_var = nil) prolog(num_of_var) + render_rec(list) + epilog end def check_var(list) return -4 * list[1] if list[0] == :var raise "lvalue required for #{list.inspect}" end def render_rec(list) case list.first when :lit [0xb8, list[1]].pack("CL") when :arg [0x8b, 0105, 4 + list[1] * 4].pack("C*") when :do list[1..-1].map{|x| render_rec(x)}.join when :var [0x8b, 0105, -4 * list[1] ].pack("C*") when :assign id = check_var(list[1]) render_rec(list[2]) + [0x89, 0105, id].pack("C*") when :+, :-, :&, :^, :| render_rec(list[2]) + "\x50" + render_rec(list[1]) + [0132, "+|ab&-^".index(list.first.to_s) << 3 | 3, 0302].pack("C*") when :<, :>, :'==', :'!=', :>=, :<= v = list.first.to_s l = v.length f = v.ord rescue v[0] u = "0000G+000000<HF>".index((f + (l > 1 ? 10 : 0)).chr) render_rec(list[2]) + "\x50" + render_rec(list[1]) + [0132, 073, 0302, 0x0f, 0x90 + u, 0300, 0x81, 0340, 0xff, 0x00, 0x00, 0x00].pack("C*") when :nil; "" when :if cond, thenpart, elsepart = list[1..-1].map{|x| render_rec(x)} thenpart += [0xe9, elsepart.length].pack("CL") cond += [0x85, 0300, 0x75, 0x05, 0xe9, thenpart.length].pack("CCCCCL") cond + thenpart + elsepart when :for init, cond, incr, body = list[1..-1].map{|x| render_rec(x)} addbyte = [0x85, 0300, 0x75, 0x05, 0xe9, body.size + incr.size + 5].pack("CCCCCL") fbody = body + incr + [0xe9, -(body.size + incr.size + cond.size + addbyte.size + 5)].pack("CL") init + cond + addbyte + fbody end end x = render( [:do, [:assign, [:var, 1], [:lit, 0]], [:for, [:assign, [:var, 2], [:lit, 1]], [:<, [:var, 2], [:lit, 101]], [:assign, [:var, 2], [:+, [:var, 2], [:lit, 1]]], [:assign, [:var, 1], [:+, [:var, 1], [:var, 2]]] ], [:var, 1] ], 2 ) =begin int var1 = 0; for(int var2 = 1; var2 < 101; var2+=1) var1 += var2; return var1 =end p CallWindowProc.call x, 0, 0, 0, 0 #=>5050 |
Orz%%%%%%%%%%%%%%%%%%