metasm 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
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