metasm 1.0.3 → 1.0.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +3 -0
- data.tar.gz.sig +0 -0
- data/Gemfile +3 -2
- data/metasm.gemspec +3 -2
- data/metasm.rb +4 -1
- data/metasm/compile_c.rb +2 -2
- data/metasm/cpu/arc/decode.rb +0 -21
- data/metasm/cpu/arc/main.rb +4 -4
- data/metasm/cpu/arm/decode.rb +1 -5
- data/metasm/cpu/arm/main.rb +3 -3
- data/metasm/cpu/arm64/decode.rb +2 -6
- data/metasm/cpu/arm64/main.rb +5 -5
- data/metasm/cpu/bpf/decode.rb +3 -35
- data/metasm/cpu/bpf/main.rb +5 -5
- data/metasm/cpu/bpf/render.rb +1 -12
- data/metasm/cpu/cy16/decode.rb +0 -6
- data/metasm/cpu/cy16/main.rb +3 -3
- data/metasm/cpu/cy16/render.rb +0 -11
- data/metasm/cpu/dalvik/decode.rb +4 -26
- data/metasm/cpu/dalvik/main.rb +20 -2
- data/metasm/cpu/dalvik/opcodes.rb +3 -2
- data/metasm/cpu/{mips/compile_c.rb → ebpf.rb} +5 -2
- data/metasm/cpu/ebpf/debug.rb +61 -0
- data/metasm/cpu/ebpf/decode.rb +142 -0
- data/metasm/cpu/ebpf/main.rb +58 -0
- data/metasm/cpu/ebpf/opcodes.rb +97 -0
- data/metasm/cpu/ebpf/render.rb +36 -0
- data/metasm/cpu/ia32/debug.rb +39 -1
- data/metasm/cpu/ia32/decode.rb +111 -90
- data/metasm/cpu/ia32/decompile.rb +45 -37
- data/metasm/cpu/ia32/main.rb +10 -0
- data/metasm/cpu/ia32/parse.rb +6 -0
- data/metasm/cpu/mcs51/decode.rb +1 -1
- data/metasm/cpu/mcs51/main.rb +11 -0
- data/metasm/cpu/mips/decode.rb +8 -18
- data/metasm/cpu/mips/main.rb +3 -3
- data/metasm/cpu/mips/opcodes.rb +1 -1
- data/metasm/cpu/msp430/decode.rb +2 -6
- data/metasm/cpu/msp430/main.rb +3 -3
- data/metasm/cpu/openrisc.rb +11 -0
- data/metasm/cpu/openrisc/debug.rb +106 -0
- data/metasm/cpu/openrisc/decode.rb +182 -0
- data/metasm/cpu/openrisc/decompile.rb +350 -0
- data/metasm/cpu/openrisc/main.rb +70 -0
- data/metasm/cpu/openrisc/opcodes.rb +109 -0
- data/metasm/cpu/openrisc/render.rb +37 -0
- data/metasm/cpu/ppc/decode.rb +0 -25
- data/metasm/cpu/ppc/main.rb +6 -6
- data/metasm/cpu/ppc/opcodes.rb +3 -4
- data/metasm/cpu/python/decode.rb +0 -20
- data/metasm/cpu/python/main.rb +1 -1
- data/metasm/cpu/sh4/decode.rb +2 -6
- data/metasm/cpu/sh4/main.rb +25 -23
- data/metasm/cpu/st20/decode.rb +0 -7
- data/metasm/cpu/webasm.rb +11 -0
- data/metasm/cpu/webasm/debug.rb +31 -0
- data/metasm/cpu/webasm/decode.rb +321 -0
- data/metasm/cpu/webasm/decompile.rb +386 -0
- data/metasm/cpu/webasm/encode.rb +104 -0
- data/metasm/cpu/webasm/main.rb +81 -0
- data/metasm/cpu/webasm/opcodes.rb +214 -0
- data/metasm/cpu/x86_64/compile_c.rb +13 -9
- data/metasm/cpu/x86_64/parse.rb +1 -1
- data/metasm/cpu/z80/decode.rb +0 -27
- data/metasm/cpu/z80/main.rb +3 -3
- data/metasm/cpu/z80/render.rb +0 -11
- data/metasm/debug.rb +43 -8
- data/metasm/decode.rb +62 -14
- data/metasm/decompile.rb +793 -466
- data/metasm/disassemble.rb +188 -131
- data/metasm/disassemble_api.rb +30 -17
- data/metasm/dynldr.rb +2 -2
- data/metasm/encode.rb +8 -2
- data/metasm/exe_format/autoexe.rb +2 -0
- data/metasm/exe_format/coff.rb +21 -3
- data/metasm/exe_format/coff_decode.rb +12 -0
- data/metasm/exe_format/coff_encode.rb +6 -3
- data/metasm/exe_format/dex.rb +13 -3
- data/metasm/exe_format/elf.rb +12 -2
- data/metasm/exe_format/elf_decode.rb +59 -1
- data/metasm/exe_format/main.rb +2 -0
- data/metasm/exe_format/mz.rb +1 -0
- data/metasm/exe_format/pe.rb +25 -3
- data/metasm/exe_format/wasm.rb +402 -0
- data/metasm/gui/dasm_decomp.rb +171 -95
- data/metasm/gui/dasm_graph.rb +61 -2
- data/metasm/gui/dasm_hex.rb +2 -2
- data/metasm/gui/dasm_main.rb +45 -19
- data/metasm/gui/debug.rb +13 -4
- data/metasm/gui/gtk.rb +12 -4
- data/metasm/main.rb +108 -103
- data/metasm/os/emulator.rb +175 -0
- data/metasm/os/main.rb +11 -6
- data/metasm/parse.rb +23 -12
- data/metasm/parse_c.rb +189 -135
- data/metasm/preprocessor.rb +16 -1
- data/misc/openrisc-parser.rb +79 -0
- data/samples/dasm-plugins/scanxrefs.rb +6 -4
- data/samples/dasm-plugins/selfmodify.rb +8 -8
- data/samples/dbg-plugins/trace_func.rb +1 -1
- data/samples/disassemble-gui.rb +14 -3
- data/samples/emubios.rb +251 -0
- data/samples/emudbg.rb +127 -0
- data/samples/lindebug.rb +79 -78
- data/samples/metasm-shell.rb +8 -8
- data/tests/all.rb +1 -1
- data/tests/expression.rb +2 -0
- data/tests/graph_layout.rb +1 -1
- data/tests/ia32.rb +1 -0
- data/tests/mips.rb +1 -1
- data/tests/preprocessor.rb +18 -0
- metadata +124 -6
- metadata.gz.sig +0 -0
@@ -0,0 +1,175 @@
|
|
1
|
+
# This file is part of Metasm, the Ruby assembly manipulation suite
|
2
|
+
# Copyright (C) 2006-2009 Yoann GUILLOT
|
3
|
+
#
|
4
|
+
# Licence is LGPL, see LICENCE in the top-level directory
|
5
|
+
|
6
|
+
|
7
|
+
require 'metasm/os/main'
|
8
|
+
require 'metasm/debug'
|
9
|
+
|
10
|
+
module Metasm
|
11
|
+
# a VirtualString mapping the segments from a disassembler
|
12
|
+
class VirtualMemoryDasm < VirtualString
|
13
|
+
attr_accessor :disassembler
|
14
|
+
|
15
|
+
def initialize(disassembler, addr_start = 0, length = nil)
|
16
|
+
@disassembler = disassembler
|
17
|
+
length ||= disassembler.sections.map { |k, v| k.kind_of?(Integer) ? k + v.length : 0 }.max
|
18
|
+
super(addr_start, length)
|
19
|
+
end
|
20
|
+
|
21
|
+
def dup(addr = @addr_start, len = @length)
|
22
|
+
self.class.new(@disassembler, addr, len)
|
23
|
+
end
|
24
|
+
|
25
|
+
# reads an aligned page from the file, at file offset addr
|
26
|
+
def read_range(addr, len=@pagelength)
|
27
|
+
@disassembler.read_raw_data(addr, len)
|
28
|
+
end
|
29
|
+
|
30
|
+
def page_invalid?(addr)
|
31
|
+
!@disassembler.get_section_at(addr)
|
32
|
+
end
|
33
|
+
|
34
|
+
# overwrite a section of the file
|
35
|
+
def rewrite_at(addr, data)
|
36
|
+
if e = @disassembler.get_section_at(addr)
|
37
|
+
e[0].data[addr - e[1], data.length] = data
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def decode_imm(addr, len, cpu)
|
42
|
+
@disassembler.decode_int(addr, len)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
# this class implements a virtual debugger over an emulated cpu (based on cpu#get_backtrace_binding)
|
47
|
+
class EmuDebugger < Debugger
|
48
|
+
attr_accessor :ctx
|
49
|
+
# lambda called everytime we emulate a di
|
50
|
+
# receives the di as parameter
|
51
|
+
# if it returns nil, the di is emulated as usual, if it returns true no further processing is done for this di
|
52
|
+
# dont forget to handle reg_pc !
|
53
|
+
attr_accessor :callback_emulate_di
|
54
|
+
# lambda called everytime we cannot find an instruction at the current PC
|
55
|
+
# return true if the context was fixed
|
56
|
+
attr_accessor :callback_unknown_pc
|
57
|
+
|
58
|
+
def initialize(disassembler)
|
59
|
+
@pid = @tid = 0
|
60
|
+
attach(disassembler)
|
61
|
+
end
|
62
|
+
|
63
|
+
def shortname; 'emudbg'; end
|
64
|
+
|
65
|
+
def attach(disassembler)
|
66
|
+
@memory = VirtualMemoryDasm.new(disassembler)
|
67
|
+
@cpu = disassembler.cpu
|
68
|
+
@disassembler = disassembler
|
69
|
+
@ctx = {}
|
70
|
+
@state = :stopped
|
71
|
+
@symbols = disassembler.prog_binding.invert
|
72
|
+
@symbols_len = @symbols.keys.inject({}) { |h, s| h.update s => 1 }
|
73
|
+
@modulemap = {}
|
74
|
+
@breakpoint = {}
|
75
|
+
@breakpoint_memory = {}
|
76
|
+
@breakpoint_thread = {}
|
77
|
+
end
|
78
|
+
|
79
|
+
def detach
|
80
|
+
end
|
81
|
+
|
82
|
+
def initialize_disassembler
|
83
|
+
end
|
84
|
+
def initialize_cpu
|
85
|
+
end
|
86
|
+
def initialize_memory
|
87
|
+
end
|
88
|
+
def invalidate
|
89
|
+
end
|
90
|
+
|
91
|
+
def memory_get_page(addr, len)
|
92
|
+
@memory[addr, len]
|
93
|
+
end
|
94
|
+
|
95
|
+
def get_reg_value(r)
|
96
|
+
if r.to_s =~ /flags?_(.+)/i
|
97
|
+
f = $1.downcase.to_sym
|
98
|
+
get_flag_value(f)
|
99
|
+
else
|
100
|
+
@ctx[r] || 0
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
def set_reg_value(r, v)
|
105
|
+
if r.to_s =~ /flags?_(.+)/i
|
106
|
+
f = $1.downcase.to_sym
|
107
|
+
set_flag_value(f, v)
|
108
|
+
else
|
109
|
+
@ctx[r] = v
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
def do_check_target
|
114
|
+
true
|
115
|
+
end
|
116
|
+
|
117
|
+
def do_wait_target
|
118
|
+
true
|
119
|
+
end
|
120
|
+
|
121
|
+
def do_continue
|
122
|
+
while not @breakpoint[pc] and do_singlestep # TODO check bp#enabled
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
def do_enable_bp(b) # no need to actually patch code in memory
|
127
|
+
end
|
128
|
+
|
129
|
+
def do_disable_bp(b)
|
130
|
+
end
|
131
|
+
|
132
|
+
def do_singlestep
|
133
|
+
di = @disassembler.di_at(pc)
|
134
|
+
if not di
|
135
|
+
@disassembler.disassemble_fast(pc)
|
136
|
+
di = @disassembler.di_at(pc)
|
137
|
+
end
|
138
|
+
if not di
|
139
|
+
if callback_unknown_pc and callback_unknown_pc.call()
|
140
|
+
return true
|
141
|
+
end
|
142
|
+
return
|
143
|
+
end
|
144
|
+
|
145
|
+
if callback_emulate_di
|
146
|
+
ret = callback_emulate_di.call(di)
|
147
|
+
return true if ret
|
148
|
+
end
|
149
|
+
|
150
|
+
return if di.opcode.props[:stopexec] and not di.opcode.props[:setip]
|
151
|
+
|
152
|
+
# 2-pass to respect binding atomicity
|
153
|
+
fbd = @disassembler.get_fwdemu_binding(di, register_pc, self)
|
154
|
+
|
155
|
+
fbd.map { |k, v|
|
156
|
+
if k.kind_of?(Indirection)
|
157
|
+
k = Indirection.new(resolve(k.pointer), k.len, k.origin)
|
158
|
+
end
|
159
|
+
[k, resolve(v)]
|
160
|
+
}.each { |k, v|
|
161
|
+
case k
|
162
|
+
when Indirection
|
163
|
+
v = v & ((1 << (k.len*8)) - 1)
|
164
|
+
memory_write_int(k.pointer, v, k.len)
|
165
|
+
when Symbol
|
166
|
+
set_reg_value(k, v)
|
167
|
+
when /^dummy_metasm_/
|
168
|
+
else
|
169
|
+
puts "singlestep: badkey #{k.inspect} = #{v}"
|
170
|
+
end
|
171
|
+
}
|
172
|
+
true
|
173
|
+
end
|
174
|
+
end
|
175
|
+
end
|
data/metasm/os/main.rb
CHANGED
@@ -246,14 +246,14 @@ class VirtualString
|
|
246
246
|
def read_range(from, len)
|
247
247
|
from += @addr_start
|
248
248
|
if not len
|
249
|
-
base, page = cache_get_page(from)
|
250
|
-
page[from - base]
|
249
|
+
base, page, inval = cache_get_page(from)
|
250
|
+
page[from - base] if not inval
|
251
251
|
elsif len <= @pagelength
|
252
|
-
base, page = cache_get_page(from)
|
253
|
-
s = page[from - base, len]
|
252
|
+
base, page, inval = cache_get_page(from)
|
253
|
+
s = page[from - base, len] if not inval
|
254
254
|
if from+len-base > @pagelength # request crosses a page boundary
|
255
|
-
base, page = cache_get_page(from+len)
|
256
|
-
s << page[0, from+len-base]
|
255
|
+
base, page, inval = cache_get_page(from+len)
|
256
|
+
s << page[0, from+len-base] if s and not inval
|
257
257
|
end
|
258
258
|
s
|
259
259
|
else
|
@@ -272,6 +272,11 @@ class VirtualString
|
|
272
272
|
# overwrites a section of the original data
|
273
273
|
#def rewrite_at(addr, content)
|
274
274
|
#end
|
275
|
+
|
276
|
+
# decode an integer
|
277
|
+
def decode_imm(addr, len, cpu)
|
278
|
+
Expression.decode_imm(self, len, cpu, addr)
|
279
|
+
end
|
275
280
|
end
|
276
281
|
|
277
282
|
# on-demand reading of a file
|
data/metasm/parse.rb
CHANGED
@@ -26,18 +26,10 @@ class CPU
|
|
26
26
|
while tok = lexer.readtok and parse_prefix(i, tok.raw)
|
27
27
|
lexer.skip_space_eol
|
28
28
|
end
|
29
|
-
return if not tok
|
30
|
-
|
31
|
-
# allow '.' in opcode name
|
32
|
-
tok = tok.dup
|
33
|
-
while ntok = lexer.nexttok and ntok.type == :punct and ntok.raw == '.'
|
34
|
-
tok.raw << lexer.readtok.raw
|
35
|
-
ntok = lexer.readtok
|
36
|
-
raise tok, 'invalid opcode name' if not ntok or ntok.type != :string
|
37
|
-
tok.raw << ntok.raw
|
38
|
-
end
|
39
29
|
|
40
|
-
|
30
|
+
lexer.unreadtok(tok)
|
31
|
+
tok = parse_instruction_mnemonic(lexer)
|
32
|
+
return if not tok
|
41
33
|
|
42
34
|
i.opname = tok.raw
|
43
35
|
i.backtrace = tok.backtrace
|
@@ -63,6 +55,23 @@ class CPU
|
|
63
55
|
i
|
64
56
|
end
|
65
57
|
|
58
|
+
# return a lexer token with an instruction mnemonic in #raw
|
59
|
+
# allows '.' in opcode name
|
60
|
+
# return nil at eof
|
61
|
+
def parse_instruction_mnemonic(lexer)
|
62
|
+
return if not tok = lexer.readtok
|
63
|
+
tok = tok.dup
|
64
|
+
while ntok = lexer.nexttok and ntok.type == :punct and ntok.raw == '.'
|
65
|
+
tok.raw << lexer.readtok.raw
|
66
|
+
ntok = lexer.readtok
|
67
|
+
raise tok, 'invalid opcode name' if not ntok or ntok.type != :string
|
68
|
+
tok.raw << ntok.raw
|
69
|
+
end
|
70
|
+
|
71
|
+
raise tok, 'invalid opcode' if not opcode_list_byname[tok.raw]
|
72
|
+
tok
|
73
|
+
end
|
74
|
+
|
66
75
|
def parse_instruction_checkproto(i)
|
67
76
|
opcode_list_byname[i.opname].to_a.find { |o|
|
68
77
|
o.args.length == i.args.length and o.args.zip(i.args).all? { |f, a| parse_arg_valid?(o, f, a) }
|
@@ -421,7 +430,7 @@ class ExeFormat
|
|
421
430
|
@cursource << Padding.new(fillwith, tok.backtrace) << Offset.new(e, tok.backtrace)
|
422
431
|
|
423
432
|
else
|
424
|
-
@cpu.parse_parser_instruction(
|
433
|
+
@cpu.parse_parser_instruction(@lexer, tok)
|
425
434
|
end
|
426
435
|
end
|
427
436
|
|
@@ -746,6 +755,8 @@ class Expression
|
|
746
755
|
|
747
756
|
# for boolean operators, true is 1 (or anything != 0), false is 0
|
748
757
|
def parse(lexer)
|
758
|
+
lexer = Preprocessor.new(lexer) if lexer.kind_of?(::String)
|
759
|
+
|
749
760
|
opstack = []
|
750
761
|
stack = []
|
751
762
|
|
data/metasm/parse_c.rb
CHANGED
@@ -22,7 +22,17 @@ module C
|
|
22
22
|
__builtin_offsetof
|
23
23
|
].inject({}) { |h, w| h.update w => true }
|
24
24
|
|
25
|
+
module Misc
|
26
|
+
attr_accessor :misc
|
27
|
+
|
28
|
+
def with_misc(m)
|
29
|
+
@misc = m if m or misc
|
30
|
+
self
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
25
34
|
class Statement
|
35
|
+
include Misc
|
26
36
|
end
|
27
37
|
|
28
38
|
module Typed # allows quick testing whether an object is an CExpr or a Variable
|
@@ -114,6 +124,7 @@ module C
|
|
114
124
|
|
115
125
|
class Type
|
116
126
|
include Attributes
|
127
|
+
include Misc
|
117
128
|
attr_accessor :qualifier # const volatile
|
118
129
|
|
119
130
|
def pointer? ; false end
|
@@ -758,6 +769,7 @@ module C
|
|
758
769
|
class Variable
|
759
770
|
include Attributes
|
760
771
|
include Typed
|
772
|
+
include Misc
|
761
773
|
|
762
774
|
attr_accessor :type
|
763
775
|
attr_accessor :initializer # CExpr / Block (for Functions)
|
@@ -773,6 +785,8 @@ module C
|
|
773
785
|
# found in a block's Statements, used to know the initialization order
|
774
786
|
# eg { int i; i = 4; struct foo { int k; } toto = {i}; }
|
775
787
|
class Declaration
|
788
|
+
include Misc
|
789
|
+
|
776
790
|
attr_accessor :var
|
777
791
|
def initialize(var)
|
778
792
|
@var = var
|
@@ -946,8 +960,8 @@ module C
|
|
946
960
|
raise ftok, 'unterminated asm block' if not tok = parser.lexer.readtok
|
947
961
|
break if tok.type == :punct and tok.raw == '}'
|
948
962
|
case tok.type
|
949
|
-
when :space; body << ' '
|
950
|
-
when :eol; body << "\n"
|
963
|
+
when :space; body << ' ' unless body.empty?
|
964
|
+
when :eol; body << "\n" unless body.empty?
|
951
965
|
when :punct; body << tok.raw
|
952
966
|
when :quoted; body << CExpression.string_inspect(tok.value) # concat adjacent c strings
|
953
967
|
when :string
|
@@ -1056,12 +1070,15 @@ module C
|
|
1056
1070
|
class CExpression < Statement
|
1057
1071
|
include Typed
|
1058
1072
|
|
1073
|
+
AssignOp = [:'=', :'+=', :'-=', :'*=', :'/=', :'%=', :'^=', :'&=', :'|=', :'>>=', :'<<=', :'++', :'--']
|
1074
|
+
|
1059
1075
|
# may be :,, :., :'->', :funcall (function, [arglist]), :[] (array indexing), nil (cast)
|
1060
1076
|
attr_accessor :op
|
1061
1077
|
# nil/CExpr/Variable/Label/::String( = :quoted/struct member name)/::Integer/::Float/Block
|
1062
1078
|
attr_accessor :lexpr, :rexpr
|
1063
1079
|
# a Type
|
1064
1080
|
attr_accessor :type
|
1081
|
+
|
1065
1082
|
def initialize(l, o, r, t)
|
1066
1083
|
raise "invalid CExpr #{[l, o, r, t].inspect}" if (o and not o.kind_of? ::Symbol) or not t.kind_of? Type
|
1067
1084
|
@lexpr, @op, @rexpr, @type = l, o, r, t
|
@@ -1092,7 +1109,7 @@ module C
|
|
1092
1109
|
# sub-arrays in args are to be passed to self.[] recursively (syntaxic sugar)
|
1093
1110
|
splat = lambda { |e| e.kind_of?(::Array) ? self[*e] : e }
|
1094
1111
|
|
1095
|
-
args.shift while args.first == nil # CExpr[nil, :&, bla] => CExpr[:&, bla]
|
1112
|
+
args.shift while args.length > 0 and args.first == nil # CExpr[nil, :&, bla] => CExpr[:&, bla]
|
1096
1113
|
|
1097
1114
|
case args.length
|
1098
1115
|
when 4
|
@@ -1114,9 +1131,9 @@ module C
|
|
1114
1131
|
|
1115
1132
|
case op
|
1116
1133
|
when :funcall
|
1117
|
-
|
1118
|
-
|
1119
|
-
|
1134
|
+
rt = x1.type.untypedef
|
1135
|
+
rt = rt.type.untypedef if rt.pointer?
|
1136
|
+
new(x1, op, x2, rt.type)
|
1120
1137
|
when :[]; new(x1, op, x2, x1.type.untypedef.type)
|
1121
1138
|
when :+; new(x1, op, x2, (x2.type.pointer? ? x2.type : x1.type))
|
1122
1139
|
when :-; new(x1, op, x2, ((x1.type.pointer? and x2.type.pointer?) ? BaseType.new(:int) : x2.type.pointer? ? x2.type : x1.type))
|
@@ -3176,7 +3193,7 @@ EOH
|
|
3176
3193
|
end
|
3177
3194
|
|
3178
3195
|
# parse a given String as an AllocCStruct
|
3179
|
-
# offset is an
|
3196
|
+
# offset is an optional offset from the string start
|
3180
3197
|
# modification to the structure will modify the underlying string
|
3181
3198
|
def decode_c_struct(structname, str, offset=0)
|
3182
3199
|
struct = find_c_struct(structname)
|
@@ -3321,19 +3338,49 @@ EOH
|
|
3321
3338
|
end
|
3322
3339
|
end
|
3323
3340
|
|
3341
|
+
# used to render a C to a source string, while keeping the information of which each character comes from which C object
|
3342
|
+
class CRenderString < ::String
|
3343
|
+
attr_accessor :my_c # default C obj with which raw characters are associated
|
3344
|
+
# hash offset => C::Statement, means bytes from this offset to the next entry comes from rendering this C object
|
3345
|
+
def c_at_offset
|
3346
|
+
@c_at_offset ||= {}
|
3347
|
+
end
|
3348
|
+
|
3349
|
+
# concatenate another CRenderString: merge @c_at_offset
|
3350
|
+
def <<(o)
|
3351
|
+
if o.kind_of?(self.class)
|
3352
|
+
o.c_at_offset.each { |k, v|
|
3353
|
+
c_at_offset[length+k] ||= v
|
3354
|
+
}
|
3355
|
+
elsif my_c
|
3356
|
+
c_at_offset[length] ||= my_c
|
3357
|
+
end
|
3358
|
+
super(o)
|
3359
|
+
end
|
3360
|
+
|
3361
|
+
def initialize(*a)
|
3362
|
+
if cs = a.grep(Statement).first
|
3363
|
+
a -= [cs]
|
3364
|
+
@my_c = cs
|
3365
|
+
c_at_offset[0] = cs
|
3366
|
+
end
|
3367
|
+
super(*a)
|
3368
|
+
end
|
3369
|
+
end
|
3370
|
+
|
3324
3371
|
class Statement
|
3325
|
-
def self.dump(e, scope, r=[
|
3372
|
+
def self.dump(e, scope, r=[CRenderString.new], dep=[])
|
3326
3373
|
case e
|
3327
3374
|
when nil; r.last << ';'
|
3328
3375
|
when Block
|
3329
3376
|
r.last << ' ' if not r.last.empty?
|
3330
3377
|
r.last << '{'
|
3331
|
-
tr, dep = e.dump(scope, [
|
3378
|
+
tr, dep = e.dump(scope, [CRenderString.new], dep)
|
3332
3379
|
tr.pop if tr.last.empty?
|
3333
3380
|
r.concat tr.map { |s| Case.dump_indent(s) }
|
3334
|
-
(r.last[-1] == ?{ ? r.last : r) << '}'
|
3381
|
+
(r.last[-1] == ?{ ? r.last : r) << CRenderString.new('}')
|
3335
3382
|
else
|
3336
|
-
tr, dep = e.dump(scope, [
|
3383
|
+
tr, dep = e.dump(scope, [CRenderString.new], dep)
|
3337
3384
|
r.concat tr.map { |s| Case.dump_indent(s) }
|
3338
3385
|
end
|
3339
3386
|
[r, dep]
|
@@ -3348,7 +3395,7 @@ EOH
|
|
3348
3395
|
def to_s() dump(nil)[0].join("\n") end
|
3349
3396
|
|
3350
3397
|
# return array of c source lines and array of dependencies (objects)
|
3351
|
-
def dump(scp, r=[
|
3398
|
+
def dump(scp, r=[CRenderString.new], dep=[])
|
3352
3399
|
mydefs = @symbol.values.grep(TypeDef) + @struct.values + anonymous_enums.to_a
|
3353
3400
|
todo_rndr = {}
|
3354
3401
|
todo_deps = {}
|
@@ -3360,7 +3407,7 @@ EOH
|
|
3360
3407
|
[r, dep]
|
3361
3408
|
end
|
3362
3409
|
|
3363
|
-
def dump_reorder(mydefs, todo_rndr, todo_deps, r=[
|
3410
|
+
def dump_reorder(mydefs, todo_rndr, todo_deps, r=[CRenderString.new], dep=[])
|
3364
3411
|
val = todo_deps.values.flatten.uniq
|
3365
3412
|
dep |= val
|
3366
3413
|
dep -= mydefs | todo_deps.keys
|
@@ -3375,6 +3422,7 @@ EOH
|
|
3375
3422
|
# predeclare structs involved in cyclic dependencies
|
3376
3423
|
dep_cycle = lambda { |ary|
|
3377
3424
|
# sexyness inside (c)
|
3425
|
+
# XXX 5 years later, i have no idea whats going on here
|
3378
3426
|
deps = todo_deps[ary.last]
|
3379
3427
|
if deps.include? ary.first; ary
|
3380
3428
|
elsif (deps-ary).find { |d| deps = dep_cycle[ary + [d]] }; deps
|
@@ -3384,7 +3432,7 @@ EOH
|
|
3384
3432
|
oldc = nil
|
3385
3433
|
while c = dep_cycle[[t]]
|
3386
3434
|
break if oldc == c
|
3387
|
-
r << "#{t.kind_of?(Struct) ? 'struct' : 'union'} #{t.name};" if not oldc
|
3435
|
+
r << CRenderString.new(t, "#{t.kind_of?(Struct) ? 'struct' : 'union'} #{t.name};") if not oldc
|
3388
3436
|
oldc = c
|
3389
3437
|
c.each { |s|
|
3390
3438
|
# XXX struct z { struct a* }; struct a { void (*foo)(struct z); };
|
@@ -3403,7 +3451,7 @@ EOH
|
|
3403
3451
|
end
|
3404
3452
|
todo_now.sort_by { |k| k.name || '0' }.each { |k|
|
3405
3453
|
if k.kind_of? Variable and k.type.kind_of? Function and k.initializer
|
3406
|
-
r <<
|
3454
|
+
r << CRenderString.new
|
3407
3455
|
r.concat todo_rndr.delete(k)
|
3408
3456
|
else
|
3409
3457
|
r.pop if r.last == ''
|
@@ -3413,12 +3461,12 @@ EOH
|
|
3413
3461
|
todo_deps.delete k
|
3414
3462
|
}
|
3415
3463
|
todo_deps.each_key { |k| todo_deps[k] -= todo_now }
|
3416
|
-
r <<
|
3464
|
+
r << CRenderString.new << CRenderString.new << CRenderString.new
|
3417
3465
|
end
|
3418
3466
|
|
3419
3467
|
@statements.each { |s|
|
3420
|
-
r <<
|
3421
|
-
if s.kind_of?
|
3468
|
+
r << CRenderString.new if not r.last.empty?
|
3469
|
+
if s.kind_of?(Block)
|
3422
3470
|
r, dep = Statement.dump(s, self, r, dep)
|
3423
3471
|
else
|
3424
3472
|
r, dep = s.dump(self, r, dep)
|
@@ -3429,10 +3477,10 @@ EOH
|
|
3429
3477
|
end
|
3430
3478
|
end
|
3431
3479
|
class Declaration
|
3432
|
-
def dump(scope, r=[
|
3433
|
-
tr, dep = @var.dump_def(scope, [
|
3434
|
-
if @var.kind_of?
|
3435
|
-
r <<
|
3480
|
+
def dump(scope, r=[CRenderString.new], dep=[])
|
3481
|
+
tr, dep = @var.dump_def(scope, [CRenderString.new], dep)
|
3482
|
+
if @var.kind_of?(Variable) and @var.type.kind_of?(Function) and @var.initializer
|
3483
|
+
r << CRenderString.new
|
3436
3484
|
r.concat tr
|
3437
3485
|
else
|
3438
3486
|
r.pop if r.last == ''
|
@@ -3461,14 +3509,14 @@ EOH
|
|
3461
3509
|
end
|
3462
3510
|
end
|
3463
3511
|
class Variable
|
3464
|
-
def dump(scope, r=[
|
3512
|
+
def dump(scope, r=[CRenderString.new], dep=[])
|
3465
3513
|
if name
|
3466
3514
|
dep |= [scope.symbol_ancestors[@name]]
|
3467
3515
|
r.last << @name
|
3468
3516
|
end
|
3469
3517
|
[r, dep]
|
3470
3518
|
end
|
3471
|
-
def dump_def(scope, r=[
|
3519
|
+
def dump_def(scope, r=[CRenderString.new], dep=[], skiptype=false)
|
3472
3520
|
# int a=1, b=2;
|
3473
3521
|
r.last << dump_attributes_pre
|
3474
3522
|
if not skiptype
|
@@ -3476,7 +3524,7 @@ EOH
|
|
3476
3524
|
r, dep = @type.base.dump(scope, r, dep)
|
3477
3525
|
r.last << ' ' if name
|
3478
3526
|
end
|
3479
|
-
r, dep = @type.dump_declarator([(name ? @name.dup : '') << dump_attributes], scope, r, dep)
|
3527
|
+
r, dep = @type.dump_declarator([CRenderString.new(name ? @name.dup : '') << dump_attributes], scope, r, dep)
|
3480
3528
|
|
3481
3529
|
if initializer
|
3482
3530
|
r.last << ' = ' if not @type.kind_of?(Function)
|
@@ -3490,7 +3538,7 @@ EOH
|
|
3490
3538
|
end
|
3491
3539
|
end
|
3492
3540
|
class Type
|
3493
|
-
def dump_initializer(init, scope, r=[
|
3541
|
+
def dump_initializer(init, scope, r=[CRenderString.new], dep=[])
|
3494
3542
|
case init
|
3495
3543
|
when ::Numeric
|
3496
3544
|
r.last << init.to_s
|
@@ -3502,9 +3550,9 @@ EOH
|
|
3502
3550
|
end
|
3503
3551
|
end
|
3504
3552
|
|
3505
|
-
def dump_declarator(decl, scope, r=[
|
3553
|
+
def dump_declarator(decl, scope, r=[CRenderString.new], dep=[])
|
3506
3554
|
r.last << decl.shift
|
3507
|
-
r.concat decl
|
3555
|
+
r.concat decl.map { |d| CRenderString.new << d }
|
3508
3556
|
[r, dep]
|
3509
3557
|
end
|
3510
3558
|
|
@@ -3512,11 +3560,11 @@ EOH
|
|
3512
3560
|
dump(*a)
|
3513
3561
|
end
|
3514
3562
|
|
3515
|
-
def dump_cast(scope, r=[
|
3563
|
+
def dump_cast(scope, r=[CRenderString.new], dep=[])
|
3516
3564
|
r.last << '('
|
3517
3565
|
r.last << dump_attributes_pre if not kind_of? TypeDef
|
3518
3566
|
r, dep = base.dump(scope, r, dep)
|
3519
|
-
r, dep = dump_declarator([kind_of?(TypeDef) ? '' : dump_attributes], scope, r, dep)
|
3567
|
+
r, dep = dump_declarator([CRenderString.new(kind_of?(TypeDef) ? '' : dump_attributes)], scope, r, dep)
|
3520
3568
|
r.last << ')'
|
3521
3569
|
[r, dep]
|
3522
3570
|
end
|
@@ -3526,28 +3574,29 @@ EOH
|
|
3526
3574
|
end
|
3527
3575
|
end
|
3528
3576
|
class Pointer
|
3529
|
-
def dump_declarator(decl, scope, r=[
|
3577
|
+
def dump_declarator(decl, scope, r=[CRenderString.new], dep=[])
|
3530
3578
|
d = decl[0]
|
3531
|
-
decl[0] =
|
3579
|
+
decl[0] = CRenderString.new
|
3580
|
+
decl[0] << '*'
|
3532
3581
|
decl[0] << ' ' << @qualifier.map { |q| q.to_s }.join(' ') << ' ' if qualifier
|
3533
3582
|
decl[0] << d
|
3534
|
-
if @type.kind_of?
|
3535
|
-
decl[0] = '(' << decl[0]
|
3583
|
+
if @type.kind_of?(Function) or @type.kind_of?(Array)
|
3584
|
+
decl[0] = CRenderString.new << '(' << decl[0]
|
3536
3585
|
decl.last << ')'
|
3537
3586
|
end
|
3538
3587
|
@type.dump_declarator(decl, scope, r, dep)
|
3539
3588
|
end
|
3540
3589
|
end
|
3541
3590
|
class Array
|
3542
|
-
def dump_declarator(decl, scope, r=[
|
3591
|
+
def dump_declarator(decl, scope, r=[CRenderString.new], dep=[])
|
3543
3592
|
decl.last << '()' if decl.last.empty?
|
3544
3593
|
decl.last << '['
|
3545
3594
|
decl, dep = CExpression.dump(@length, scope, decl, dep) if length
|
3546
3595
|
decl.last << ']'
|
3547
3596
|
@type.dump_declarator(decl, scope, r, dep)
|
3548
3597
|
end
|
3549
|
-
def dump_initializer(init, scope, r=[
|
3550
|
-
return super(init, scope, r, dep) if not init.kind_of?
|
3598
|
+
def dump_initializer(init, scope, r=[CRenderString.new], dep=[])
|
3599
|
+
return super(init, scope, r, dep) if not init.kind_of?(::Array)
|
3551
3600
|
r.last << '{ '
|
3552
3601
|
showname = false
|
3553
3602
|
init.each_with_index { |v, i|
|
@@ -3556,21 +3605,21 @@ EOH
|
|
3556
3605
|
next
|
3557
3606
|
end
|
3558
3607
|
r.last << ', ' if r.last[-2, 2] != '{ '
|
3559
|
-
rt = [
|
3608
|
+
rt = [CRenderString.new]
|
3560
3609
|
if showname
|
3561
3610
|
showname = false
|
3562
|
-
rt << "[#{i}] = "
|
3611
|
+
rt << CRenderString.new("[#{i}] = ")
|
3563
3612
|
end
|
3564
3613
|
rt, dep = @type.dump_initializer(v, scope, rt, dep)
|
3565
3614
|
r.last << rt.shift
|
3566
|
-
r.concat rt.map { |s| "\t" << s }
|
3615
|
+
r.concat rt.map { |s| CRenderString.new << "\t" << s }
|
3567
3616
|
}
|
3568
3617
|
r.last << ' }'
|
3569
3618
|
[r, dep]
|
3570
3619
|
end
|
3571
3620
|
end
|
3572
3621
|
class Function
|
3573
|
-
def dump_declarator(decl, scope, r=[
|
3622
|
+
def dump_declarator(decl, scope, r=[CRenderString.new], dep=[])
|
3574
3623
|
decl.last << '()' if decl.last.empty?
|
3575
3624
|
decl.last << '('
|
3576
3625
|
if args
|
@@ -3589,12 +3638,12 @@ EOH
|
|
3589
3638
|
@type.dump_declarator(decl, scope, r, dep)
|
3590
3639
|
end
|
3591
3640
|
|
3592
|
-
def dump_initializer(init, scope, r=[
|
3593
|
-
Statement.dump(init, scope, r <<
|
3641
|
+
def dump_initializer(init, scope, r=[CRenderString.new], dep=[])
|
3642
|
+
Statement.dump(init, scope, r << CRenderString.new, dep)
|
3594
3643
|
end
|
3595
3644
|
end
|
3596
3645
|
class BaseType
|
3597
|
-
def dump(scope, r=[
|
3646
|
+
def dump(scope, r=[CRenderString.new], dep=[])
|
3598
3647
|
r.last << @qualifier.map { |q| q.to_s << ' ' }.join if qualifier
|
3599
3648
|
r.last << @specifier.to_s << ' ' if specifier and @name != :ptr
|
3600
3649
|
r.last << case @name
|
@@ -3607,27 +3656,27 @@ EOH
|
|
3607
3656
|
end
|
3608
3657
|
end
|
3609
3658
|
class TypeDef
|
3610
|
-
def dump(scope, r=[
|
3659
|
+
def dump(scope, r=[CRenderString.new], dep=[])
|
3611
3660
|
r.last << @qualifier.map { |q| q.to_s << ' ' }.join if qualifier
|
3612
3661
|
r.last << @name
|
3613
3662
|
dep |= [scope.symbol_ancestors[@name]]
|
3614
3663
|
[r, dep]
|
3615
3664
|
end
|
3616
3665
|
|
3617
|
-
def dump_def(scope, r=[
|
3666
|
+
def dump_def(scope, r=[CRenderString.new], dep=[])
|
3618
3667
|
r.last << 'typedef '
|
3619
3668
|
r.last << dump_attributes_pre
|
3620
3669
|
r, dep = @type.base.dump(scope, r, dep)
|
3621
3670
|
r.last << ' '
|
3622
|
-
@type.dump_declarator([(name ? @name.dup : '') << dump_attributes], scope, r, dep)
|
3671
|
+
@type.dump_declarator([CRenderString.new(name ? @name.dup : '') << dump_attributes], scope, r, dep)
|
3623
3672
|
end
|
3624
3673
|
|
3625
|
-
def dump_initializer(init, scope, r=[
|
3674
|
+
def dump_initializer(init, scope, r=[CRenderString.new], dep=[])
|
3626
3675
|
@type.dump_initializer(init, scope, r, dep)
|
3627
3676
|
end
|
3628
3677
|
end
|
3629
3678
|
class Union
|
3630
|
-
def dump(scope, r=[
|
3679
|
+
def dump(scope, r=[CRenderString.new], dep=[])
|
3631
3680
|
if name
|
3632
3681
|
r.last << @qualifier.map { |q| q.to_s << ' ' }.join if qualifier
|
3633
3682
|
r.last << self.class.name.downcase[/(?:.*::)?(.*)/, 1] << ' ' << @name
|
@@ -3638,26 +3687,26 @@ EOH
|
|
3638
3687
|
end
|
3639
3688
|
end
|
3640
3689
|
|
3641
|
-
def dump_def(scope, r=[
|
3642
|
-
r <<
|
3690
|
+
def dump_def(scope, r=[CRenderString.new], dep=[])
|
3691
|
+
r << CRenderString.new
|
3643
3692
|
r.last << @qualifier.map { |q| q.to_s << ' ' }.join if qualifier
|
3644
3693
|
r.last << self.class.name.downcase[/(?:.*::)?(.*)/, 1]
|
3645
3694
|
r.last << ' ' << @name if name
|
3646
3695
|
if members
|
3647
3696
|
r.last << ' {'
|
3648
3697
|
@members.each_with_index { |m,i|
|
3649
|
-
tr, dep = m.dump_def(scope, [
|
3698
|
+
tr, dep = m.dump_def(scope, [CRenderString.new], dep)
|
3650
3699
|
tr.last << ':' << @bits[i].to_s if bits and @bits[i]
|
3651
3700
|
tr.last << ';'
|
3652
|
-
r.concat tr.map { |s| "\t" << s }
|
3701
|
+
r.concat tr.map { |s| CRenderString.new << "\t" << s }
|
3653
3702
|
}
|
3654
|
-
r << '}'
|
3703
|
+
r << CRenderString.new('}')
|
3655
3704
|
end
|
3656
3705
|
r.last << dump_attributes
|
3657
3706
|
[r, dep]
|
3658
3707
|
end
|
3659
3708
|
|
3660
|
-
def dump_initializer(init, scope, r=[
|
3709
|
+
def dump_initializer(init, scope, r=[CRenderString.new], dep=[])
|
3661
3710
|
return super(init, scope, r, dep) if not init.kind_of? ::Array
|
3662
3711
|
r.last << '{ '
|
3663
3712
|
showname = false
|
@@ -3667,21 +3716,21 @@ EOH
|
|
3667
3716
|
next
|
3668
3717
|
end
|
3669
3718
|
r.last << ', ' if r.last[-2, 2] != '{ '
|
3670
|
-
rt = [
|
3719
|
+
rt = [CRenderString.new]
|
3671
3720
|
if showname
|
3672
3721
|
showname = false
|
3673
3722
|
rt << ".#{m.name} = "
|
3674
3723
|
end
|
3675
3724
|
rt, dep = m.type.dump_initializer(i, scope, rt, dep)
|
3676
3725
|
r.last << rt.shift
|
3677
|
-
r.concat rt.map { |s| "\t" << s }
|
3726
|
+
r.concat rt.map { |s| CRenderString.new << "\t" << s }
|
3678
3727
|
}
|
3679
3728
|
r.last << ' }'
|
3680
3729
|
[r, dep]
|
3681
3730
|
end
|
3682
3731
|
end
|
3683
3732
|
class Struct
|
3684
|
-
def dump_def(scope, r=[
|
3733
|
+
def dump_def(scope, r=[CRenderString.new], dep=[])
|
3685
3734
|
if pack
|
3686
3735
|
r, dep = super(scope, r, dep)
|
3687
3736
|
r.last <<
|
@@ -3695,7 +3744,7 @@ EOH
|
|
3695
3744
|
end
|
3696
3745
|
end
|
3697
3746
|
class Enum
|
3698
|
-
def dump(scope, r=[
|
3747
|
+
def dump(scope, r=[CRenderString.new], dep=[])
|
3699
3748
|
if name
|
3700
3749
|
r.last << @qualifier.map { |q| q.to_s << ' ' }.join if qualifier
|
3701
3750
|
r.last << 'enum ' << @name
|
@@ -3706,7 +3755,7 @@ EOH
|
|
3706
3755
|
end
|
3707
3756
|
end
|
3708
3757
|
|
3709
|
-
def dump_def(scope, r=[
|
3758
|
+
def dump_def(scope, r=[CRenderString.new], dep=[])
|
3710
3759
|
r.last << @qualifier.map { |q| q.to_s << ' ' }.join if qualifier
|
3711
3760
|
r.last << 'enum'
|
3712
3761
|
r.last << ' ' << @name if name
|
@@ -3726,7 +3775,7 @@ EOH
|
|
3726
3775
|
[r, dep]
|
3727
3776
|
end
|
3728
3777
|
|
3729
|
-
def dump_initializer(init, scope, r=[
|
3778
|
+
def dump_initializer(init, scope, r=[CRenderString.new], dep=[])
|
3730
3779
|
if members and (
|
3731
3780
|
k = @members.index(init) or
|
3732
3781
|
(init.kind_of? CExpression and not init.op and k = @members.index(init.rexpr))
|
@@ -3739,14 +3788,14 @@ EOH
|
|
3739
3788
|
end
|
3740
3789
|
end
|
3741
3790
|
class If
|
3742
|
-
def dump(scope, r=[
|
3743
|
-
r.last << 'if ('
|
3791
|
+
def dump(scope, r=[CRenderString.new], dep=[])
|
3792
|
+
r.last << CRenderString.new(self, 'if (')
|
3744
3793
|
r, dep = CExpression.dump(@test, scope, r, dep)
|
3745
3794
|
r.last << ')'
|
3746
3795
|
r, dep = Statement.dump(@bthen, scope, r, dep)
|
3747
3796
|
if belse
|
3748
|
-
@bthen.kind_of?(Block) ? (r.last << ' else') : (r << 'else')
|
3749
|
-
if @belse.kind_of?
|
3797
|
+
@bthen.kind_of?(Block) ? (r.last << CRenderString.new(' else')) : (r << CRenderString.new(self, 'else'))
|
3798
|
+
if @belse.kind_of?(If)
|
3750
3799
|
# skip indent
|
3751
3800
|
r.last << ' '
|
3752
3801
|
r, dep = @belse.dump(scope, r, dep)
|
@@ -3758,9 +3807,9 @@ EOH
|
|
3758
3807
|
end
|
3759
3808
|
end
|
3760
3809
|
class For
|
3761
|
-
def dump(scope, r=[
|
3762
|
-
r.last << 'for ('
|
3763
|
-
if @init.kind_of?
|
3810
|
+
def dump(scope, r=[CRenderString.new], dep=[])
|
3811
|
+
r.last << CRenderString.new(self, 'for (')
|
3812
|
+
if @init.kind_of?(Block)
|
3764
3813
|
scope = @init
|
3765
3814
|
skiptype = false
|
3766
3815
|
@init.symbol.each_value { |s|
|
@@ -3784,56 +3833,57 @@ EOH
|
|
3784
3833
|
end
|
3785
3834
|
end
|
3786
3835
|
class While
|
3787
|
-
def dump(scope, r=[
|
3788
|
-
r.last << 'while ('
|
3836
|
+
def dump(scope, r=[CRenderString.new], dep=[])
|
3837
|
+
r.last << CRenderString.new(self, 'while (')
|
3789
3838
|
r, dep = CExpression.dump(@test, scope, r, dep)
|
3790
3839
|
r.last << ')'
|
3791
3840
|
Statement.dump(@body, scope, r, dep)
|
3792
3841
|
end
|
3793
3842
|
end
|
3794
3843
|
class DoWhile
|
3795
|
-
def dump(scope, r=[
|
3796
|
-
r.last << 'do'
|
3844
|
+
def dump(scope, r=[CRenderString.new], dep=[])
|
3845
|
+
r.last << CRenderString.new(self, 'do')
|
3797
3846
|
r, dep = Statement.dump(@body, scope, r, dep)
|
3798
|
-
|
3847
|
+
r << CRenderString.new if not @body.kind_of?(Block)
|
3848
|
+
r.last << CRenderString.new(self, ' while (')
|
3799
3849
|
r, dep = CExpression.dump(@test, scope, r, dep)
|
3800
3850
|
r.last << ');'
|
3801
3851
|
[r, dep]
|
3802
3852
|
end
|
3803
3853
|
end
|
3804
3854
|
class Switch
|
3805
|
-
def dump(scope, r=[
|
3806
|
-
r.last << 'switch ('
|
3855
|
+
def dump(scope, r=[CRenderString.new], dep=[])
|
3856
|
+
r.last << CRenderString.new(self, 'switch (')
|
3807
3857
|
r, dep = CExpression.dump(@test, scope, r, dep)
|
3808
3858
|
r.last << ')'
|
3809
|
-
r.last << ' {' if @body.kind_of?
|
3810
|
-
tr, dep = @body.dump(scope, [
|
3859
|
+
r.last << ' {' if @body.kind_of?(Block)
|
3860
|
+
tr, dep = @body.dump(scope, [CRenderString.new], dep)
|
3811
3861
|
r.concat tr.map { |s| Case.dump_indent(s, true) }
|
3812
|
-
r << '}' if @body.kind_of? Block
|
3862
|
+
r << CRenderString.new('}') if @body.kind_of? Block
|
3813
3863
|
[r, dep]
|
3814
3864
|
end
|
3815
3865
|
end
|
3816
3866
|
class Continue
|
3817
|
-
def dump(scope, r=[
|
3818
|
-
r.last << 'continue;'
|
3867
|
+
def dump(scope, r=[CRenderString.new], dep=[])
|
3868
|
+
r.last << CRenderString.new(self, 'continue;')
|
3819
3869
|
[r, dep]
|
3820
3870
|
end
|
3821
3871
|
end
|
3822
3872
|
class Break
|
3823
|
-
def dump(scope, r=[
|
3824
|
-
r.last << 'break;'
|
3873
|
+
def dump(scope, r=[CRenderString.new], dep=[])
|
3874
|
+
r.last << CRenderString.new(self, 'break;')
|
3825
3875
|
[r, dep]
|
3826
3876
|
end
|
3827
3877
|
end
|
3828
3878
|
class Goto
|
3829
|
-
def dump(scope, r=[
|
3830
|
-
r.last << "goto #@target;"
|
3879
|
+
def dump(scope, r=[CRenderString.new], dep=[])
|
3880
|
+
r.last << CRenderString.new(self, "goto #@target;")
|
3831
3881
|
[r, dep]
|
3832
3882
|
end
|
3833
3883
|
end
|
3834
3884
|
class Return
|
3835
|
-
def dump(scope, r=[
|
3836
|
-
r.last << 'return '
|
3885
|
+
def dump(scope, r=[CRenderString.new], dep=[])
|
3886
|
+
r.last << CRenderString.new(self, 'return ')
|
3837
3887
|
r, dep = CExpression.dump(@value, scope, r, dep)
|
3838
3888
|
r.last.chop! if r.last[-1] == ?\ # the space character
|
3839
3889
|
r.last << ';'
|
@@ -3841,12 +3891,12 @@ EOH
|
|
3841
3891
|
end
|
3842
3892
|
end
|
3843
3893
|
class Case
|
3844
|
-
def dump(scope, r=[
|
3894
|
+
def dump(scope, r=[CRenderString.new], dep=[])
|
3845
3895
|
case @expr
|
3846
3896
|
when 'default'
|
3847
3897
|
r.last << @expr
|
3848
3898
|
else
|
3849
|
-
r.last << 'case '
|
3899
|
+
r.last << CRenderString.new(self, 'case ')
|
3850
3900
|
r, dep = CExpression.dump(@expr, scope, r, dep)
|
3851
3901
|
if exprup
|
3852
3902
|
r.last << ' ... '
|
@@ -3859,35 +3909,35 @@ EOH
|
|
3859
3909
|
|
3860
3910
|
def self.dump_indent(s, short=false)
|
3861
3911
|
case s
|
3862
|
-
when /^(case|default)\W/; (short ? ' ' : "\t") << s
|
3863
|
-
when /^\s+(case|default)\W/; "\t" << s
|
3912
|
+
when /^(case|default)\W/; CRenderString.new(short ? ' ' : "\t") << s
|
3913
|
+
when /^\s+(case|default)\W/; CRenderString.new("\t") << s
|
3864
3914
|
when /:$/; s
|
3865
|
-
else "\t" << s
|
3915
|
+
else CRenderString.new("\t") << s
|
3866
3916
|
end
|
3867
3917
|
end
|
3868
3918
|
end
|
3869
3919
|
class Label
|
3870
|
-
def dump(scope, r=[
|
3871
|
-
r.last << @name << ':'
|
3920
|
+
def dump(scope, r=[CRenderString.new], dep=[])
|
3921
|
+
r.last << CRenderString.new(self, @name) << ':'
|
3872
3922
|
dump_inner(scope, r, dep)
|
3873
3923
|
end
|
3874
|
-
def dump_inner(scope, r=[
|
3924
|
+
def dump_inner(scope, r=[CRenderString.new], dep=[])
|
3875
3925
|
if not @statement; [r, dep]
|
3876
|
-
elsif @statement.kind_of?
|
3877
|
-
else @statement.dump(scope, r <<
|
3926
|
+
elsif @statement.kind_of?(Block); Statement.dump(@statement, scope, r, dep)
|
3927
|
+
else @statement.dump(scope, r << CRenderString.new, dep)
|
3878
3928
|
end
|
3879
3929
|
end
|
3880
3930
|
end
|
3881
3931
|
class Asm
|
3882
|
-
def dump(scope, r=[
|
3883
|
-
r.last << 'asm '
|
3932
|
+
def dump(scope, r=[CRenderString.new], dep=[])
|
3933
|
+
r.last << CRenderString.new(self, 'asm ')
|
3884
3934
|
r.last << 'volatile ' if @volatile
|
3885
3935
|
r.last << '('
|
3886
|
-
r.last << CExpression.string_inspect(@body)
|
3936
|
+
r.last << CRenderString.new(self, CExpression.string_inspect(@body))
|
3887
3937
|
if @output or @input or @clobber
|
3888
3938
|
if @output and @output != []
|
3889
3939
|
# TODO
|
3890
|
-
r << ': /* todo */'
|
3940
|
+
r << CRenderString.new(': /* todo */')
|
3891
3941
|
elsif (@input and @input != []) or (@clobber and @clobber != [])
|
3892
3942
|
r.last << ' :'
|
3893
3943
|
end
|
@@ -3895,13 +3945,13 @@ EOH
|
|
3895
3945
|
if @input or @clobber
|
3896
3946
|
if @input and @input != []
|
3897
3947
|
# TODO
|
3898
|
-
r << ': /* todo */'
|
3948
|
+
r << CRenderString.new(': /* todo */')
|
3899
3949
|
elsif @clobber and @clobber != []
|
3900
3950
|
r.last << ' :'
|
3901
3951
|
end
|
3902
3952
|
end
|
3903
3953
|
if @clobber and @clobber != []
|
3904
|
-
r << (': ' << @clobber.map { |c| CExpression.string_inspect(c) }.join(', '))
|
3954
|
+
r << (CRenderString.new(': ') << @clobber.map { |c| CExpression.string_inspect(c) }.join(', '))
|
3905
3955
|
end
|
3906
3956
|
r.last << ');'
|
3907
3957
|
[r, dep]
|
@@ -3910,18 +3960,20 @@ EOH
|
|
3910
3960
|
class CExpression
|
3911
3961
|
def self.string_inspect(s)
|
3912
3962
|
# keep all ascii printable except \ and "
|
3913
|
-
'"' + s.gsub(/[^ !\x23-\x5b\x5d-\x7e]/) { |o|
|
3963
|
+
'"' + s.gsub(/[^ !\x23-\x5b\x5d-\x7e]/) { |o|
|
3964
|
+
case hex = o.unpack('H*').first.downcase
|
3965
|
+
when '00'; '\\0'
|
3966
|
+
when '0a'; '\\n'
|
3967
|
+
when '0d'; '\\r'
|
3968
|
+
when '1b'; '\\e'
|
3969
|
+
when '22'; '\\"'
|
3970
|
+
when '5c'; '\\\\'
|
3971
|
+
else "\\x#{hex}"
|
3972
|
+
end
|
3973
|
+
} + '"'
|
3914
3974
|
end
|
3915
3975
|
|
3916
|
-
def self.dump(e, scope, r=[
|
3917
|
-
if $DEBUG
|
3918
|
-
brace = false
|
3919
|
-
case e
|
3920
|
-
when CExpression, Variable
|
3921
|
-
r, dep = e.type.dump_cast(scope, r, dep)
|
3922
|
-
end
|
3923
|
-
r.last << '('
|
3924
|
-
end
|
3976
|
+
def self.dump(e, scope, r=[CRenderString.new], dep=[], brace = false)
|
3925
3977
|
r, dep = \
|
3926
3978
|
case e
|
3927
3979
|
when ::Numeric; r.last << e.to_s ; [r, dep]
|
@@ -3931,20 +3983,22 @@ EOH
|
|
3931
3983
|
when nil; [r, dep]
|
3932
3984
|
else raise 'wtf?' + e.inspect
|
3933
3985
|
end
|
3934
|
-
if $DEBUG
|
3935
|
-
r.last << ')'
|
3936
|
-
end
|
3937
3986
|
[r, dep]
|
3938
3987
|
end
|
3939
3988
|
|
3940
|
-
def dump(scope, r=[
|
3989
|
+
def dump(scope, r=[CRenderString.new], dep=[])
|
3941
3990
|
r, dep = dump_inner(scope, r, dep)
|
3942
|
-
r.last << ';'
|
3991
|
+
r.last << CRenderString.new(self, ';')
|
3943
3992
|
[r, dep]
|
3944
3993
|
end
|
3945
3994
|
|
3946
|
-
def dump_inner(scope, r=[
|
3947
|
-
r.last <<
|
3995
|
+
def dump_inner(scope, r=[CRenderString.new], dep=[], brace = false)
|
3996
|
+
r.last << CRenderString.new(self)
|
3997
|
+
if misc and misc[:custom_display]
|
3998
|
+
r.last << misc[:custom_display]
|
3999
|
+
return [r, dep]
|
4000
|
+
end
|
4001
|
+
r.last << '(' if brace and @op != :'->' and @op != :'.' and @op != :'[]' and (@op or @rexpr.kind_of?(CExpression))
|
3948
4002
|
if not @lexpr
|
3949
4003
|
if not @op
|
3950
4004
|
case @rexpr
|
@@ -3960,7 +4014,7 @@ EOH
|
|
3960
4014
|
else
|
3961
4015
|
r.last << re.to_s
|
3962
4016
|
end
|
3963
|
-
if @type.kind_of?
|
4017
|
+
if @type.kind_of?(BaseType)
|
3964
4018
|
r.last << 'U' if @type.specifier == :unsigned
|
3965
4019
|
case @type.name
|
3966
4020
|
when :longlong, :__int64; r.last << 'LL'
|
@@ -3969,7 +4023,7 @@ EOH
|
|
3969
4023
|
end
|
3970
4024
|
end
|
3971
4025
|
when ::String
|
3972
|
-
r.last << 'L' if @type.kind_of?
|
4026
|
+
r.last << 'L' if @type.kind_of?(Pointer) and @type.type.kind_of?(BaseType) and @type.type.name == :short
|
3973
4027
|
r.last << CExpression.string_inspect(@rexpr)
|
3974
4028
|
when CExpression # cast
|
3975
4029
|
r, dep = @type.dump_cast(scope, r, dep)
|
@@ -3982,11 +4036,11 @@ EOH
|
|
3982
4036
|
r.last << ' )'
|
3983
4037
|
when Label
|
3984
4038
|
r.last << '&&' << @rexpr.name
|
3985
|
-
else raise "wtf? #{inspect}"
|
4039
|
+
else raise "(wtf? #{inspect})"
|
3986
4040
|
end
|
3987
4041
|
else
|
3988
4042
|
r.last << @op.to_s
|
3989
|
-
r, dep = CExpression.dump(@rexpr, scope, r, dep, (@rexpr.kind_of?
|
4043
|
+
r, dep = CExpression.dump(@rexpr, scope, r, dep, (@rexpr.kind_of?(C::CExpression) and @rexpr.lexpr))
|
3990
4044
|
end
|
3991
4045
|
elsif not @rexpr
|
3992
4046
|
r, dep = CExpression.dump(@lexpr, scope, r, dep)
|
@@ -3995,15 +4049,15 @@ EOH
|
|
3995
4049
|
case @op
|
3996
4050
|
when :'->', :'.'
|
3997
4051
|
r, dep = CExpression.dump(@lexpr, scope, r, dep, true)
|
3998
|
-
r.last << @op.to_s << @rexpr
|
4052
|
+
r.last << CRenderString.new(self, @op.to_s) << @rexpr
|
3999
4053
|
when :'[]'
|
4000
4054
|
r, dep = CExpression.dump(@lexpr, scope, r, dep, true)
|
4001
4055
|
r.last << '['
|
4002
|
-
l = lexpr if lexpr.kind_of?
|
4003
|
-
l = lexpr.lexpr.type.untypedef.findmember(lexpr.rexpr) if lexpr.kind_of?
|
4004
|
-
l = lexpr.lexpr.type.pointed.untypedef.findmember(lexpr.rexpr) if lexpr.kind_of?
|
4056
|
+
l = lexpr if lexpr.kind_of?(Variable)
|
4057
|
+
l = lexpr.lexpr.type.untypedef.findmember(lexpr.rexpr) if lexpr.kind_of?(CExpression) and lexpr.op == :'.'
|
4058
|
+
l = lexpr.lexpr.type.pointed.untypedef.findmember(lexpr.rexpr) if lexpr.kind_of?(CExpression) and lexpr.op == :'->'
|
4005
4059
|
# honor __attribute__((indexenum(enumname)))
|
4006
|
-
if l and l.attributes and rexpr.kind_of?
|
4060
|
+
if l and l.attributes and rexpr.kind_of?(CExpression) and not rexpr.op and rexpr.rexpr.kind_of?(::Integer) and
|
4007
4061
|
n = l.has_attribute_var('indexenum') and enum = scope.struct_ancestors[n] and i = enum.members.index(rexpr.rexpr)
|
4008
4062
|
r.last << i
|
4009
4063
|
dep |= [enum]
|
@@ -4016,22 +4070,22 @@ EOH
|
|
4016
4070
|
r.last << '('
|
4017
4071
|
@rexpr.each { |arg|
|
4018
4072
|
r.last << ', ' if r.last[-1] != ?(
|
4019
|
-
r, dep = CExpression.dump(arg, scope, r, dep)
|
4073
|
+
r, dep = CExpression.dump(arg, scope, r, dep, (arg.kind_of?(CExpression) and arg.op == :','))
|
4020
4074
|
}
|
4021
4075
|
r.last << ')'
|
4022
4076
|
when :'?:'
|
4023
4077
|
r, dep = CExpression.dump(@lexpr, scope, r, dep, true)
|
4024
|
-
r.last << ' ? '
|
4078
|
+
r.last << CRenderString.new(self, ' ? ')
|
4025
4079
|
r, dep = CExpression.dump(@rexpr[0], scope, r, dep, true)
|
4026
|
-
r.last << ' : '
|
4080
|
+
r.last << CRenderString.new(self, ' : ')
|
4027
4081
|
r, dep = CExpression.dump(@rexpr[1], scope, r, dep, true)
|
4028
4082
|
else
|
4029
|
-
r, dep = CExpression.dump(@lexpr, scope, r, dep, (@lexpr.kind_of?
|
4030
|
-
r.last << ' ' << @op.to_s << ' '
|
4031
|
-
r, dep = CExpression.dump(@rexpr, scope, r, dep, (@rexpr.kind_of?
|
4083
|
+
r, dep = CExpression.dump(@lexpr, scope, r, dep, (@lexpr.kind_of?(CExpression) and @lexpr.lexpr and @lexpr.op != @op and @lexpr.op != :funcall))
|
4084
|
+
r.last << CRenderString.new(self, ' ' << @op.to_s << ' ')
|
4085
|
+
r, dep = CExpression.dump(@rexpr, scope, r, dep, (@rexpr.kind_of?(CExpression) and @rexpr.lexpr and @rexpr.op != @op and @rexpr.op != :funcall and @op != :'='))
|
4032
4086
|
end
|
4033
4087
|
end
|
4034
|
-
r.last << ')' if brace and @op != :'->' and @op != :'.' and @op != :'[]' and (@op or @rexpr.kind_of?
|
4088
|
+
r.last << ')' if brace and @op != :'->' and @op != :'.' and @op != :'[]' and (@op or @rexpr.kind_of?(CExpression))
|
4035
4089
|
[r, dep]
|
4036
4090
|
end
|
4037
4091
|
|