metasm 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (192) hide show
  1. data/BUGS +11 -0
  2. data/CREDITS +17 -0
  3. data/README +270 -0
  4. data/TODO +114 -0
  5. data/doc/code_organisation.txt +146 -0
  6. data/doc/const_missing.txt +16 -0
  7. data/doc/core_classes.txt +75 -0
  8. data/doc/feature_list.txt +53 -0
  9. data/doc/index.txt +59 -0
  10. data/doc/install_notes.txt +170 -0
  11. data/doc/style.css +3 -0
  12. data/doc/use_cases.txt +18 -0
  13. data/lib/metasm.rb +80 -0
  14. data/lib/metasm/arm.rb +12 -0
  15. data/lib/metasm/arm/debug.rb +39 -0
  16. data/lib/metasm/arm/decode.rb +167 -0
  17. data/lib/metasm/arm/encode.rb +77 -0
  18. data/lib/metasm/arm/main.rb +75 -0
  19. data/lib/metasm/arm/opcodes.rb +177 -0
  20. data/lib/metasm/arm/parse.rb +130 -0
  21. data/lib/metasm/arm/render.rb +55 -0
  22. data/lib/metasm/compile_c.rb +1457 -0
  23. data/lib/metasm/dalvik.rb +8 -0
  24. data/lib/metasm/dalvik/decode.rb +196 -0
  25. data/lib/metasm/dalvik/main.rb +60 -0
  26. data/lib/metasm/dalvik/opcodes.rb +366 -0
  27. data/lib/metasm/decode.rb +213 -0
  28. data/lib/metasm/decompile.rb +2659 -0
  29. data/lib/metasm/disassemble.rb +2068 -0
  30. data/lib/metasm/disassemble_api.rb +1280 -0
  31. data/lib/metasm/dynldr.rb +1329 -0
  32. data/lib/metasm/encode.rb +333 -0
  33. data/lib/metasm/exe_format/a_out.rb +194 -0
  34. data/lib/metasm/exe_format/autoexe.rb +82 -0
  35. data/lib/metasm/exe_format/bflt.rb +189 -0
  36. data/lib/metasm/exe_format/coff.rb +455 -0
  37. data/lib/metasm/exe_format/coff_decode.rb +901 -0
  38. data/lib/metasm/exe_format/coff_encode.rb +1078 -0
  39. data/lib/metasm/exe_format/dex.rb +457 -0
  40. data/lib/metasm/exe_format/dol.rb +145 -0
  41. data/lib/metasm/exe_format/elf.rb +923 -0
  42. data/lib/metasm/exe_format/elf_decode.rb +979 -0
  43. data/lib/metasm/exe_format/elf_encode.rb +1375 -0
  44. data/lib/metasm/exe_format/macho.rb +827 -0
  45. data/lib/metasm/exe_format/main.rb +228 -0
  46. data/lib/metasm/exe_format/mz.rb +164 -0
  47. data/lib/metasm/exe_format/nds.rb +172 -0
  48. data/lib/metasm/exe_format/pe.rb +437 -0
  49. data/lib/metasm/exe_format/serialstruct.rb +246 -0
  50. data/lib/metasm/exe_format/shellcode.rb +114 -0
  51. data/lib/metasm/exe_format/xcoff.rb +167 -0
  52. data/lib/metasm/gui.rb +23 -0
  53. data/lib/metasm/gui/cstruct.rb +373 -0
  54. data/lib/metasm/gui/dasm_coverage.rb +199 -0
  55. data/lib/metasm/gui/dasm_decomp.rb +369 -0
  56. data/lib/metasm/gui/dasm_funcgraph.rb +103 -0
  57. data/lib/metasm/gui/dasm_graph.rb +1354 -0
  58. data/lib/metasm/gui/dasm_hex.rb +543 -0
  59. data/lib/metasm/gui/dasm_listing.rb +599 -0
  60. data/lib/metasm/gui/dasm_main.rb +906 -0
  61. data/lib/metasm/gui/dasm_opcodes.rb +291 -0
  62. data/lib/metasm/gui/debug.rb +1228 -0
  63. data/lib/metasm/gui/gtk.rb +884 -0
  64. data/lib/metasm/gui/qt.rb +495 -0
  65. data/lib/metasm/gui/win32.rb +3004 -0
  66. data/lib/metasm/gui/x11.rb +621 -0
  67. data/lib/metasm/ia32.rb +14 -0
  68. data/lib/metasm/ia32/compile_c.rb +1523 -0
  69. data/lib/metasm/ia32/debug.rb +193 -0
  70. data/lib/metasm/ia32/decode.rb +1167 -0
  71. data/lib/metasm/ia32/decompile.rb +564 -0
  72. data/lib/metasm/ia32/encode.rb +314 -0
  73. data/lib/metasm/ia32/main.rb +233 -0
  74. data/lib/metasm/ia32/opcodes.rb +872 -0
  75. data/lib/metasm/ia32/parse.rb +327 -0
  76. data/lib/metasm/ia32/render.rb +91 -0
  77. data/lib/metasm/main.rb +1193 -0
  78. data/lib/metasm/mips.rb +11 -0
  79. data/lib/metasm/mips/compile_c.rb +7 -0
  80. data/lib/metasm/mips/decode.rb +253 -0
  81. data/lib/metasm/mips/encode.rb +51 -0
  82. data/lib/metasm/mips/main.rb +72 -0
  83. data/lib/metasm/mips/opcodes.rb +443 -0
  84. data/lib/metasm/mips/parse.rb +51 -0
  85. data/lib/metasm/mips/render.rb +43 -0
  86. data/lib/metasm/os/gnu_exports.rb +270 -0
  87. data/lib/metasm/os/linux.rb +1112 -0
  88. data/lib/metasm/os/main.rb +1686 -0
  89. data/lib/metasm/os/remote.rb +527 -0
  90. data/lib/metasm/os/windows.rb +2027 -0
  91. data/lib/metasm/os/windows_exports.rb +745 -0
  92. data/lib/metasm/parse.rb +876 -0
  93. data/lib/metasm/parse_c.rb +3938 -0
  94. data/lib/metasm/pic16c/decode.rb +42 -0
  95. data/lib/metasm/pic16c/main.rb +17 -0
  96. data/lib/metasm/pic16c/opcodes.rb +68 -0
  97. data/lib/metasm/ppc.rb +11 -0
  98. data/lib/metasm/ppc/decode.rb +264 -0
  99. data/lib/metasm/ppc/decompile.rb +251 -0
  100. data/lib/metasm/ppc/encode.rb +51 -0
  101. data/lib/metasm/ppc/main.rb +129 -0
  102. data/lib/metasm/ppc/opcodes.rb +410 -0
  103. data/lib/metasm/ppc/parse.rb +52 -0
  104. data/lib/metasm/preprocessor.rb +1277 -0
  105. data/lib/metasm/render.rb +130 -0
  106. data/lib/metasm/sh4.rb +8 -0
  107. data/lib/metasm/sh4/decode.rb +336 -0
  108. data/lib/metasm/sh4/main.rb +292 -0
  109. data/lib/metasm/sh4/opcodes.rb +381 -0
  110. data/lib/metasm/x86_64.rb +12 -0
  111. data/lib/metasm/x86_64/compile_c.rb +1025 -0
  112. data/lib/metasm/x86_64/debug.rb +59 -0
  113. data/lib/metasm/x86_64/decode.rb +268 -0
  114. data/lib/metasm/x86_64/encode.rb +264 -0
  115. data/lib/metasm/x86_64/main.rb +135 -0
  116. data/lib/metasm/x86_64/opcodes.rb +118 -0
  117. data/lib/metasm/x86_64/parse.rb +68 -0
  118. data/misc/bottleneck.rb +61 -0
  119. data/misc/cheader-findpppath.rb +58 -0
  120. data/misc/hexdiff.rb +74 -0
  121. data/misc/hexdump.rb +55 -0
  122. data/misc/metasm-all.rb +13 -0
  123. data/misc/objdiff.rb +47 -0
  124. data/misc/objscan.rb +40 -0
  125. data/misc/pdfparse.rb +661 -0
  126. data/misc/ppc_pdf2oplist.rb +192 -0
  127. data/misc/tcp_proxy_hex.rb +84 -0
  128. data/misc/txt2html.rb +440 -0
  129. data/samples/a.out.rb +31 -0
  130. data/samples/asmsyntax.rb +77 -0
  131. data/samples/bindiff.rb +555 -0
  132. data/samples/compilation-steps.rb +49 -0
  133. data/samples/cparser_makestackoffset.rb +55 -0
  134. data/samples/dasm-backtrack.rb +38 -0
  135. data/samples/dasmnavig.rb +318 -0
  136. data/samples/dbg-apihook.rb +228 -0
  137. data/samples/dbghelp.rb +143 -0
  138. data/samples/disassemble-gui.rb +102 -0
  139. data/samples/disassemble.rb +133 -0
  140. data/samples/dump_upx.rb +95 -0
  141. data/samples/dynamic_ruby.rb +1929 -0
  142. data/samples/elf_list_needed.rb +46 -0
  143. data/samples/elf_listexports.rb +33 -0
  144. data/samples/elfencode.rb +25 -0
  145. data/samples/exeencode.rb +128 -0
  146. data/samples/factorize-headers-elfimports.rb +77 -0
  147. data/samples/factorize-headers-peimports.rb +109 -0
  148. data/samples/factorize-headers.rb +43 -0
  149. data/samples/gdbclient.rb +583 -0
  150. data/samples/generate_libsigs.rb +102 -0
  151. data/samples/hotfix_gtk_dbg.rb +59 -0
  152. data/samples/install_win_env.rb +78 -0
  153. data/samples/lindebug.rb +924 -0
  154. data/samples/linux_injectsyscall.rb +95 -0
  155. data/samples/machoencode.rb +31 -0
  156. data/samples/metasm-shell.rb +91 -0
  157. data/samples/pe-hook.rb +69 -0
  158. data/samples/pe-ia32-cpuid.rb +203 -0
  159. data/samples/pe-mips.rb +35 -0
  160. data/samples/pe-shutdown.rb +78 -0
  161. data/samples/pe-testrelocs.rb +51 -0
  162. data/samples/pe-testrsrc.rb +24 -0
  163. data/samples/pe_listexports.rb +31 -0
  164. data/samples/peencode.rb +19 -0
  165. data/samples/peldr.rb +494 -0
  166. data/samples/preprocess-flatten.rb +19 -0
  167. data/samples/r0trace.rb +308 -0
  168. data/samples/rubstop.rb +399 -0
  169. data/samples/scan_pt_gnu_stack.rb +54 -0
  170. data/samples/scanpeexports.rb +62 -0
  171. data/samples/shellcode-c.rb +40 -0
  172. data/samples/shellcode-dynlink.rb +146 -0
  173. data/samples/source.asm +34 -0
  174. data/samples/struct_offset.rb +47 -0
  175. data/samples/testpe.rb +32 -0
  176. data/samples/testraw.rb +45 -0
  177. data/samples/win32genloader.rb +132 -0
  178. data/samples/win32hooker-advanced.rb +169 -0
  179. data/samples/win32hooker.rb +96 -0
  180. data/samples/win32livedasm.rb +33 -0
  181. data/samples/win32remotescan.rb +133 -0
  182. data/samples/wintrace.rb +92 -0
  183. data/tests/all.rb +8 -0
  184. data/tests/dasm.rb +39 -0
  185. data/tests/dynldr.rb +35 -0
  186. data/tests/encodeddata.rb +132 -0
  187. data/tests/ia32.rb +82 -0
  188. data/tests/mips.rb +116 -0
  189. data/tests/parse_c.rb +239 -0
  190. data/tests/preprocessor.rb +269 -0
  191. data/tests/x86_64.rb +62 -0
  192. metadata +255 -0
@@ -0,0 +1,3938 @@
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/main'
8
+ require 'metasm/preprocessor'
9
+
10
+ module Metasm
11
+ # c parser
12
+ # inspired from http://www.math.grin.edu/~stone/courses/languages/C-syntax.xhtml
13
+ module C
14
+ Keyword = %w[struct union enum if else for while do switch goto
15
+ register extern auto static typedef const volatile
16
+ void int float double char signed unsigned long short
17
+ case continue break return default __attribute__
18
+ asm __asm __asm__ sizeof typeof
19
+ __declspec __cdecl __stdcall __fastcall __noreturn
20
+ inline __inline __inline__ __volatile__
21
+ __int8 __int16 __int32 __int64
22
+ __builtin_offsetof
23
+ ].inject({}) { |h, w| h.update w => true }
24
+
25
+ class Statement
26
+ end
27
+
28
+ module Typed # allows quick testing whether an object is an CExpr or a Variable
29
+ end
30
+
31
+ class Block < Statement
32
+ attr_accessor :symbol # hash name => Type/Variable/enum value
33
+ attr_accessor :struct # hash name => Struct/Union/Enum
34
+ attr_accessor :outer # parent block
35
+ attr_accessor :statements # array of Statement/Declaration
36
+ attr_accessor :anonymous_enums # array of anonymous Enum
37
+
38
+ def initialize(outer, statements=[], symbol={}, struct={})
39
+ @outer = outer
40
+ @statements = statements
41
+ @symbol = symbol
42
+ @struct = struct
43
+ end
44
+
45
+ def struct_ancestors
46
+ @outer ? @outer.struct_ancestors.merge(@struct) : @struct
47
+ end
48
+
49
+ def symbol_ancestors
50
+ @outer ? @outer.symbol_ancestors.merge(@symbol) : @symbol
51
+ end
52
+ end
53
+
54
+ module Attributes
55
+ attr_accessor :attributes
56
+
57
+ DECLSPECS = %w[cdecl stdcall fastcall inline naked thiscall noreturn]
58
+
59
+ # parses a sequence of __attribute__((anything)) into self.attributes (array of string)
60
+ def parse_attributes(parser, allow_declspec = false)
61
+ while tok = parser.skipspaces and tok.type == :string
62
+ case keyword = tok.raw
63
+ when '__attribute__', '__declspec' # synonymous: __attribute__((foo)) == __declspec(foo)
64
+ raise tok || parser if not tok = parser.skipspaces or tok.type != :punct or tok.raw != '('
65
+ raise tok || parser if keyword == '__attribute__' and (not tok = parser.skipspaces or tok.type != :punct or tok.raw != '(')
66
+ nest = 0
67
+ attrib = ''
68
+ loop do
69
+ raise parser if not tok = parser.skipspaces
70
+ if tok.type == :punct and tok.raw == ')'
71
+ if nest == 0
72
+ raise tok || parser if keyword == '__attribute__' and (not tok = parser.skipspaces or tok.type != :punct or tok.raw != ')')
73
+ break
74
+ else
75
+ nest -= 1
76
+ end
77
+ elsif tok.type == :punct and tok.raw == '('
78
+ nest += 1
79
+ elsif nest == 0 and tok.type == :punct and tok.raw == ','
80
+ raise tok || parser if not allow_declspec and DECLSPECS.include? attrib
81
+ add_attribute attrib
82
+ attrib = ''
83
+ next
84
+ end
85
+ attrib << tok.raw
86
+ end
87
+ raise tok || parser, "attr #{attrib.inspect} not allowed here" if not allow_declspec and DECLSPECS.include? attrib
88
+ else
89
+ if allow_declspec and DECLSPECS.include? keyword.gsub('_', '')
90
+ attrib = keyword.gsub('_', '')
91
+ else break
92
+ end
93
+ end
94
+ add_attribute(attrib)
95
+ end
96
+ parser.unreadtok tok
97
+ end
98
+
99
+ # checks if the object has an attribute in its attribute list
100
+ def has_attribute(attr)
101
+ attributes.to_a.include? attr
102
+ end
103
+
104
+ # adds an attribute to the object attribute list if it is not already in it
105
+ def add_attribute(attr)
106
+ (@attributes ||= []) << attr if not has_attribute(attr)
107
+ end
108
+
109
+ # checks if the object has an attributes a la __attribute__((attr(stuff))), returns 'stuff' (raw, no split on ',' or anything)
110
+ def has_attribute_var(attr)
111
+ $1 if attributes.to_a.find { |a| a =~ /^#{attr}\((.*)\)$/ }
112
+ end
113
+ end
114
+
115
+ class Type
116
+ include Attributes
117
+ attr_accessor :qualifier # const volatile
118
+
119
+ def pointer? ; false end
120
+ def arithmetic? ; false end
121
+ def integral? ; false end
122
+ def float? ; false end
123
+ def void? ; false end
124
+ def base ; self end
125
+ def untypedef ; self end
126
+
127
+ def parse_initializer(parser, scope)
128
+ raise parser, 'expr expected' if not ret = CExpression.parse(parser, scope, false)
129
+ p, i = pointer?, integral?
130
+ r = ret.reduce(parser) if p or i
131
+ if (not p and not i) or (i and not r.kind_of? ::Integer) or (p and r != 0)
132
+ parser.check_compatible_type(parser, ret.type, self)
133
+ end
134
+ ret
135
+ end
136
+
137
+ def parse_initializer_designator(parser, scope, value, idx, root=true)
138
+ if not root and (not nt = parser.skipspaces or nt.type != :punct or nt.raw != '=')
139
+ raise nt || parser, '"=" expected'
140
+ end
141
+ value[idx] = parse_initializer(parser, scope)
142
+ idx + 1
143
+ end
144
+ end
145
+ class BaseType < Type
146
+ attr_accessor :name # :int :long :longlong :short :double :longdouble :float :char :void :__int8/16/32/64
147
+ attr_accessor :specifier # sign specifier only
148
+
149
+ def arithmetic? ; @name != :void end
150
+ def integral? ; [:char, :short, :int, :long, :longlong, :ptr,
151
+ :__int8, :__int16, :__int32, :__int64].include? @name end
152
+ def signed? ; specifier != :unsigned end
153
+ def float? ; [:float, :double, :longdouble].include? @name end
154
+ def void? ; @name == :void end
155
+ def align(parser) @name == :double ? 4 : parser.typesize[@name] end
156
+
157
+ def initialize(name, *specs)
158
+ @name = name
159
+ specs.each { |s|
160
+ case s
161
+ when :const, :volatile; (@qualifier ||= []) << s
162
+ when :signed, :unsigned; @specifier = s
163
+ when nil
164
+ else raise "internal error, got #{name.inspect} #{specs.inspect}"
165
+ end
166
+ }
167
+ end
168
+
169
+ def ==(o)
170
+ o.object_id == self.object_id or
171
+ (o.class == self.class and o.name == self.name and o.specifier == self.specifier and o.attributes == self.attributes)
172
+ end
173
+ end
174
+ class TypeDef < Type
175
+ attr_accessor :name
176
+ attr_accessor :type
177
+ attr_accessor :backtrace
178
+
179
+ def initialize(name, type, backtrace)
180
+ @name, @type, @backtrace = name, type, backtrace
181
+ end
182
+
183
+ def parse_initializer(parser, scope)
184
+ @type.parse_initializer(parser, scope)
185
+ end
186
+
187
+ def pointer? ; @type.pointer? end
188
+ def arithmetic? ; @type.arithmetic? end
189
+ def integral? ; @type.integral? end
190
+ def signed? ; @type.signed? end # relevant only if integral? returns true
191
+ def float? ; @type.float? end
192
+ def void? ; @type.void? end
193
+ def untypedef ; @type.untypedef end
194
+ def align(parser) @type.align(parser) end # XXX __attribute__ ?
195
+ def pointed ; @type.pointed end
196
+ end
197
+ class Function < Type
198
+ attr_accessor :type # return type
199
+ attr_accessor :args # [name, Variable]
200
+ attr_accessor :varargs # true/false
201
+
202
+ def initialize(type=nil, args=nil)
203
+ @type = type
204
+ @args = args if args
205
+ end
206
+
207
+ def base ; @type.base ; end
208
+ end
209
+ class Union < Type
210
+ attr_accessor :members # [Variable]
211
+ attr_accessor :bits # [bits] or nil
212
+ attr_accessor :name
213
+ attr_accessor :backtrace
214
+
215
+ attr_accessor :fldoffset, :fldbitoffset, :fldlist
216
+
217
+ def align(parser) @members.to_a.map { |m| m.type.align(parser) }.max end
218
+
219
+ # there is only one instance of a given named struct per parser
220
+ # so we just compare struct names here
221
+ # for comparison between parsers, see #compare_deep
222
+ def ==(o)
223
+ o.object_id == self.object_id or
224
+ (o.class == self.class and o.name == self.name and ((o.name and true) or compare_deep(o)))
225
+ end
226
+
227
+ # compare to another structure, comparing members recursively (names and type)
228
+ # returns true if the self is same as o
229
+ def compare_deep(o, seen = [])
230
+ return true if o.object_id == self.object_id
231
+ return if o.class != self.class or o.name != self.name or o.attributes != self.attributes
232
+ o.members.to_a.zip(self.members.to_a).each { |om, sm|
233
+ return if om.name != sm.name
234
+ return if om.type != sm.type
235
+ if om.type.pointer?
236
+ ot = om.type
237
+ st = sm.type
238
+ 500.times { # limit for selfpointers (shouldnt happen)
239
+ break if not ot.pointer?
240
+ ot = ot.pointed.untypedef
241
+ st = st.pointed.untypedef
242
+ }
243
+ if ot.kind_of?(C::Union) and ot.name and not seen.include?(ot)
244
+ return if not st.compare_deep(ot, seen+[ot])
245
+ end
246
+ end
247
+ }
248
+ true
249
+ end
250
+
251
+ def findmember(name, igncase=false)
252
+ raise parser, 'undefined structure' if not @members
253
+ return @fldlist[name] if fldlist and @fldlist[name]
254
+
255
+ name = name.downcase if igncase
256
+ if m = @members.find { |m_| (n = m_.name) and (igncase ? n.downcase : n) == name }
257
+ return m
258
+ else
259
+ @members.each { |m_|
260
+ if t = m_.type.untypedef and t.kind_of? Union and mm = t.findmember(name, igncase)
261
+ return mm
262
+ end
263
+ }
264
+ end
265
+
266
+ nil
267
+ end
268
+
269
+ def offsetof(parser, name)
270
+ raise parser, 'undefined structure' if not @members
271
+ update_member_cache(parser) if not fldlist
272
+ return 0 if @fldlist[name]
273
+
274
+ if name.kind_of?(Variable)
275
+ return 0 if @members.include? name
276
+ raise ParseError, 'unknown union member'
277
+ end
278
+
279
+ raise parser, 'unknown union member' if not findmember(name)
280
+
281
+ @members.find { |m|
282
+ m.type.untypedef.kind_of? Union and m.type.untypedef.findmember(name)
283
+ }.type.untypedef.offsetof(parser, name)
284
+ end
285
+
286
+ def bitoffsetof(parser, name)
287
+ raise parser, 'undefined structure' if not @members
288
+ update_member_cache(parser) if not fldlist
289
+ return if @fldlist[name] or @members.include?(name)
290
+ raise parser, 'undefined union' if not @members
291
+ raise parser, 'unknown union member' if not findmember(name)
292
+
293
+ @members.find { |m|
294
+ m.type.untypedef.kind_of? Union and m.type.untypedef.findmember(name)
295
+ }.type.untypedef.bitoffsetof(parser, name)
296
+ end
297
+
298
+ def parse_members(parser, scope)
299
+ @fldlist = nil if fldlist # invalidate fld offset cache
300
+ @members = []
301
+ # parse struct/union members in definition
302
+ loop do
303
+ raise parser if not tok = parser.skipspaces
304
+ break if tok.type == :punct and tok.raw == '}'
305
+ parser.unreadtok tok
306
+
307
+ raise tok, 'invalid struct member type' if not basetype = Variable.parse_type(parser, scope)
308
+ loop do
309
+ member = basetype.dup
310
+ member.parse_declarator(parser, scope)
311
+ member.type.length ||= 0 if member.type.kind_of?(Array) # struct { char blarg[]; };
312
+ raise member.backtrace, 'member redefinition' if member.name and @members.find { |m| m.name == member.name }
313
+ @members << member
314
+
315
+ raise tok || parser if not tok = parser.skipspaces or tok.type != :punct
316
+
317
+ if tok.raw == ':' # bits
318
+ raise tok, 'bad type for bitslice' if not member.type.integral?
319
+ bits = nil
320
+ raise tok, "bad bit count #{bits.inspect}" if not bits = CExpression.parse(parser, scope, false) or
321
+ not bits.constant? or !(bits = bits.reduce(parser)).kind_of? ::Integer
322
+ #raise tok, 'need more bits' if bits > 8*parser.sizeof(member)
323
+ # WORD wReserved:17; => yay windows.h
324
+ (@bits ||= [])[@members.length-1] = bits
325
+ raise tok || parser, '"," or ";" expected' if not tok = parser.skipspaces or tok.type != :punct
326
+ end
327
+
328
+ case tok.raw
329
+ when ';'; break
330
+ when ','
331
+ when '}'; parser.unreadtok(tok); break
332
+ else raise tok, '"," or ";" expected'
333
+ end
334
+ end
335
+ end
336
+ parse_attributes(parser)
337
+ end
338
+
339
+ # updates the @fldoffset / @fldbitoffset hash storing the offset of members
340
+ def update_member_cache(parser)
341
+ @fldlist = {}
342
+ @members.to_a.each { |m|
343
+ @fldlist[m.name] = m if m.name
344
+ }
345
+ end
346
+
347
+ def parse_initializer(parser, scope)
348
+ if tok = parser.skipspaces and tok.type == :punct and tok.raw == '{'
349
+ # struct x toto = { 1, .4, .member[0][6].bla = 12 };
350
+ raise tok, 'undefined struct' if not @members
351
+ ret = []
352
+ if tok = parser.skipspaces and (tok.type != :punct or tok.raw != '}')
353
+ parser.unreadtok tok
354
+ idx = 0
355
+ loop do
356
+ idx = parse_initializer_designator(parser, scope, ret, idx, true)
357
+ raise tok || parser, '"," or "}" expected' if not tok = parser.skipspaces or tok.type != :punct or (tok.raw != '}' and tok.raw != ',')
358
+ break if tok.raw == '}'
359
+ raise tok, 'struct is smaller than that' if idx >= @members.length
360
+ end
361
+ end
362
+ ret
363
+ else
364
+ parser.unreadtok tok
365
+ super(parser, scope)
366
+ end
367
+ end
368
+
369
+ # parses a designator+initializer eg '.toto = 4' or '.tutu[42][12].bla = 16' or (root ? '4' : '=4')
370
+ def parse_initializer_designator(parser, scope, value, idx, root=true)
371
+ if nt = parser.skipspaces and nt.type == :punct and nt.raw == '.' and
372
+ nnt = parser.skipspaces and nnt.type == :string and
373
+ findmember(nnt.raw)
374
+ raise nnt, 'unhandled indirect initializer' if not nidx = @members.index(@members.find { |m| m.name == nnt.raw }) # TODO
375
+ if not root
376
+ value[idx] ||= [] # AryRecorder may change [] to AryRec.new, can't do v = v[i] ||= []
377
+ value = value[idx]
378
+ end
379
+ idx = nidx
380
+ @members[idx].type.untypedef.parse_initializer_designator(parser, scope, value, idx, false)
381
+ else
382
+ parser.unreadtok nnt
383
+ if root
384
+ parser.unreadtok nt
385
+ value[idx] = @members[idx].type.parse_initializer(parser, scope)
386
+ else
387
+ raise nt || parser, '"=" expected' if not nt or nt.type != :punct or nt.raw != '='
388
+ value[idx] = parse_initializer(parser, scope)
389
+ end
390
+ end
391
+ idx + 1
392
+ end
393
+ end
394
+ class Struct < Union
395
+ attr_accessor :pack
396
+
397
+ def align(parser) [@members.to_a.map { |m| m.type.align(parser) }.max || 1, (pack || 8)].min end
398
+
399
+ def offsetof(parser, name)
400
+ raise parser, 'undefined structure' if not @members
401
+ update_member_cache(parser) if not fldlist
402
+ return @fldoffset[name] if @fldoffset[name]
403
+
404
+ # this is almost never reached, only for <struct>.offsetof(anonymoussubstructmembername)
405
+ raise parser, 'unknown structure member' if (name.kind_of?(::String) ? !findmember(name) : !@members.include?(name))
406
+
407
+ indirect = true if name.kind_of?(::String) and not @fldlist[name]
408
+
409
+ al = align(parser)
410
+ off = 0
411
+ bit_off = 0
412
+ isz = nil
413
+
414
+ @members.each_with_index { |m, i|
415
+ if bits and b = @bits[i]
416
+ if not isz
417
+ mal = [m.type.align(parser), al].min
418
+ off = (off + mal - 1) / mal * mal
419
+ end
420
+ isz = parser.sizeof(m)
421
+ if b == 0 or (bit_off > 0 and bit_off + b > 8*isz)
422
+ bit_off = 0
423
+ mal = [m.type.align(parser), al].min
424
+ off = (off + isz + mal - 1) / mal * mal
425
+ end
426
+ break if m.name == name or m == name
427
+ bit_off += b
428
+ else
429
+ if isz
430
+ off += isz
431
+ bit_off = 0
432
+ isz = nil
433
+ end
434
+ mal = [m.type.align(parser), al].min
435
+ off = (off + mal - 1) / mal * mal
436
+ if m.name == name or m == name
437
+ break
438
+ elsif indirect and m.type.untypedef.kind_of? Union and m.type.untypedef.findmember(name)
439
+ off += m.type.untypedef.offsetof(parser, name)
440
+ break
441
+ else
442
+ off += parser.sizeof(m)
443
+ end
444
+ end
445
+ }
446
+ off
447
+ end
448
+
449
+ # returns the [bitoffset, bitlength] of the field if it is a bitfield
450
+ # this should be added to the offsetof(field)
451
+ def bitoffsetof(parser, name)
452
+ raise parser, 'undefined structure' if not @members
453
+ update_member_cache(parser) if not fldlist
454
+ return @fldbitoffset[name] if fldbitoffset and @fldbitoffset[name]
455
+ return if @fldlist[name] or @members.include?(name)
456
+ raise parser, 'undefined union' if not @members
457
+ raise parser, 'unknown union member' if not findmember(name)
458
+
459
+ @members.find { |m|
460
+ m.type.untypedef.kind_of? Union and m.type.untypedef.findmember(name)
461
+ }.type.untypedef.bitoffsetof(parser, name)
462
+ end
463
+
464
+ def parse_members(parser, scope)
465
+ super(parser, scope)
466
+
467
+ if has_attribute 'packed'
468
+ @pack = 1
469
+ elsif p = has_attribute_var('pack')
470
+ @pack = p[/\d+/].to_i
471
+ raise parser, "illegal struct pack(#{p})" if @pack == 0
472
+ end
473
+ end
474
+
475
+ # updates the @fldoffset / @fldbitoffset hash storing the offset of members
476
+ def update_member_cache(parser)
477
+ super(parser)
478
+
479
+ @fldoffset = {}
480
+ @fldbitoffset = {} if fldbitoffset
481
+
482
+ al = align(parser)
483
+ off = 0
484
+ bit_off = 0
485
+ isz = nil
486
+
487
+ @members.each_with_index { |m, i|
488
+ if bits and b = @bits[i]
489
+ if not isz
490
+ mal = [m.type.align(parser), al].min
491
+ off = (off + mal - 1) / mal * mal
492
+ end
493
+ isz = parser.sizeof(m)
494
+ if b == 0 or (bit_off > 0 and bit_off + b > 8*isz)
495
+ bit_off = 0
496
+ mal = [m.type.align(parser), al].min
497
+ off = (off + isz + mal - 1) / mal * mal
498
+ end
499
+ if m.name
500
+ @fldoffset[m.name] = off
501
+ @fldbitoffset ||= {}
502
+ @fldbitoffset[m.name] = [bit_off, b]
503
+ end
504
+ bit_off += b
505
+ else
506
+ if isz
507
+ off += isz
508
+ bit_off = 0
509
+ isz = nil
510
+ end
511
+ mal = [m.type.align(parser), al].min
512
+ off = (off + mal - 1) / mal * mal
513
+ @fldoffset[m.name] = off if m.name
514
+ off += parser.sizeof(m)
515
+ end
516
+ }
517
+ end
518
+ end
519
+ class Enum < Type
520
+ # name => value
521
+ attr_accessor :members
522
+ attr_accessor :name
523
+ attr_accessor :backtrace
524
+
525
+ def align(parser) BaseType.new(:int).align(parser) end
526
+
527
+ def arithmetic?; true end
528
+ def integral?; true end
529
+ def signed?; false end
530
+
531
+ def parse_members(parser, scope)
532
+ val = -1
533
+ @members = {}
534
+ loop do
535
+ raise parser if not tok = parser.skipspaces
536
+ break if tok.type == :punct and tok.raw == '}'
537
+
538
+ name = tok.raw
539
+ raise tok, 'bad enum name' if tok.type != :string or Keyword[name] or (?0..?9).include?(name[0])
540
+
541
+ raise parser if not tok = parser.skipspaces
542
+ if tok.type == :punct and tok.raw == '='
543
+ raise tok || parser if not val = CExpression.parse(parser, scope, false) or not val = val.reduce(parser) or not tok = parser.skipspaces
544
+ else
545
+ val += 1
546
+ end
547
+ raise tok, "enum value #{name} redefinition" if scope.symbol[name] and scope.symbol[name] != val
548
+ @members[name] = val
549
+ scope.symbol[name] = val
550
+
551
+ if tok.type == :punct and tok.raw == '}'
552
+ break
553
+ elsif tok.type == :punct and tok.raw == ','
554
+ else raise tok, '"," or "}" expected'
555
+ end
556
+ end
557
+ parse_attributes(parser)
558
+ end
559
+
560
+ end
561
+ class Pointer < Type
562
+ attr_accessor :type
563
+
564
+ def initialize(type=nil)
565
+ @type = type
566
+ end
567
+
568
+ def pointer? ; true ; end
569
+ def arithmetic? ; true ; end
570
+ def base ; @type.base ; end
571
+ def align(parser) BaseType.new(:ptr).align(parser) end
572
+ def pointed ; @type end
573
+
574
+ def ==(o)
575
+ o.class == self.class and o.type == self.type
576
+ end
577
+ end
578
+ class Array < Pointer
579
+ attr_accessor :length
580
+
581
+ def initialize(type=nil, length=nil)
582
+ super(type)
583
+ @length = length if length
584
+ end
585
+
586
+ def align(parser) @type.align(parser) end
587
+
588
+ def parse_initializer(parser, scope)
589
+ raise parser, 'cannot initialize dynamic array' if @length.kind_of? CExpression
590
+ if tok = parser.skipspaces and tok.type == :punct and tok.raw == '{'
591
+ # struct x foo[] = { { 4 }, [12].tutu = 2 };
592
+ ret = []
593
+ if tok = parser.skipspaces and (tok.type != :punct or tok.raw != '}')
594
+ parser.unreadtok tok
595
+ idx = 0
596
+ loop do
597
+ idx = parse_initializer_designator(parser, scope, ret, idx, true)
598
+ raise tok || parser, '"," or "}" expected' if not tok = parser.skipspaces or tok.type != :punct or (tok.raw != '}' and tok.raw != ',')
599
+ break if tok.raw == '}'
600
+ # allow int x[] = {1, 2, 3, };
601
+ break if tok = parser.skipspaces and tok.type == :punct and tok.raw == '}'
602
+ parser.unreadtok tok
603
+ raise tok, 'array is smaller than that' if length and idx >= @length
604
+ end
605
+ end
606
+ ret
607
+ else
608
+ parser.unreadtok tok
609
+ i = super(parser, scope)
610
+ if i.kind_of? CExpression and not i.op and i.rexpr.kind_of? String and @length and i.rexpr.length > @length
611
+ puts tok.exception("initializer is too long (#{i.rexpr.length} for #@length)").message if $VERBOSE
612
+ i.rexpr = i.rexpr[0, @length]
613
+ end
614
+ i
615
+ end
616
+ end
617
+
618
+ # this class is a hack to support [1 ... 4] array initializer
619
+ # it stores the effects of subsequent initializers (eg [1 ... 4].toto[48].bla[2 ... 57] = 12)
620
+ # which are later played back on the range
621
+ class AryRecorder
622
+ attr_accessor :log
623
+ def initialize
624
+ @log = []
625
+ end
626
+
627
+ def []=(idx, val)
628
+ val = self.class.new if val == []
629
+ @log[idx] = val
630
+ end
631
+
632
+ def [](idx)
633
+ @log[idx]
634
+ end
635
+
636
+ def playback_idx(i)
637
+ case v = @log[i]
638
+ when self.class; v.playback
639
+ else v
640
+ end
641
+ end
642
+
643
+ def playback(ary=[])
644
+ @log.each_with_index { |v, i| ary[i] = playback_idx(i) }
645
+ ary
646
+ end
647
+ end
648
+
649
+ # parses a designator+initializer eg '[12] = 4' or '[42].bla = 16' or '[3 ... 8] = 28'
650
+ def parse_initializer_designator(parser, scope, value, idx, root=true)
651
+ # root = true for 1st invocation (x = { 4 }) => immediate value allowed
652
+ # or false for recursive invocations (x = { .y = 4 }) => need '=' sign before immediate
653
+ if nt = parser.skipspaces and nt.type == :punct and nt.raw == '['
654
+ if not root
655
+ value[idx] ||= [] # AryRecorder may change [] to AryRec.new, can't do v = v[i] ||= []
656
+ value = value[idx]
657
+ end
658
+ raise nt, 'const expected' if not idx = CExpression.parse(parser, scope) or not idx.constant? or not idx = idx.reduce(parser) or not idx.kind_of? ::Integer
659
+ nt = parser.skipspaces
660
+ if nt and nt.type == :punct and nt.raw == '.' # range
661
+ raise nt || parser, '".." expected' if not nt = parser.skipspaces or nt.type != :punct or nt.raw != '.'
662
+ raise nt || parser, '"." expected' if not nt = parser.skipspaces or nt.type != :punct or nt.raw != '.'
663
+ raise nt, 'const expected' if not eidx = CExpression.parse(parser, scope) or not eidx.constant? or not eidx = eidx.reduce(parser) or not eidx.kind_of? ::Integer
664
+ raise nt, 'bad range' if eidx < idx
665
+ nt = parser.skipspaces
666
+ realvalue = value
667
+ value = AryRecorder.new
668
+ end
669
+ raise nt || parser, '"]" expected' if not nt or nt.type != :punct or nt.raw != ']'
670
+ raise nt, 'array is smaller than that' if length and (eidx||idx) >= @length
671
+ @type.untypedef.parse_initializer_designator(parser, scope, value, idx, false)
672
+ if eidx
673
+ (idx..eidx).each { |i| realvalue[i] = value.playback_idx(idx) }
674
+ idx = eidx # next default value = eidx+1 (eg int x[] = { [1 ... 3] = 4, 5 } => x[4] = 5)
675
+ end
676
+ else
677
+ if root
678
+ parser.unreadtok nt
679
+ value[idx] = @type.parse_initializer(parser, scope)
680
+ else
681
+ raise nt || parser, '"=" expected' if not nt or nt.type != :punct or nt.raw != '='
682
+ value[idx] = parse_initializer(parser, scope)
683
+ end
684
+ end
685
+ idx + 1
686
+ end
687
+ end
688
+
689
+ class Variable
690
+ include Attributes
691
+ include Typed
692
+
693
+ attr_accessor :type
694
+ attr_accessor :initializer # CExpr / Block (for Functions)
695
+ attr_accessor :name
696
+ attr_accessor :storage # auto register static extern typedef
697
+ attr_accessor :backtrace # definition backtrace info (the name token)
698
+
699
+ def initialize(name=nil, type=nil)
700
+ @name, @type = name, type
701
+ end
702
+ end
703
+
704
+ # found in a block's Statements, used to know the initialization order
705
+ # eg { int i; i = 4; struct foo { int k; } toto = {i}; }
706
+ class Declaration
707
+ attr_accessor :var
708
+ def initialize(var)
709
+ @var = var
710
+ end
711
+ end
712
+
713
+ class If < Statement
714
+ attr_accessor :test # expression
715
+ attr_accessor :bthen, :belse # statements
716
+ def initialize(test, bthen, belse=nil)
717
+ @test = test
718
+ @bthen = bthen
719
+ @belse = belse if belse
720
+ end
721
+
722
+ def self.parse(parser, scope, nest)
723
+ tok = nil
724
+ raise tok || self, '"(" expected' if not tok = parser.skipspaces or tok.type != :punct or tok.raw != '('
725
+ raise tok, 'expr expected' if not expr = CExpression.parse(parser, scope) or not expr.type.arithmetic?
726
+ raise tok || self, '")" expected' if not tok = parser.skipspaces or tok.type != :punct or tok.raw != ')'
727
+ bthen = parser.parse_statement scope, nest
728
+ if tok = parser.skipspaces and tok.type == :string and tok.raw == 'else'
729
+ belse = parser.parse_statement scope, nest
730
+ else
731
+ parser.unreadtok tok
732
+ end
733
+
734
+ new expr, bthen, belse
735
+ end
736
+ end
737
+ class For < Statement
738
+ attr_accessor :init, :test, :iter # CExpressions, init may be Block
739
+ attr_accessor :body
740
+ def initialize(init, test, iter, body)
741
+ @init, @test, @iter, @body = init, test, iter, body
742
+ end
743
+
744
+ def self.parse(parser, scope, nest)
745
+ tok = nil
746
+ raise tok || parser, '"(" expected' if not tok = parser.skipspaces or tok.type != :punct or tok.raw != '('
747
+ init = forscope = Block.new(scope)
748
+ if not parser.parse_definition(forscope)
749
+ forscope = scope
750
+ init = CExpression.parse(parser, forscope)
751
+ raise tok || parser, '";" expected' if not tok = parser.skipspaces or tok.type != :punct or tok.raw != ';'
752
+ end
753
+ test = CExpression.parse(parser, forscope)
754
+ raise tok || parser, '";" expected' if not tok = parser.skipspaces or tok.type != :punct or tok.raw != ';'
755
+ raise tok, 'bad test expression in for loop' if test and not test.type.arithmetic?
756
+ iter = CExpression.parse(parser, forscope)
757
+ raise tok || parser, '")" expected' if not tok = parser.skipspaces or tok.type != :punct or tok.raw != ')'
758
+
759
+ new init, test, iter, parser.parse_statement(forscope, nest + [:loop])
760
+ end
761
+ end
762
+ class While < Statement
763
+ attr_accessor :test
764
+ attr_accessor :body
765
+
766
+ def initialize(test, body)
767
+ @test = test
768
+ @body = body
769
+ end
770
+
771
+ def self.parse(parser, scope, nest)
772
+ tok = nil
773
+ raise tok || parser, '"(" expected' if not tok = parser.skipspaces or tok.type != :punct or tok.raw != '('
774
+ raise tok, 'expr expected' if not expr = CExpression.parse(parser, scope) or not expr.type.arithmetic?
775
+ raise tok || parser, '")" expected' if not tok = parser.skipspaces or tok.type != :punct or tok.raw != ')'
776
+
777
+ new expr, parser.parse_statement(scope, nest + [:loop])
778
+ end
779
+ end
780
+ class DoWhile < While
781
+ def self.parse(parser, scope, nest)
782
+ body = parser.parse_statement(scope, nest + [:loop])
783
+ tok = nil
784
+ raise tok || parser, '"while" expected' if not tok = parser.skipspaces or tok.type != :string or tok.raw != 'while'
785
+ raise tok || parser, '"(" expected' if not tok = parser.skipspaces or tok.type != :punct or tok.raw != '('
786
+ raise tok, 'expr expected' if not expr = CExpression.parse(parser, scope) or not expr.type.arithmetic?
787
+ raise tok || parser, '")" expected' if not tok = parser.skipspaces or tok.type != :punct or tok.raw != ')'
788
+ parser.checkstatementend(tok)
789
+
790
+ new expr, body
791
+ end
792
+ end
793
+ class Switch < Statement
794
+ attr_accessor :test, :body
795
+
796
+ def initialize(test, body)
797
+ @test = test
798
+ @body = body
799
+ end
800
+
801
+ def self.parse(parser, scope, nest)
802
+ raise tok || parser, '"(" expected' if not tok = parser.skipspaces or tok.type != :punct or tok.raw != '('
803
+ raise tok, 'expr expected' if not expr = CExpression.parse(parser, scope) or not expr.type.integral?
804
+ raise tok || parser, '")" expected' if not tok = parser.skipspaces or tok.type != :punct or tok.raw != ')'
805
+
806
+ new expr, parser.parse_statement(scope, nest + [:switch])
807
+ end
808
+ end
809
+
810
+ class Continue < Statement
811
+ end
812
+ class Break < Statement
813
+ end
814
+ class Goto < Statement
815
+ attr_accessor :target
816
+ def initialize(target)
817
+ @target = target
818
+ end
819
+ end
820
+ class Return < Statement
821
+ attr_accessor :value
822
+ def initialize(value)
823
+ @value = value
824
+ end
825
+ end
826
+ class Label < Statement
827
+ attr_accessor :name
828
+ attr_accessor :statement
829
+ def initialize(name, statement=nil)
830
+ @name, @statement = name, statement
831
+ end
832
+ end
833
+ class Case < Label
834
+ attr_accessor :expr, :exprup # exprup if range, expr may be 'default'
835
+ def initialize(expr, exprup, statement)
836
+ @expr, @statement = expr, statement
837
+ @exprup = exprup if exprup
838
+ end
839
+
840
+ def self.parse(parser, scope, nest)
841
+ raise parser, 'invalid case' if not expr = CExpression.parse(parser, scope) or not expr.constant? or not expr.type.integral?
842
+ raise tok || parser, '":" or "..." expected' if not tok = parser.skipspaces or tok.type != :punct or (tok.raw != ':' and tok.raw != '.')
843
+ if tok.raw == '.'
844
+ raise tok || parser, '".." expected' if not tok = parser.skipspaces or tok.type != :punct or tok.raw != '.'
845
+ raise tok || parser, '"." expected' if not tok = parser.skipspaces or tok.type != :punct or tok.raw != '.'
846
+ raise tok, 'invalid case range' if not exprup = CExpression.parse(parser, scope) or not exprup.constant? or not exprup.type.integral?
847
+ raise tok || parser, '":" expected' if not tok = parser.skipspaces or tok.type != :punct or tok.raw != ':'
848
+ end
849
+ body = parser.parse_statement scope, nest
850
+ new expr, exprup, body
851
+ end
852
+ end
853
+
854
+ # inline asm statement
855
+ class Asm < Statement
856
+ include Attributes
857
+ attr_accessor :body # asm source (::String)
858
+ attr_accessor :output, :input, :clobber # I/O, gcc-style (::Array)
859
+ attr_accessor :backtrace # body Token
860
+ attr_accessor :volatile
861
+
862
+ def initialize(body, backtrace, output=nil, input=nil, clobber=nil, volatile=nil)
863
+ @body, @backtrace, @output, @input, @clobber, @volatile = body, backtrace, output, input, clobber, volatile
864
+ end
865
+
866
+ def self.parse(parser, scope)
867
+ if tok = parser.skipspaces and tok.type == :string and (tok.raw == 'volatile' or tok.raw == '__volatile__')
868
+ volatile = true
869
+ tok = parser.skipspaces
870
+ end
871
+ if not tok or tok.type != :punct or tok.raw != '('
872
+ # detect MS-style inline asm: "__asm .* __asm .*" or "asm { [\s.]* }"
873
+ ftok = tok
874
+ body = ''
875
+ if tok.type == :punct and tok.raw == '{'
876
+ loop do
877
+ raise ftok, 'unterminated asm block' if not tok = parser.lexer.readtok
878
+ break if tok.type == :punct and tok.raw == '}'
879
+ case tok.type
880
+ when :space; body << ' '
881
+ when :eol; body << "\n"
882
+ when :punct; body << tok.raw
883
+ when :quoted; body << tok.value.inspect # concat adjacent c strings
884
+ when :string
885
+ body << \
886
+ case tok.raw
887
+ when 'asm', '__asm', '__asm__'; "\n"
888
+ when '_emit'; 'db'
889
+ else tok.raw
890
+ end
891
+ end
892
+ end
893
+ # allow shell-style heredoc: asm <<EOS\n<asm>\nEOS
894
+ elsif tok.type == :punct and tok.raw == '<'
895
+ raise ftok, 'bad asm heredoc' if not tok = parser.lexer.readtok or tok.type != :punct or tok.raw != '<'
896
+ delimiter = parser.lexer.readtok
897
+ if delimiter.type == :punct and delimiter.raw == '-'
898
+ skipspc = true
899
+ delimiter = parser.lexer.readtok
900
+ end
901
+ raise ftok, 'bad asm heredoc delim' if delimiter.type != :string or not tok = parser.lexer.readtok or tok.type != :eol
902
+ nl = true
903
+ loop do
904
+ raise ftok, 'unterminated heredoc' if not tok = parser.lexer.readtok
905
+ break if nl and tok.raw == delimiter.raw
906
+ raw = tok.raw
907
+ raw = "\n" if skipspc and tok.type == :eol
908
+ body << raw
909
+ nl = (tok.type == :eol and (raw[-1] == ?\n or raw[-1] == ?\r))
910
+ end
911
+ # MS single-instr: asm inc eax;
912
+ # also allow asm "foo bar\nbaz";
913
+ else
914
+ parser.lexer.unreadtok tok
915
+ loop do
916
+ break if not tok = parser.lexer.readtok or tok.type == :eol
917
+ case tok.type
918
+ when :space; body << ' '
919
+ when :punct
920
+ case tok.raw
921
+ when '}'
922
+ parser.lexer.unreadtok tok
923
+ break
924
+ else body << tok.raw
925
+ end
926
+ when :quoted; body << (body.empty? ? tok.value : tok.value.inspect) # asm "pop\nret" VS asm add al, 'z'
927
+ when :string
928
+ body << \
929
+ case tok.raw
930
+ when 'asm', '__asm', '__asm__'; "\n"
931
+ when '_emit'; 'db'
932
+ else tok.raw
933
+ end
934
+ end
935
+ end
936
+ end
937
+ return new(body, ftok, nil, nil, nil, volatile)
938
+ end
939
+ raise tok || parser, '"(" expected' if not tok or tok.type != :punct or tok.raw != '('
940
+ raise tok || parser, 'qstring expected' if not tok = parser.skipspaces or tok.type != :quoted
941
+ body = tok
942
+ ret = new body.value, body
943
+ tok = parser.skipspaces
944
+ raise tok || parser, '":" or ")" expected' if not tok or tok.type != :punct or (tok.raw != ':' and tok.raw != ')')
945
+
946
+ if tok.raw == ':'
947
+ ret.output = []
948
+ raise parser if not tok = parser.skipspaces
949
+ while tok.type == :quoted
950
+ type = tok.value
951
+ raise tok, 'expr expected' if not var = CExpression.parse_value(parser, scope)
952
+ ret.output << [type, var]
953
+ raise tok || parser, '":" or "," or ")" expected' if not tok = parser.skipspaces or tok.type != :punct or (tok.raw != ',' and tok.raw != ')' and tok.raw != ':')
954
+ break if tok.raw == ':' or tok.raw == ')'
955
+ raise tok || parser, 'qstring expected' if not tok = parser.skipspaces or tok.type != :quoted
956
+ end
957
+ end
958
+ if tok.raw == ':'
959
+ ret.input = []
960
+ raise parser if not tok = parser.skipspaces
961
+ while tok.type == :quoted
962
+ type = tok.value
963
+ raise tok, 'expr expected' if not var = CExpression.parse_value(parser, scope)
964
+ ret.input << [type, var]
965
+ raise tok || parser, '":" or "," or ")" expected' if not tok = parser.skipspaces or tok.type != :punct or (tok.raw != ',' and tok.raw != ')' and tok.raw != ':')
966
+ break if tok.raw == ':' or tok.raw == ')'
967
+ raise tok || parser, 'qstring expected' if not tok = parser.skipspaces or tok.type != :quoted
968
+ end
969
+ end
970
+ if tok.raw == ':'
971
+ ret.clobber = []
972
+ raise parser if not tok = parser.skipspaces
973
+ while tok.type == :quoted
974
+ ret.clobber << tok.value
975
+ raise tok || parser, '"," or ")" expected' if not tok = parser.skipspaces or tok.type != :punct or (tok.raw != ',' and tok.raw != ')')
976
+ break if tok.raw == ')'
977
+ raise tok || parser, 'qstring expected' if not tok = parser.skipspaces or tok.type != :quoted
978
+ end
979
+ end
980
+ raise tok || parser, '")" expected' if not tok or tok.type != :punct or tok.raw != ')'
981
+ ret.parse_attributes(parser)
982
+ parser.checkstatementend(tok)
983
+ ret
984
+ end
985
+ end
986
+
987
+ class CExpression < Statement
988
+ include Typed
989
+
990
+ # may be :,, :., :'->', :funcall (function, [arglist]), :[] (array indexing), nil (cast)
991
+ attr_accessor :op
992
+ # nil/CExpr/Variable/Label/::String( = :quoted/struct member name)/::Integer/::Float/Block
993
+ attr_accessor :lexpr, :rexpr
994
+ # a Type
995
+ attr_accessor :type
996
+ def initialize(l, o, r, t)
997
+ raise "invalid CExpr #{[l, o, r, t].inspect}" if (o and not o.kind_of? ::Symbol) or not t.kind_of? Type
998
+ @lexpr, @op, @rexpr, @type = l, o, r, t
999
+ end
1000
+
1001
+ # overwrites @lexpr @op @rexpr @type from the arg
1002
+ def replace(o)
1003
+ @lexpr, @op, @rexpr, @type = o.lexpr, o.op, o.rexpr, o.type
1004
+ self
1005
+ end
1006
+
1007
+ # deep copy of the object
1008
+ # recurses only within CExpressions, anything else is copied by reference
1009
+ def deep_dup
1010
+ n = dup
1011
+ n.lexpr = n.lexpr.deep_dup if n.lexpr.kind_of? CExpression
1012
+ n.rexpr = n.rexpr.deep_dup if n.rexpr.kind_of? CExpression
1013
+ n.rexpr = n.rexpr.map { |e| e.kind_of?(CExpression) ? e.deep_dup : e } if n.rexpr.kind_of? ::Array
1014
+ n
1015
+ end
1016
+
1017
+ # recursive constructor with automatic type inference
1018
+ # e.g. CExpression[foo, :+, [:*, bar]]
1019
+ # assumes root args are correctly typed (eg *foo => foo must be a pointer)
1020
+ # take care to use [int] with immediates, e.g. CExpression[foo, :+, [2]]
1021
+ # CExpr[some_cexpr] returns some_cexpr
1022
+ def self.[](*args)
1023
+ # sub-arrays in args are to be passed to self.[] recursively (syntaxic sugar)
1024
+ splat = lambda { |e| e.kind_of?(::Array) ? self[*e] : e }
1025
+
1026
+ args.shift while args.first == nil # CExpr[nil, :&, bla] => CExpr[:&, bla]
1027
+
1028
+ case args.length
1029
+ when 4
1030
+ op = args[1]
1031
+ if op == :funcall or op == :'?:'
1032
+ x2 = args[2].map { |a| splat[a] } if args[2]
1033
+ else
1034
+ x2 = splat[args[2]]
1035
+ end
1036
+ new(splat[args[0]], op, x2, args[3])
1037
+ when 3
1038
+ op = args[1]
1039
+ x1 = splat[args[0]]
1040
+ if op == :funcall or op == :'?:'
1041
+ x2 = args[2].map { |a| splat[a] } if args[2]
1042
+ else
1043
+ x2 = splat[args[2]]
1044
+ end
1045
+
1046
+ case op
1047
+ when :funcall
1048
+ rt = x1.type.untypedef
1049
+ rt = rt.type.untypedef if rt.pointer?
1050
+ new(x1, op, x2, rt.type)
1051
+ when :[]; new(x1, op, x2, x1.type.untypedef.type)
1052
+ when :+; new(x1, op, x2, (x2.type.pointer? ? x2.type : x1.type))
1053
+ when :-; new(x1, op, x2, ((x1.type.pointer? and x2.type.pointer?) ? BaseType.new(:int) : x2.type.pointer? ? x2.type : x1.type))
1054
+ when :'&&', :'||', :==, :'!=', :>, :<, :<=, :>=; new(x1, op, x2, BaseType.new(:int))
1055
+ when :'.', :'->'
1056
+ t = x1.type.untypedef
1057
+ t = t.type.untypedef if op == :'->' and x1.type.pointer?
1058
+ raise "parse error: #{t} has no member #{x2}" if not t.kind_of? Union or not m = t.findmember(x2)
1059
+ new(x1, op, x2, m.type)
1060
+ when :'?:'; new(x1, op, x2, x2[0].type)
1061
+ when :','; new(x1, op, x2, x2.type)
1062
+ else new(x1, op, x2, x1.type)
1063
+ end
1064
+ when 2
1065
+ x0 = splat[args[0]]
1066
+ x1 = splat[args[1]]
1067
+ x0, x1 = x1, x0 if x0.kind_of? Type
1068
+ if x1.kind_of? Type; new(nil, nil, x0, x1) # (cast)r
1069
+ elsif x0 == :*; new(nil, x0, x1, x1.type.untypedef.type) # *r
1070
+ elsif x0 == :& and x1.kind_of? CExpression and x1.type.kind_of? C::Array; new(nil, nil, x1, Pointer.new(x1.type.type))
1071
+ elsif x0 == :&; new(nil, x0, x1, Pointer.new(x1.type)) # &r
1072
+ elsif x0 == :'!'; new(nil, x0, x1, BaseType.new(:int)) # &r
1073
+ elsif x1.kind_of? ::Symbol; new(x0, x1, nil, x0.type) # l++
1074
+ else new(nil, x0, x1, x1.type) # +r
1075
+ end
1076
+ when 1
1077
+ x = splat[args[0]]
1078
+ case x
1079
+ when CExpression; x
1080
+ when ::Integer; new(nil, nil, x, BaseType.new(:int)) # XXX range => __int64 ?
1081
+ when ::Float; new(nil, nil, x, BaseType.new(:double))
1082
+ when ::String; new(nil, nil, x, Pointer.new(BaseType.new(:char)))
1083
+ else new(nil, nil, x, x.type)
1084
+ end
1085
+ else raise "parse error CExpr[*#{args.inspect}]"
1086
+ end
1087
+ end
1088
+ end
1089
+
1090
+
1091
+ class Parser
1092
+ # creates a new CParser, parses all top-level statements
1093
+ def self.parse(text)
1094
+ new.parse text
1095
+ end
1096
+
1097
+ # parses the current lexer content (or the text arg) for toplevel definitions
1098
+ def parse(text=nil, filename='<unk>', lineno=1)
1099
+ @lexer.feed text, filename, lineno if text
1100
+ nil while not @lexer.eos? and (parse_definition(@toplevel) or parse_toplevel_statement(@toplevel))
1101
+ raise @lexer.readtok || self, 'invalid definition' if not @lexer.eos?
1102
+ sanity_checks
1103
+ self
1104
+ end
1105
+
1106
+ # parses a C file
1107
+ def parse_file(file)
1108
+ parse(File.read(file), file)
1109
+ end
1110
+
1111
+ attr_accessor :lexer, :toplevel, :typesize, :pragma_pack
1112
+ attr_accessor :endianness
1113
+ attr_accessor :allow_bad_c
1114
+ # allowed arguments: ExeFormat, CPU, Preprocessor, Symbol (for the data model)
1115
+ def initialize(*args)
1116
+ model = args.grep(Symbol).first || :ilp32
1117
+ lexer = args.grep(Preprocessor).first || Preprocessor.new
1118
+ exe = args.grep(ExeFormat).first
1119
+ cpu = args.grep(CPU).first
1120
+ cpu ||= exe.cpu if exe
1121
+ @lexer = lexer
1122
+ @prev_pragma_callback = @lexer.pragma_callback
1123
+ @lexer.pragma_callback = lambda { |tok| parse_pragma_callback(tok) }
1124
+ @toplevel = Block.new(nil)
1125
+ @unreadtoks = []
1126
+ @endianness = cpu ? cpu.endianness : :big
1127
+ @typesize = { :void => 1, :__int8 => 1, :__int16 => 2, :__int32 => 4, :__int64 => 8,
1128
+ :char => 1, :float => 4, :double => 8, :longdouble => 12 }
1129
+ send model
1130
+ cpu.tune_cparser(self) if cpu
1131
+ exe.tune_cparser(self) if exe
1132
+ end
1133
+
1134
+ def ilp16
1135
+ @typesize.update :short => 2, :ptr => 2,
1136
+ :int => 2, :long => 4, :longlong => 4
1137
+ end
1138
+
1139
+ def lp32
1140
+ @typesize.update :short => 2, :ptr => 4,
1141
+ :int => 2, :long => 4, :longlong => 8
1142
+ end
1143
+ def ilp32
1144
+ @typesize.update :short => 2, :ptr => 4,
1145
+ :int => 4, :long => 4, :longlong => 8
1146
+ end
1147
+
1148
+ def llp64
1149
+ @typesize.update :short => 2, :ptr => 8,
1150
+ :int => 4, :long => 4, :longlong => 8
1151
+ end
1152
+ def lp64
1153
+ @typesize.update :short => 2, :ptr => 8,
1154
+ :int => 4, :long => 8, :longlong => 8
1155
+ end
1156
+ def ilp64
1157
+ @typesize.update :short => 2, :ptr => 8,
1158
+ :int => 8, :long => 8, :longlong => 8
1159
+ end
1160
+
1161
+ def parse_pragma_callback(otok)
1162
+ case otok.raw
1163
+ when 'pack'
1164
+ nil while lp = @lexer.readtok and lp.type == :space
1165
+ nil while rp = @lexer.readtok and rp.type == :space
1166
+ if not rp or rp.type != :punct or rp.raw != ')'
1167
+ v1 = rp
1168
+ nil while rp = @lexer.readtok and rp.type == :space
1169
+ end
1170
+ if rp and rp.type == :punct and rp.raw == ','
1171
+ nil while v2 = @lexer.readtok and v2.type == :space
1172
+ nil while rp = @lexer.readtok and rp.type == :space
1173
+ end
1174
+ raise otok if not rp or lp.type != :punct or rp.type != :punct or lp.raw != '(' or rp.raw != ')'
1175
+ raise otok if (v1 and v1.type != :string) or (v2 and (v2.type != :string or v2.raw =~ /[^\d]/))
1176
+ if not v1
1177
+ @pragma_pack = nil
1178
+ elsif v1.raw == 'push'
1179
+ @pragma_pack_stack ||= []
1180
+ @pragma_pack_stack << pragma_pack
1181
+ @pragma_pack = v2.raw.to_i if v2
1182
+ raise v2, 'bad pack value' if pragma_pack == 0
1183
+ elsif v1.raw == 'pop'
1184
+ @pragma_pack_stack ||= []
1185
+ raise v1, 'pack stack empty' if @pragma_pack_stack.empty?
1186
+ @pragma_pack = @pragma_pack_stack.pop
1187
+ @pragma_pack = v2.raw.to_i if v2 and v2.raw # #pragma pack(pop, 4) => pop stack, but use 4 as pack value (imho)
1188
+ raise v2, 'bad pack value' if @pragma_pack == 0
1189
+ elsif v1.raw =~ /^\d+$/
1190
+ raise v2, '2nd arg unexpected' if v2
1191
+ @pragma_pack = v1.raw.to_i
1192
+ raise v1, 'bad pack value' if @pragma_pack == 0
1193
+ else raise otok
1194
+ end
1195
+ # the caller checks for :eol
1196
+ when 'warning'
1197
+ if $DEBUG
1198
+ @prev_pragma_callback[otok]
1199
+ else
1200
+ # silent discard
1201
+ nil while tok = @lexer.readtok_nopp and tok.type != :eol
1202
+ @lexer.unreadtok tok
1203
+ end
1204
+ when 'prepare_visualstudio'
1205
+ prepare_visualstudio
1206
+ when 'prepare_gcc'
1207
+ prepare_gcc
1208
+ when 'data_model' # XXX use carefully, should be the very first thing parsed
1209
+ nil while lp = @lexer.readtok and lp.type == :space
1210
+ if lp.type != :string or lp.raw !~ /^s?[il]?lp(16|32|64)$/ or not respond_to? lp.raw
1211
+ raise lp, "invalid data model (use lp32/lp64/llp64/ilp64)"
1212
+ else
1213
+ send lp.raw
1214
+ end
1215
+ else @prev_pragma_callback[otok]
1216
+ end
1217
+ end
1218
+
1219
+ def prepare_visualstudio
1220
+ @lexer.define_weak('_WIN32')
1221
+ @lexer.define_weak('_WIN32_WINNT', 0x500)
1222
+ @lexer.define_weak('_INTEGRAL_MAX_BITS', 64)
1223
+ @lexer.define_weak('__w64')
1224
+ @lexer.define_weak('_cdecl', '__cdecl') # typo ? seen in winreg.h
1225
+ @lexer.define_weak('_fastcall', '__fastcall') # typo ? seen in ntddk.h
1226
+ @lexer.define_weak('_MSC_VER', 1300) # handle '#pragma once' and _declspec(noreturn)
1227
+ @lexer.define_weak('__forceinline', '__inline')
1228
+ @lexer.define_weak('__ptr32') # needed with msc_ver 1300, don't understand their use
1229
+ @lexer.define_weak('__ptr64')
1230
+ end
1231
+
1232
+ def prepare_gcc
1233
+ @lexer.define_weak('__GNUC__', 2) # otherwise __attribute__ is defined to void..
1234
+ @lexer.define_weak('__STDC__')
1235
+ @lexer.define_weak('__const', 'const')
1236
+ @lexer.define_weak('__signed', 'signed')
1237
+ @lexer.define_weak('__signed__', 'signed')
1238
+ @lexer.define_weak('__volatile', 'volatile')
1239
+ if not @lexer.definition['__builtin_constant_p']
1240
+ # magic macro to check if its arg is an immediate value
1241
+ @lexer.define_weak('__builtin_constant_p', '0')
1242
+ @lexer.definition['__builtin_constant_p'].args = [Preprocessor::Token.new([])]
1243
+ end
1244
+ @lexer.nodefine_strong('alloca') # TODO __builtin_alloca
1245
+ @lexer.hooked_include['stddef.h'] = <<EOH
1246
+ /* simplified, define all at first invocation. may break things... */
1247
+ #undef __need_ptrdiff_t
1248
+ #undef __need_size_t
1249
+ #undef __need_wint_t
1250
+ #undef __need_wchar_t
1251
+ #undef __need_NULL
1252
+ #undef NULL
1253
+ #if !defined (_STDDEF_H)
1254
+ #define _STDDEF_H
1255
+ #define __PTRDIFF_TYPE__ long int
1256
+ typedef __PTRDIFF_TYPE__ ptrdiff_t;
1257
+ #define __SIZE_TYPE__ long unsigned int
1258
+ typedef __SIZE_TYPE__ size_t;
1259
+ #define __WINT_TYPE__ unsigned int
1260
+ typedef __WINT_TYPE__ wint_t;
1261
+ #define __WCHAR_TYPE__ int
1262
+ typedef __WCHAR_TYPE__ wchar_t;
1263
+ #define NULL 0
1264
+ #define offsetof(TYPE, MEMBER) __builtin_offsetof (TYPE, MEMBER)
1265
+ #endif
1266
+ EOH
1267
+ # TODO va_args
1268
+ @lexer.hooked_include['stdarg.h'] = <<EOH
1269
+ // TODO
1270
+ typedef void* __gnuc_va_list;
1271
+ /*
1272
+ typedef void* va_list;
1273
+ #define va_start(v, l)
1274
+ #define va_end(v)
1275
+ #define va_arg(v, l)
1276
+ #define va_copy(d, s)
1277
+ */
1278
+ EOH
1279
+ @lexer.hooked_include['limits.h'] = <<EOH
1280
+ #define CHAR_BIT 8
1281
+ #define SCHAR_MIN (-128)
1282
+ #define SCHAR_MAX 127
1283
+ #define UCHAR_MAX 255
1284
+ #ifdef __CHAR_UNSIGNED__
1285
+ # define CHAR_MIN 0
1286
+ # define CHAR_MAX UCHAR_MAX
1287
+ #else
1288
+ # define CHAR_MIN SCHAR_MIN
1289
+ # define CHAR_MAX SCHAR_MAX
1290
+ #endif
1291
+ #define UINT_MAX #{(1 << (8*@typesize[:int]))-1}U
1292
+ #define INT_MAX (UINT_MAX >> 1)
1293
+ #define INT_MIN (-INT_MAX - 1)
1294
+ #define ULONG_MAX #{(1 << (8*@typesize[:long]))-1}UL
1295
+ #define LONG_MAX (ULONG_MAX >> 1L)
1296
+ #define LONG_MIN (-LONG_MAX - 1L)
1297
+ EOH
1298
+ end
1299
+
1300
+ # C sanity checks
1301
+ def sanity_checks
1302
+ return if not $VERBOSE
1303
+ # TODO
1304
+ end
1305
+
1306
+ # checks that the types are compatible (variable predeclaration, function argument..)
1307
+ # strict = false for func call/assignment (eg char compatible with int -- but int is incompatible with char)
1308
+ # output warnings only
1309
+ def check_compatible_type(tok, oldtype, newtype, strict = false, checked = [])
1310
+ return if not $VERBOSE
1311
+ oldtype = oldtype.untypedef
1312
+ newtype = newtype.untypedef
1313
+ oldtype = BaseType.new(:int) if oldtype.kind_of? Enum
1314
+ newtype = BaseType.new(:int) if newtype.kind_of? Enum
1315
+
1316
+ puts tok.exception('type qualifier mismatch').message if oldtype.qualifier.to_a.uniq.length > newtype.qualifier.to_a.uniq.length
1317
+
1318
+ # avoid infinite recursion
1319
+ return if checked.include? oldtype
1320
+ checked = checked + [oldtype]
1321
+
1322
+ begin
1323
+ case newtype
1324
+ when Function
1325
+ raise tok, 'type error' if not oldtype.kind_of? Function
1326
+ check_compatible_type tok, oldtype.type, newtype.type, strict, checked
1327
+ if oldtype.args and newtype.args
1328
+ if oldtype.args.length != newtype.args.length or
1329
+ oldtype.varargs != newtype.varargs
1330
+ raise tok, 'type error'
1331
+ end
1332
+ oldtype.args.zip(newtype.args) { |oa, na|
1333
+ # begin ; rescue ParseError: raise $!.message + "in parameter #{oa.name}" end
1334
+ check_compatible_type tok, oa.type, na.type, strict, checked
1335
+ }
1336
+ end
1337
+ when Pointer
1338
+ if oldtype.kind_of? BaseType and oldtype.integral?
1339
+ puts tok.exception('making pointer from integer without a cast').message
1340
+ return
1341
+ end
1342
+ raise tok, 'type error' if not oldtype.kind_of? Pointer
1343
+ hasvoid = true if (t = newtype.type.untypedef).kind_of? BaseType and t.name == :void
1344
+ hasvoid = true if (t = oldtype.type.untypedef).kind_of? BaseType and t.name == :void # struct foo *f = NULL;
1345
+ if strict and not hasvoid
1346
+ check_compatible_type tok, oldtype.type, newtype.type, strict, checked
1347
+ end
1348
+ when Union
1349
+ raise tok, 'type error' if not oldtype.class == newtype.class
1350
+ if oldtype.members and newtype.members
1351
+ if oldtype.members.length != newtype.members.length
1352
+ raise tok, 'bad member count'
1353
+ end
1354
+ oldtype.members.zip(newtype.members) { |om, nm|
1355
+ # raise tok if om.name and nm.name and om.name != nm.name # don't care
1356
+ check_compatible_type tok, om.type, nm.type, strict, checked
1357
+ }
1358
+ end
1359
+ when BaseType
1360
+ raise tok, 'type error' if not oldtype.kind_of? BaseType
1361
+ if strict
1362
+ if oldtype.name != newtype.name or
1363
+ oldtype.specifier != newtype.specifier
1364
+ raise tok, 'type error'
1365
+ end
1366
+ else
1367
+ raise tok, 'type error' if @typesize[newtype.name] == 0 and @typesize[oldtype.name] > 0
1368
+ puts tok.exception('type size mismatch, may lose bits').message if @typesize[oldtype.name] > @typesize[newtype.name]
1369
+ puts tok.exception('sign mismatch').message if oldtype.specifier != newtype.specifier and @typesize[newtype.name] == @typesize[oldtype.name]
1370
+ end
1371
+ end
1372
+ rescue ParseError
1373
+ raise $! if checked.length != 1 # bubble up
1374
+ oname = (oldtype.to_s rescue oldtype.class.name)
1375
+ nname = (newtype.to_s rescue newtype.class.name)
1376
+ puts $!.message + " incompatible type #{oname} to #{nname}"
1377
+ end
1378
+ end
1379
+
1380
+ # allows 'raise self'
1381
+ def exception(msg='EOF unexpected')
1382
+ @lexer.exception msg
1383
+ end
1384
+
1385
+ # reads a token, convert 'L"foo"' to a :quoted
1386
+ def readtok_longstr
1387
+ if t = @lexer.readtok and t.type == :string and t.raw == 'L' and
1388
+ nt = @lexer.readtok and nt.type == :quoted and nt.raw[0] == ?"
1389
+ nt.raw[0, 0] = 'L'
1390
+ nt
1391
+ elsif t and t.type == :punct and t.raw == '/' and
1392
+ # nt has not been read
1393
+ nt = @lexer.readtok and nt.type == :punct and nt.raw == '/'
1394
+ # windows.h has a #define some_type_name /##/, and VS interprets this as a comment..
1395
+ puts @lexer.exception('#defined //').message if $VERBOSE
1396
+ t = @lexer.readtok while t and t.type != :eol
1397
+ t
1398
+ else
1399
+ @lexer.unreadtok nt
1400
+ t
1401
+ end
1402
+ end
1403
+ private :readtok_longstr
1404
+
1405
+ # reads a token from self.lexer
1406
+ # concatenates strings, merges spaces/eol to ' ', handles wchar strings, allows $@_ in :string
1407
+ def readtok
1408
+ if not t = @unreadtoks.pop
1409
+ return if not t = readtok_longstr
1410
+ case t.type
1411
+ when :space, :eol
1412
+ # merge consecutive :space/:eol
1413
+ t = t.dup
1414
+ t.type = :space
1415
+ t.raw = ' '
1416
+ nil while nt = @lexer.readtok and (nt.type == :eol or nt.type == :space)
1417
+ @lexer.unreadtok nt
1418
+
1419
+ when :quoted
1420
+ # merge consecutive :quoted
1421
+ t = t.dup
1422
+ while nt = readtok_longstr
1423
+ case nt.type
1424
+ when :quoted
1425
+ if t.raw[0] == ?" and nt.raw[0, 2] == 'L"'
1426
+ # ensure wide prefix is set
1427
+ t.raw[0, 0] = 'L'
1428
+ end
1429
+ t.raw << ' ' << nt.raw
1430
+ t.value << nt.value
1431
+ when :space, :eol
1432
+ else break
1433
+ end
1434
+ end
1435
+ @lexer.unreadtok nt
1436
+ else
1437
+ if (t.type == :punct and (t.raw == '_' or t.raw == '@' or t.raw == '$')) or t.type == :string
1438
+ t = t.dup
1439
+ t.type = :string
1440
+ nt = nil
1441
+ t.raw << nt.raw while nt = @lexer.readtok and ((nt.type == :punct and (nt.raw == '_' or nt.raw == '@' or nt.raw == '$')) or nt.type == :string)
1442
+ @lexer.unreadtok nt
1443
+ end
1444
+ end
1445
+ end
1446
+ t
1447
+ end
1448
+
1449
+ def eos?
1450
+ @unreadtoks.empty? and @lexer.eos?
1451
+ end
1452
+
1453
+ def unreadtok(tok)
1454
+ @unreadtoks << tok if tok
1455
+ end
1456
+
1457
+ # returns the next non-space/non-eol token
1458
+ def skipspaces
1459
+ nil while t = readtok and t.type == :space
1460
+ t
1461
+ end
1462
+
1463
+ # checks that we are at the end of a statement, ie an ';' character (consumed), or a '}' (not consumed)
1464
+ # otherwise, raise either the given token or self.
1465
+ def checkstatementend(tok=nil)
1466
+ raise tok || self, '";" expected' if not tok = skipspaces or tok.type != :punct or (tok.raw != ';' and tok.raw != '}')
1467
+ unreadtok tok if tok.raw == '}'
1468
+ end
1469
+
1470
+ # returns the size of a type in bytes
1471
+ def sizeof(var, type=nil)
1472
+ var, type = nil, var if var.kind_of? Type and not type
1473
+ type ||= var.type
1474
+ # XXX double-check class apparition order ('when' checks inheritance)
1475
+ case type
1476
+ when Array
1477
+ case type.length
1478
+ when nil
1479
+ if var.kind_of? CExpression and not var.lexpr and not var.op and var.rexpr.kind_of? Variable
1480
+ var = var.rexpr
1481
+ end
1482
+ raise self, 'unknown array size' if not var.kind_of? Variable or not var.initializer
1483
+ init = var.initializer
1484
+ init = init.rexpr if init.kind_of? C::CExpression and not init.op and init.rexpr.kind_of? ::String
1485
+ case init
1486
+ when ::String; sizeof(nil, type.type) * (init.length + 1)
1487
+ when ::Array
1488
+ v = init.compact.first
1489
+ v ? (sizeof(nil, type.type) * init.length) : 0
1490
+ else sizeof(init)
1491
+ end
1492
+ when ::Integer; type.length * sizeof(type.type)
1493
+ when CExpression
1494
+ len = type.length.reduce(self)
1495
+ raise self, 'unknown array size' if not len.kind_of? ::Integer
1496
+ len * sizeof(type)
1497
+ else raise self, 'unknown array size'
1498
+ end
1499
+ when Pointer
1500
+ if var.kind_of? CExpression and not var.op and var.rexpr.kind_of? ::String
1501
+ # sizeof("lolz") => 5
1502
+ sizeof(nil, type.type) * (var.rexpr.length + 1)
1503
+ else
1504
+ @typesize[:ptr]
1505
+ end
1506
+ when Function
1507
+ # raise
1508
+ 1 # gcc
1509
+ when BaseType
1510
+ @typesize[type.name]
1511
+ when Enum
1512
+ @typesize[:int]
1513
+ when Struct
1514
+ raise self, "unknown structure size #{type.name}" if not type.members
1515
+ al = type.align(self)
1516
+ lm = type.members.last
1517
+ lm ? (type.offsetof(self, lm) + sizeof(lm) + al - 1) / al * al : 0
1518
+ when Union
1519
+ raise self, "unknown structure size #{type.name}" if not type.members
1520
+ type.members.map { |m| sizeof(m) }.max || 0
1521
+ when TypeDef
1522
+ sizeof(var, type.type)
1523
+ end
1524
+ end
1525
+
1526
+ # parses variable/function definition/declaration/initialization
1527
+ # populates scope.symbols and scope.struct
1528
+ # raises on redefinitions
1529
+ # returns false if no definition found
1530
+ def parse_definition(scope)
1531
+ return false if not basetype = Variable.parse_type(self, scope, true)
1532
+
1533
+ # check struct predeclaration
1534
+ tok = skipspaces
1535
+ if tok and tok.type == :punct and tok.raw == ';' and basetype.type and
1536
+ (basetype.type.kind_of? Union or basetype.type.kind_of? Enum)
1537
+ return true
1538
+ else unreadtok tok
1539
+ end
1540
+
1541
+ nofunc = false
1542
+ loop do
1543
+ var = basetype.dup
1544
+ var.parse_declarator(self, scope)
1545
+
1546
+ raise var.backtrace if not var.name # barrel roll
1547
+
1548
+ if prev = scope.symbol[var.name]
1549
+ if prev.kind_of? TypeDef and var.storage == :typedef
1550
+ check_compatible_type(var.backtrace, prev.type, var.type, true)
1551
+ # windows.h redefines many typedefs with the same definition
1552
+ puts "redefining typedef #{var.name}" if $VERBOSE
1553
+ var = prev
1554
+ elsif not prev.kind_of?(Variable) or
1555
+ prev.initializer or
1556
+ (prev.storage != :extern and prev.storage != var.storage) or
1557
+ (scope != @toplevel and prev.storage != :static)
1558
+ if prev.kind_of? ::Integer # enum value
1559
+ prev = (scope.struct.values.grep(Enum) + scope.anonymous_enums.to_a).find { |e| e.members.index(prev) }
1560
+ end
1561
+ raise var.backtrace, "redefinition, previous is #{prev.backtrace.exception(nil).message rescue :unknown}"
1562
+ else
1563
+ check_compatible_type var.backtrace, prev.type, var.type, true
1564
+ (var.attributes ||= []).concat prev.attributes if prev.attributes
1565
+ end
1566
+ elsif var.storage == :typedef
1567
+ attrs = var.attributes
1568
+ var = TypeDef.new var.name, var.type, var.backtrace
1569
+ var.attributes = attrs if attrs
1570
+ end
1571
+ scope.statements << Declaration.new(var) unless var.kind_of? TypeDef
1572
+
1573
+ raise tok || self, 'punctuation expected' if not tok = skipspaces or (tok.type != :punct and not %w[asm __asm __asm__].include? tok.raw)
1574
+
1575
+ case tok.raw
1576
+ when '{'
1577
+ # function body
1578
+ raise tok if nofunc or not var.kind_of? Variable or not var.type.kind_of? Function
1579
+ scope.symbol[var.name] = var
1580
+ body = var.initializer = Block.new(scope)
1581
+ var.type.args ||= []
1582
+ var.type.args.each { |v|
1583
+ # put func parameters in func body scope
1584
+ # arg redefinition is checked in parse_declarator
1585
+ if not v.name
1586
+ puts "unnamed argument in definition of #{var.name}" if $DEBUG
1587
+ next # should raise to be compliant
1588
+ end
1589
+ body.symbol[v.name] = v # XXX will need special check in stack allocator
1590
+ }
1591
+
1592
+ loop do
1593
+ raise tok || self, var.backtrace.exception('"}" expected for end of function') if not tok = skipspaces
1594
+ break if tok.type == :punct and tok.raw == '}'
1595
+ unreadtok tok
1596
+ if not parse_definition(body)
1597
+ body.statements << parse_statement(body, [var.type.type])
1598
+ end
1599
+ end
1600
+ if $VERBOSE and not body.statements.last.kind_of? Return and not body.statements.last.kind_of? Asm
1601
+ puts tok.exception('missing function return value').message if not var.type.type.untypedef.kind_of? BaseType or var.type.type.untypedef.name != :void
1602
+ end
1603
+ break
1604
+ when 'asm', '__asm', '__asm__'
1605
+ # GCC function redirection
1606
+ # void foo(void) __asm__("bar"); => when code uses 'foo', silently redirect to 'bar' instead
1607
+ raise tok if nofunc or not var.kind_of? Variable or not var.type.kind_of? Function
1608
+ # most of the time, 'bar' is not defined anywhere, so we support it only
1609
+ # to allow parsing of headers using it, hoping noone will actually use them
1610
+ unused = Asm.parse(self, scope)
1611
+ puts "unsupported gcc-style __asm__ function redirect #{var.name.inspect} => #{unused.body.inspect}" if $VERBOSE
1612
+ break
1613
+ when '='
1614
+ # variable initialization
1615
+ raise tok, '"{" or ";" expected' if var.type.kind_of? Function
1616
+ raise tok, 'cannot initialize extern variable' if var.storage == :extern
1617
+ scope.symbol[var.name] = var # allow initializer to reference var, eg 'void *ptr = &ptr;'
1618
+ var.initializer = var.type.parse_initializer(self, scope)
1619
+ if var.initializer.kind_of?(CExpression) and (scope == @toplevel or var.storage == :static)
1620
+ raise tok, "initializer for static #{var.name} is not constant" if not var.initializer.constant?
1621
+ end
1622
+ reference_value = lambda { |e, v|
1623
+ found = false
1624
+ case e
1625
+ when Variable; found = true if e == v
1626
+ when CExpression; e.walk { |ee| found ||= reference_value[ee, v] } if e.op != :& or e.lexpr
1627
+ end
1628
+ found
1629
+ }
1630
+ raise tok, "initializer for #{var.name} is not constant (selfreference)" if reference_value[var.initializer, var]
1631
+ raise tok || self, '"," or ";" expected' if not tok = skipspaces or tok.type != :punct
1632
+ else
1633
+ scope.symbol[var.name] = var
1634
+ end
1635
+
1636
+ case tok.raw
1637
+ when ','; nofunc = true
1638
+ when ';'; break
1639
+ when '}'; unreadtok(tok); break
1640
+ else raise tok, '";" or "," expected'
1641
+ end
1642
+ end
1643
+ true
1644
+ end
1645
+
1646
+ # parses toplevel statements, return nil if none found
1647
+ # toplevel statements are ';' and 'asm <..>'
1648
+ def parse_toplevel_statement(scope)
1649
+ if tok = skipspaces and tok.type == :punct and tok.raw == ';'
1650
+ true
1651
+ elsif tok and tok.type == :punct and tok.raw == '{'
1652
+ raise tok || self, '"}" expected' if not tok = skipspaces or tok.type != :punct or tok.raw != '}'
1653
+ true
1654
+ elsif tok and tok.type == :string and %w[asm __asm __asm__].include? tok.raw
1655
+ scope.statements << Asm.parse(self, scope)
1656
+ true
1657
+ end
1658
+ end
1659
+
1660
+ # returns a statement or raise
1661
+ def parse_statement(scope, nest)
1662
+ raise self, 'statement expected' if not tok = skipspaces
1663
+
1664
+ if tok.type == :punct and tok.raw == '{'
1665
+ body = Block.new scope
1666
+ loop do
1667
+ raise tok || self, '"}" expected' if not tok = skipspaces
1668
+ break if tok.type == :punct and tok.raw == '}'
1669
+ unreadtok tok
1670
+ if not parse_definition(body)
1671
+ body.statements << parse_statement(body, nest)
1672
+ end
1673
+ end
1674
+ return body
1675
+ elsif tok.type == :punct and tok.raw == ';'
1676
+ return Block.new(scope)
1677
+ elsif tok.type != :string
1678
+ unreadtok tok
1679
+ raise tok, 'expr expected' if not expr = CExpression.parse(self, scope)
1680
+ checkstatementend(tok)
1681
+
1682
+ if $VERBOSE and not nest.include?(:expression) and (expr.op or not expr.type.untypedef.kind_of? BaseType or expr.type.untypedef.name != :void) and CExpression.constant?(expr)
1683
+ puts tok.exception("statement with no effect : #{expr}").message
1684
+ end
1685
+ return expr
1686
+ end
1687
+
1688
+ case tok.raw
1689
+ when 'if'
1690
+ If.parse self, scope, nest
1691
+ when 'while'
1692
+ While.parse self, scope, nest
1693
+ when 'do'
1694
+ DoWhile.parse self, scope, nest
1695
+ when 'for'
1696
+ For.parse self, scope, nest
1697
+ when 'switch'
1698
+ Switch.parse self, scope, nest
1699
+ when 'goto'
1700
+ raise tok || self, 'label expected' if not tok = skipspaces or tok.type != :string
1701
+ name = tok.raw
1702
+ checkstatementend(tok)
1703
+ Goto.new name
1704
+ when 'return'
1705
+ expr = CExpression.parse(self, scope) # nil allowed
1706
+ p, i = nest[0].pointer?, nest[0].integral? if expr
1707
+ r = expr.reduce(self) if p or i
1708
+ if (not p and not i) or (i and not r.kind_of? ::Integer) or (p and r != 0)
1709
+ check_compatible_type(tok, (expr ? expr.type : BaseType.new(:void)), nest[0])
1710
+ end
1711
+ checkstatementend(tok)
1712
+ Return.new expr
1713
+ when 'case'
1714
+ raise tok, 'case out of switch' if not nest.include? :switch
1715
+ Case.parse self, scope, nest
1716
+ when 'default'
1717
+ raise tok || self, '":" expected' if not tok = skipspaces or tok.type != :punct or tok.raw != ':'
1718
+ raise tok, 'case out of switch' if not nest.include? :switch
1719
+ Case.new 'default', nil, parse_statement(scope, nest)
1720
+ when 'continue'
1721
+ checkstatementend(tok)
1722
+ raise tok, 'continue out of loop' if not nest.include? :loop
1723
+ Continue.new
1724
+ when 'break'
1725
+ checkstatementend(tok)
1726
+ raise tok, 'break out of loop' if not nest.include? :loop and not nest.include? :switch
1727
+ Break.new
1728
+ when 'asm', '__asm', '__asm__'
1729
+ Asm.parse self, scope
1730
+ else
1731
+ if ntok = skipspaces and ntok.type == :punct and ntok.raw == ':'
1732
+ begin
1733
+ st = parse_statement(scope, nest)
1734
+ rescue ParseError
1735
+ puts "label without statement, #{$!.message}" if $VERBOSE
1736
+ end
1737
+ Label.new tok.raw, st
1738
+ else
1739
+ unreadtok ntok
1740
+ unreadtok tok
1741
+ raise tok, 'expr expected' if not expr = CExpression.parse(self, scope)
1742
+ checkstatementend(tok)
1743
+
1744
+ if $VERBOSE and not nest.include?(:expression) and (expr.op or not expr.type.untypedef.kind_of? BaseType or expr.type.untypedef.name != :void) and CExpression.constant?(expr)
1745
+ puts tok.exception("statement with no effect : #{expr}").message
1746
+ end
1747
+ expr
1748
+ end
1749
+ end
1750
+ end
1751
+
1752
+ # check if a macro definition has a numeric value
1753
+ # returns this value or nil
1754
+ def macro_numeric(m)
1755
+ d = @lexer.definition[m]
1756
+ return if not d.kind_of? Preprocessor::Macro or d.args or d.varargs
1757
+ # filter metasm-defined vars (eg __PE__ / _M_IX86)
1758
+ return if not d.name or not bt = d.name.backtrace or (bt[0][0] != ?" and bt[0][0] != ?<)
1759
+ raise 'cannot macro_numeric with unparsed data' if not eos?
1760
+ @lexer.feed m
1761
+ if e = CExpression.parse(self, Block.new(@toplevel)) and eos?
1762
+ v = e.reduce(self)
1763
+ return v if v.kind_of? ::Numeric
1764
+ end
1765
+ readtok until eos?
1766
+ nil
1767
+ rescue ParseError
1768
+ readtok until eos?
1769
+ nil
1770
+ end
1771
+
1772
+ # returns all numeric constants defined with their value, either macros or enums
1773
+ def numeric_constants
1774
+ ret = []
1775
+ # macros
1776
+ @lexer.definition.each_key { |k|
1777
+ if v = macro_numeric(k)
1778
+ ret << [k, v]
1779
+ end
1780
+ }
1781
+ # enums
1782
+ @toplevel.symbol.each { |k, v|
1783
+ ret << [k, v] if v.kind_of? ::Numeric
1784
+ }
1785
+ ret
1786
+ end
1787
+ end
1788
+
1789
+ class Variable
1790
+ # parses a variable basetype/qualifier/(storage if allow_value), returns a new variable of this type
1791
+ # populates scope.struct
1792
+ def self.parse_type(parser, scope, allow_value = false)
1793
+ var = new
1794
+ qualifier = []
1795
+ tok = nil
1796
+ loop do
1797
+ var.parse_attributes(parser, true)
1798
+ break if not tok = parser.skipspaces
1799
+ if tok.type != :string
1800
+ parser.unreadtok tok
1801
+ break
1802
+ end
1803
+
1804
+ case tok.raw
1805
+ when 'const', 'volatile'
1806
+ qualifier << tok.raw.to_sym
1807
+ next
1808
+ when 'register', 'auto', 'static', 'typedef', 'extern'
1809
+ raise tok, 'storage specifier not allowed here' if not allow_value
1810
+ raise tok, 'multiple storage class' if var.storage
1811
+ var.storage = tok.raw.to_sym
1812
+ next
1813
+ when 'struct'
1814
+ var.type = Struct.new
1815
+ var.type.pack = parser.pragma_pack if parser.pragma_pack
1816
+ var.parse_type_struct(parser, scope)
1817
+ when 'union'
1818
+ var.type = Union.new
1819
+ var.parse_type_struct(parser, scope)
1820
+ when 'enum'
1821
+ var.type = Enum.new
1822
+ var.parse_type_struct(parser, scope)
1823
+ when 'typeof'
1824
+ if ntok = parser.skipspaces and ntok.type == :punct and ntok.raw == '('
1825
+ # check type
1826
+ if v = parse_type(parser, scope)
1827
+ v.parse_declarator(parser, scope)
1828
+ raise tok if v.name != false
1829
+ raise tok if not ntok = parser.skipspaces or ntok.type != :punct or ntok.raw != ')'
1830
+ else
1831
+ raise tok, 'expr expected' if not v = CExpression.parse(parser, scope)
1832
+ raise tok if not ntok = parser.skipspaces or ntok.type != :punct or ntok.raw != ')'
1833
+ end
1834
+ else
1835
+ parser.unreadtok ntok
1836
+ raise tok, 'expr expected' if not v = CExpression.parse_value(parser, scope)
1837
+ end
1838
+ var.type = v.type # TypeDef.new('typeof', v.type, tok)
1839
+ when 'long', 'short', 'signed', 'unsigned', 'int', 'char', 'float', 'double',
1840
+ 'void', '__int8', '__int16', '__int32', '__int64',
1841
+ 'intptr_t', 'uintptr_t'
1842
+ parser.unreadtok tok
1843
+ var.parse_type_base(parser, scope)
1844
+ else
1845
+ if type = scope.symbol_ancestors[tok.raw] and type.kind_of? TypeDef
1846
+ var.type = type.dup
1847
+ else
1848
+ parser.unreadtok tok
1849
+ end
1850
+ end
1851
+
1852
+ break
1853
+ end
1854
+
1855
+ if not var.type
1856
+ raise tok || parser, 'bad type name' if not qualifier.empty? or var.storage
1857
+ nil
1858
+ else
1859
+ var.type.qualifier = var.type.qualifier.to_a | qualifier if not qualifier.empty?
1860
+ var.type.parse_attributes(parser, true)
1861
+ var
1862
+ end
1863
+ end
1864
+
1865
+ # parses a structure/union/enum declaration
1866
+ def parse_type_struct(parser, scope)
1867
+ @type.parse_attributes(parser)
1868
+ if tok = parser.skipspaces and tok.type == :punct and tok.raw == '{'
1869
+ # anonymous struct, ok
1870
+ @type.backtrace = tok
1871
+ if @type.kind_of? Enum
1872
+ (scope.anonymous_enums ||= []) << @type
1873
+ end
1874
+ elsif tok and tok.type == :string
1875
+ name = tok.raw
1876
+ raise tok, 'bad struct name' if Keyword[name] or (?0..?9).include?(name[0])
1877
+ @type.backtrace = tok
1878
+ @type.name = name
1879
+ @type.parse_attributes(parser)
1880
+ raise parser if not ntok = parser.skipspaces
1881
+ if ntok.type != :punct or ntok.raw != '{'
1882
+ raise tok, "struct/union confusion" if scope.struct[name] and scope.struct[name].class != @type.class
1883
+ # variable declaration
1884
+ parser.unreadtok ntok
1885
+ if ntok.type == :punct and ntok.raw == ';'
1886
+ # struct predeclaration
1887
+ # allow redefinition
1888
+ @type = scope.struct[name] ||= @type
1889
+ else
1890
+ # check that the structure exists
1891
+ struct = scope.struct_ancestors[name]
1892
+ # allow incomplete types, usage as var type will raise later
1893
+ struct = scope.struct[name] = @type if not struct
1894
+ raise tok, 'unknown struct' if struct.class != @type.class
1895
+ (struct.attributes ||= []).concat @type.attributes if @type.attributes
1896
+ (struct.qualifier ||= []).concat @type.qualifier if @type.qualifier # XXX const struct foo bar => bar is const, not foo...
1897
+ @type = struct
1898
+ end
1899
+ return
1900
+ end
1901
+ if scope.struct[name] and scope.struct[name].members
1902
+ # redefinition of an existing struct, save for later comparison
1903
+ oldstruct = scope.struct[name]
1904
+ raise tok, "struct/union confusion" if oldstruct.class != @type.class
1905
+ elsif struct = scope.struct[name]
1906
+ raise tok, "struct/union confusion" if struct.class != @type.class
1907
+ (struct.attributes ||= []).concat @type.attributes if @type.attributes
1908
+ (struct.qualifier ||= []).concat @type.qualifier if @type.qualifier
1909
+ struct.backtrace = @type.backtrace
1910
+ struct.name = @type.name
1911
+ @type = struct
1912
+ else
1913
+ scope.struct[name] = @type
1914
+ end
1915
+ else
1916
+ raise tok || parser, 'struct name or "{" expected'
1917
+ end
1918
+
1919
+ @type.parse_members(parser, scope)
1920
+
1921
+ if oldstruct
1922
+ if not @type.compare_deep(oldstruct)
1923
+ raise tok, "conflicting struct redefinition (old at #{oldstruct.backtrace.exception(nil).message rescue :unknown})"
1924
+ end
1925
+ @type = oldstruct
1926
+ end
1927
+ end
1928
+
1929
+ # parses int/long int/long long/double etc
1930
+ def parse_type_base(parser, scope)
1931
+ specifier = []
1932
+ qualifier = []
1933
+ name = :int
1934
+ tok = nil
1935
+ loop do
1936
+ raise parser if not tok = parser.skipspaces
1937
+ if tok.type != :string
1938
+ parser.unreadtok tok
1939
+ break
1940
+ end
1941
+ case tok.raw
1942
+ when 'const', 'volatile'
1943
+ qualifier << tok.raw.to_sym
1944
+ when 'long', 'short', 'signed', 'unsigned'
1945
+ specifier << tok.raw.to_sym
1946
+ when 'int', 'char', 'void', 'float', 'double', '__int8', '__int16', '__int32', '__int64'
1947
+ name = tok.raw.to_sym
1948
+ break
1949
+ when 'intptr_t', 'uintptr_t'
1950
+ name = :ptr
1951
+ specifier << :unsigned if tok.raw == 'uintptr_t'
1952
+ break
1953
+ else
1954
+ parser.unreadtok tok
1955
+ break
1956
+ end
1957
+ end
1958
+
1959
+ case name
1960
+ when :double # long double
1961
+ if specifier == [:long]
1962
+ name = :longdouble
1963
+ specifier.clear
1964
+ elsif not specifier.empty?
1965
+ raise tok || parser, 'invalid specifier list'
1966
+ end
1967
+ when :int # short, long, long long X signed, unsigned
1968
+ # Array#count not available on old ruby (eg 1.8.4), so use ary.len - (ary-stuff).len
1969
+ specifier = specifier - [:long] + [:longlong] if specifier.length - (specifier-[:long]).length == 2
1970
+ if specifier.length - (specifier-[:signed, :unsigned]).length > 1 or specifier.length - (specifier-[:short, :long, :longlong]).length > 1
1971
+ raise tok || parser, 'invalid specifier list'
1972
+ else
1973
+ name = (specifier & [:longlong, :long, :short])[0] || :int
1974
+ specifier -= [:longlong, :long, :short]
1975
+ end
1976
+ specifier.delete :signed # default
1977
+ when :char # signed, unsigned
1978
+ # signed char != char and unsigned char != char
1979
+ if (specifier & [:signed, :unsigned]).length > 1 or (specifier & [:short, :long]).length > 0
1980
+ raise tok || parser, 'invalid specifier list'
1981
+ end
1982
+ when :__int8, :__int16, :__int32, :__int64, :ptr
1983
+ if (specifier & [:signed, :unsigned]).length > 1 or (specifier & [:short, :long]).length > 0
1984
+ raise tok || parser, 'invalid specifier list'
1985
+ end
1986
+ specifier.delete :signed # default
1987
+ else # none
1988
+ raise tok || parser, 'invalid type' if not specifier.empty?
1989
+ end
1990
+
1991
+ @type = BaseType.new(name, *specifier)
1992
+ @type.qualifier = qualifier if not qualifier.empty?
1993
+ end
1994
+
1995
+ # updates @type and @name, parses pointer/arrays/function declarations
1996
+ # parses anonymous declarators (@name will be false)
1997
+ # the caller is responsible for detecting redefinitions
1998
+ # scope used only in CExpression.parse for array sizes and function prototype argument types
1999
+ # rec for internal use only
2000
+ def parse_declarator(parser, scope, rec = false)
2001
+ parse_attributes(parser, true)
2002
+ tok = parser.skipspaces
2003
+ # read upto name
2004
+ if tok and tok.type == :punct and tok.raw == '*'
2005
+ ptr = Pointer.new
2006
+ ptr.parse_attributes(parser)
2007
+ while ntok = parser.skipspaces and ntok.type == :string
2008
+ case ntok.raw
2009
+ when 'const', 'volatile'
2010
+ (ptr.qualifier ||= []) << ntok.raw.to_sym
2011
+ ptr.parse_attributes(parser)
2012
+ else break
2013
+ end
2014
+ end
2015
+ parser.unreadtok ntok
2016
+ parse_declarator(parser, scope, true)
2017
+ t = self
2018
+ t = t.type while t.type and (t.type.kind_of?(Pointer) or t.type.kind_of?(Function))
2019
+ ptr.type = t.type
2020
+ t.type = ptr
2021
+ if t.kind_of? Function and ptr.attributes
2022
+ @attributes ||= []
2023
+ @attributes |= ptr.attributes
2024
+ ptr.attributes = nil
2025
+ end
2026
+ return
2027
+ elsif tok and tok.type == :punct and tok.raw == '('
2028
+ parse_declarator(parser, scope, true)
2029
+ raise tok || parser, '")" expected' if not tok = parser.skipspaces or tok.type != :punct or tok.raw != ')'
2030
+ elsif tok and tok.type == :string
2031
+ case tok.raw
2032
+ when 'const', 'volatile'
2033
+ (@type.qualifier ||= []) << tok.raw.to_sym
2034
+ return parse_declarator(parser, scope, rec)
2035
+ when 'register', 'auto', 'static', 'typedef', 'extern'
2036
+ raise tok, 'multiple storage class' if storage
2037
+ @storage = tok.raw.to_sym
2038
+ puts tok.exception('misplaced storage specifier').message if $VERBOSE
2039
+ return parse_declarator(parser, scope, rec)
2040
+ end
2041
+ raise tok if name or name == false
2042
+ raise tok, 'bad var name' if Keyword[tok.raw] or (?0..?9).include?(tok.raw[0])
2043
+ @name = tok.raw
2044
+ @backtrace = tok
2045
+ parse_attributes(parser, true)
2046
+ else
2047
+ # unnamed
2048
+ raise tok || parser if name or name == false
2049
+ @name = false
2050
+ @backtrace = tok
2051
+ parser.unreadtok tok
2052
+ parse_attributes(parser, true)
2053
+ end
2054
+ parse_declarator_postfix(parser, scope)
2055
+ if not rec
2056
+ raise @backtrace, 'void type is invalid' if name and (t = @type.untypedef).kind_of? BaseType and
2057
+ t.name == :void and storage != :typedef
2058
+ raise @backtrace, "incomplete type #{@type.name}" if (@type.kind_of? Union or @type.kind_of? Enum) and
2059
+ not @type.members and storage != :typedef and storage != :extern # gcc uses an undefined extern struct just to cast it later (_IO_FILE_plus)
2060
+ end
2061
+ end
2062
+
2063
+ # parses array/function type
2064
+ def parse_declarator_postfix(parser, scope)
2065
+ if tok = parser.skipspaces and tok.type == :punct and tok.raw == '['
2066
+ # array indexing
2067
+ idx = CExpression.parse(parser, scope) # may be nil
2068
+ if idx and (scope == parser.toplevel or storage == :static)
2069
+ raise tok, 'array size is not constant' if not idx.constant?
2070
+ idx = idx.reduce(parser)
2071
+ elsif idx and nidx = idx.reduce(parser) and nidx.kind_of? ::Integer
2072
+ idx = nidx
2073
+ end
2074
+ t = self
2075
+ t = t.type while t.type and (t.type.kind_of?(Pointer) or t.type.kind_of?(Function))
2076
+ t.type = Array.new t.type
2077
+ t.type.length = idx
2078
+ raise tok || parser, '"]" expected' if not tok = parser.skipspaces or tok.type != :punct or tok.raw != ']'
2079
+ parse_attributes(parser) # should be type.attrs, but this is should be more compiler-compatible
2080
+ elsif tok and tok.type == :punct and tok.raw == '('
2081
+ # function prototype
2082
+ # void __attribute__((noreturn)) func() => attribute belongs to func
2083
+ if @type and @type.attributes
2084
+ @attributes ||= []
2085
+ @attributes |= @type.attributes
2086
+ @type.attributes = nil
2087
+ end
2088
+ t = self
2089
+ t = t.type while t.type and (t.type.kind_of?(Pointer) or t.type.kind_of?(Function))
2090
+ t.type = Function.new t.type
2091
+ if not tok = parser.skipspaces or tok.type != :punct or tok.raw != ')'
2092
+ parser.unreadtok tok
2093
+ t.type.args = []
2094
+ oldstyle = false # int func(a, b) int a; double b; { stuff; }
2095
+ loop do
2096
+ raise parser if not tok = parser.skipspaces
2097
+ if tok.type == :punct and tok.raw == '.' # variadic function
2098
+ raise parser, '".." expected' if not tok = parser.skipspaces or tok.type != :punct or tok.raw != '.'
2099
+ raise parser, '"." expected' if not tok = parser.skipspaces or tok.type != :punct or tok.raw != '.'
2100
+ raise parser, '")" expected' if not tok = parser.skipspaces or tok.type != :punct or tok.raw != ')'
2101
+ t.type.varargs = true
2102
+ break
2103
+ elsif tok.type == :string and tok.raw == 'register'
2104
+ storage = :register
2105
+ else
2106
+ parser.unreadtok tok
2107
+ end
2108
+
2109
+ if oldstyle or not v = Variable.parse_type(parser, scope)
2110
+ raise tok if not @name # no oldstyle in casts
2111
+ tok = parser.skipspaces
2112
+ oldstyle ||= [tok] # arg to raise() later
2113
+ oldstyle << tok.raw
2114
+ else
2115
+ v.storage = storage if storage
2116
+ v.parse_declarator(parser, scope)
2117
+ v.type = Pointer.new(v.type.type) if v.type.kind_of? Array
2118
+ v.type = Pointer.new(v.type) if v.type.kind_of? Function
2119
+
2120
+ t.type.args << v if not v.type.untypedef.kind_of? BaseType or v.type.untypedef.name != :void
2121
+ end
2122
+
2123
+ if tok = parser.skipspaces and tok.type == :punct and tok.raw == ','
2124
+ raise tok, '")" expected' if v and t.type.args.last != v # last arg of type :void
2125
+ elsif tok and tok.type == :punct and tok.raw == ')'
2126
+ break
2127
+ else raise tok || parser, '"," or ")" expected'
2128
+ end
2129
+ end
2130
+ if oldstyle
2131
+ parse_attributes(parser, true)
2132
+ ra = oldstyle.shift
2133
+ while t.type.args.compact.length != oldstyle.length
2134
+ raise ra, "invalid prototype" if not vb = Variable.parse_type(parser, scope)
2135
+ loop do
2136
+ v = vb.dup
2137
+ v.parse_declarator(parser, scope)
2138
+ v.type = Pointer.new(v.type.type) if v.type.kind_of? Array
2139
+ v.type = Pointer.new(v.type) if v.type.kind_of? Function
2140
+ raise parser, "unknown arg #{v.name.inspect}" if not i = oldstyle.index(v.name)
2141
+ t.type.args[i] = v
2142
+ raise parser, '"," or ";" expected' if not tok = parser.skipspaces or tok.type != :punct or (tok.raw != ';' and tok.raw != ',')
2143
+ break if tok.raw == ';'
2144
+ end
2145
+ end
2146
+ parse_attributes(parser, true)
2147
+ raise parser, '"{" expected' if not tok = parser.skipspaces or tok.type != :punct or tok.raw != '{'
2148
+ parser.unreadtok tok
2149
+ end
2150
+ namedargs = t.type.args.map { |a| a.name }.compact - [false]
2151
+ raise tok, "duplicate argument name #{namedargs.find { |a| namedargs.index(a) != namedargs.rindex(a) }.inspect}" if namedargs.length != namedargs.uniq.length
2152
+ end
2153
+ parse_attributes(parser, true) # should be type.attrs, but this should be more existing-compiler-compatible
2154
+ else
2155
+ parser.unreadtok tok
2156
+ return
2157
+ end
2158
+ parse_declarator_postfix(parser, scope)
2159
+ end
2160
+ end
2161
+
2162
+ class Variable
2163
+ def ===(o)
2164
+ self == o or (o.class == CExpression and not o.op and o.rexpr == self)
2165
+ end
2166
+ end
2167
+
2168
+ class CExpression
2169
+ def self.lvalue?(e)
2170
+ e.kind_of?(self) ? e.lvalue? : (e.kind_of? Variable and e.name)
2171
+ end
2172
+ def lvalue?
2173
+ case @op
2174
+ when :*; true if not @lexpr
2175
+ when :'[]', :'.', :'->'; true
2176
+ when nil # cast
2177
+ CExpression.lvalue?(@rexpr)
2178
+ else false
2179
+ end
2180
+ end
2181
+
2182
+ def self.constant?(e)
2183
+ e.kind_of?(self) ? e.constant? : true
2184
+ end
2185
+ def constant?
2186
+ # gcc considers '1, 2' not constant
2187
+ if [:',', :funcall, :'=', :'--', :'++', :'+=', :'-=', :'*=', :'/=', :'>>=', :'<<=', :'&=', :'|=', :'^=', :'%=', :'->', :'[]'].include?(@op)
2188
+ false
2189
+ elsif @op == :'*' and not @lexpr; false
2190
+ elsif not @lexpr and not @op and @rexpr.kind_of? Block; false
2191
+ else
2192
+ out = true
2193
+ walk { |e| break out = false if not CExpression.constant?(e) }
2194
+ out
2195
+ end
2196
+ end
2197
+
2198
+ def self.reduce(parser, e)
2199
+ e.kind_of?(self) ? e.reduce(parser) : e
2200
+ end
2201
+ def reduce(parser)
2202
+ # parser used for arithmetic overflows (need basic type sizes)
2203
+ case @op
2204
+ when :'&&'
2205
+ case l = CExpression.reduce(parser, @lexpr)
2206
+ when 0; 0
2207
+ when ::Integer
2208
+ case r = CExpression.reduce(parser, @rexpr)
2209
+ when 0; 0
2210
+ when ::Integer; 1
2211
+ else CExpression.new(l, @op, r, @type)
2212
+ end
2213
+ else CExpression.new(l, @op, @rexpr, @type)
2214
+ end
2215
+ when :'||'
2216
+ case l = CExpression.reduce(parser, @lexpr)
2217
+ when 0
2218
+ case r = CExpression.reduce(parser, @rexpr)
2219
+ when 0; 0
2220
+ when ::Integer; 1
2221
+ else CExpression.new(l, @op, r, @type)
2222
+ end
2223
+ when ::Integer; 1
2224
+ else CExpression.new(l, @op, @rexpr, @type)
2225
+ end
2226
+ when :'!'
2227
+ case r = CExpression.reduce(parser, @rexpr)
2228
+ when 0; 1
2229
+ when ::Integer; 0
2230
+ else CExpression.new(nil, @op, r, @type)
2231
+ end
2232
+ when :'!=', :'==', :'<', :'>', :'>=', :'<='
2233
+ l = CExpression.reduce(parser, @lexpr)
2234
+ r = CExpression.reduce(parser, @rexpr)
2235
+ if l.kind_of?(::Integer) and r.kind_of?(::Integer)
2236
+ if @op == :'!='; l != r ? 1 : 0
2237
+ else l.send(@op, r) ? 1 : 0
2238
+ end
2239
+ else
2240
+ l = CExpression.new(nil, nil, l, BaseType.new(:int)) if l.kind_of? ::Integer
2241
+ r = CExpression.new(nil, nil, r, BaseType.new(:int)) if r.kind_of? ::Integer
2242
+ CExpression.new(l, @op, r, @type)
2243
+ end
2244
+ when :'.'
2245
+ le = CExpression.reduce(parser, @lexpr)
2246
+ if le.kind_of? Variable and le.initializer.kind_of? ::Array
2247
+ midx = le.type.members.index(le.type.findmember(@rexpr))
2248
+ CExpression.reduce(parser, le.initializer[midx] || 0)
2249
+ else
2250
+ CExpression.new(le, @op, @rexpr, @type)
2251
+ end
2252
+ when :'?:'
2253
+ case c = CExpression.reduce(parser, @lexpr)
2254
+ when 0; CExpression.reduce(parser, @rexpr[0])
2255
+ when ::Integer; CExpression.reduce(parser, @rexpr[1])
2256
+ else CExpression.new(c, @op, @rexpr, @type)
2257
+ end
2258
+ when :'+', :'-', :'*', :'/', :'^', :'%', :'&', :'|', :'>>', :'<<', :'~', nil
2259
+ t = @type.untypedef
2260
+ case t
2261
+ when BaseType
2262
+ when Pointer; return self if @op
2263
+ else
2264
+ return @rexpr if not @op and not @lexpr and @rexpr.kind_of? Variable and @rexpr.type == @type
2265
+ return self # raise parser, 'not arithmetic type'
2266
+ end
2267
+
2268
+ # compute value
2269
+ r = CExpression.reduce(parser, @rexpr)
2270
+ ret = \
2271
+ if not @lexpr
2272
+ # unary
2273
+ case @op
2274
+ when :'+', nil, :'-', :'~'
2275
+ return CExpression.new(nil, @op, r, @type) if not r.kind_of? ::Numeric
2276
+ case @op
2277
+ when :'-'; -r
2278
+ when :'~'; ~r
2279
+ else r
2280
+ end
2281
+ else return CExpression.new(nil, @op, r, @type)
2282
+ end
2283
+ else
2284
+ l = CExpression.reduce(parser, @lexpr)
2285
+ if not l.kind_of?(::Numeric) or not r.kind_of?(::Numeric)
2286
+ l = CExpression.new(nil, nil, l, BaseType.new(:int)) if l.kind_of? ::Integer
2287
+ r = CExpression.new(nil, nil, r, BaseType.new(:int)) if r.kind_of? ::Integer
2288
+ return CExpression.new(l, @op, r, @type)
2289
+ end
2290
+ l.send(@op, r)
2291
+ end
2292
+
2293
+ # overflow
2294
+ tn = (t.pointer? ? :ptr : t.name)
2295
+ case tn
2296
+ when :char, :short, :int, :long, :ptr, :longlong, :__int8, :__int16, :__int32, :__int64
2297
+ max = 1 << (8*parser.typesize[tn])
2298
+ ret = ret.to_i & (max-1)
2299
+ if not t.pointer? and t.specifier != :unsigned and (ret & (max >> 1)) > 0 # char == unsigned char
2300
+ ret - max
2301
+ else
2302
+ ret
2303
+ end
2304
+ when :float, :double, :longdouble
2305
+ ret.to_f # TODO
2306
+ end
2307
+ when :funcall
2308
+ l = CExpression.reduce(parser, @lexpr)
2309
+ r = @rexpr.map { |rr|
2310
+ rr = CExpression.reduce(parser, rr)
2311
+ rr = CExpression.new(nil, nil, rr, BaseType.new(:int)) if rr.kind_of? ::Integer
2312
+ rr
2313
+ }
2314
+ CExpression.new(l, @op, r, @type)
2315
+ else
2316
+ l = CExpression.reduce(parser, @lexpr) if @lexpr
2317
+ r = CExpression.reduce(parser, @rexpr) if @rexpr
2318
+ l = CExpression.new(nil, nil, l, BaseType.new(:int)) if l.kind_of? ::Integer
2319
+ r = CExpression.new(nil, nil, r, BaseType.new(:int)) if r.kind_of? ::Integer
2320
+ CExpression.new(l, @op, r, @type)
2321
+ end
2322
+ end
2323
+
2324
+ def ==(o)
2325
+ o.object_id == self.object_id or
2326
+ (self.class == o.class and op == o.op and lexpr == o.lexpr and rexpr == o.rexpr)
2327
+ end
2328
+
2329
+ def ===(o)
2330
+ (self.class == o.class and op == o.op and lexpr === o.lexpr and rexpr === o.rexpr) or
2331
+ (o.class == Variable and not @op and @rexpr == o)
2332
+ end
2333
+
2334
+ NegateOp = { :== => :'!=', :'!=' => :==, :> => :<=, :>= => :<, :< => :>=, :<= => :> }
2335
+ # returns a CExpr negating this one (eg 'x' => '!x', 'a > b' => 'a <= b'...)
2336
+ def self.negate(e)
2337
+ e.kind_of?(self) ? e.negate : CExpression[:'!', e]
2338
+ end
2339
+ def negate
2340
+ if @op == :'!'
2341
+ CExpression[@rexpr]
2342
+ elsif nop = NegateOp[@op]
2343
+ if nop == :== and @rexpr.kind_of? CExpression and not @rexpr.op and @rexpr.rexpr == 0 and
2344
+ @lexpr.kind_of? CExpression and [:==, :'!=', :>, :<, :>=, :<=, :'!'].include? @lexpr.op
2345
+ # (a > b) != 0 => (a > b)
2346
+ CExpression[@lexpr]
2347
+ else
2348
+ CExpression.new(@lexpr, nop, @rexpr, @type)
2349
+ end
2350
+ elsif nop = { :'||' => :'&&', :'&&' => :'||' }[@op]
2351
+ CExpression.new(CExpression.negate(@lexpr), nop, CExpression.negate(@rexpr), @type)
2352
+ else
2353
+ CExpression[:'!', self]
2354
+ end
2355
+ end
2356
+
2357
+ def walk
2358
+ case @op
2359
+ when :funcall, :'?:'
2360
+ yield @lexpr
2361
+ @rexpr.each { |arg| yield arg }
2362
+ when :'->', :'.'
2363
+ yield @lexpr
2364
+ else
2365
+ yield @lexpr if @lexpr
2366
+ yield @rexpr if @rexpr
2367
+ end
2368
+ end
2369
+
2370
+ def complexity
2371
+ cx = 1
2372
+ walk { |e| cx += e.complexity if e.kind_of?(CExpression) }
2373
+ cx
2374
+ end
2375
+
2376
+ RIGHTASSOC = [:'=', :'+=', :'-=', :'*=', :'/=', :'%=', :'&=',
2377
+ :'|=', :'^=', :'<<=', :'>>=', :'?:'
2378
+ ].inject({}) { |h, op| h.update op => true }
2379
+
2380
+ # key = operator, value = hash regrouping operators of lower precedence
2381
+ # funcall/array index/member dereference/sizeof are handled in parse_value
2382
+ OP_PRIO = [[:','], [:'?:'], [:'=', :'+=', :'-=', :'*=', :'/=',
2383
+ :'%=', :'&=', :'|=', :'^=', :'<<=', :'>>='], [:'||'],
2384
+ [:'&&'], [:|], [:^], [:&], [:'==', :'!='],
2385
+ [:'<', :'>', :'<=', :'>='], [:<<, :>>], [:+, :-],
2386
+ [:*, :/, :%], ].inject({}) { |h, oplist|
2387
+ lessprio = h.keys.inject({}) { |hh, op| hh.update op => true }
2388
+ oplist.each { |op| lessprio.update op => true } if RIGHTASSOC[oplist.first]
2389
+ oplist.each { |op| h[op] = lessprio }
2390
+ h }
2391
+
2392
+ class << self
2393
+ # reads a binary operator from the parser, returns the corresponding symbol or nil
2394
+ def readop(parser)
2395
+ if not op = parser.skipspaces or op.type != :punct
2396
+ parser.unreadtok op
2397
+ return
2398
+ end
2399
+
2400
+ case op.raw
2401
+ when '>', '<', '|', '&' # << >> || &&
2402
+ if ntok = parser.readtok and ntok.type == :punct and ntok.raw == op.raw
2403
+ op.raw << ntok.raw
2404
+ else
2405
+ parser.unreadtok ntok
2406
+ end
2407
+ when '!' # != (mandatory)
2408
+ if not ntok = parser.readtok or ntok.type != :punct and ntok.raw != '='
2409
+ parser.unreadtok op
2410
+ return
2411
+ end
2412
+ op.raw << ntok.raw
2413
+ when '+', '-', '*', '/', '%', '^', '=', ',', '?', ':', '>>', '<<', '||', '&&',
2414
+ '+=','-=','*=','/=','%=','^=','==','&=','|=','!=' # ok
2415
+ else # bad
2416
+ parser.unreadtok op
2417
+ return
2418
+ end
2419
+
2420
+ # may be followed by '='
2421
+ case op.raw
2422
+ when '+', '-', '*', '/', '%', '^', '&', '|', '>>', '<<', '<', '>', '='
2423
+ if ntok = parser.readtok and ntok.type == :punct and ntok.raw == '='
2424
+ op.raw << ntok.raw
2425
+ else
2426
+ parser.unreadtok ntok
2427
+ end
2428
+ end
2429
+
2430
+ op.value = op.raw.to_sym
2431
+ op
2432
+ end
2433
+
2434
+ # parse sizeof offsetof float immediate etc into tok.value
2435
+ def parse_intfloat(parser, scope, tok)
2436
+ if tok.type == :string and not tok.value
2437
+ case tok.raw
2438
+ when 'sizeof'
2439
+ if ntok = parser.skipspaces and ntok.type == :punct and ntok.raw == '('
2440
+ # check type
2441
+ if v = Variable.parse_type(parser, scope)
2442
+ v.parse_declarator(parser, scope)
2443
+ raise tok if v.name != false
2444
+ raise tok if not ntok = parser.skipspaces or ntok.type != :punct or ntok.raw != ')'
2445
+ else
2446
+ raise tok, 'expr expected' if not v = parse(parser, scope)
2447
+ raise tok if not ntok = parser.skipspaces or ntok.type != :punct or ntok.raw != ')'
2448
+ end
2449
+ else
2450
+ parser.unreadtok ntok
2451
+ raise tok, 'expr expected' if not v = parse_value(parser, scope)
2452
+ end
2453
+ tok.value = parser.sizeof(v)
2454
+ return
2455
+ when '__builtin_offsetof'
2456
+ raise tok if not ntok = parser.skipspaces or ntok.type != :punct or ntok.raw != '('
2457
+ raise tok if not ntok = parser.skipspaces or ntok.type != :string or ntok.raw != 'struct'
2458
+ raise tok if not ntok = parser.skipspaces or ntok.type != :string
2459
+ raise tok, 'unknown structure' if not struct = scope.struct_ancestors[ntok.raw] or not struct.kind_of? Union or not struct.members
2460
+ raise tok if not ntok = parser.skipspaces or ntok.type != :punct or ntok.raw != ','
2461
+ raise tok if not ntok = parser.skipspaces or ntok.type != :string
2462
+ tok.value = struct.offsetof(parser, ntok.raw)
2463
+ raise tok if not ntok = parser.skipspaces or ntok.type != :punct or ntok.raw != ')'
2464
+ return
2465
+ end
2466
+ end
2467
+
2468
+ Expression.parse_num_value(parser, tok)
2469
+ end
2470
+
2471
+ # returns the next value from parser (parenthesised expression, immediate, variable, unary operators)
2472
+ def parse_value(parser, scope)
2473
+ return if not tok = parser.skipspaces
2474
+ case tok.type
2475
+ when :string
2476
+ parse_intfloat(parser, scope, tok)
2477
+ val = tok.value || tok.raw
2478
+ if val.kind_of? ::String
2479
+ raise tok, 'undefined variable' if not val = scope.symbol_ancestors[val]
2480
+ end
2481
+ case val
2482
+ when Type
2483
+ raise tok, 'invalid variable'
2484
+ when Variable
2485
+ val = parse_value_postfix(parser, scope, val)
2486
+ when ::Float
2487
+ # parse suffix
2488
+ type = :double
2489
+ if (?0..?9).include?(tok.raw[0])
2490
+ case tok.raw.downcase[-1]
2491
+ when ?l; type = :longdouble
2492
+ when ?f; type = :float
2493
+ end
2494
+ end
2495
+ val = CExpression[val, BaseType.new(type)]
2496
+
2497
+ when ::Integer
2498
+ # parse suffix
2499
+ # XXX 010h ?
2500
+ type = :int
2501
+ specifier = []
2502
+ if (?0..?9).include?(tok.raw[0])
2503
+ suffix = tok.raw.downcase[-3, 3] || tok.raw.downcase[-2, 2] || tok.raw.downcase[-1, 1] # short string
2504
+ specifier << :unsigned if suffix.include?('u') # XXX or tok.raw.downcase[1] == ?x
2505
+ type = :longlong if suffix.count('l') == 2
2506
+ type = :long if suffix.count('l') == 1
2507
+ end
2508
+ val = CExpression[val, BaseType.new(type, *specifier)]
2509
+ else raise parser, "internal error #{val.inspect}"
2510
+ end
2511
+
2512
+ when :quoted
2513
+ if tok.raw[0] == ?'
2514
+ raise tok, 'invalid character constant' if not [1, 2, 4, 8].include? tok.value.length # TODO 0fill
2515
+ val = CExpression[Expression.decode_imm(tok.value, tok.value.length, :big), BaseType.new(:int)]
2516
+ else
2517
+ val = CExpression[tok.value, Pointer.new(BaseType.new(tok.raw[0, 2] == 'L"' ? :short : :char))]
2518
+ val = parse_value_postfix(parser, scope, val)
2519
+ end
2520
+
2521
+ when :punct
2522
+ case tok.raw
2523
+ when '('
2524
+ ntok = nil
2525
+ # check type casting
2526
+ if v = Variable.parse_type(parser, scope)
2527
+ v.parse_declarator(parser, scope)
2528
+ (v.type.attributes ||= []).concat v.attributes if v.attributes
2529
+ raise tok, 'bad cast' if v.name != false
2530
+ raise ntok || tok, 'no ")" found' if not ntok = parser.skipspaces or ntok.type != :punct or ntok.raw != ')'
2531
+ raise ntok, 'expr expected' if not val = parse_value(parser, scope) # parses postfix too
2532
+ #raise ntok, 'unable to cast a struct' if val.type.untypedef.kind_of? Union
2533
+ val = CExpression[[val], v.type]
2534
+ # check compound statement expression
2535
+ elsif ntok = parser.skipspaces and ntok.type == :punct and ntok.raw == '{'
2536
+ parser.unreadtok ntok
2537
+ blk = parser.parse_statement(scope, [:expression]) # XXX nesting ?
2538
+ raise ntok || tok, 'no ")" found' if not ntok = parser.skipspaces or ntok.type != :punct or ntok.raw != ')'
2539
+ type = blk.statements.last.kind_of?(CExpression) ? blk.statements.last.type : BaseType.new(:void)
2540
+ val = CExpression[blk, type]
2541
+ else
2542
+ parser.unreadtok ntok
2543
+ if not val = parse(parser, scope)
2544
+ parser.unreadtok tok
2545
+ return
2546
+ end
2547
+ raise ntok || tok, 'no ")" found' if not ntok = parser.readtok or ntok.type != :punct or ntok.raw != ')'
2548
+ val = parse_value_postfix(parser, scope, val)
2549
+ end
2550
+ when '.' # float
2551
+ parse_intfloat(parser, scope, tok)
2552
+ if not tok.value
2553
+ parser.unreadtok tok
2554
+ return
2555
+ end
2556
+ val = tok.value || tok.raw
2557
+ type = :double
2558
+ case tok.raw.downcase[-1]
2559
+ when ?l; type = :longdouble
2560
+ when ?f; type = :float
2561
+ end
2562
+ val = CExpression.new[val, BaseType.new(type)]
2563
+
2564
+ when '+', '-', '&', '!', '~', '*', '--', '++', '&&'
2565
+ # unary prefix
2566
+ # may have been read ahead
2567
+
2568
+ raise parser if not ntok = parser.readtok
2569
+ # check for -- ++ &&
2570
+ if ntok.type == :punct and ntok.raw == tok.raw and %w[+ - &].include?(tok.raw)
2571
+ tok.raw << ntok.raw
2572
+ else
2573
+ parser.unreadtok ntok
2574
+ end
2575
+
2576
+ case tok.raw
2577
+ when '&'
2578
+ val = parse_value(parser, scope)
2579
+ if val.kind_of? CExpression and val.op == :& and not val.lexpr and
2580
+ (val.rexpr.kind_of? Variable or val.rexpr.kind_of? CExpression) and val.rexpr.type.kind_of? Function
2581
+ # &&function == &function
2582
+ elsif (val.kind_of? CExpression or val.kind_of? Variable) and val.type.kind_of? Array
2583
+ # &ary = ary
2584
+ else
2585
+ raise parser, "invalid lvalue #{val}" if not CExpression.lvalue?(val) and not parser.allow_bad_c
2586
+ raise val.backtrace, 'cannot take addr of register' if val.kind_of? Variable and val.storage == :register and not parser.allow_bad_c
2587
+ val = CExpression.new(nil, tok.raw.to_sym, val, Pointer.new(val.type))
2588
+ end
2589
+ when '++', '--'
2590
+ val = parse_value(parser, scope)
2591
+ raise parser, "invalid lvalue #{val}" if not CExpression.lvalue?(val) and not parser.allow_bad_c
2592
+ val = CExpression.new(nil, tok.raw.to_sym, val, val.type)
2593
+ when '&&'
2594
+ raise tok, 'label name expected' if not val = parser.skipspaces or val.type != :string
2595
+ val = CExpression.new(nil, nil, Label.new(val.raw, nil), Pointer.new(BaseType.new(:void)))
2596
+ when '*'
2597
+ raise tok, 'expr expected' if not val = parse_value(parser, scope)
2598
+ raise tok, 'not a pointer' if not val.type.pointer? and not parser.allow_bad_c
2599
+ newtype = val.type.pointer? ? val.type.pointed : BaseType.new(:int)
2600
+ if not newtype.untypedef.kind_of? Function # *fptr == fptr
2601
+ val = CExpression.new(nil, tok.raw.to_sym, val, newtype)
2602
+ end
2603
+ when '~', '!', '+', '-'
2604
+ raise tok, 'expr expected' if not val = parse_value(parser, scope)
2605
+ raise tok, 'type not arithmetic' if not val.type.arithmetic? and not parser.allow_bad_c
2606
+ val = CExpression.new(nil, tok.raw.to_sym, val, val.type)
2607
+ val.type = BaseType.new(:int) if tok.raw == '!'
2608
+ else raise tok, 'internal error'
2609
+ end
2610
+ else
2611
+ parser.unreadtok tok
2612
+ return
2613
+ end
2614
+ else
2615
+ parser.unreadtok tok
2616
+ return
2617
+ end
2618
+
2619
+ if val.kind_of? Variable and val.type.kind_of? Function
2620
+ # void (*bla)() = printf; => ...= &printf;
2621
+ val = CExpression[:&, val]
2622
+ end
2623
+
2624
+ val
2625
+ end
2626
+
2627
+ # parse postfix forms (postincrement, array index, struct member dereference)
2628
+ def parse_value_postfix(parser, scope, val)
2629
+ tok = parser.skipspaces
2630
+ nval = \
2631
+ if tok and tok.type == :punct
2632
+ case tok.raw
2633
+ when '+', '++', '-', '--', '->'
2634
+ ntok = parser.readtok
2635
+ if (tok.raw == '+' or tok.raw == '-') and ntok and ntok.type == :punct and
2636
+ (ntok.raw == tok.raw or (tok.raw == '-' and ntok.raw == '>'))
2637
+ tok.raw << ntok.raw
2638
+ else
2639
+ parser.unreadtok ntok
2640
+ end
2641
+ case tok.raw
2642
+ when '+', '-'
2643
+ nil
2644
+ when '++', '--'
2645
+ raise parser, "#{val}: invalid lvalue" if not CExpression.lvalue?(val)
2646
+ CExpression.new(val, tok.raw.to_sym, nil, val.type)
2647
+ when '->'
2648
+ # XXX allow_bad_c..
2649
+ raise tok, "#{val}: not a pointer" if not val.type.pointer?
2650
+ type = val.type.pointed.untypedef
2651
+ raise tok, "#{val}: bad pointer" if not type.kind_of? Union
2652
+ raise tok, "#{val}: incomplete type" if not type.members
2653
+ raise tok, "#{val}: invalid member" if not tok = parser.skipspaces or tok.type != :string or not m = type.findmember(tok.raw)
2654
+ CExpression.new(val, :'->', tok.raw, m.type)
2655
+ end
2656
+ when '.'
2657
+ type = val.type.untypedef
2658
+ if not ntok = parser.skipspaces or ntok.type != :string or not type.kind_of? Union
2659
+ parser.unreadtok ntok
2660
+ nil
2661
+ else
2662
+ raise ntok, "#{val}: incomplete type" if not type.members
2663
+ raise ntok, "#{val}: invalid member" if not m = type.findmember(ntok.raw)
2664
+ CExpression.new(val, :'.', ntok.raw, m.type)
2665
+ end
2666
+ when '['
2667
+ raise tok, "#{val}: index expected" if not idx = parse(parser, scope)
2668
+ val, idx = idx, val if not val.type.pointer? # fake support of "4[tab]"
2669
+ raise tok, "#{val}: not a pointer" if not val.type.pointer?
2670
+ raise tok, "#{val}: invalid index" if not idx.type.integral?
2671
+ raise tok, "#{val}: get perpendicular ! (elsewhere)" if idx.kind_of?(CExpression) and idx.op == :','
2672
+ raise tok || parser, "']' expected" if not tok = parser.skipspaces or tok.type != :punct or tok.raw != ']'
2673
+ type = val.type.untypedef.type
2674
+ # TODO boundscheck (and become king of the universe)
2675
+ CExpression.new(val, :'[]', idx, type)
2676
+ when '('
2677
+ type = val.type.untypedef
2678
+ type = type.type.untypedef if type.kind_of? Pointer
2679
+ raise tok, "#{val}: not a function" if not type.kind_of? Function
2680
+
2681
+ args = []
2682
+ loop do
2683
+ a = parse(parser, scope, false)
2684
+ break if not a
2685
+ args << a
2686
+ if not ntok = parser.skipspaces or ntok.type != :punct or ntok.raw != ','
2687
+ parser.unreadtok ntok
2688
+ break
2689
+ end
2690
+ end
2691
+ raise ntok || parser, "#{val}: ')' expected" if not ntok = parser.skipspaces or ntok.type != :punct or ntok.raw != ')'
2692
+
2693
+ type.args ||= []
2694
+ raise tok, "#{val}: bad argument count: #{args.length} for #{type.args.length}" if (type.varargs ? (args.length < type.args.length) : (args.length != type.args.length))
2695
+ type.args.zip(args) { |ta, a|
2696
+ p, i = ta.type.pointer?, ta.type.integral?
2697
+ r = a.reduce(parser) if p or i
2698
+ if (not p and not i) or (i and not r.kind_of? ::Integer) or (p and r != 0)
2699
+ tok = tok.dup ; tok.raw = a.to_s
2700
+ parser.check_compatible_type(tok, a.type, ta.type)
2701
+ end
2702
+ }
2703
+ CExpression.new(val, :funcall, args, type.type)
2704
+ end
2705
+ end
2706
+
2707
+ if nval
2708
+ parse_value_postfix(parser, scope, nval)
2709
+ else
2710
+ parser.unreadtok tok
2711
+ val
2712
+ end
2713
+ end
2714
+
2715
+ def parse(parser, scope, allow_coma = true)
2716
+ opstack = []
2717
+ stack = []
2718
+
2719
+ popstack = lambda {
2720
+ r, l = stack.pop, stack.pop
2721
+ case op = opstack.pop
2722
+ when :'?:'
2723
+ stack << CExpression.new(stack.pop, op, [l, r], l.type)
2724
+ when :','
2725
+ stack << CExpression.new(l, op, r, r.type)
2726
+ when :'='
2727
+ parser.check_compatible_type(parser, r.type, l.type)
2728
+ stack << CExpression.new(l, op, r, l.type)
2729
+ when :'&&', :'||'
2730
+ stack << CExpression.new(l, op, r, BaseType.new(:int))
2731
+ else
2732
+ # XXX struct == struct ?
2733
+ raise parser, "invalid type #{l.type} #{l} for #{op.inspect}" if not l.type.arithmetic? and not parser.allow_bad_c
2734
+ raise parser, "invalid type #{r.type} #{r} for #{op.inspect}" if not r.type.arithmetic? and not parser.allow_bad_c
2735
+
2736
+ if l.type.pointer? and r.type.pointer?
2737
+ type = \
2738
+ case op
2739
+ when :'-'; BaseType.new(:long) # addr_t or sumthin ?
2740
+ when :'-='; l.type
2741
+ when :'>', :'>=', :'<', :'<=', :'==', :'!='; BaseType.new(:long)
2742
+ else raise parser, "cannot do #{op.inspect} on pointers" unless parser.allow_bad_c ; l.type
2743
+ end
2744
+ elsif l.type.pointer? or r.type.pointer?
2745
+ puts parser.exception("should not #{op.inspect} a pointer").message if $VERBOSE and not [:'+', :'-', :'=', :'+=', :'-=', :==, :'!='].include? op
2746
+ type = l.type.pointer? ? l.type : r.type
2747
+ else
2748
+ # yay integer promotion
2749
+ lt = l.type.untypedef
2750
+ rt = r.type.untypedef
2751
+ if (t = lt).name == :longdouble or (t = rt).name == :longdouble or
2752
+ (t = lt).name == :double or (t = rt).name == :double or
2753
+ (t = lt).name == :float or (t = rt).name == :float
2754
+ # long double > double > float ...
2755
+ type = t
2756
+ elsif true
2757
+ # custom integer rules based on type sizes
2758
+ lts = parser.typesize[lt.name]
2759
+ rts = parser.typesize[rt.name]
2760
+ its = parser.typesize[:int]
2761
+ if not lts or not rts
2762
+ type = BaseType.new(:int)
2763
+ elsif lts > rts and lts >= its
2764
+ type = lt
2765
+ elsif rts > lts and rts >= its
2766
+ type = rt
2767
+ elsif lts == rts and lts >= its
2768
+ type = lt
2769
+ type = rt if rt.specifier == :unsigned
2770
+ else
2771
+ type = BaseType.new(:int)
2772
+ end
2773
+ # end of custom rules
2774
+ elsif ((t = lt).name == :long and t.specifier == :unsigned) or
2775
+ ((t = rt).name == :long and t.specifier == :unsigned)
2776
+ # ... ulong ...
2777
+ type = t
2778
+ elsif (lt.name == :long and rt.name == :int and rt.specifier == :unsigned) or
2779
+ (rt.name == :long and lt.name == :int and lt.specifier == :unsigned)
2780
+ # long+uint => ulong
2781
+ type = BaseType.new(:long, :unsigned)
2782
+ elsif (t = lt).name == :long or (t = rt).name == :long or
2783
+ ((t = lt).name == :int and t.specifier == :unsigned) or
2784
+ ((t = rt).name == :int and t.specifier == :unsigned)
2785
+ # ... long > uint ...
2786
+ type = t
2787
+ else
2788
+ # int
2789
+ type = BaseType.new(:int)
2790
+ end
2791
+ end
2792
+
2793
+ case op
2794
+ when :'>', :'>=', :'<', :'<=', :'==', :'!='
2795
+ # cast both sides
2796
+ l = CExpression[l, type] if l.type != type
2797
+ r = CExpression[r, type] if r.type != type
2798
+ stack << CExpression.new(l, op, r, BaseType.new(:int))
2799
+ else
2800
+ # promote result
2801
+ stack << CExpression.new(l, op, r, type)
2802
+ end
2803
+ end
2804
+ }
2805
+
2806
+ return if not e = parse_value(parser, scope)
2807
+
2808
+ stack << e
2809
+
2810
+ while op = readop(parser)
2811
+ case op.value
2812
+ when :'?'
2813
+ # a, b ? c, d : e, f == a, (b ? (c, d) : e), f
2814
+ until opstack.empty? or OP_PRIO[opstack.last][:'?:']
2815
+ popstack[]
2816
+ end
2817
+ stack << parse(parser, scope)
2818
+ raise op || parser, '":" expected' if not op = readop(parser) or op.value != :':'
2819
+ op = op.dup
2820
+ op.value = :'?:'
2821
+ when :':'
2822
+ parser.unreadtok op
2823
+ break
2824
+ else
2825
+ if not allow_coma and op.value == :','
2826
+ parser.unreadtok op
2827
+ break
2828
+ end
2829
+ until opstack.empty? or OP_PRIO[op.value][opstack.last]
2830
+ popstack[]
2831
+ end
2832
+ end
2833
+
2834
+ raise op, 'need rhs' if not e = parse_value(parser, scope)
2835
+ stack << e
2836
+ opstack << op.value
2837
+ end
2838
+
2839
+ until opstack.empty?
2840
+ popstack[]
2841
+ end
2842
+
2843
+ CExpression[stack.first]
2844
+ end
2845
+ end
2846
+ end
2847
+
2848
+
2849
+
2850
+ #
2851
+ # AllocCStruct: ruby interpreter memory-mapped structure
2852
+ #
2853
+
2854
+ # this maps a C structure from a C parser to a ruby String
2855
+ # struct members are accessed through obj['fldname']
2856
+ # obj.fldname is an alias
2857
+ class AllocCStruct
2858
+ # str is a reference to the underlying ruby String
2859
+ # stroff is the offset from the start of this string (non-nul for nested structs)
2860
+ # cp is a reference to the C::Parser
2861
+ # struct to the C::Union/Struct/Array
2862
+ # sizeof is the byte size of the C struct
2863
+ attr_accessor :str, :stroff, :cp, :struct
2864
+ attr_writer :sizeof
2865
+ def initialize(cp, struct, str=nil, stroff=0)
2866
+ @cp, @struct = cp, struct
2867
+ @str = str || [0].pack('C')*sizeof
2868
+ @stroff = stroff
2869
+ end
2870
+
2871
+ def sizeof
2872
+ @sizeof ||= @cp.sizeof(@struct)
2873
+ end
2874
+
2875
+ def [](*a)
2876
+ if @struct.kind_of? C::Array and a.length == 1 and @struct.length and a[0].kind_of? Integer
2877
+ i = a[0]
2878
+ raise "#{i} out of bounds 0...#{@struct.length}" if i < 0 or i >= @struct.length
2879
+ off = @stroff + i*@cp.sizeof(@struct.type)
2880
+ return @cp.decode_c_value(@str, @struct.type, off)
2881
+ end
2882
+
2883
+ return @str[@stroff..-1][*a] if a.length != 1
2884
+ a = a.first
2885
+ return @str[@stroff..-1][a] if not a.kind_of? Symbol and not a.kind_of? String and not a.kind_of? C::Variable
2886
+ f = a
2887
+ raise "#{a.inspect} not a member" if not f.kind_of? C::Variable and not f = @struct.findmember(a.to_s, true)
2888
+ a = f.name || f
2889
+ off = @stroff + @struct.offsetof(@cp, a)
2890
+ if bf = @struct.bitoffsetof(@cp, a)
2891
+ ft = C::BaseType.new((bf[0] + bf[1] > 32) ? :__int64 : :__int32)
2892
+ v = @cp.decode_c_value(@str, ft, off)
2893
+ (v >> bf[0]) & ((1 << bf[1])-1)
2894
+ else
2895
+ @cp.decode_c_value(@str, f, off)
2896
+ end
2897
+ end
2898
+
2899
+ def []=(*a)
2900
+ if @struct.kind_of? C::Array and a.length == 2 and @struct.length and a[0].kind_of? Integer
2901
+ i = a[0]
2902
+ raise "#{i} out of bounds 0...#{@struct.length}" if i < 0 or i >= @struct.length
2903
+ off = @stroff + i*@cp.sizeof(@struct.type)
2904
+ val = @cp.encode_c_value(@struct.type, a[1])
2905
+ @str[off, val.length] = val
2906
+ return
2907
+ end
2908
+
2909
+ if not a.first.kind_of? Symbol and not a.first.kind_of? String and not a.first.kind_of? C::Variable
2910
+ # patch @str[@stroff..-1] like a string
2911
+ # so we must find the intended start offset, and add @stroff to it
2912
+ if @stroff != 0
2913
+ case a.first
2914
+ when Range
2915
+ if a.first.begin >= 0
2916
+ a[0] = ::Range.new(a[0].begin+@stroff, a[0].end+@stroff, a[0].exclude_end?)
2917
+ else raise 'no can do, use positive index'
2918
+ end
2919
+ when Integer
2920
+ if a.first >= 0
2921
+ a[0] += @stroff
2922
+ else raise 'no can do, use positive index'
2923
+ end
2924
+ else raise 'no can do'
2925
+ end
2926
+ end
2927
+
2928
+ return @str.send(:'[]=', *a) # XXX *should* work...
2929
+ end
2930
+
2931
+ a, val = a
2932
+ raise "#{a.inspect} not a struct member" if not a.kind_of? C::Variable and not f = @struct.findmember(a.to_s, true)
2933
+ a = f.name if a.kind_of? String or a.kind_of? Symbol
2934
+ val = sizeof if val == :size
2935
+ off = @stroff + @struct.offsetof(@cp, a)
2936
+
2937
+ if bf = @struct.bitoffsetof(@cp, a)
2938
+ raise "only Integers supported in bitfield #{a}, got #{val.inspect}" if not val.kind_of?(::Integer)
2939
+ # struct { int i:8; }; => size 8 or 32 ?
2940
+ ft = C::BaseType.new((bf[0] + bf[1] > 32) ? :__int64 : :__int32)
2941
+ mask = ((1 << bf[1]) - 1) << bf[0]
2942
+ preval = @cp.decode_c_value(@str, ft, off)
2943
+ val = (preval & ~mask) | ((val << bf[0]) & mask)
2944
+ f = ft
2945
+ end
2946
+
2947
+ val = @cp.encode_c_value(f, val)
2948
+ @str[off, val.length] = val
2949
+ end
2950
+
2951
+ # virtual accessors to members
2952
+ # struct.foo is aliased to struct['foo'],
2953
+ # struct.foo = 42 aliased to struct['foo'] = 42
2954
+ def method_missing(on, *a)
2955
+ n = on.to_s
2956
+ if n[-1] == ?=
2957
+ send :[]=, n[0...-1], *a
2958
+ else
2959
+ super(on, *a) if not @struct.kind_of?(C::Union) or not @struct.findmember(n, true)
2960
+ send :[], n, *a
2961
+ end
2962
+ end
2963
+
2964
+ def to_s(off=nil, maxdepth=500)
2965
+ return '{ /* ... */ }' if maxdepth <= 0
2966
+ str = ['']
2967
+ if @struct.kind_of?(C::Array)
2968
+ str.last << "#{@struct.type} x[#{@struct.length}] = " if not off
2969
+ mlist = (0...@struct.length)
2970
+ fldoff = mlist.inject({}) { |h, i| h.update i => i*@cp.sizeof(@struct.type) }
2971
+ elsif @struct.kind_of?(C::Struct)
2972
+ str.last << "struct #{@struct.name || '_'} x = " if not off
2973
+ @struct.update_member_cache(@cp) if not @struct.fldlist
2974
+ fldoff = @struct.fldoffset
2975
+ fbo = @struct.fldbitoffset || {}
2976
+ mlist = @struct.members.map { |m| m.name || m }
2977
+ else
2978
+ str.last << "union #{@struct.name || '_'} x = " if not off
2979
+ mlist = @struct.members.map { |m| m.name || m }
2980
+ end
2981
+ str.last << '{'
2982
+ mlist.each { |k|
2983
+ if k.kind_of? Variable # anonymous member
2984
+ curoff = off.to_i + @struct.offsetof(@cp, k)
2985
+ val = self[k]
2986
+ k = '?'
2987
+ else
2988
+ curoff = off.to_i + (fldoff ? fldoff[k].to_i : 0)
2989
+ val = self[k]
2990
+ end
2991
+ if val.kind_of?(::Integer)
2992
+ if val >= 0x100
2993
+ val = '0x%X, // +%x' % [val, curoff]
2994
+ elsif val <= -0x100
2995
+ val = '-0x%X, // +%x' % [-val, curoff]
2996
+ else
2997
+ val = '%d, // +%x' % [val, curoff]
2998
+ end
2999
+ elsif val.kind_of? AllocCStruct
3000
+ val = val.to_s(curoff, maxdepth-1)
3001
+ elsif not val
3002
+ val = 'NULL, // +%x' % curoff # pointer with NULL value
3003
+ else
3004
+ val = val.to_s.sub(/$/, ', // +%x' % curoff)
3005
+ end
3006
+ val = val.gsub("\n", "\n\t")
3007
+ str << "\t#{k.kind_of?(::Integer) ? "[#{k}]" : ".#{k}"} = #{val}"
3008
+ }
3009
+ str << '}'
3010
+ str.last << (off ? ',' : ';')
3011
+ str.join("\n")
3012
+ end
3013
+
3014
+ def to_array
3015
+ raise NoMethodError, "Not an Array" if not @struct.kind_of?(C::Array)
3016
+ ary = []
3017
+ @struct.length.times { |i| ary << self[i] }
3018
+ ary
3019
+ end
3020
+
3021
+ def to_strz
3022
+ raise NoMethodError, "Not an Array" if not @struct.kind_of?(C::Array)
3023
+ a = to_array
3024
+ a[a.index(0)..-1] = [] if a.index(0)
3025
+ a.pack('C*')
3026
+ end
3027
+ end
3028
+
3029
+ class Parser
3030
+ # find a Struct/Union object from a struct name/typedef name
3031
+ # raises if it cant find it
3032
+ def find_c_struct(structname)
3033
+ structname = structname.to_s if structname.kind_of?(::Symbol)
3034
+ if structname.kind_of?(::String) and not struct = @toplevel.struct[structname]
3035
+ struct = @toplevel.symbol[structname]
3036
+ raise "unknown struct #{structname.inspect}" if not struct
3037
+ struct = struct.type.untypedef
3038
+ struct = struct.pointed while struct.pointer?
3039
+ raise "unknown struct #{structname.inspect}" if not struct.kind_of? C::Union
3040
+ end
3041
+ struct = structname if structname.kind_of? C::Union
3042
+ raise "unknown struct #{structname.inspect}" if not struct.kind_of? C::Union
3043
+ struct
3044
+ end
3045
+
3046
+ # find a C::Type (struct/union/typedef/basetype) from a string
3047
+ def find_c_type(typename)
3048
+ typename = typename.to_s if typename.kind_of? ::Symbol
3049
+ if typename.kind_of?(::String) and not type = @toplevel.struct[typename]
3050
+ if type = @toplevel.symbol[typename]
3051
+ type = type.type.untypedef
3052
+ else
3053
+ begin
3054
+ lexer.feed(typename)
3055
+ b = C::Block.new(@toplevel)
3056
+ var = Variable.parse_type(self, b)
3057
+ var.parse_declarator(self, b)
3058
+ type = var.type
3059
+ rescue
3060
+ end
3061
+ end
3062
+ end
3063
+ type = typename if typename.kind_of?(C::Type)
3064
+ raise "unknown type #{typename.inspect}" if not type.kind_of? C::Type
3065
+ type
3066
+ end
3067
+
3068
+ # allocate a new AllocCStruct from the struct/struct typedef name of the current toplevel
3069
+ # optionally populate the fields using the 'values' hash
3070
+ def alloc_c_struct(structname, values=nil)
3071
+ struct = find_c_struct(structname)
3072
+ st = AllocCStruct.new(self, struct)
3073
+ values.each { |k, v| st[k] = v } if values
3074
+ st
3075
+ end
3076
+
3077
+ # parse a given String as an AllocCStruct
3078
+ # offset is an optionnal offset from the string start
3079
+ # modification to the structure will modify the underlying string
3080
+ def decode_c_struct(structname, str, offset=0)
3081
+ struct = find_c_struct(structname)
3082
+ AllocCStruct.new(self, struct, str, offset)
3083
+ end
3084
+
3085
+ # allocate an array of types
3086
+ # init is either the length of the array, or an array of initial values
3087
+ def alloc_c_ary(typename, init=1)
3088
+ type = find_c_type(typename)
3089
+ len = init.kind_of?(Integer) ? init : init.length
3090
+ struct = C::Array.new(type, len)
3091
+ st = AllocCStruct.new(self, struct)
3092
+ if init.kind_of?(::Array)
3093
+ init.each_with_index { |v, i|
3094
+ st[i] = v
3095
+ }
3096
+ end
3097
+ st
3098
+ end
3099
+
3100
+ # "cast" a string to C::Array
3101
+ def decode_c_ary(typename, len, str, offset=0)
3102
+ type = find_c_type(typename)
3103
+ struct = C::Array.new(type, len)
3104
+ AllocCStruct.new(self, struct, str, offset)
3105
+ end
3106
+
3107
+ # convert (pack) a ruby value into a C buffer
3108
+ # packs integers, converts Strings to their C pointer (using DynLdr)
3109
+ def encode_c_value(type, val)
3110
+ type = type.type if type.kind_of? Variable
3111
+
3112
+ case val
3113
+ when nil; val = 0
3114
+ when ::Integer
3115
+ when ::String
3116
+ val = DynLdr.str_ptr(val)
3117
+ when ::Hash
3118
+ type = type.pointed while type.pointer?
3119
+ raise "need a struct ptr for #{type} #{val.inspect}" if not type.kind_of? Union
3120
+ buf = alloc_c_struct(type, val)
3121
+ val.instance_variable_set('@rb2c', buf) # GC trick
3122
+ val = buf
3123
+ when ::Proc
3124
+ val = DynLdr.convert_rb2c(type, val) # allocate a DynLdr callback
3125
+ when AllocCStruct
3126
+ val = DynLdr.str_ptr(val.str) + val.stroff
3127
+ #when ::Float # TODO
3128
+ else raise "TODO #{val.inspect}"
3129
+ end
3130
+
3131
+ val = Expression.encode_immediate(val, sizeof(type), @endianness) if val.kind_of?(::Integer)
3132
+
3133
+ val
3134
+ end
3135
+
3136
+ def decode_c_value(str, type, off=0)
3137
+ type = type.type if type.kind_of? Variable
3138
+ type = type.untypedef
3139
+ if type.kind_of? C::Union or type.kind_of? C::Array
3140
+ return AllocCStruct.new(self, type, str, off)
3141
+ end
3142
+ val = Expression.decode_immediate(str, sizeof(type), @endianness, off)
3143
+ val = Expression.make_signed(val, sizeof(type)*8) if type.integral? and type.signed?
3144
+ val = nil if val == 0 and type.pointer?
3145
+ val
3146
+ end
3147
+ end
3148
+
3149
+
3150
+ #
3151
+ # Dumper : objects => C source
3152
+ #
3153
+
3154
+ class Parser
3155
+ # returns a big string containing all definitions from headers used in the source (including macros)
3156
+ def factorize(*a)
3157
+ factorize_init
3158
+ parse(*a)
3159
+ raise @lexer.readtok || self, 'eof expected' if not @lexer.eos?
3160
+ factorize_final
3161
+ end
3162
+
3163
+ def factorize_init
3164
+ @lexer.traced_macros = []
3165
+ end
3166
+
3167
+ def factorize_final
3168
+ # now find all types/defs not coming from the standard headers
3169
+ # all
3170
+ all = @toplevel.struct.values + @toplevel.symbol.values
3171
+ all -= all.grep(::Integer) # Enum values
3172
+
3173
+ # list of definitions of user-defined objects
3174
+ userdefined = all.find_all { |t|
3175
+ t.backtrace.backtrace.grep(::String).grep(/^</).empty?
3176
+ }
3177
+
3178
+ @toplevel.statements.clear # don't want all Declarations
3179
+
3180
+ # a macro is fine too
3181
+ @lexer.dump_macros(@lexer.traced_macros, false) + "\n\n" +
3182
+ dump_definitions(userdefined, userdefined)
3183
+ end
3184
+
3185
+ # returns a big string representing the definitions of all terms appearing in +list+, excluding +exclude+
3186
+ # includes dependencies
3187
+ def dump_definitions(list, exclude=[])
3188
+ # recurse all dependencies
3189
+ todo_rndr = {}
3190
+ todo_deps = {}
3191
+ list.each { |t|
3192
+ todo_rndr[t], todo_deps[t] = t.dump_def(@toplevel)
3193
+ }
3194
+ # c.toplevel.anonymous_enums.to_a.each { |t| todo_rndr[t], todo_deps[t] = t.dump_def(c.toplevel) }
3195
+ while !(ar = (todo_deps.values.flatten - todo_deps.keys)).empty?
3196
+ ar.each { |t|
3197
+ todo_rndr[t], todo_deps[t] = t.dump_def(@toplevel)
3198
+ }
3199
+ end
3200
+ exclude.each { |t| todo_deps.delete t ; todo_rndr.delete t }
3201
+ todo_deps.each_key { |t| todo_deps[t] -= exclude }
3202
+
3203
+ all = @toplevel.struct.values + @toplevel.symbol.values
3204
+ all -= all.grep(::Integer) # Enum values
3205
+
3206
+ r, dep = @toplevel.dump_reorder(all, todo_rndr, todo_deps)
3207
+ r.join("\n")
3208
+ end
3209
+
3210
+ # returns a string containing the C definition(s) of toplevel functions, with their dependencies
3211
+ def dump_definition(*funcnames)
3212
+ oldst = @toplevel.statements
3213
+ @toplevel.statements = []
3214
+ dump_definitions(funcnames.map { |f| @toplevel.symbol[f] })
3215
+ ensure
3216
+ @toplevel.statements = oldst
3217
+ end
3218
+
3219
+ def to_s
3220
+ @toplevel.dump(nil)[0].join("\n")
3221
+ end
3222
+ end
3223
+
3224
+ class Statement
3225
+ def self.dump(e, scope, r=[''], dep=[])
3226
+ case e
3227
+ when nil; r.last << ';'
3228
+ when Block
3229
+ r.last << ' ' if not r.last.empty?
3230
+ r.last << '{'
3231
+ tr, dep = e.dump(scope, [''], dep)
3232
+ tr.pop if tr.last.empty?
3233
+ r.concat tr.map { |s| Case.dump_indent(s) }
3234
+ (r.last[-1] == ?{ ? r.last : r) << '}'
3235
+ else
3236
+ tr, dep = e.dump(scope, [''], dep)
3237
+ r.concat tr.map { |s| Case.dump_indent(s) }
3238
+ end
3239
+ [r, dep]
3240
+ end
3241
+
3242
+ def to_s
3243
+ dump(Block.new(nil))[0].join(' ')
3244
+ end
3245
+ end
3246
+
3247
+ class Block
3248
+ def to_s() dump(nil)[0].join("\n") end
3249
+
3250
+ # return array of c source lines and array of dependencies (objects)
3251
+ def dump(scp, r=[''], dep=[])
3252
+ mydefs = @symbol.values.grep(TypeDef) + @struct.values + anonymous_enums.to_a
3253
+ todo_rndr = {}
3254
+ todo_deps = {}
3255
+ mydefs.each { |t| # filter out Enum values
3256
+ todo_rndr[t], todo_deps[t] = t.dump_def(self)
3257
+ }
3258
+ r, dep = dump_reorder(mydefs, todo_rndr, todo_deps, r, dep)
3259
+ dep -= @symbol.values + @struct.values
3260
+ [r, dep]
3261
+ end
3262
+
3263
+ def dump_reorder(mydefs, todo_rndr, todo_deps, r=[''], dep=[])
3264
+ val = todo_deps.values.flatten.uniq
3265
+ dep |= val
3266
+ dep -= mydefs | todo_deps.keys
3267
+ todo_deps.each { |k, v| v.delete k }
3268
+ ext = val - mydefs
3269
+ if ext.length > todo_deps.length
3270
+ todo_deps.each_key { |k| todo_deps[k] = todo_deps[k] & mydefs }
3271
+ else
3272
+ ext.each { |k| todo_deps.each_value { |v| v.delete k } }
3273
+ end
3274
+
3275
+ # predeclare structs involved in cyclic dependencies
3276
+ dep_cycle = lambda { |ary|
3277
+ # sexyness inside (c)
3278
+ deps = todo_deps[ary.last]
3279
+ if deps.include? ary.first; ary
3280
+ elsif (deps-ary).find { |d| deps = dep_cycle[ary + [d]] }; deps
3281
+ end
3282
+ }
3283
+ todo_rndr.keys.grep(Union).find_all { |t| t.name }.sort_by { |t| t.name }.each { |t|
3284
+ oldc = nil
3285
+ while c = dep_cycle[[t]]
3286
+ break if oldc == c
3287
+ r << "#{t.kind_of?(Struct) ? 'struct' : 'union'} #{t.name};" if not oldc
3288
+ oldc = c
3289
+ c.each { |s|
3290
+ # XXX struct z { struct a* }; struct a { void (*foo)(struct z); };
3291
+ todo_deps[s].delete t unless s.kind_of? Union and
3292
+ s.members.find { |sm| sm.type.untypedef == t }
3293
+ }
3294
+ end
3295
+ }
3296
+
3297
+ loop do
3298
+ break if todo_rndr.empty?
3299
+ todo_now = todo_deps.keys.find_all { |k| todo_deps[k].empty? }
3300
+ if todo_now.empty?
3301
+ r << '// dependency problem, this may not compile'
3302
+ todo_now = todo_deps.keys
3303
+ end
3304
+ todo_now.sort_by { |k| k.name || '0' }.each { |k|
3305
+ if k.kind_of? Variable and k.type.kind_of? Function and k.initializer
3306
+ r << ''
3307
+ r.concat todo_rndr.delete(k)
3308
+ else
3309
+ r.pop if r.last == ''
3310
+ r.concat todo_rndr.delete(k)
3311
+ r.last << ';'
3312
+ end
3313
+ todo_deps.delete k
3314
+ }
3315
+ todo_deps.each_key { |k| todo_deps[k] -= todo_now }
3316
+ r << '' << '' << ''
3317
+ end
3318
+
3319
+ @statements.each { |s|
3320
+ r << '' if not r.last.empty?
3321
+ if s.kind_of? Block
3322
+ r, dep = Statement.dump(s, self, r, dep)
3323
+ else
3324
+ r, dep = s.dump(self, r, dep)
3325
+ end
3326
+ }
3327
+
3328
+ [r, dep]
3329
+ end
3330
+ end
3331
+ class Declaration
3332
+ def dump(scope, r=[''], dep=[])
3333
+ tr, dep = @var.dump_def(scope, [''], dep)
3334
+ if @var.kind_of? Variable and @var.type.kind_of? Function and @var.initializer
3335
+ r << ''
3336
+ r.concat tr
3337
+ else
3338
+ r.pop if r.last == ''
3339
+ r.concat tr
3340
+ r.last << ';'
3341
+ end
3342
+ [r, dep]
3343
+ end
3344
+
3345
+ def to_s
3346
+ dump(Block.new(nil))[0].join(' ')
3347
+ end
3348
+ end
3349
+ module Attributes
3350
+ def dump_attributes
3351
+ if attributes
3352
+ (attributes - DECLSPECS).map { |a| " __attribute__((#{a}))" }.join
3353
+ else ''
3354
+ end
3355
+ end
3356
+ def dump_attributes_pre
3357
+ if attributes
3358
+ (attributes & DECLSPECS).map { |a| "__#{a} " }.join
3359
+ else ''
3360
+ end
3361
+ end
3362
+ end
3363
+ class Variable
3364
+ def dump(scope, r=[''], dep=[])
3365
+ if name
3366
+ dep |= [scope.symbol_ancestors[@name]]
3367
+ r.last << @name
3368
+ end
3369
+ [r, dep]
3370
+ end
3371
+ def dump_def(scope, r=[''], dep=[], skiptype=false)
3372
+ # int a=1, b=2;
3373
+ r.last << dump_attributes_pre
3374
+ if not skiptype
3375
+ r.last << @storage.to_s << ' ' if storage
3376
+ r, dep = @type.base.dump(scope, r, dep)
3377
+ r.last << ' ' if name
3378
+ end
3379
+ r, dep = @type.dump_declarator([(name ? @name.dup : '') << dump_attributes], scope, r, dep)
3380
+
3381
+ if initializer
3382
+ r.last << ' = ' if not @type.kind_of?(Function)
3383
+ r, dep = @type.dump_initializer(@initializer, scope, r, dep)
3384
+ end
3385
+ [r, dep]
3386
+ end
3387
+
3388
+ def to_s
3389
+ dump(Block.new(nil))[0].join(' ')
3390
+ end
3391
+ end
3392
+ class Type
3393
+ def dump_initializer(init, scope, r=[''], dep=[])
3394
+ case init
3395
+ when ::Numeric
3396
+ r.last << init.to_s
3397
+ [r, dep]
3398
+ when ::Array
3399
+ r.last << init.inspect
3400
+ [r, dep]
3401
+ else init.dump_inner(scope, r, dep)
3402
+ end
3403
+ end
3404
+
3405
+ def dump_declarator(decl, scope, r=[''], dep=[])
3406
+ r.last << decl.shift
3407
+ r.concat decl
3408
+ [r, dep]
3409
+ end
3410
+
3411
+ def dump_def(*a)
3412
+ dump(*a)
3413
+ end
3414
+
3415
+ def dump_cast(scope, r=[''], dep=[])
3416
+ r.last << '('
3417
+ r.last << dump_attributes_pre if not kind_of? TypeDef
3418
+ r, dep = base.dump(scope, r, dep)
3419
+ r, dep = dump_declarator([kind_of?(TypeDef) ? '' : dump_attributes], scope, r, dep)
3420
+ r.last << ')'
3421
+ [r, dep]
3422
+ end
3423
+
3424
+ def to_s
3425
+ dump_cast(Block.new(nil))[0].join(' ')
3426
+ end
3427
+ end
3428
+ class Pointer
3429
+ def dump_declarator(decl, scope, r=[''], dep=[])
3430
+ d = decl[0]
3431
+ decl[0] = '*'
3432
+ decl[0] << ' ' << @qualifier.map { |q| q.to_s }.join(' ') << ' ' if qualifier
3433
+ decl[0] << d
3434
+ if @type.kind_of? Function or @type.kind_of? Array
3435
+ decl[0] = '(' << decl[0]
3436
+ decl.last << ')'
3437
+ end
3438
+ @type.dump_declarator(decl, scope, r, dep)
3439
+ end
3440
+ end
3441
+ class Array
3442
+ def dump_declarator(decl, scope, r=[''], dep=[])
3443
+ decl.last << '()' if decl.last.empty?
3444
+ decl.last << '['
3445
+ decl, dep = CExpression.dump(@length, scope, decl, dep) if length
3446
+ decl.last << ']'
3447
+ @type.dump_declarator(decl, scope, r, dep)
3448
+ end
3449
+ def dump_initializer(init, scope, r=[''], dep=[])
3450
+ return super(init, scope, r, dep) if not init.kind_of? ::Array
3451
+ r.last << '{ '
3452
+ showname = false
3453
+ init.each_with_index { |v, i|
3454
+ if not v
3455
+ showname = true
3456
+ next
3457
+ end
3458
+ r.last << ', ' if r.last[-2, 2] != '{ '
3459
+ rt = ['']
3460
+ if showname
3461
+ showname = false
3462
+ rt << "[#{i}] = "
3463
+ end
3464
+ rt, dep = @type.dump_initializer(v, scope, rt, dep)
3465
+ r.last << rt.shift
3466
+ r.concat rt.map { |s| "\t" << s }
3467
+ }
3468
+ r.last << ' }'
3469
+ [r, dep]
3470
+ end
3471
+ end
3472
+ class Function
3473
+ def dump_declarator(decl, scope, r=[''], dep=[])
3474
+ decl.last << '()' if decl.last.empty?
3475
+ decl.last << '('
3476
+ if args
3477
+ @args.each { |arg|
3478
+ decl.last << ', ' if decl.last[-1] != ?(
3479
+ decl, dep = arg.dump_def(scope, decl, dep)
3480
+ }
3481
+ if varargs
3482
+ decl.last << ', ' if decl.last[-1] != ?(
3483
+ decl.last << '...'
3484
+ else
3485
+ decl.last << 'void' if @args.empty?
3486
+ end
3487
+ end
3488
+ decl.last << ')'
3489
+ @type.dump_declarator(decl, scope, r, dep)
3490
+ end
3491
+
3492
+ def dump_initializer(init, scope, r=[''], dep=[])
3493
+ Statement.dump(init, scope, r << '', dep)
3494
+ end
3495
+ end
3496
+ class BaseType
3497
+ def dump(scope, r=[''], dep=[])
3498
+ r.last << @qualifier.map { |q| q.to_s << ' ' }.join if qualifier
3499
+ r.last << @specifier.to_s << ' ' if specifier and @name != :ptr
3500
+ r.last << case @name
3501
+ when :longlong; 'long long'
3502
+ when :longdouble; 'long double'
3503
+ when :ptr; specifier == :unsigned ? 'uintptr_t' : 'intptr_t'
3504
+ else @name.to_s
3505
+ end
3506
+ [r, dep]
3507
+ end
3508
+ end
3509
+ class TypeDef
3510
+ def dump(scope, r=[''], dep=[])
3511
+ r.last << @qualifier.map { |q| q.to_s << ' ' }.join if qualifier
3512
+ r.last << @name
3513
+ dep |= [scope.symbol_ancestors[@name]]
3514
+ [r, dep]
3515
+ end
3516
+
3517
+ def dump_def(scope, r=[''], dep=[])
3518
+ r.last << 'typedef '
3519
+ r.last << dump_attributes_pre
3520
+ r, dep = @type.base.dump(scope, r, dep)
3521
+ r.last << ' '
3522
+ @type.dump_declarator([(name ? @name.dup : '') << dump_attributes], scope, r, dep)
3523
+ end
3524
+
3525
+ def dump_initializer(init, scope, r=[''], dep=[])
3526
+ @type.dump_initializer(init, scope, r, dep)
3527
+ end
3528
+ end
3529
+ class Union
3530
+ def dump(scope, r=[''], dep=[])
3531
+ if name
3532
+ r.last << @qualifier.map { |q| q.to_s << ' ' }.join if qualifier
3533
+ r.last << self.class.name.downcase[/(?:.*::)?(.*)/, 1] << ' ' << @name
3534
+ dep |= [scope.struct_ancestors[@name]]
3535
+ [r, dep]
3536
+ else
3537
+ dump_def(scope, r, dep)
3538
+ end
3539
+ end
3540
+
3541
+ def dump_def(scope, r=[''], dep=[])
3542
+ r << ''
3543
+ r.last << @qualifier.map { |q| q.to_s << ' ' }.join if qualifier
3544
+ r.last << self.class.name.downcase[/(?:.*::)?(.*)/, 1]
3545
+ r.last << ' ' << @name if name
3546
+ if members
3547
+ r.last << ' {'
3548
+ @members.each_with_index { |m,i|
3549
+ tr, dep = m.dump_def(scope, [''], dep)
3550
+ tr.last << ':' << @bits[i].to_s if bits and @bits[i]
3551
+ tr.last << ';'
3552
+ r.concat tr.map { |s| "\t" << s }
3553
+ }
3554
+ r << '}'
3555
+ end
3556
+ r.last << dump_attributes
3557
+ [r, dep]
3558
+ end
3559
+
3560
+ def dump_initializer(init, scope, r=[''], dep=[])
3561
+ return super(init, scope, r, dep) if not init.kind_of? ::Array
3562
+ r.last << '{ '
3563
+ showname = false
3564
+ @members.zip(init) { |m, i|
3565
+ if not i
3566
+ showname = true
3567
+ next
3568
+ end
3569
+ r.last << ', ' if r.last[-2, 2] != '{ '
3570
+ rt = ['']
3571
+ if showname
3572
+ showname = false
3573
+ rt << ".#{m.name} = "
3574
+ end
3575
+ rt, dep = m.type.dump_initializer(i, scope, rt, dep)
3576
+ r.last << rt.shift
3577
+ r.concat rt.map { |s| "\t" << s }
3578
+ }
3579
+ r.last << ' }'
3580
+ [r, dep]
3581
+ end
3582
+ end
3583
+ class Struct
3584
+ def dump_def(scope, r=[''], dep=[])
3585
+ if pack
3586
+ r, dep = super(scope, r, dep)
3587
+ r.last <<
3588
+ if @pack == 1; (has_attribute('packed') or has_attribute_var('pack')) ? '' : " __attribute__((packed))"
3589
+ else has_attribute_var('pack') ? '' : " __attribute__((pack(#@pack)))"
3590
+ end
3591
+ [r, dep]
3592
+ else
3593
+ super(scope, r, dep)
3594
+ end
3595
+ end
3596
+ end
3597
+ class Enum
3598
+ def dump(scope, r=[''], dep=[])
3599
+ if name
3600
+ r.last << @qualifier.map { |q| q.to_s << ' ' }.join if qualifier
3601
+ r.last << 'enum ' << @name
3602
+ dep |= [scope.struct_ancestors[@name]]
3603
+ [r, dep]
3604
+ else
3605
+ dump_def(scope, r, dep)
3606
+ end
3607
+ end
3608
+
3609
+ def dump_def(scope, r=[''], dep=[])
3610
+ r.last << @qualifier.map { |q| q.to_s << ' ' }.join if qualifier
3611
+ r.last << 'enum'
3612
+ r.last << ' ' << @name if name
3613
+ if members
3614
+ r.last << ' { '
3615
+ val = -1
3616
+ @members.sort_by { |m, v| v }.each { |m, v|
3617
+ r.last << ', ' if r.last[-2, 2] != '{ '
3618
+ r.last << m
3619
+ if v != (val += 1)
3620
+ val = v
3621
+ r.last << ' = ' << val.to_s
3622
+ end
3623
+ }
3624
+ r.last << ' }'
3625
+ end
3626
+ [r, dep]
3627
+ end
3628
+
3629
+ def dump_initializer(init, scope, r=[''], dep=[])
3630
+ if members and (
3631
+ k = @members.index(init) or
3632
+ (init.kind_of? CExpression and not init.op and k = @members.index(init.rexpr))
3633
+ )
3634
+ r.last << k
3635
+ dep |= [scope.struct_ancestors[@name]]
3636
+ [r, dep]
3637
+ else super(init, scope, r, dep)
3638
+ end
3639
+ end
3640
+ end
3641
+ class If
3642
+ def dump(scope, r=[''], dep=[])
3643
+ r.last << 'if ('
3644
+ r, dep = CExpression.dump(@test, scope, r, dep)
3645
+ r.last << ')'
3646
+ r, dep = Statement.dump(@bthen, scope, r, dep)
3647
+ if belse
3648
+ @bthen.kind_of?(Block) ? (r.last << ' else') : (r << 'else')
3649
+ if @belse.kind_of? If
3650
+ # skip indent
3651
+ r.last << ' '
3652
+ r, dep = @belse.dump(scope, r, dep)
3653
+ else
3654
+ r, dep = Statement.dump(@belse, scope, r, dep)
3655
+ end
3656
+ end
3657
+ [r, dep]
3658
+ end
3659
+ end
3660
+ class For
3661
+ def dump(scope, r=[''], dep=[])
3662
+ r.last << 'for ('
3663
+ if @init.kind_of? Block
3664
+ scope = @init
3665
+ skiptype = false
3666
+ @init.symbol.each_value { |s|
3667
+ r.last << ', ' if skiptype
3668
+ r, dep = s.dump_def(scope, r, dep, skiptype)
3669
+ skiptype = true
3670
+ }
3671
+ else
3672
+ r, dep = CExpression.dump(@init, scope, r, dep)
3673
+ end
3674
+ r.last << ' ' if @init
3675
+ r.last << ';'
3676
+ r.last << ' ' if @test
3677
+ r, dep = CExpression.dump(@test, scope, r, dep)
3678
+ r.last << ' ' if @test
3679
+ r.last << ';'
3680
+ r.last << ' ' if @iter
3681
+ r, dep = CExpression.dump(@iter, scope, r, dep)
3682
+ r.last << ')'
3683
+ Statement.dump(@body, scope, r, dep)
3684
+ end
3685
+ end
3686
+ class While
3687
+ def dump(scope, r=[''], dep=[])
3688
+ r.last << 'while ('
3689
+ r, dep = CExpression.dump(@test, scope, r, dep)
3690
+ r.last << ')'
3691
+ Statement.dump(@body, scope, r, dep)
3692
+ end
3693
+ end
3694
+ class DoWhile
3695
+ def dump(scope, r=[''], dep=[])
3696
+ r.last << 'do'
3697
+ r, dep = Statement.dump(@body, scope, r, dep)
3698
+ @body.kind_of?(Block) ? (r.last << ' while (') : (r << 'while (')
3699
+ r, dep = CExpression.dump(@test, scope, r, dep)
3700
+ r.last << ');'
3701
+ [r, dep]
3702
+ end
3703
+ end
3704
+ class Switch
3705
+ def dump(scope, r=[''], dep=[])
3706
+ r.last << 'switch ('
3707
+ r, dep = CExpression.dump(@test, scope, r, dep)
3708
+ r.last << ')'
3709
+ r.last << ' {' if @body.kind_of? Block
3710
+ tr, dep = @body.dump(scope, [''], dep)
3711
+ r.concat tr.map { |s| Case.dump_indent(s, true) }
3712
+ r << '}' if @body.kind_of? Block
3713
+ [r, dep]
3714
+ end
3715
+ end
3716
+ class Continue
3717
+ def dump(scope, r=[''], dep=[])
3718
+ r.last << 'continue;'
3719
+ [r, dep]
3720
+ end
3721
+ end
3722
+ class Break
3723
+ def dump(scope, r=[''], dep=[])
3724
+ r.last << 'break;'
3725
+ [r, dep]
3726
+ end
3727
+ end
3728
+ class Goto
3729
+ def dump(scope, r=[''], dep=[])
3730
+ r.last << "goto #@target;"
3731
+ [r, dep]
3732
+ end
3733
+ end
3734
+ class Return
3735
+ def dump(scope, r=[''], dep=[])
3736
+ r.last << 'return '
3737
+ r, dep = CExpression.dump(@value, scope, r, dep)
3738
+ r.last.chop! if r.last[-1] == ?\ # the space character
3739
+ r.last << ';'
3740
+ [r, dep]
3741
+ end
3742
+ end
3743
+ class Case
3744
+ def dump(scope, r=[''], dep=[])
3745
+ case @expr
3746
+ when 'default'
3747
+ r.last << @expr
3748
+ else
3749
+ r.last << 'case '
3750
+ r, dep = CExpression.dump(@expr, scope, r, dep)
3751
+ if exprup
3752
+ r.last << ' ... '
3753
+ r, dep = CExpression.dump(@exprup, scope, r, dep)
3754
+ end
3755
+ end
3756
+ r.last << ':'
3757
+ dump_inner(scope, r, dep)
3758
+ end
3759
+
3760
+ def self.dump_indent(s, short=false)
3761
+ case s
3762
+ when /^(case|default)\W/; (short ? ' ' : "\t") << s
3763
+ when /^\s+(case|default)\W/; "\t" << s
3764
+ when /:$/; s
3765
+ else "\t" << s
3766
+ end
3767
+ end
3768
+ end
3769
+ class Label
3770
+ def dump(scope, r=[''], dep=[])
3771
+ r.last << @name << ':'
3772
+ dump_inner(scope, r, dep)
3773
+ end
3774
+ def dump_inner(scope, r=[''], dep=[])
3775
+ if not @statement; [r, dep]
3776
+ elsif @statement.kind_of? Block; Statement.dump(@statement, scope, r, dep)
3777
+ else @statement.dump(scope, r << '', dep)
3778
+ end
3779
+ end
3780
+ end
3781
+ class Asm
3782
+ def dump(scope, r=[''], dep=[])
3783
+ r.last << 'asm '
3784
+ r.last << 'volatile ' if @volatile
3785
+ r.last << '('
3786
+ r.last << @body.inspect
3787
+ if @output or @input or @clobber
3788
+ if @output and @output != []
3789
+ # TODO
3790
+ r << ': /* todo */'
3791
+ elsif (@input and @input != []) or (@clobber and @clobber != [])
3792
+ r.last << ' :'
3793
+ end
3794
+ end
3795
+ if @input or @clobber
3796
+ if @input and @input != []
3797
+ # TODO
3798
+ r << ': /* todo */'
3799
+ elsif @clobber and @clobber != []
3800
+ r.last << ' :'
3801
+ end
3802
+ end
3803
+ if @clobber and @clobber != []
3804
+ r << (': ' << @clobber.map { |c| c.inspect }.join(', '))
3805
+ end
3806
+ r.last << ');'
3807
+ [r, dep]
3808
+ end
3809
+ end
3810
+ class CExpression
3811
+ def self.dump(e, scope, r=[''], dep=[], brace = false)
3812
+ if $DEBUG
3813
+ brace = false
3814
+ case e
3815
+ when CExpression, Variable
3816
+ r, dep = e.type.dump_cast(scope, r, dep)
3817
+ end
3818
+ r.last << '('
3819
+ end
3820
+ r, dep = \
3821
+ case e
3822
+ when ::Numeric; r.last << e.to_s ; [r, dep]
3823
+ when ::String; r.last << e.inspect ; [r, dep]
3824
+ when CExpression; e.dump_inner(scope, r, dep, brace)
3825
+ when Variable; e.dump(scope, r, dep)
3826
+ when nil; [r, dep]
3827
+ else raise 'wtf?' + e.inspect
3828
+ end
3829
+ if $DEBUG
3830
+ r.last << ')'
3831
+ end
3832
+ [r, dep]
3833
+ end
3834
+
3835
+ def dump(scope, r=[''], dep=[])
3836
+ r, dep = dump_inner(scope, r, dep)
3837
+ r.last << ';'
3838
+ [r, dep]
3839
+ end
3840
+
3841
+ def dump_inner(scope, r=[''], dep=[], brace = false)
3842
+ r.last << '(' if brace and @op != :'->' and @op != :'.' and @op != :'[]' and (@op or @rexpr.kind_of? CExpression)
3843
+ if not @lexpr
3844
+ if not @op
3845
+ case @rexpr
3846
+ when ::Numeric
3847
+ if @rexpr < 0
3848
+ r.last << ?-
3849
+ re = -@rexpr
3850
+ else
3851
+ re = @rexpr
3852
+ end
3853
+ if re >= 0x1000
3854
+ r.last << ("0x%X" % re)
3855
+ else
3856
+ r.last << re.to_s
3857
+ end
3858
+ if @type.kind_of? BaseType
3859
+ r.last << 'U' if @type.specifier == :unsigned
3860
+ case @type.name
3861
+ when :longlong, :__int64; r.last << 'LL'
3862
+ when :long, :longdouble; r.last << 'L'
3863
+ when :float; r.last << 'F'
3864
+ end
3865
+ end
3866
+ when ::String
3867
+ r.last << 'L' if @type.kind_of? Pointer and @type.type.kind_of? BaseType and @type.type.name == :short
3868
+ r.last << @rexpr.inspect
3869
+ when CExpression # cast
3870
+ r, dep = @type.dump_cast(scope, r, dep)
3871
+ r, dep = CExpression.dump(@rexpr, scope, r, dep, true)
3872
+ when Variable
3873
+ r, dep = @rexpr.dump(scope, r, dep)
3874
+ when Block
3875
+ r.last << '('
3876
+ r, dep = Statement.dump(@rexpr, scope, r, dep)
3877
+ r.last << ' )'
3878
+ when Label
3879
+ r.last << '&&' << @rexpr.name
3880
+ else raise "wtf? #{inspect}"
3881
+ end
3882
+ else
3883
+ r.last << @op.to_s
3884
+ r, dep = CExpression.dump(@rexpr, scope, r, dep, (@rexpr.kind_of? C::CExpression and @rexpr.lexpr))
3885
+ end
3886
+ elsif not @rexpr
3887
+ r, dep = CExpression.dump(@lexpr, scope, r, dep)
3888
+ r.last << @op.to_s
3889
+ else
3890
+ case @op
3891
+ when :'->', :'.'
3892
+ r, dep = CExpression.dump(@lexpr, scope, r, dep, true)
3893
+ r.last << @op.to_s << @rexpr
3894
+ when :'[]'
3895
+ r, dep = CExpression.dump(@lexpr, scope, r, dep, true)
3896
+ r.last << '['
3897
+ l = lexpr if lexpr.kind_of? Variable
3898
+ l = lexpr.lexpr.type.untypedef.findmember(lexpr.rexpr) if lexpr.kind_of? CExpression and lexpr.op == :'.'
3899
+ l = lexpr.lexpr.type.pointed.untypedef.findmember(lexpr.rexpr) if lexpr.kind_of? CExpression and lexpr.op == :'->'
3900
+ # honor __attribute__((indexenum(enumname)))
3901
+ if l and l.attributes and rexpr.kind_of? CExpression and not rexpr.op and rexpr.rexpr.kind_of? ::Integer and
3902
+ n = l.has_attribute_var('indexenum') and enum = scope.struct_ancestors[n] and i = enum.members.index(rexpr.rexpr)
3903
+ r.last << i
3904
+ dep |= [enum]
3905
+ else
3906
+ r, dep = CExpression.dump(@rexpr, scope, r, dep)
3907
+ end
3908
+ r.last << ']'
3909
+ when :funcall
3910
+ r, dep = CExpression.dump(@lexpr, scope, r, dep, true)
3911
+ r.last << '('
3912
+ @rexpr.each { |arg|
3913
+ r.last << ', ' if r.last[-1] != ?(
3914
+ r, dep = CExpression.dump(arg, scope, r, dep)
3915
+ }
3916
+ r.last << ')'
3917
+ when :'?:'
3918
+ r, dep = CExpression.dump(@lexpr, scope, r, dep, true)
3919
+ r.last << ' ? '
3920
+ r, dep = CExpression.dump(@rexpr[0], scope, r, dep, true)
3921
+ r.last << ' : '
3922
+ r, dep = CExpression.dump(@rexpr[1], scope, r, dep, true)
3923
+ else
3924
+ r, dep = CExpression.dump(@lexpr, scope, r, dep, (@lexpr.kind_of? CExpression and @lexpr.lexpr and @lexpr.op != @op))
3925
+ r.last << ' ' << @op.to_s << ' '
3926
+ r, dep = CExpression.dump(@rexpr, scope, r, dep, (@rexpr.kind_of? CExpression and @rexpr.lexpr and @rexpr.op != @op and @rexpr.op != :funcall))
3927
+ end
3928
+ end
3929
+ r.last << ')' if brace and @op != :'->' and @op != :'.' and @op != :'[]' and (@op or @rexpr.kind_of? CExpression)
3930
+ [r, dep]
3931
+ end
3932
+
3933
+ def to_s
3934
+ dump_inner(Block.new(nil))[0].join(' ')
3935
+ end
3936
+ end
3937
+ end
3938
+ end