metasm 1.0.0 → 1.0.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (276) hide show
  1. checksums.yaml +7 -0
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +3 -0
  4. data/.gitignore +3 -0
  5. data/.hgtags +3 -0
  6. data/Gemfile +3 -0
  7. data/INSTALL +61 -0
  8. data/LICENCE +458 -0
  9. data/README +29 -21
  10. data/Rakefile +10 -0
  11. data/TODO +10 -12
  12. data/doc/code_organisation.txt +3 -1
  13. data/doc/core/DynLdr.txt +247 -0
  14. data/doc/core/ExeFormat.txt +43 -0
  15. data/doc/core/Expression.txt +220 -0
  16. data/doc/core/GNUExports.txt +27 -0
  17. data/doc/core/Ia32.txt +236 -0
  18. data/doc/core/SerialStruct.txt +108 -0
  19. data/doc/core/VirtualString.txt +145 -0
  20. data/doc/core/WindowsExports.txt +61 -0
  21. data/doc/core/index.txt +1 -0
  22. data/doc/style.css +6 -3
  23. data/doc/usage/debugger.txt +327 -0
  24. data/doc/usage/index.txt +1 -0
  25. data/doc/use_cases.txt +2 -2
  26. data/metasm.gemspec +23 -0
  27. data/{lib/metasm.rb → metasm.rb} +15 -3
  28. data/{lib/metasm → metasm}/compile_c.rb +15 -9
  29. data/metasm/cpu/arc.rb +8 -0
  30. data/metasm/cpu/arc/decode.rb +404 -0
  31. data/metasm/cpu/arc/main.rb +191 -0
  32. data/metasm/cpu/arc/opcodes.rb +588 -0
  33. data/metasm/cpu/arm.rb +14 -0
  34. data/{lib/metasm → metasm/cpu}/arm/debug.rb +2 -2
  35. data/{lib/metasm → metasm/cpu}/arm/decode.rb +15 -18
  36. data/{lib/metasm → metasm/cpu}/arm/encode.rb +23 -8
  37. data/{lib/metasm → metasm/cpu}/arm/main.rb +3 -6
  38. data/metasm/cpu/arm/opcodes.rb +324 -0
  39. data/{lib/metasm → metasm/cpu}/arm/parse.rb +25 -13
  40. data/{lib/metasm → metasm/cpu}/arm/render.rb +2 -2
  41. data/metasm/cpu/arm64.rb +15 -0
  42. data/metasm/cpu/arm64/debug.rb +38 -0
  43. data/metasm/cpu/arm64/decode.rb +285 -0
  44. data/metasm/cpu/arm64/encode.rb +41 -0
  45. data/metasm/cpu/arm64/main.rb +105 -0
  46. data/metasm/cpu/arm64/opcodes.rb +232 -0
  47. data/metasm/cpu/arm64/parse.rb +20 -0
  48. data/metasm/cpu/arm64/render.rb +95 -0
  49. data/{lib/metasm/mips/compile_c.rb → metasm/cpu/bpf.rb} +4 -2
  50. data/metasm/cpu/bpf/decode.rb +110 -0
  51. data/metasm/cpu/bpf/main.rb +60 -0
  52. data/metasm/cpu/bpf/opcodes.rb +81 -0
  53. data/metasm/cpu/bpf/render.rb +30 -0
  54. data/{lib/metasm/ppc.rb → metasm/cpu/cy16.rb} +2 -4
  55. data/metasm/cpu/cy16/decode.rb +247 -0
  56. data/metasm/cpu/cy16/main.rb +63 -0
  57. data/metasm/cpu/cy16/opcodes.rb +78 -0
  58. data/metasm/cpu/cy16/render.rb +30 -0
  59. data/metasm/cpu/dalvik.rb +11 -0
  60. data/{lib/metasm → metasm/cpu}/dalvik/decode.rb +34 -34
  61. data/{lib/metasm → metasm/cpu}/dalvik/main.rb +71 -4
  62. data/{lib/metasm → metasm/cpu}/dalvik/opcodes.rb +21 -12
  63. data/{lib/metasm/mips.rb → metasm/cpu/ebpf.rb} +3 -4
  64. data/metasm/cpu/ebpf/debug.rb +61 -0
  65. data/metasm/cpu/ebpf/decode.rb +142 -0
  66. data/metasm/cpu/ebpf/main.rb +58 -0
  67. data/metasm/cpu/ebpf/opcodes.rb +97 -0
  68. data/metasm/cpu/ebpf/render.rb +36 -0
  69. data/metasm/cpu/ia32.rb +17 -0
  70. data/{lib/metasm → metasm/cpu}/ia32/compile_c.rb +23 -9
  71. data/{lib/metasm → metasm/cpu}/ia32/debug.rb +44 -6
  72. data/{lib/metasm → metasm/cpu}/ia32/decode.rb +342 -128
  73. data/{lib/metasm → metasm/cpu}/ia32/decompile.rb +75 -53
  74. data/{lib/metasm → metasm/cpu}/ia32/encode.rb +19 -13
  75. data/{lib/metasm → metasm/cpu}/ia32/main.rb +66 -8
  76. data/metasm/cpu/ia32/opcodes.rb +1424 -0
  77. data/{lib/metasm → metasm/cpu}/ia32/parse.rb +55 -17
  78. data/{lib/metasm → metasm/cpu}/ia32/render.rb +32 -5
  79. data/metasm/cpu/mcs51.rb +8 -0
  80. data/metasm/cpu/mcs51/decode.rb +99 -0
  81. data/metasm/cpu/mcs51/main.rb +87 -0
  82. data/metasm/cpu/mcs51/opcodes.rb +120 -0
  83. data/metasm/cpu/mips.rb +14 -0
  84. data/metasm/cpu/mips/debug.rb +42 -0
  85. data/{lib/metasm → metasm/cpu}/mips/decode.rb +59 -38
  86. data/{lib/metasm → metasm/cpu}/mips/encode.rb +4 -3
  87. data/{lib/metasm → metasm/cpu}/mips/main.rb +13 -6
  88. data/{lib/metasm → metasm/cpu}/mips/opcodes.rb +87 -18
  89. data/{lib/metasm → metasm/cpu}/mips/parse.rb +1 -1
  90. data/{lib/metasm → metasm/cpu}/mips/render.rb +1 -1
  91. data/{lib/metasm/dalvik.rb → metasm/cpu/msp430.rb} +1 -1
  92. data/metasm/cpu/msp430/decode.rb +243 -0
  93. data/metasm/cpu/msp430/main.rb +62 -0
  94. data/metasm/cpu/msp430/opcodes.rb +101 -0
  95. data/metasm/cpu/openrisc.rb +11 -0
  96. data/metasm/cpu/openrisc/debug.rb +106 -0
  97. data/metasm/cpu/openrisc/decode.rb +182 -0
  98. data/metasm/cpu/openrisc/decompile.rb +350 -0
  99. data/metasm/cpu/openrisc/main.rb +70 -0
  100. data/metasm/cpu/openrisc/opcodes.rb +109 -0
  101. data/metasm/cpu/openrisc/render.rb +37 -0
  102. data/{lib/metasm → metasm/cpu}/pic16c/decode.rb +6 -7
  103. data/{lib/metasm → metasm/cpu}/pic16c/main.rb +0 -0
  104. data/{lib/metasm → metasm/cpu}/pic16c/opcodes.rb +1 -1
  105. data/metasm/cpu/ppc.rb +11 -0
  106. data/{lib/metasm → metasm/cpu}/ppc/decode.rb +18 -37
  107. data/{lib/metasm → metasm/cpu}/ppc/decompile.rb +3 -3
  108. data/{lib/metasm → metasm/cpu}/ppc/encode.rb +2 -2
  109. data/{lib/metasm → metasm/cpu}/ppc/main.rb +23 -18
  110. data/{lib/metasm → metasm/cpu}/ppc/opcodes.rb +11 -6
  111. data/metasm/cpu/ppc/parse.rb +55 -0
  112. data/metasm/cpu/python.rb +8 -0
  113. data/metasm/cpu/python/decode.rb +116 -0
  114. data/metasm/cpu/python/main.rb +36 -0
  115. data/metasm/cpu/python/opcodes.rb +180 -0
  116. data/{lib/metasm → metasm/cpu}/sh4.rb +1 -1
  117. data/{lib/metasm → metasm/cpu}/sh4/decode.rb +50 -23
  118. data/{lib/metasm → metasm/cpu}/sh4/main.rb +38 -27
  119. data/{lib/metasm → metasm/cpu}/sh4/opcodes.rb +7 -8
  120. data/metasm/cpu/st20.rb +9 -0
  121. data/metasm/cpu/st20/decode.rb +173 -0
  122. data/metasm/cpu/st20/decompile.rb +283 -0
  123. data/metasm/cpu/st20/main.rb +37 -0
  124. data/metasm/cpu/st20/opcodes.rb +140 -0
  125. data/{lib/metasm/arm.rb → metasm/cpu/webasm.rb} +4 -5
  126. data/metasm/cpu/webasm/debug.rb +31 -0
  127. data/metasm/cpu/webasm/decode.rb +321 -0
  128. data/metasm/cpu/webasm/decompile.rb +386 -0
  129. data/metasm/cpu/webasm/encode.rb +104 -0
  130. data/metasm/cpu/webasm/main.rb +81 -0
  131. data/metasm/cpu/webasm/opcodes.rb +214 -0
  132. data/metasm/cpu/x86_64.rb +15 -0
  133. data/{lib/metasm → metasm/cpu}/x86_64/compile_c.rb +40 -25
  134. data/{lib/metasm → metasm/cpu}/x86_64/debug.rb +4 -4
  135. data/{lib/metasm → metasm/cpu}/x86_64/decode.rb +58 -15
  136. data/{lib/metasm → metasm/cpu}/x86_64/encode.rb +59 -28
  137. data/{lib/metasm → metasm/cpu}/x86_64/main.rb +18 -6
  138. data/metasm/cpu/x86_64/opcodes.rb +138 -0
  139. data/{lib/metasm → metasm/cpu}/x86_64/parse.rb +12 -4
  140. data/metasm/cpu/x86_64/render.rb +35 -0
  141. data/metasm/cpu/z80.rb +9 -0
  142. data/metasm/cpu/z80/decode.rb +286 -0
  143. data/metasm/cpu/z80/main.rb +67 -0
  144. data/metasm/cpu/z80/opcodes.rb +224 -0
  145. data/metasm/cpu/z80/render.rb +48 -0
  146. data/{lib/metasm/os/main.rb → metasm/debug.rb} +201 -407
  147. data/{lib/metasm → metasm}/decode.rb +104 -24
  148. data/{lib/metasm → metasm}/decompile.rb +804 -478
  149. data/{lib/metasm → metasm}/disassemble.rb +385 -170
  150. data/{lib/metasm → metasm}/disassemble_api.rb +684 -105
  151. data/{lib/metasm → metasm}/dynldr.rb +231 -138
  152. data/{lib/metasm → metasm}/encode.rb +20 -5
  153. data/{lib/metasm → metasm}/exe_format/a_out.rb +9 -6
  154. data/{lib/metasm → metasm}/exe_format/autoexe.rb +3 -0
  155. data/{lib/metasm → metasm}/exe_format/bflt.rb +57 -27
  156. data/{lib/metasm → metasm}/exe_format/coff.rb +35 -7
  157. data/{lib/metasm → metasm}/exe_format/coff_decode.rb +70 -23
  158. data/{lib/metasm → metasm}/exe_format/coff_encode.rb +24 -22
  159. data/{lib/metasm → metasm}/exe_format/dex.rb +26 -8
  160. data/{lib/metasm → metasm}/exe_format/dol.rb +1 -0
  161. data/{lib/metasm → metasm}/exe_format/elf.rb +108 -58
  162. data/{lib/metasm → metasm}/exe_format/elf_decode.rb +202 -36
  163. data/{lib/metasm → metasm}/exe_format/elf_encode.rb +126 -32
  164. data/metasm/exe_format/gb.rb +65 -0
  165. data/metasm/exe_format/javaclass.rb +424 -0
  166. data/{lib/metasm → metasm}/exe_format/macho.rb +218 -16
  167. data/{lib/metasm → metasm}/exe_format/main.rb +28 -3
  168. data/{lib/metasm → metasm}/exe_format/mz.rb +2 -0
  169. data/{lib/metasm → metasm}/exe_format/nds.rb +7 -4
  170. data/{lib/metasm → metasm}/exe_format/pe.rb +96 -11
  171. data/metasm/exe_format/pyc.rb +167 -0
  172. data/{lib/metasm → metasm}/exe_format/serialstruct.rb +67 -14
  173. data/{lib/metasm → metasm}/exe_format/shellcode.rb +7 -3
  174. data/metasm/exe_format/shellcode_rwx.rb +114 -0
  175. data/metasm/exe_format/swf.rb +205 -0
  176. data/metasm/exe_format/wasm.rb +402 -0
  177. data/{lib/metasm → metasm}/exe_format/xcoff.rb +7 -7
  178. data/metasm/exe_format/zip.rb +335 -0
  179. data/metasm/gui.rb +13 -0
  180. data/{lib/metasm → metasm}/gui/cstruct.rb +35 -41
  181. data/{lib/metasm → metasm}/gui/dasm_coverage.rb +11 -11
  182. data/{lib/metasm → metasm}/gui/dasm_decomp.rb +177 -114
  183. data/{lib/metasm → metasm}/gui/dasm_funcgraph.rb +0 -0
  184. data/metasm/gui/dasm_graph.rb +1754 -0
  185. data/{lib/metasm → metasm}/gui/dasm_hex.rb +16 -12
  186. data/{lib/metasm → metasm}/gui/dasm_listing.rb +43 -28
  187. data/{lib/metasm → metasm}/gui/dasm_main.rb +360 -77
  188. data/{lib/metasm → metasm}/gui/dasm_opcodes.rb +5 -19
  189. data/{lib/metasm → metasm}/gui/debug.rb +109 -34
  190. data/{lib/metasm → metasm}/gui/gtk.rb +174 -44
  191. data/{lib/metasm → metasm}/gui/qt.rb +14 -4
  192. data/{lib/metasm → metasm}/gui/win32.rb +180 -43
  193. data/{lib/metasm → metasm}/gui/x11.rb +59 -59
  194. data/{lib/metasm → metasm}/main.rb +421 -286
  195. data/metasm/os/emulator.rb +175 -0
  196. data/{lib/metasm/os/remote.rb → metasm/os/gdbremote.rb} +146 -54
  197. data/{lib/metasm → metasm}/os/gnu_exports.rb +1 -1
  198. data/{lib/metasm → metasm}/os/linux.rb +628 -151
  199. data/metasm/os/main.rb +335 -0
  200. data/{lib/metasm → metasm}/os/windows.rb +151 -58
  201. data/{lib/metasm → metasm}/os/windows_exports.rb +141 -0
  202. data/{lib/metasm → metasm}/parse.rb +49 -36
  203. data/{lib/metasm → metasm}/parse_c.rb +405 -246
  204. data/{lib/metasm → metasm}/preprocessor.rb +71 -41
  205. data/{lib/metasm → metasm}/render.rb +14 -38
  206. data/misc/hexdump.rb +4 -3
  207. data/misc/lint.rb +58 -0
  208. data/misc/objdiff.rb +4 -1
  209. data/misc/objscan.rb +1 -1
  210. data/misc/openrisc-parser.rb +79 -0
  211. data/misc/txt2html.rb +9 -7
  212. data/samples/bindiff.rb +3 -4
  213. data/samples/dasm-plugins/bindiff.rb +15 -0
  214. data/samples/dasm-plugins/bookmark.rb +133 -0
  215. data/samples/dasm-plugins/c_constants.rb +57 -0
  216. data/samples/dasm-plugins/colortheme_solarized.rb +125 -0
  217. data/samples/dasm-plugins/cppobj_funcall.rb +60 -0
  218. data/samples/dasm-plugins/dasm_all.rb +70 -0
  219. data/samples/dasm-plugins/demangle_cpp.rb +31 -0
  220. data/samples/dasm-plugins/deobfuscate.rb +251 -0
  221. data/samples/dasm-plugins/dump_text.rb +35 -0
  222. data/samples/dasm-plugins/export_graph_svg.rb +86 -0
  223. data/samples/dasm-plugins/findgadget.rb +75 -0
  224. data/samples/dasm-plugins/hl_opcode.rb +32 -0
  225. data/samples/dasm-plugins/hotfix_gtk_dbg.rb +19 -0
  226. data/samples/dasm-plugins/imm2off.rb +34 -0
  227. data/samples/dasm-plugins/match_libsigs.rb +93 -0
  228. data/samples/dasm-plugins/patch_file.rb +95 -0
  229. data/samples/dasm-plugins/scanfuncstart.rb +36 -0
  230. data/samples/dasm-plugins/scanxrefs.rb +29 -0
  231. data/samples/dasm-plugins/selfmodify.rb +197 -0
  232. data/samples/dasm-plugins/stringsxrefs.rb +28 -0
  233. data/samples/dasmnavig.rb +1 -1
  234. data/samples/dbg-apihook.rb +24 -9
  235. data/samples/dbg-plugins/heapscan.rb +283 -0
  236. data/samples/dbg-plugins/heapscan/compiled_heapscan_lin.c +155 -0
  237. data/samples/dbg-plugins/heapscan/compiled_heapscan_win.c +128 -0
  238. data/samples/dbg-plugins/heapscan/graphheap.rb +616 -0
  239. data/samples/dbg-plugins/heapscan/heapscan.rb +709 -0
  240. data/samples/dbg-plugins/heapscan/winheap.h +174 -0
  241. data/samples/dbg-plugins/heapscan/winheap7.h +307 -0
  242. data/samples/dbg-plugins/trace_func.rb +214 -0
  243. data/samples/disassemble-gui.rb +48 -7
  244. data/samples/disassemble.rb +31 -6
  245. data/samples/dump_upx.rb +24 -12
  246. data/samples/dynamic_ruby.rb +35 -27
  247. data/samples/elfencode.rb +15 -0
  248. data/samples/emubios.rb +251 -0
  249. data/samples/emudbg.rb +127 -0
  250. data/samples/exeencode.rb +6 -5
  251. data/samples/factorize-headers-peimports.rb +1 -1
  252. data/samples/lindebug.rb +186 -391
  253. data/samples/metasm-shell.rb +68 -57
  254. data/samples/peldr.rb +2 -2
  255. data/tests/all.rb +1 -1
  256. data/tests/arc.rb +26 -0
  257. data/tests/dynldr.rb +22 -4
  258. data/tests/expression.rb +57 -0
  259. data/tests/graph_layout.rb +285 -0
  260. data/tests/ia32.rb +80 -26
  261. data/tests/mcs51.rb +27 -0
  262. data/tests/mips.rb +10 -3
  263. data/tests/preprocessor.rb +18 -0
  264. data/tests/x86_64.rb +66 -18
  265. metadata +465 -219
  266. metadata.gz.sig +2 -0
  267. data/lib/metasm/arm/opcodes.rb +0 -177
  268. data/lib/metasm/gui.rb +0 -23
  269. data/lib/metasm/gui/dasm_graph.rb +0 -1354
  270. data/lib/metasm/ia32.rb +0 -14
  271. data/lib/metasm/ia32/opcodes.rb +0 -872
  272. data/lib/metasm/ppc/parse.rb +0 -52
  273. data/lib/metasm/x86_64.rb +0 -12
  274. data/lib/metasm/x86_64/opcodes.rb +0 -118
  275. data/samples/gdbclient.rb +0 -583
  276. data/samples/rubstop.rb +0 -399
@@ -740,6 +740,147 @@ EOL
740
740
  end
741
741
 
742
742
  patch_rubylib_to_current_interpreter
743
+
744
+ # mandiant import hash crap with ordinal imports (from pefile.py)
745
+ ih_ws232 = {
746
+ 1 => 'accept', 2 => 'bind', 3 => 'closesocket', 4 => 'connect',
747
+ 5 => 'getpeername', 6 => 'getsockname', 7 => 'getsockopt', 8 => 'htonl',
748
+ 9 => 'htons', 10 => 'ioctlsocket', 11 => 'inet_addr', 12 => 'inet_ntoa',
749
+ 13 => 'listen', 14 => 'ntohl', 15 => 'ntohs', 16 => 'recv',
750
+ 17 => 'recvfrom', 18 => 'select', 19 => 'send', 20 => 'sendto',
751
+ 21 => 'setsockopt', 22 => 'shutdown', 23 => 'socket', 24 => 'GetAddrInfoW',
752
+ 25 => 'GetNameInfoW', 26 => 'WSApSetPostRoutine', 27 => 'FreeAddrInfoW', 28 => 'WPUCompleteOverlappedRequest',
753
+ 29 => 'WSAAccept', 30 => 'WSAAddressToStringA', 31 => 'WSAAddressToStringW', 32 => 'WSACloseEvent',
754
+ 33 => 'WSAConnect', 34 => 'WSACreateEvent', 35 => 'WSADuplicateSocketA', 36 => 'WSADuplicateSocketW',
755
+ 37 => 'WSAEnumNameSpaceProvidersA', 38 => 'WSAEnumNameSpaceProvidersW', 39 => 'WSAEnumNetworkEvents', 40 => 'WSAEnumProtocolsA',
756
+ 41 => 'WSAEnumProtocolsW', 42 => 'WSAEventSelect', 43 => 'WSAGetOverlappedResult', 44 => 'WSAGetQOSByName',
757
+ 45 => 'WSAGetServiceClassInfoA', 46 => 'WSAGetServiceClassInfoW', 47 => 'WSAGetServiceClassNameByClassIdA', 48 => 'WSAGetServiceClassNameByClassIdW',
758
+ 49 => 'WSAHtonl', 50 => 'WSAHtons', 51 => 'gethostbyaddr', 52 => 'gethostbyname',
759
+ 53 => 'getprotobyname', 54 => 'getprotobynumber', 55 => 'getservbyname', 56 => 'getservbyport',
760
+ 57 => 'gethostname', 58 => 'WSAInstallServiceClassA', 59 => 'WSAInstallServiceClassW', 60 => 'WSAIoctl',
761
+ 61 => 'WSAJoinLeaf', 62 => 'WSALookupServiceBeginA', 63 => 'WSALookupServiceBeginW', 64 => 'WSALookupServiceEnd',
762
+ 65 => 'WSALookupServiceNextA', 66 => 'WSALookupServiceNextW', 67 => 'WSANSPIoctl', 68 => 'WSANtohl',
763
+ 69 => 'WSANtohs', 70 => 'WSAProviderConfigChange', 71 => 'WSARecv', 72 => 'WSARecvDisconnect',
764
+ 73 => 'WSARecvFrom', 74 => 'WSARemoveServiceClass', 75 => 'WSAResetEvent', 76 => 'WSASend',
765
+ 77 => 'WSASendDisconnect', 78 => 'WSASendTo', 79 => 'WSASetEvent', 80 => 'WSASetServiceA',
766
+ 81 => 'WSASetServiceW', 82 => 'WSASocketA', 83 => 'WSASocketW', 84 => 'WSAStringToAddressA',
767
+ 85 => 'WSAStringToAddressW', 86 => 'WSAWaitForMultipleEvents', 87 => 'WSCDeinstallProvider', 88 => 'WSCEnableNSProvider',
768
+ 89 => 'WSCEnumProtocols', 90 => 'WSCGetProviderPath', 91 => 'WSCInstallNameSpace', 92 => 'WSCInstallProvider',
769
+ 93 => 'WSCUnInstallNameSpace', 94 => 'WSCUpdateProvider', 95 => 'WSCWriteNameSpaceOrder', 96 => 'WSCWriteProviderOrder',
770
+ 97 => 'freeaddrinfo', 98 => 'getaddrinfo', 99 => 'getnameinfo', 101 => 'WSAAsyncSelect',
771
+ 102 => 'WSAAsyncGetHostByAddr', 103 => 'WSAAsyncGetHostByName', 104 => 'WSAAsyncGetProtoByNumber', 105 => 'WSAAsyncGetProtoByName',
772
+ 106 => 'WSAAsyncGetServByPort', 107 => 'WSAAsyncGetServByName', 108 => 'WSACancelAsyncRequest', 109 => 'WSASetBlockingHook',
773
+ 110 => 'WSAUnhookBlockingHook', 111 => 'WSAGetLastError', 112 => 'WSASetLastError', 113 => 'WSACancelBlockingCall',
774
+ 114 => 'WSAIsBlocking', 115 => 'WSAStartup', 116 => 'WSACleanup', 151 => '__WSAFDIsSet',
775
+ 500 => 'WEP',
776
+ }
777
+
778
+ IMPORT_HASH = {
779
+ 'ws2_32' => ih_ws232,
780
+ 'wsock2' => ih_ws232,
781
+ 'oleaut' => {
782
+ 2 => 'SysAllocString', 3 => 'SysReAllocString', 4 => 'SysAllocStringLen', 5 => 'SysReAllocStringLen',
783
+ 6 => 'SysFreeString', 7 => 'SysStringLen', 8 => 'VariantInit', 9 => 'VariantClear',
784
+ 10 => 'VariantCopy', 11 => 'VariantCopyInd', 12 => 'VariantChangeType', 13 => 'VariantTimeToDosDateTime',
785
+ 14 => 'DosDateTimeToVariantTime', 15 => 'SafeArrayCreate', 16 => 'SafeArrayDestroy', 17 => 'SafeArrayGetDim',
786
+ 18 => 'SafeArrayGetElemsize', 19 => 'SafeArrayGetUBound', 20 => 'SafeArrayGetLBound', 21 => 'SafeArrayLock',
787
+ 22 => 'SafeArrayUnlock', 23 => 'SafeArrayAccessData', 24 => 'SafeArrayUnaccessData', 25 => 'SafeArrayGetElement',
788
+ 26 => 'SafeArrayPutElement', 27 => 'SafeArrayCopy', 28 => 'DispGetParam', 29 => 'DispGetIDsOfNames',
789
+ 30 => 'DispInvoke', 31 => 'CreateDispTypeInfo', 32 => 'CreateStdDispatch', 33 => 'RegisterActiveObject',
790
+ 34 => 'RevokeActiveObject', 35 => 'GetActiveObject', 36 => 'SafeArrayAllocDescriptor', 37 => 'SafeArrayAllocData',
791
+ 38 => 'SafeArrayDestroyDescriptor', 39 => 'SafeArrayDestroyData', 40 => 'SafeArrayRedim', 41 => 'SafeArrayAllocDescriptorEx',
792
+ 42 => 'SafeArrayCreateEx', 43 => 'SafeArrayCreateVectorEx', 44 => 'SafeArraySetRecordInfo', 45 => 'SafeArrayGetRecordInfo',
793
+ 46 => 'VarParseNumFromStr', 47 => 'VarNumFromParseNum', 48 => 'VarI2FromUI1', 49 => 'VarI2FromI4',
794
+ 50 => 'VarI2FromR4', 51 => 'VarI2FromR8', 52 => 'VarI2FromCy', 53 => 'VarI2FromDate',
795
+ 54 => 'VarI2FromStr', 55 => 'VarI2FromDisp', 56 => 'VarI2FromBool', 57 => 'SafeArraySetIID',
796
+ 58 => 'VarI4FromUI1', 59 => 'VarI4FromI2', 60 => 'VarI4FromR4', 61 => 'VarI4FromR8',
797
+ 62 => 'VarI4FromCy', 63 => 'VarI4FromDate', 64 => 'VarI4FromStr', 65 => 'VarI4FromDisp',
798
+ 66 => 'VarI4FromBool', 67 => 'SafeArrayGetIID', 68 => 'VarR4FromUI1', 69 => 'VarR4FromI2',
799
+ 70 => 'VarR4FromI4', 71 => 'VarR4FromR8', 72 => 'VarR4FromCy', 73 => 'VarR4FromDate',
800
+ 74 => 'VarR4FromStr', 75 => 'VarR4FromDisp', 76 => 'VarR4FromBool', 77 => 'SafeArrayGetVartype',
801
+ 78 => 'VarR8FromUI1', 79 => 'VarR8FromI2', 80 => 'VarR8FromI4', 81 => 'VarR8FromR4',
802
+ 82 => 'VarR8FromCy', 83 => 'VarR8FromDate', 84 => 'VarR8FromStr', 85 => 'VarR8FromDisp',
803
+ 86 => 'VarR8FromBool', 87 => 'VarFormat', 88 => 'VarDateFromUI1', 89 => 'VarDateFromI2',
804
+ 90 => 'VarDateFromI4', 91 => 'VarDateFromR4', 92 => 'VarDateFromR8', 93 => 'VarDateFromCy',
805
+ 94 => 'VarDateFromStr', 95 => 'VarDateFromDisp', 96 => 'VarDateFromBool', 97 => 'VarFormatDateTime',
806
+ 98 => 'VarCyFromUI1', 99 => 'VarCyFromI2', 100 => 'VarCyFromI4', 101 => 'VarCyFromR4',
807
+ 102 => 'VarCyFromR8', 103 => 'VarCyFromDate', 104 => 'VarCyFromStr', 105 => 'VarCyFromDisp',
808
+ 106 => 'VarCyFromBool', 107 => 'VarFormatNumber', 108 => 'VarBstrFromUI1', 109 => 'VarBstrFromI2',
809
+ 110 => 'VarBstrFromI4', 111 => 'VarBstrFromR4', 112 => 'VarBstrFromR8', 113 => 'VarBstrFromCy',
810
+ 114 => 'VarBstrFromDate', 115 => 'VarBstrFromDisp', 116 => 'VarBstrFromBool', 117 => 'VarFormatPercent',
811
+ 118 => 'VarBoolFromUI1', 119 => 'VarBoolFromI2', 120 => 'VarBoolFromI4', 121 => 'VarBoolFromR4',
812
+ 122 => 'VarBoolFromR8', 123 => 'VarBoolFromDate', 124 => 'VarBoolFromCy', 125 => 'VarBoolFromStr',
813
+ 126 => 'VarBoolFromDisp', 127 => 'VarFormatCurrency', 128 => 'VarWeekdayName', 129 => 'VarMonthName',
814
+ 130 => 'VarUI1FromI2', 131 => 'VarUI1FromI4', 132 => 'VarUI1FromR4', 133 => 'VarUI1FromR8',
815
+ 134 => 'VarUI1FromCy', 135 => 'VarUI1FromDate', 136 => 'VarUI1FromStr', 137 => 'VarUI1FromDisp',
816
+ 138 => 'VarUI1FromBool', 139 => 'VarFormatFromTokens', 140 => 'VarTokenizeFormatString', 141 => 'VarAdd',
817
+ 142 => 'VarAnd', 143 => 'VarDiv', 144 => 'DllCanUnloadNow', 145 => 'DllGetClassObject',
818
+ 146 => 'DispCallFunc', 147 => 'VariantChangeTypeEx', 148 => 'SafeArrayPtrOfIndex', 149 => 'SysStringByteLen',
819
+ 150 => 'SysAllocStringByteLen', 151 => 'DllRegisterServer', 152 => 'VarEqv', 153 => 'VarIdiv',
820
+ 154 => 'VarImp', 155 => 'VarMod', 156 => 'VarMul', 157 => 'VarOr',
821
+ 158 => 'VarPow', 159 => 'VarSub', 160 => 'CreateTypeLib', 161 => 'LoadTypeLib',
822
+ 162 => 'LoadRegTypeLib', 163 => 'RegisterTypeLib', 164 => 'QueryPathOfRegTypeLib', 165 => 'LHashValOfNameSys',
823
+ 166 => 'LHashValOfNameSysA', 167 => 'VarXor', 168 => 'VarAbs', 169 => 'VarFix',
824
+ 170 => 'OaBuildVersion', 171 => 'ClearCustData', 172 => 'VarInt', 173 => 'VarNeg',
825
+ 174 => 'VarNot', 175 => 'VarRound', 176 => 'VarCmp', 177 => 'VarDecAdd',
826
+ 178 => 'VarDecDiv', 179 => 'VarDecMul', 180 => 'CreateTypeLib2', 181 => 'VarDecSub',
827
+ 182 => 'VarDecAbs', 183 => 'LoadTypeLibEx', 184 => 'SystemTimeToVariantTime', 185 => 'VariantTimeToSystemTime',
828
+ 186 => 'UnRegisterTypeLib', 187 => 'VarDecFix', 188 => 'VarDecInt', 189 => 'VarDecNeg',
829
+ 190 => 'VarDecFromUI1', 191 => 'VarDecFromI2', 192 => 'VarDecFromI4', 193 => 'VarDecFromR4',
830
+ 194 => 'VarDecFromR8', 195 => 'VarDecFromDate', 196 => 'VarDecFromCy', 197 => 'VarDecFromStr',
831
+ 198 => 'VarDecFromDisp', 199 => 'VarDecFromBool', 200 => 'GetErrorInfo', 201 => 'SetErrorInfo',
832
+ 202 => 'CreateErrorInfo', 203 => 'VarDecRound', 204 => 'VarDecCmp', 205 => 'VarI2FromI1',
833
+ 206 => 'VarI2FromUI2', 207 => 'VarI2FromUI4', 208 => 'VarI2FromDec', 209 => 'VarI4FromI1',
834
+ 210 => 'VarI4FromUI2', 211 => 'VarI4FromUI4', 212 => 'VarI4FromDec', 213 => 'VarR4FromI1',
835
+ 214 => 'VarR4FromUI2', 215 => 'VarR4FromUI4', 216 => 'VarR4FromDec', 217 => 'VarR8FromI1',
836
+ 218 => 'VarR8FromUI2', 219 => 'VarR8FromUI4', 220 => 'VarR8FromDec', 221 => 'VarDateFromI1',
837
+ 222 => 'VarDateFromUI2', 223 => 'VarDateFromUI4', 224 => 'VarDateFromDec', 225 => 'VarCyFromI1',
838
+ 226 => 'VarCyFromUI2', 227 => 'VarCyFromUI4', 228 => 'VarCyFromDec', 229 => 'VarBstrFromI1',
839
+ 230 => 'VarBstrFromUI2', 231 => 'VarBstrFromUI4', 232 => 'VarBstrFromDec', 233 => 'VarBoolFromI1',
840
+ 234 => 'VarBoolFromUI2', 235 => 'VarBoolFromUI4', 236 => 'VarBoolFromDec', 237 => 'VarUI1FromI1',
841
+ 238 => 'VarUI1FromUI2', 239 => 'VarUI1FromUI4', 240 => 'VarUI1FromDec', 241 => 'VarDecFromI1',
842
+ 242 => 'VarDecFromUI2', 243 => 'VarDecFromUI4', 244 => 'VarI1FromUI1', 245 => 'VarI1FromI2',
843
+ 246 => 'VarI1FromI4', 247 => 'VarI1FromR4', 248 => 'VarI1FromR8', 249 => 'VarI1FromDate',
844
+ 250 => 'VarI1FromCy', 251 => 'VarI1FromStr', 252 => 'VarI1FromDisp', 253 => 'VarI1FromBool',
845
+ 254 => 'VarI1FromUI2', 255 => 'VarI1FromUI4', 256 => 'VarI1FromDec', 257 => 'VarUI2FromUI1',
846
+ 258 => 'VarUI2FromI2', 259 => 'VarUI2FromI4', 260 => 'VarUI2FromR4', 261 => 'VarUI2FromR8',
847
+ 262 => 'VarUI2FromDate', 263 => 'VarUI2FromCy', 264 => 'VarUI2FromStr', 265 => 'VarUI2FromDisp',
848
+ 266 => 'VarUI2FromBool', 267 => 'VarUI2FromI1', 268 => 'VarUI2FromUI4', 269 => 'VarUI2FromDec',
849
+ 270 => 'VarUI4FromUI1', 271 => 'VarUI4FromI2', 272 => 'VarUI4FromI4', 273 => 'VarUI4FromR4',
850
+ 274 => 'VarUI4FromR8', 275 => 'VarUI4FromDate', 276 => 'VarUI4FromCy', 277 => 'VarUI4FromStr',
851
+ 278 => 'VarUI4FromDisp', 279 => 'VarUI4FromBool', 280 => 'VarUI4FromI1', 281 => 'VarUI4FromUI2',
852
+ 282 => 'VarUI4FromDec', 283 => 'BSTR_UserSize', 284 => 'BSTR_UserMarshal', 285 => 'BSTR_UserUnmarshal',
853
+ 286 => 'BSTR_UserFree', 287 => 'VARIANT_UserSize', 288 => 'VARIANT_UserMarshal', 289 => 'VARIANT_UserUnmarshal',
854
+ 290 => 'VARIANT_UserFree', 291 => 'LPSAFEARRAY_UserSize', 292 => 'LPSAFEARRAY_UserMarshal', 293 => 'LPSAFEARRAY_UserUnmarshal',
855
+ 294 => 'LPSAFEARRAY_UserFree', 295 => 'LPSAFEARRAY_Size', 296 => 'LPSAFEARRAY_Marshal', 297 => 'LPSAFEARRAY_Unmarshal',
856
+ 298 => 'VarDecCmpR8', 299 => 'VarCyAdd', 300 => 'DllUnregisterServer', 301 => 'OACreateTypeLib2',
857
+ 303 => 'VarCyMul', 304 => 'VarCyMulI4', 305 => 'VarCySub', 306 => 'VarCyAbs',
858
+ 307 => 'VarCyFix', 308 => 'VarCyInt', 309 => 'VarCyNeg', 310 => 'VarCyRound',
859
+ 311 => 'VarCyCmp', 312 => 'VarCyCmpR8', 313 => 'VarBstrCat', 314 => 'VarBstrCmp',
860
+ 315 => 'VarR8Pow', 316 => 'VarR4CmpR8', 317 => 'VarR8Round', 318 => 'VarCat',
861
+ 319 => 'VarDateFromUdateEx', 322 => 'GetRecordInfoFromGuids', 323 => 'GetRecordInfoFromTypeInfo', 325 => 'SetVarConversionLocaleSetting',
862
+ 326 => 'GetVarConversionLocaleSetting', 327 => 'SetOaNoCache', 329 => 'VarCyMulI8', 330 => 'VarDateFromUdate',
863
+ 331 => 'VarUdateFromDate', 332 => 'GetAltMonthNames', 333 => 'VarI8FromUI1', 334 => 'VarI8FromI2',
864
+ 335 => 'VarI8FromR4', 336 => 'VarI8FromR8', 337 => 'VarI8FromCy', 338 => 'VarI8FromDate',
865
+ 339 => 'VarI8FromStr', 340 => 'VarI8FromDisp', 341 => 'VarI8FromBool', 342 => 'VarI8FromI1',
866
+ 343 => 'VarI8FromUI2', 344 => 'VarI8FromUI4', 345 => 'VarI8FromDec', 346 => 'VarI2FromI8',
867
+ 347 => 'VarI2FromUI8', 348 => 'VarI4FromI8', 349 => 'VarI4FromUI8', 360 => 'VarR4FromI8',
868
+ 361 => 'VarR4FromUI8', 362 => 'VarR8FromI8', 363 => 'VarR8FromUI8', 364 => 'VarDateFromI8',
869
+ 365 => 'VarDateFromUI8', 366 => 'VarCyFromI8', 367 => 'VarCyFromUI8', 368 => 'VarBstrFromI8',
870
+ 369 => 'VarBstrFromUI8', 370 => 'VarBoolFromI8', 371 => 'VarBoolFromUI8', 372 => 'VarUI1FromI8',
871
+ 373 => 'VarUI1FromUI8', 374 => 'VarDecFromI8', 375 => 'VarDecFromUI8', 376 => 'VarI1FromI8',
872
+ 377 => 'VarI1FromUI8', 378 => 'VarUI2FromI8', 379 => 'VarUI2FromUI8', 401 => 'OleLoadPictureEx',
873
+ 402 => 'OleLoadPictureFileEx', 411 => 'SafeArrayCreateVector', 412 => 'SafeArrayCopyData', 413 => 'VectorFromBstr',
874
+ 414 => 'BstrFromVector', 415 => 'OleIconToCursor', 416 => 'OleCreatePropertyFrameIndirect', 417 => 'OleCreatePropertyFrame',
875
+ 418 => 'OleLoadPicture', 419 => 'OleCreatePictureIndirect', 420 => 'OleCreateFontIndirect', 421 => 'OleTranslateColor',
876
+ 422 => 'OleLoadPictureFile', 423 => 'OleSavePictureFile', 424 => 'OleLoadPicturePath', 425 => 'VarUI4FromI8',
877
+ 426 => 'VarUI4FromUI8', 427 => 'VarI8FromUI8', 428 => 'VarUI8FromI8', 429 => 'VarUI8FromUI1',
878
+ 430 => 'VarUI8FromI2', 431 => 'VarUI8FromR4', 432 => 'VarUI8FromR8', 433 => 'VarUI8FromCy',
879
+ 434 => 'VarUI8FromDate', 435 => 'VarUI8FromStr', 436 => 'VarUI8FromDisp', 437 => 'VarUI8FromBool',
880
+ 438 => 'VarUI8FromI1', 439 => 'VarUI8FromUI2', 440 => 'VarUI8FromUI4', 441 => 'VarUI8FromDec',
881
+ 442 => 'RegisterTypeLibForUser', 443 => 'UnRegisterTypeLibForUser',
882
+ },
883
+ }
743
884
  end
744
885
  end
745
886
 
@@ -26,18 +26,10 @@ class CPU
26
26
  while tok = lexer.readtok and parse_prefix(i, tok.raw)
27
27
  lexer.skip_space_eol
28
28
  end
29
- return if not tok
30
29
 
31
- # allow '.' in opcode name
32
- tok = tok.dup
33
- while ntok = lexer.nexttok and ntok.type == :punct and ntok.raw == '.'
34
- tok.raw << lexer.readtok.raw
35
- ntok = lexer.readtok
36
- raise tok, 'invalid opcode name' if not ntok or ntok.type != :string
37
- tok.raw << ntok.raw
38
- end
39
-
40
- raise tok, 'invalid opcode' if not opcode_list_byname[tok.raw]
30
+ lexer.unreadtok(tok)
31
+ tok = parse_instruction_mnemonic(lexer)
32
+ return if not tok
41
33
 
42
34
  i.opname = tok.raw
43
35
  i.backtrace = tok.backtrace
@@ -63,6 +55,23 @@ class CPU
63
55
  i
64
56
  end
65
57
 
58
+ # return a lexer token with an instruction mnemonic in #raw
59
+ # allows '.' in opcode name
60
+ # return nil at eof
61
+ def parse_instruction_mnemonic(lexer)
62
+ return if not tok = lexer.readtok
63
+ tok = tok.dup
64
+ while ntok = lexer.nexttok and ntok.type == :punct and ntok.raw == '.'
65
+ tok.raw << lexer.readtok.raw
66
+ ntok = lexer.readtok
67
+ raise tok, 'invalid opcode name' if not ntok or ntok.type != :string
68
+ tok.raw << ntok.raw
69
+ end
70
+
71
+ raise tok, 'invalid opcode' if not opcode_list_byname[tok.raw]
72
+ tok
73
+ end
74
+
66
75
  def parse_instruction_checkproto(i)
67
76
  opcode_list_byname[i.opname].to_a.find { |o|
68
77
  o.args.length == i.args.length and o.args.zip(i.args).all? { |f, a| parse_arg_valid?(o, f, a) }
@@ -159,13 +168,20 @@ class AsmPreprocessor < Preprocessor
159
168
  end
160
169
  end
161
170
 
171
+ class Preprocessor::Token
172
+ # token already preprocessed for macro def/expansion
173
+ attr_accessor :alreadyapp
174
+ end
175
+
162
176
  # the program (used to create new label names)
163
177
  attr_accessor :program
164
178
  # hash macro name => Macro
165
179
  attr_accessor :macro
180
+ attr_accessor :may_apreprocess
166
181
 
167
182
  def initialize(text='', program=nil)
168
183
  @program = program
184
+ @may_apreprocess = false
169
185
  @macro = {}
170
186
  super(text)
171
187
  end
@@ -184,13 +200,21 @@ class AsmPreprocessor < Preprocessor
184
200
  t
185
201
  end
186
202
 
187
- # reads a token, handles macros/comments/integers/etc
188
- # argument is for internal use
189
- def readtok(rec = false)
203
+ def feed!(*a)
204
+ super(*a)
205
+ if not @may_apreprocess and (@text =~ / (macro|equ) / or not @macro.empty?)
206
+ @may_apreprocess = true
207
+ end
208
+ self
209
+ end
210
+
211
+ # reads a token, handles macros/comments/etc
212
+ def readtok
190
213
  tok = super()
214
+ return tok if not tok or tok.alreadyapp
191
215
 
192
216
  # handle ; comments
193
- if tok and tok.type == :punct and tok.raw == ';'
217
+ if tok.type == :punct and tok.raw[0] == ?;
194
218
  tok.type = :eol
195
219
  begin
196
220
  tok = tok.dup
@@ -203,30 +227,13 @@ class AsmPreprocessor < Preprocessor
203
227
  end
204
228
  end
205
229
 
206
- # aggregate space/eol
207
- if tok and (tok.type == :space or tok.type == :eol)
208
- if ntok = readtok(true) and ntok.type == :space
209
- tok = tok.dup
210
- tok.raw << ntok.raw
211
- elsif ntok and ntok.type == :eol
212
- tok = tok.dup
213
- tok.raw << ntok.raw
214
- tok.type = :eol
215
- else
216
- unreadtok ntok
217
- end
218
- end
219
-
220
-
221
230
  # handle macros
222
- # the rec parameter is used to avoid reading the whole text at once when reading ahead to check 'macro' keyword
223
- if not rec and tok and tok.type == :string
231
+ if @may_apreprocess and tok.type == :string
224
232
  if @macro[tok.raw]
225
233
  @macro[tok.raw].apply(tok, self, @program).reverse_each { |t| unreadtok t }
226
234
  tok = readtok
227
-
228
235
  else
229
- if ntok = readtok(true) and ntok.type == :space and nntok = readtok(true) and nntok.type == :string and (nntok.raw == 'macro' or nntok.raw == 'equ')
236
+ if ntok = super() and ntok.type == :space and nntok = super() and nntok.type == :string and (nntok.raw == 'macro' or nntok.raw == 'equ')
230
237
  puts "W: asm: redefinition of macro #{tok.raw} at #{tok.backtrace_str}, previous definition at #{@macro[tok.raw].name.backtrace_str}" if @macro[tok.raw]
231
238
  m = Macro.new tok
232
239
  # XXX this allows nested macro definition..
@@ -252,6 +259,7 @@ class AsmPreprocessor < Preprocessor
252
259
  end
253
260
  end
254
261
 
262
+ tok.alreadyapp = true if tok
255
263
  tok
256
264
  end
257
265
  end
@@ -314,6 +322,7 @@ class ExeFormat
314
322
  lname = @locallabels_bkw[tok.raw] = @locallabels_fwd.delete(tok.raw) || new_label('local_'+tok.raw)
315
323
  else
316
324
  lname = tok.raw
325
+ raise tok, "invalid label name: #{lname.inspect} is reserved" if @cpu.check_reserved_name(lname)
317
326
  raise tok, "label redefinition" if new_label(lname) != lname
318
327
  end
319
328
  l = Label.new(lname)
@@ -421,7 +430,7 @@ class ExeFormat
421
430
  @cursource << Padding.new(fillwith, tok.backtrace) << Offset.new(e, tok.backtrace)
422
431
 
423
432
  else
424
- @cpu.parse_parser_instruction(self, tok)
433
+ @cpu.parse_parser_instruction(@lexer, tok)
425
434
  end
426
435
  end
427
436
 
@@ -746,6 +755,8 @@ class Expression
746
755
 
747
756
  # for boolean operators, true is 1 (or anything != 0), false is 0
748
757
  def parse(lexer)
758
+ lexer = Preprocessor.new(lexer) if lexer.kind_of?(::String)
759
+
749
760
  opstack = []
750
761
  stack = []
751
762
 
@@ -780,7 +791,7 @@ class Expression
780
791
  pp = Preprocessor.new(str)
781
792
 
782
793
  e = parse(pp, &b)
783
-
794
+
784
795
  # update arg
785
796
  len = pp.pos
786
797
  pp.queue.each { |t| len -= t.raw.length }
@@ -821,6 +832,8 @@ class IndExpression < Expression
821
832
  break
822
833
  when ':' # symbols, eg ':eax'
823
834
  n = lexer.readtok
835
+ nil while tok = lexer.readtok and tok.type == :space
836
+ lexer.unreadtok tok
824
837
  return n.raw.to_sym
825
838
  else
826
839
  lexer.unreadtok tok
@@ -22,7 +22,17 @@ module C
22
22
  __builtin_offsetof
23
23
  ].inject({}) { |h, w| h.update w => true }
24
24
 
25
+ module Misc
26
+ attr_accessor :misc
27
+
28
+ def with_misc(m)
29
+ @misc = m if m or misc
30
+ self
31
+ end
32
+ end
33
+
25
34
  class Statement
35
+ include Misc
26
36
  end
27
37
 
28
38
  module Typed # allows quick testing whether an object is an CExpr or a Variable
@@ -114,6 +124,7 @@ module C
114
124
 
115
125
  class Type
116
126
  include Attributes
127
+ include Misc
117
128
  attr_accessor :qualifier # const volatile
118
129
 
119
130
  def pointer? ; false end
@@ -249,7 +260,7 @@ module C
249
260
  end
250
261
 
251
262
  def findmember(name, igncase=false)
252
- raise parser, 'undefined structure' if not @members
263
+ raise 'undefined structure' if not members
253
264
  return @fldlist[name] if fldlist and @fldlist[name]
254
265
 
255
266
  name = name.downcase if igncase
@@ -267,7 +278,7 @@ module C
267
278
  end
268
279
 
269
280
  def offsetof(parser, name)
270
- raise parser, 'undefined structure' if not @members
281
+ raise parser, 'undefined structure' if not members
271
282
  update_member_cache(parser) if not fldlist
272
283
  return 0 if @fldlist[name]
273
284
 
@@ -284,7 +295,7 @@ module C
284
295
  end
285
296
 
286
297
  def bitoffsetof(parser, name)
287
- raise parser, 'undefined structure' if not @members
298
+ raise parser, 'undefined structure' if not members
288
299
  update_member_cache(parser) if not fldlist
289
300
  return if @fldlist[name] or @members.include?(name)
290
301
  raise parser, 'undefined union' if not @members
@@ -390,6 +401,22 @@ module C
390
401
  end
391
402
  idx + 1
392
403
  end
404
+
405
+ # resolve structptr + offset into 'str.membername'
406
+ # handles 'var.substruct1.array[12].foo'
407
+ # updates str
408
+ # returns the final member type itself
409
+ # works for Struct/Union/Array
410
+ def expand_member_offset(c_parser, off, str)
411
+ # XXX choose in members, check sizeof / prefer structs
412
+ m = @members.first
413
+ str << '.' << m.name if m.name
414
+ if m.type.respond_to?(:expand_member_offset)
415
+ m.type.expand_member_offset(c_parser, off, str)
416
+ else
417
+ m.type
418
+ end
419
+ end
393
420
  end
394
421
  class Struct < Union
395
422
  attr_accessor :pack
@@ -397,9 +424,10 @@ module C
397
424
  def align(parser) [@members.to_a.map { |m| m.type.align(parser) }.max || 1, (pack || 8)].min end
398
425
 
399
426
  def offsetof(parser, name)
400
- raise parser, 'undefined structure' if not @members
427
+ raise parser, 'undefined structure' if not members
401
428
  update_member_cache(parser) if not fldlist
402
429
  return @fldoffset[name] if @fldoffset[name]
430
+ return @fldoffset[name.name] if name.respond_to?(:name) and @fldoffset[name.name]
403
431
 
404
432
  # this is almost never reached, only for <struct>.offsetof(anonymoussubstructmembername)
405
433
  raise parser, 'unknown structure member' if (name.kind_of?(::String) ? !findmember(name) : !@members.include?(name))
@@ -433,7 +461,7 @@ module C
433
461
  end
434
462
  mal = [m.type.align(parser), al].min
435
463
  off = (off + mal - 1) / mal * mal
436
- if m.name == name or m == name
464
+ if m.name == name or m == name
437
465
  break
438
466
  elsif indirect and m.type.untypedef.kind_of? Union and m.type.untypedef.findmember(name)
439
467
  off += m.type.untypedef.offsetof(parser, name)
@@ -449,18 +477,28 @@ module C
449
477
  # returns the [bitoffset, bitlength] of the field if it is a bitfield
450
478
  # this should be added to the offsetof(field)
451
479
  def bitoffsetof(parser, name)
452
- raise parser, 'undefined structure' if not @members
480
+ raise parser, 'undefined structure' if not members
453
481
  update_member_cache(parser) if not fldlist
454
482
  return @fldbitoffset[name] if fldbitoffset and @fldbitoffset[name]
483
+ return @fldbitoffset[name.name] if fldbitoffset and name.respond_to?(:name) and @fldbitoffset[name.name]
455
484
  return if @fldlist[name] or @members.include?(name)
456
485
  raise parser, 'undefined union' if not @members
457
486
  raise parser, 'unknown union member' if not findmember(name)
458
487
 
459
488
  @members.find { |m|
460
- m.type.untypedef.kind_of? Union and m.type.untypedef.findmember(name)
489
+ m.type.untypedef.kind_of?(Union) and m.type.untypedef.findmember(name)
461
490
  }.type.untypedef.bitoffsetof(parser, name)
462
491
  end
463
492
 
493
+ # returns the @member element that has offsetof(m) == off
494
+ def findmember_atoffset(parser, off)
495
+ return if not members
496
+ update_member_cache(parser) if not fldlist
497
+ if m = @fldoffset.index(off)
498
+ @fldlist[m]
499
+ end
500
+ end
501
+
464
502
  def parse_members(parser, scope)
465
503
  super(parser, scope)
466
504
 
@@ -515,6 +553,32 @@ module C
515
553
  end
516
554
  }
517
555
  end
556
+
557
+ # see Union#expand_member_offset
558
+ def expand_member_offset(c_parser, off, str)
559
+ members.to_a.each { |m|
560
+ mo = offsetof(c_parser, m)
561
+ if mo == off or mo + c_parser.sizeof(m) > off
562
+ if bitoffsetof(c_parser, m)
563
+ # ignore bitfields
564
+ str << "+#{off}" if off > 0
565
+ return self
566
+ end
567
+
568
+ str << '.' << m.name if m.name
569
+ if m.type.respond_to?(:expand_member_offset)
570
+ return m.type.expand_member_offset(c_parser, off-mo, str)
571
+ else
572
+ return m.type
573
+ end
574
+ elsif mo > off
575
+ break
576
+ end
577
+ }
578
+ # XXX that works only for pointer-style str
579
+ str << "+#{off}" if off > 0
580
+ nil
581
+ end
518
582
  end
519
583
  class Enum < Type
520
584
  # name => value
@@ -557,6 +621,11 @@ module C
557
621
  parse_attributes(parser)
558
622
  end
559
623
 
624
+ def compare_deep(o)
625
+ return true if o.object_id == self.object_id
626
+ return if o.class != self.class or o.name != self.name or o.attributes != self.attributes
627
+ members == o.members
628
+ end
560
629
  end
561
630
  class Pointer < Type
562
631
  attr_accessor :type
@@ -684,11 +753,23 @@ module C
684
753
  end
685
754
  idx + 1
686
755
  end
756
+
757
+ # see Union#expand_member_offset
758
+ def expand_member_offset(c_parser, off, str)
759
+ tsz = c_parser.sizeof(@type)
760
+ str << "[#{off/tsz}]"
761
+ if @type.respond_to?(:expand_member_offset)
762
+ @type.expand_member_offset(c_parser, off%tsz, str)
763
+ else
764
+ @type
765
+ end
766
+ end
687
767
  end
688
768
 
689
769
  class Variable
690
770
  include Attributes
691
771
  include Typed
772
+ include Misc
692
773
 
693
774
  attr_accessor :type
694
775
  attr_accessor :initializer # CExpr / Block (for Functions)
@@ -704,6 +785,8 @@ module C
704
785
  # found in a block's Statements, used to know the initialization order
705
786
  # eg { int i; i = 4; struct foo { int k; } toto = {i}; }
706
787
  class Declaration
788
+ include Misc
789
+
707
790
  attr_accessor :var
708
791
  def initialize(var)
709
792
  @var = var
@@ -877,10 +960,10 @@ module C
877
960
  raise ftok, 'unterminated asm block' if not tok = parser.lexer.readtok
878
961
  break if tok.type == :punct and tok.raw == '}'
879
962
  case tok.type
880
- when :space; body << ' '
881
- when :eol; body << "\n"
963
+ when :space; body << ' ' unless body.empty?
964
+ when :eol; body << "\n" unless body.empty?
882
965
  when :punct; body << tok.raw
883
- when :quoted; body << tok.value.inspect # concat adjacent c strings
966
+ when :quoted; body << CExpression.string_inspect(tok.value) # concat adjacent c strings
884
967
  when :string
885
968
  body << \
886
969
  case tok.raw
@@ -923,7 +1006,7 @@ module C
923
1006
  break
924
1007
  else body << tok.raw
925
1008
  end
926
- when :quoted; body << (body.empty? ? tok.value : tok.value.inspect) # asm "pop\nret" VS asm add al, 'z'
1009
+ when :quoted; body << (body.empty? ? tok.value : CExpression.string_inspect(tok.value)) # asm "pop\nret" VS asm add al, 'z'
927
1010
  when :string
928
1011
  body << \
929
1012
  case tok.raw
@@ -987,17 +1070,20 @@ module C
987
1070
  class CExpression < Statement
988
1071
  include Typed
989
1072
 
1073
+ AssignOp = [:'=', :'+=', :'-=', :'*=', :'/=', :'%=', :'^=', :'&=', :'|=', :'>>=', :'<<=', :'++', :'--']
1074
+
990
1075
  # may be :,, :., :'->', :funcall (function, [arglist]), :[] (array indexing), nil (cast)
991
1076
  attr_accessor :op
992
1077
  # nil/CExpr/Variable/Label/::String( = :quoted/struct member name)/::Integer/::Float/Block
993
1078
  attr_accessor :lexpr, :rexpr
994
1079
  # a Type
995
1080
  attr_accessor :type
1081
+
996
1082
  def initialize(l, o, r, t)
997
1083
  raise "invalid CExpr #{[l, o, r, t].inspect}" if (o and not o.kind_of? ::Symbol) or not t.kind_of? Type
998
1084
  @lexpr, @op, @rexpr, @type = l, o, r, t
999
1085
  end
1000
-
1086
+
1001
1087
  # overwrites @lexpr @op @rexpr @type from the arg
1002
1088
  def replace(o)
1003
1089
  @lexpr, @op, @rexpr, @type = o.lexpr, o.op, o.rexpr, o.type
@@ -1023,7 +1109,7 @@ module C
1023
1109
  # sub-arrays in args are to be passed to self.[] recursively (syntaxic sugar)
1024
1110
  splat = lambda { |e| e.kind_of?(::Array) ? self[*e] : e }
1025
1111
 
1026
- args.shift while args.first == nil # CExpr[nil, :&, bla] => CExpr[:&, bla]
1112
+ args.shift while args.length > 0 and args.first == nil # CExpr[nil, :&, bla] => CExpr[:&, bla]
1027
1113
 
1028
1114
  case args.length
1029
1115
  when 4
@@ -1033,7 +1119,7 @@ module C
1033
1119
  else
1034
1120
  x2 = splat[args[2]]
1035
1121
  end
1036
- new(splat[args[0]], op, x2, args[3])
1122
+ new(splat[args[0]], op, x2, args[3])
1037
1123
  when 3
1038
1124
  op = args[1]
1039
1125
  x1 = splat[args[0]]
@@ -1045,9 +1131,9 @@ module C
1045
1131
 
1046
1132
  case op
1047
1133
  when :funcall
1048
- rt = x1.type.untypedef
1049
- rt = rt.type.untypedef if rt.pointer?
1050
- new(x1, op, x2, rt.type)
1134
+ rt = x1.type.untypedef
1135
+ rt = rt.type.untypedef if rt.pointer?
1136
+ new(x1, op, x2, rt.type)
1051
1137
  when :[]; new(x1, op, x2, x1.type.untypedef.type)
1052
1138
  when :+; new(x1, op, x2, (x2.type.pointer? ? x2.type : x1.type))
1053
1139
  when :-; new(x1, op, x2, ((x1.type.pointer? and x2.type.pointer?) ? BaseType.new(:int) : x2.type.pointer? ? x2.type : x1.type))
@@ -1111,13 +1197,14 @@ module C
1111
1197
  attr_accessor :lexer, :toplevel, :typesize, :pragma_pack
1112
1198
  attr_accessor :endianness
1113
1199
  attr_accessor :allow_bad_c
1200
+ attr_accessor :program
1114
1201
  # allowed arguments: ExeFormat, CPU, Preprocessor, Symbol (for the data model)
1115
1202
  def initialize(*args)
1116
1203
  model = args.grep(Symbol).first || :ilp32
1117
1204
  lexer = args.grep(Preprocessor).first || Preprocessor.new
1118
- exe = args.grep(ExeFormat).first
1205
+ @program = args.grep(ExeFormat).first
1119
1206
  cpu = args.grep(CPU).first
1120
- cpu ||= exe.cpu if exe
1207
+ cpu ||= @program.cpu if @program
1121
1208
  @lexer = lexer
1122
1209
  @prev_pragma_callback = @lexer.pragma_callback
1123
1210
  @lexer.pragma_callback = lambda { |tok| parse_pragma_callback(tok) }
@@ -1128,7 +1215,7 @@ module C
1128
1215
  :char => 1, :float => 4, :double => 8, :longdouble => 12 }
1129
1216
  send model
1130
1217
  cpu.tune_cparser(self) if cpu
1131
- exe.tune_cparser(self) if exe
1218
+ @program.tune_cparser(self) if @program
1132
1219
  end
1133
1220
 
1134
1221
  def ilp16
@@ -1513,6 +1600,7 @@ EOH
1513
1600
  when Struct
1514
1601
  raise self, "unknown structure size #{type.name}" if not type.members
1515
1602
  al = type.align(self)
1603
+ al = 1 if (var.kind_of?(Attributes) and var.has_attribute('sizeof_packed')) or type.has_attribute('sizeof_packed')
1516
1604
  lm = type.members.last
1517
1605
  lm ? (type.offsetof(self, lm) + sizeof(lm) + al - 1) / al * al : 0
1518
1606
  when Union
@@ -1703,6 +1791,7 @@ EOH
1703
1791
  Goto.new name
1704
1792
  when 'return'
1705
1793
  expr = CExpression.parse(self, scope) # nil allowed
1794
+ raise tok || self, "cannot return #{expr} in function returning void" if expr and nest[0].kind_of?(Type) and nest[0].void?
1706
1795
  p, i = nest[0].pointer?, nest[0].integral? if expr
1707
1796
  r = expr.reduce(self) if p or i
1708
1797
  if (not p and not i) or (i and not r.kind_of? ::Integer) or (p and r != 0)
@@ -1770,6 +1859,7 @@ EOH
1770
1859
  end
1771
1860
 
1772
1861
  # returns all numeric constants defined with their value, either macros or enums
1862
+ # for enums, also return the enum name
1773
1863
  def numeric_constants
1774
1864
  ret = []
1775
1865
  # macros
@@ -1779,8 +1869,17 @@ EOH
1779
1869
  end
1780
1870
  }
1781
1871
  # enums
1872
+ seen_enum = {}
1873
+ @toplevel.struct.each { |k, v|
1874
+ if v.kind_of?(Enum)
1875
+ v.members.each { |kk, vv|
1876
+ ret << [kk, vv, k]
1877
+ seen_enum[kk] = true
1878
+ }
1879
+ end
1880
+ }
1782
1881
  @toplevel.symbol.each { |k, v|
1783
- ret << [k, v] if v.kind_of? ::Numeric
1882
+ ret << [k, v] if v.kind_of?(::Numeric) and not seen_enum[k]
1784
1883
  }
1785
1884
  ret
1786
1885
  end
@@ -1933,7 +2032,10 @@ EOH
1933
2032
  name = :int
1934
2033
  tok = nil
1935
2034
  loop do
1936
- raise parser if not tok = parser.skipspaces
2035
+ if not tok = parser.skipspaces
2036
+ raise parser if specifier.empty?
2037
+ break
2038
+ end
1937
2039
  if tok.type != :string
1938
2040
  parser.unreadtok tok
1939
2041
  break
@@ -2239,12 +2341,13 @@ EOH
2239
2341
  else
2240
2342
  l = CExpression.new(nil, nil, l, BaseType.new(:int)) if l.kind_of? ::Integer
2241
2343
  r = CExpression.new(nil, nil, r, BaseType.new(:int)) if r.kind_of? ::Integer
2242
- CExpression.new(l, @op, r, @type)
2344
+ CExpression.new(l, @op, r, @type)
2243
2345
  end
2244
2346
  when :'.'
2245
2347
  le = CExpression.reduce(parser, @lexpr)
2246
2348
  if le.kind_of? Variable and le.initializer.kind_of? ::Array
2247
- midx = le.type.members.index(le.type.findmember(@rexpr))
2349
+ t = le.type.untypedef
2350
+ midx = t.members.index(t.findmember(@rexpr))
2248
2351
  CExpression.reduce(parser, le.initializer[midx] || 0)
2249
2352
  else
2250
2353
  CExpression.new(le, @op, @rexpr, @type)
@@ -2282,7 +2385,7 @@ EOH
2282
2385
  end
2283
2386
  else
2284
2387
  l = CExpression.reduce(parser, @lexpr)
2285
- if not l.kind_of?(::Numeric) or not r.kind_of?(::Numeric)
2388
+ if not l.kind_of?(::Numeric) or not r.kind_of?(::Numeric)
2286
2389
  l = CExpression.new(nil, nil, l, BaseType.new(:int)) if l.kind_of? ::Integer
2287
2390
  r = CExpression.new(nil, nil, r, BaseType.new(:int)) if r.kind_of? ::Integer
2288
2391
  return CExpression.new(l, @op, r, @type)
@@ -2325,7 +2428,7 @@ EOH
2325
2428
  o.object_id == self.object_id or
2326
2429
  (self.class == o.class and op == o.op and lexpr == o.lexpr and rexpr == o.rexpr)
2327
2430
  end
2328
-
2431
+
2329
2432
  def ===(o)
2330
2433
  (self.class == o.class and op == o.op and lexpr === o.lexpr and rexpr === o.rexpr) or
2331
2434
  (o.class == Variable and not @op and @rexpr == o)
@@ -2506,6 +2609,7 @@ EOH
2506
2609
  type = :long if suffix.count('l') == 1
2507
2610
  end
2508
2611
  val = CExpression[val, BaseType.new(type, *specifier)]
2612
+ val = parse_value_postfix(parser, scope, val)
2509
2613
  else raise parser, "internal error #{val.inspect}"
2510
2614
  end
2511
2615
 
@@ -2513,6 +2617,7 @@ EOH
2513
2617
  if tok.raw[0] == ?'
2514
2618
  raise tok, 'invalid character constant' if not [1, 2, 4, 8].include? tok.value.length # TODO 0fill
2515
2619
  val = CExpression[Expression.decode_imm(tok.value, tok.value.length, :big), BaseType.new(:int)]
2620
+ val = parse_value_postfix(parser, scope, val)
2516
2621
  else
2517
2622
  val = CExpression[tok.value, Pointer.new(BaseType.new(tok.raw[0, 2] == 'L"' ? :short : :char))]
2518
2623
  val = parse_value_postfix(parser, scope, val)
@@ -2712,96 +2817,109 @@ EOH
2712
2817
  end
2713
2818
  end
2714
2819
 
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 :'='
2820
+ def parse_popstack(parser, stack, opstack)
2821
+ r = stack.pop
2822
+ l = stack.pop
2823
+ case op = opstack.pop
2824
+ when :'?:'
2825
+ stack << CExpression.new(stack.pop, op, [l, r], l.type)
2826
+ when :','
2827
+ stack << CExpression.new(l, op, r, r.type)
2828
+ when :'='
2829
+ unless r.kind_of?(CExpression) and not r.lexpr and r.type.kind_of?(BaseType) and
2830
+ ((not r.op and r.rexpr.kind_of?(Integer)) or
2831
+ (r.op == :- and r.rexpr.kind_of?(CExpression) and not r.rexpr.op and not r.rexpr.lexpr and r.rexpr.rexpr.kind_of?(Integer))) and
2832
+ l.kind_of?(Typed) and (l.type.untypedef.kind_of?(BaseType) or (l.type.untypedef.kind_of?(Pointer) and r.rexpr == 0))
2833
+ # avoid useless warnings on unsigned foo = -1 / void *foo = 0
2727
2834
  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))
2835
+ end
2836
+ if l.kind_of?(Typed) and (lt = l.type.untypedef).kind_of?(BaseType) and r.kind_of?(Typed) and (rt = r.type.untypedef).kind_of?(BaseType) and lt.specifier != :unsigned and rt.specifier == :unsigned and parser.typesize[lt.name] > parser.typesize[rt.name]
2837
+ # (int32)i = (uchar)255 => 255, not -1
2838
+ r = CExpression.new(nil, nil, r, BaseType.new(lt.name, :unsigned))
2839
+ end
2840
+ stack << CExpression.new(l, op, r, l.type)
2841
+ when :'&&', :'||'
2842
+ stack << CExpression.new(l, op, r, BaseType.new(:int))
2843
+ else
2844
+ # XXX struct == struct ?
2845
+ raise parser, "invalid type #{l.type} #{l} for #{op.inspect}" if not l.type.arithmetic? and not parser.allow_bad_c
2846
+ raise parser, "invalid type #{r.type} #{r} for #{op.inspect}" if not r.type.arithmetic? and not parser.allow_bad_c
2847
+
2848
+ if l.type.pointer? and r.type.pointer?
2849
+ type = \
2850
+ case op
2851
+ when :'-'; BaseType.new(:long) # addr_t or sumthin ?
2852
+ when :'-='; l.type
2853
+ when :'>', :'>=', :'<', :'<=', :'==', :'!='; BaseType.new(:long)
2854
+ else raise parser, "cannot do #{op.inspect} on pointers" unless parser.allow_bad_c ; l.type
2855
+ end
2856
+ elsif l.type.pointer? or r.type.pointer?
2857
+ puts parser.exception("should not #{op.inspect} a pointer").message if $VERBOSE and not [:'+', :'-', :'=', :'+=', :'-=', :==, :'!='].include? op
2858
+ type = l.type.pointer? ? l.type : r.type
2859
+ elsif RIGHTASSOC[op] and op != :'?:' # += etc
2860
+ type = l.type
2731
2861
  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
2862
+ # yay integer promotion
2863
+ lt = l.type.untypedef
2864
+ rt = r.type.untypedef
2865
+ if (t = lt).name == :longdouble or (t = rt).name == :longdouble or
2866
+ (t = lt).name == :double or (t = rt).name == :double or
2867
+ (t = lt).name == :float or (t = rt).name == :float
2868
+ # long double > double > float ...
2869
+ type = t
2870
+ elsif true
2871
+ # custom integer rules based on type sizes
2872
+ lts = parser.typesize[lt.name]
2873
+ rts = parser.typesize[rt.name]
2874
+ its = parser.typesize[:int]
2875
+ if not lts or not rts
2876
+ type = BaseType.new(:int)
2877
+ elsif lts > rts and lts >= its
2878
+ type = lt
2879
+ elsif rts > lts and rts >= its
2880
+ type = rt
2881
+ elsif lts == rts and lts >= its
2882
+ type = lt
2883
+ type = rt if rt.specifier == :unsigned
2787
2884
  else
2788
- # int
2789
2885
  type = BaseType.new(:int)
2790
2886
  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))
2887
+ # end of custom rules
2888
+ elsif ((t = lt).name == :long and t.specifier == :unsigned) or
2889
+ ((t = rt).name == :long and t.specifier == :unsigned)
2890
+ # ... ulong ...
2891
+ type = t
2892
+ elsif (lt.name == :long and rt.name == :int and rt.specifier == :unsigned) or
2893
+ (rt.name == :long and lt.name == :int and lt.specifier == :unsigned)
2894
+ # long+uint => ulong
2895
+ type = BaseType.new(:long, :unsigned)
2896
+ elsif (t = lt).name == :long or (t = rt).name == :long or
2897
+ ((t = lt).name == :int and t.specifier == :unsigned) or
2898
+ ((t = rt).name == :int and t.specifier == :unsigned)
2899
+ # ... long > uint ...
2900
+ type = t
2799
2901
  else
2800
- # promote result
2801
- stack << CExpression.new(l, op, r, type)
2902
+ # int
2903
+ type = BaseType.new(:int)
2802
2904
  end
2803
2905
  end
2804
- }
2906
+
2907
+ case op
2908
+ when :'>', :'>=', :'<', :'<=', :'==', :'!='
2909
+ # cast both sides
2910
+ l = CExpression[l, type] if l.type != type
2911
+ r = CExpression[r, type] if r.type != type
2912
+ stack << CExpression.new(l, op, r, BaseType.new(:int))
2913
+ else
2914
+ # promote result
2915
+ stack << CExpression.new(l, op, r, type)
2916
+ end
2917
+ end
2918
+ end
2919
+
2920
+ def parse(parser, scope, allow_coma = true)
2921
+ opstack = []
2922
+ stack = []
2805
2923
 
2806
2924
  return if not e = parse_value(parser, scope)
2807
2925
 
@@ -2812,7 +2930,7 @@ EOH
2812
2930
  when :'?'
2813
2931
  # a, b ? c, d : e, f == a, (b ? (c, d) : e), f
2814
2932
  until opstack.empty? or OP_PRIO[opstack.last][:'?:']
2815
- popstack[]
2933
+ parse_popstack(parser, stack, opstack)
2816
2934
  end
2817
2935
  stack << parse(parser, scope)
2818
2936
  raise op || parser, '":" expected' if not op = readop(parser) or op.value != :':'
@@ -2827,7 +2945,7 @@ EOH
2827
2945
  break
2828
2946
  end
2829
2947
  until opstack.empty? or OP_PRIO[op.value][opstack.last]
2830
- popstack[]
2948
+ parse_popstack(parser, stack, opstack)
2831
2949
  end
2832
2950
  end
2833
2951
 
@@ -2837,7 +2955,7 @@ EOH
2837
2955
  end
2838
2956
 
2839
2957
  until opstack.empty?
2840
- popstack[]
2958
+ parse_popstack(parser, stack, opstack)
2841
2959
  end
2842
2960
 
2843
2961
  CExpression[stack.first]
@@ -2929,8 +3047,9 @@ EOH
2929
3047
  end
2930
3048
 
2931
3049
  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
3050
+ f = a
3051
+ raise "#{a.inspect} not a struct member" if not f.kind_of? C::Variable and not f = @struct.findmember(a.to_s, true)
3052
+ a = f.name || f
2934
3053
  val = sizeof if val == :size
2935
3054
  off = @stroff + @struct.offsetof(@cp, a)
2936
3055
 
@@ -2972,7 +3091,6 @@ EOH
2972
3091
  str.last << "struct #{@struct.name || '_'} x = " if not off
2973
3092
  @struct.update_member_cache(@cp) if not @struct.fldlist
2974
3093
  fldoff = @struct.fldoffset
2975
- fbo = @struct.fldbitoffset || {}
2976
3094
  mlist = @struct.members.map { |m| m.name || m }
2977
3095
  else
2978
3096
  str.last << "union #{@struct.name || '_'} x = " if not off
@@ -3075,7 +3193,7 @@ EOH
3075
3193
  end
3076
3194
 
3077
3195
  # parse a given String as an AllocCStruct
3078
- # offset is an optionnal offset from the string start
3196
+ # offset is an optional offset from the string start
3079
3197
  # modification to the structure will modify the underlying string
3080
3198
  def decode_c_struct(structname, str, offset=0)
3081
3199
  struct = find_c_struct(structname)
@@ -3203,8 +3321,7 @@ EOH
3203
3321
  all = @toplevel.struct.values + @toplevel.symbol.values
3204
3322
  all -= all.grep(::Integer) # Enum values
3205
3323
 
3206
- r, dep = @toplevel.dump_reorder(all, todo_rndr, todo_deps)
3207
- r.join("\n")
3324
+ @toplevel.dump_reorder(all, todo_rndr, todo_deps)[0].join("\n")
3208
3325
  end
3209
3326
 
3210
3327
  # returns a string containing the C definition(s) of toplevel functions, with their dependencies
@@ -3221,19 +3338,49 @@ EOH
3221
3338
  end
3222
3339
  end
3223
3340
 
3341
+ # used to render a C to a source string, while keeping the information of which each character comes from which C object
3342
+ class CRenderString < ::String
3343
+ attr_accessor :my_c # default C obj with which raw characters are associated
3344
+ # hash offset => C::Statement, means bytes from this offset to the next entry comes from rendering this C object
3345
+ def c_at_offset
3346
+ @c_at_offset ||= {}
3347
+ end
3348
+
3349
+ # concatenate another CRenderString: merge @c_at_offset
3350
+ def <<(o)
3351
+ if o.kind_of?(self.class)
3352
+ o.c_at_offset.each { |k, v|
3353
+ c_at_offset[length+k] ||= v
3354
+ }
3355
+ elsif my_c
3356
+ c_at_offset[length] ||= my_c
3357
+ end
3358
+ super(o)
3359
+ end
3360
+
3361
+ def initialize(*a)
3362
+ if cs = a.grep(Statement).first
3363
+ a -= [cs]
3364
+ @my_c = cs
3365
+ c_at_offset[0] = cs
3366
+ end
3367
+ super(*a)
3368
+ end
3369
+ end
3370
+
3224
3371
  class Statement
3225
- def self.dump(e, scope, r=[''], dep=[])
3372
+ def self.dump(e, scope, r=[CRenderString.new], dep=[])
3226
3373
  case e
3227
3374
  when nil; r.last << ';'
3228
3375
  when Block
3229
3376
  r.last << ' ' if not r.last.empty?
3230
3377
  r.last << '{'
3231
- tr, dep = e.dump(scope, [''], dep)
3378
+ tr, dep = e.dump(scope, [CRenderString.new], dep)
3232
3379
  tr.pop if tr.last.empty?
3233
3380
  r.concat tr.map { |s| Case.dump_indent(s) }
3234
- (r.last[-1] == ?{ ? r.last : r) << '}'
3381
+ (r.last[-1] == ?{ ? r.last : r) << CRenderString.new('}')
3235
3382
  else
3236
- tr, dep = e.dump(scope, [''], dep)
3383
+ tr, dep = e.dump(scope, [CRenderString.new], dep)
3237
3384
  r.concat tr.map { |s| Case.dump_indent(s) }
3238
3385
  end
3239
3386
  [r, dep]
@@ -3248,7 +3395,7 @@ EOH
3248
3395
  def to_s() dump(nil)[0].join("\n") end
3249
3396
 
3250
3397
  # return array of c source lines and array of dependencies (objects)
3251
- def dump(scp, r=[''], dep=[])
3398
+ def dump(scp, r=[CRenderString.new], dep=[])
3252
3399
  mydefs = @symbol.values.grep(TypeDef) + @struct.values + anonymous_enums.to_a
3253
3400
  todo_rndr = {}
3254
3401
  todo_deps = {}
@@ -3260,7 +3407,7 @@ EOH
3260
3407
  [r, dep]
3261
3408
  end
3262
3409
 
3263
- def dump_reorder(mydefs, todo_rndr, todo_deps, r=[''], dep=[])
3410
+ def dump_reorder(mydefs, todo_rndr, todo_deps, r=[CRenderString.new], dep=[])
3264
3411
  val = todo_deps.values.flatten.uniq
3265
3412
  dep |= val
3266
3413
  dep -= mydefs | todo_deps.keys
@@ -3275,6 +3422,7 @@ EOH
3275
3422
  # predeclare structs involved in cyclic dependencies
3276
3423
  dep_cycle = lambda { |ary|
3277
3424
  # sexyness inside (c)
3425
+ # XXX 5 years later, i have no idea whats going on here
3278
3426
  deps = todo_deps[ary.last]
3279
3427
  if deps.include? ary.first; ary
3280
3428
  elsif (deps-ary).find { |d| deps = dep_cycle[ary + [d]] }; deps
@@ -3284,7 +3432,7 @@ EOH
3284
3432
  oldc = nil
3285
3433
  while c = dep_cycle[[t]]
3286
3434
  break if oldc == c
3287
- r << "#{t.kind_of?(Struct) ? 'struct' : 'union'} #{t.name};" if not oldc
3435
+ r << CRenderString.new(t, "#{t.kind_of?(Struct) ? 'struct' : 'union'} #{t.name};") if not oldc
3288
3436
  oldc = c
3289
3437
  c.each { |s|
3290
3438
  # XXX struct z { struct a* }; struct a { void (*foo)(struct z); };
@@ -3303,7 +3451,7 @@ EOH
3303
3451
  end
3304
3452
  todo_now.sort_by { |k| k.name || '0' }.each { |k|
3305
3453
  if k.kind_of? Variable and k.type.kind_of? Function and k.initializer
3306
- r << ''
3454
+ r << CRenderString.new
3307
3455
  r.concat todo_rndr.delete(k)
3308
3456
  else
3309
3457
  r.pop if r.last == ''
@@ -3313,12 +3461,12 @@ EOH
3313
3461
  todo_deps.delete k
3314
3462
  }
3315
3463
  todo_deps.each_key { |k| todo_deps[k] -= todo_now }
3316
- r << '' << '' << ''
3464
+ r << CRenderString.new << CRenderString.new << CRenderString.new
3317
3465
  end
3318
3466
 
3319
3467
  @statements.each { |s|
3320
- r << '' if not r.last.empty?
3321
- if s.kind_of? Block
3468
+ r << CRenderString.new if not r.last.empty?
3469
+ if s.kind_of?(Block)
3322
3470
  r, dep = Statement.dump(s, self, r, dep)
3323
3471
  else
3324
3472
  r, dep = s.dump(self, r, dep)
@@ -3329,10 +3477,10 @@ EOH
3329
3477
  end
3330
3478
  end
3331
3479
  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 << ''
3480
+ def dump(scope, r=[CRenderString.new], dep=[])
3481
+ tr, dep = @var.dump_def(scope, [CRenderString.new], dep)
3482
+ if @var.kind_of?(Variable) and @var.type.kind_of?(Function) and @var.initializer
3483
+ r << CRenderString.new
3336
3484
  r.concat tr
3337
3485
  else
3338
3486
  r.pop if r.last == ''
@@ -3361,14 +3509,14 @@ EOH
3361
3509
  end
3362
3510
  end
3363
3511
  class Variable
3364
- def dump(scope, r=[''], dep=[])
3512
+ def dump(scope, r=[CRenderString.new], dep=[])
3365
3513
  if name
3366
3514
  dep |= [scope.symbol_ancestors[@name]]
3367
3515
  r.last << @name
3368
3516
  end
3369
3517
  [r, dep]
3370
3518
  end
3371
- def dump_def(scope, r=[''], dep=[], skiptype=false)
3519
+ def dump_def(scope, r=[CRenderString.new], dep=[], skiptype=false)
3372
3520
  # int a=1, b=2;
3373
3521
  r.last << dump_attributes_pre
3374
3522
  if not skiptype
@@ -3376,7 +3524,7 @@ EOH
3376
3524
  r, dep = @type.base.dump(scope, r, dep)
3377
3525
  r.last << ' ' if name
3378
3526
  end
3379
- r, dep = @type.dump_declarator([(name ? @name.dup : '') << dump_attributes], scope, r, dep)
3527
+ r, dep = @type.dump_declarator([CRenderString.new(name ? @name.dup : '') << dump_attributes], scope, r, dep)
3380
3528
 
3381
3529
  if initializer
3382
3530
  r.last << ' = ' if not @type.kind_of?(Function)
@@ -3390,7 +3538,7 @@ EOH
3390
3538
  end
3391
3539
  end
3392
3540
  class Type
3393
- def dump_initializer(init, scope, r=[''], dep=[])
3541
+ def dump_initializer(init, scope, r=[CRenderString.new], dep=[])
3394
3542
  case init
3395
3543
  when ::Numeric
3396
3544
  r.last << init.to_s
@@ -3402,9 +3550,9 @@ EOH
3402
3550
  end
3403
3551
  end
3404
3552
 
3405
- def dump_declarator(decl, scope, r=[''], dep=[])
3553
+ def dump_declarator(decl, scope, r=[CRenderString.new], dep=[])
3406
3554
  r.last << decl.shift
3407
- r.concat decl
3555
+ r.concat decl.map { |d| CRenderString.new << d }
3408
3556
  [r, dep]
3409
3557
  end
3410
3558
 
@@ -3412,11 +3560,11 @@ EOH
3412
3560
  dump(*a)
3413
3561
  end
3414
3562
 
3415
- def dump_cast(scope, r=[''], dep=[])
3563
+ def dump_cast(scope, r=[CRenderString.new], dep=[])
3416
3564
  r.last << '('
3417
3565
  r.last << dump_attributes_pre if not kind_of? TypeDef
3418
3566
  r, dep = base.dump(scope, r, dep)
3419
- r, dep = dump_declarator([kind_of?(TypeDef) ? '' : dump_attributes], scope, r, dep)
3567
+ r, dep = dump_declarator([CRenderString.new(kind_of?(TypeDef) ? '' : dump_attributes)], scope, r, dep)
3420
3568
  r.last << ')'
3421
3569
  [r, dep]
3422
3570
  end
@@ -3426,28 +3574,29 @@ EOH
3426
3574
  end
3427
3575
  end
3428
3576
  class Pointer
3429
- def dump_declarator(decl, scope, r=[''], dep=[])
3577
+ def dump_declarator(decl, scope, r=[CRenderString.new], dep=[])
3430
3578
  d = decl[0]
3431
- decl[0] = '*'
3579
+ decl[0] = CRenderString.new
3580
+ decl[0] << '*'
3432
3581
  decl[0] << ' ' << @qualifier.map { |q| q.to_s }.join(' ') << ' ' if qualifier
3433
3582
  decl[0] << d
3434
- if @type.kind_of? Function or @type.kind_of? Array
3435
- decl[0] = '(' << decl[0]
3583
+ if @type.kind_of?(Function) or @type.kind_of?(Array)
3584
+ decl[0] = CRenderString.new << '(' << decl[0]
3436
3585
  decl.last << ')'
3437
3586
  end
3438
3587
  @type.dump_declarator(decl, scope, r, dep)
3439
3588
  end
3440
3589
  end
3441
3590
  class Array
3442
- def dump_declarator(decl, scope, r=[''], dep=[])
3591
+ def dump_declarator(decl, scope, r=[CRenderString.new], dep=[])
3443
3592
  decl.last << '()' if decl.last.empty?
3444
3593
  decl.last << '['
3445
3594
  decl, dep = CExpression.dump(@length, scope, decl, dep) if length
3446
3595
  decl.last << ']'
3447
3596
  @type.dump_declarator(decl, scope, r, dep)
3448
3597
  end
3449
- def dump_initializer(init, scope, r=[''], dep=[])
3450
- return super(init, scope, r, dep) if not init.kind_of? ::Array
3598
+ def dump_initializer(init, scope, r=[CRenderString.new], dep=[])
3599
+ return super(init, scope, r, dep) if not init.kind_of?(::Array)
3451
3600
  r.last << '{ '
3452
3601
  showname = false
3453
3602
  init.each_with_index { |v, i|
@@ -3456,21 +3605,21 @@ EOH
3456
3605
  next
3457
3606
  end
3458
3607
  r.last << ', ' if r.last[-2, 2] != '{ '
3459
- rt = ['']
3608
+ rt = [CRenderString.new]
3460
3609
  if showname
3461
3610
  showname = false
3462
- rt << "[#{i}] = "
3611
+ rt << CRenderString.new("[#{i}] = ")
3463
3612
  end
3464
3613
  rt, dep = @type.dump_initializer(v, scope, rt, dep)
3465
3614
  r.last << rt.shift
3466
- r.concat rt.map { |s| "\t" << s }
3615
+ r.concat rt.map { |s| CRenderString.new << "\t" << s }
3467
3616
  }
3468
3617
  r.last << ' }'
3469
3618
  [r, dep]
3470
3619
  end
3471
3620
  end
3472
3621
  class Function
3473
- def dump_declarator(decl, scope, r=[''], dep=[])
3622
+ def dump_declarator(decl, scope, r=[CRenderString.new], dep=[])
3474
3623
  decl.last << '()' if decl.last.empty?
3475
3624
  decl.last << '('
3476
3625
  if args
@@ -3489,12 +3638,12 @@ EOH
3489
3638
  @type.dump_declarator(decl, scope, r, dep)
3490
3639
  end
3491
3640
 
3492
- def dump_initializer(init, scope, r=[''], dep=[])
3493
- Statement.dump(init, scope, r << '', dep)
3641
+ def dump_initializer(init, scope, r=[CRenderString.new], dep=[])
3642
+ Statement.dump(init, scope, r << CRenderString.new, dep)
3494
3643
  end
3495
3644
  end
3496
3645
  class BaseType
3497
- def dump(scope, r=[''], dep=[])
3646
+ def dump(scope, r=[CRenderString.new], dep=[])
3498
3647
  r.last << @qualifier.map { |q| q.to_s << ' ' }.join if qualifier
3499
3648
  r.last << @specifier.to_s << ' ' if specifier and @name != :ptr
3500
3649
  r.last << case @name
@@ -3507,27 +3656,27 @@ EOH
3507
3656
  end
3508
3657
  end
3509
3658
  class TypeDef
3510
- def dump(scope, r=[''], dep=[])
3659
+ def dump(scope, r=[CRenderString.new], dep=[])
3511
3660
  r.last << @qualifier.map { |q| q.to_s << ' ' }.join if qualifier
3512
3661
  r.last << @name
3513
3662
  dep |= [scope.symbol_ancestors[@name]]
3514
3663
  [r, dep]
3515
3664
  end
3516
3665
 
3517
- def dump_def(scope, r=[''], dep=[])
3666
+ def dump_def(scope, r=[CRenderString.new], dep=[])
3518
3667
  r.last << 'typedef '
3519
3668
  r.last << dump_attributes_pre
3520
3669
  r, dep = @type.base.dump(scope, r, dep)
3521
3670
  r.last << ' '
3522
- @type.dump_declarator([(name ? @name.dup : '') << dump_attributes], scope, r, dep)
3671
+ @type.dump_declarator([CRenderString.new(name ? @name.dup : '') << dump_attributes], scope, r, dep)
3523
3672
  end
3524
3673
 
3525
- def dump_initializer(init, scope, r=[''], dep=[])
3674
+ def dump_initializer(init, scope, r=[CRenderString.new], dep=[])
3526
3675
  @type.dump_initializer(init, scope, r, dep)
3527
3676
  end
3528
3677
  end
3529
3678
  class Union
3530
- def dump(scope, r=[''], dep=[])
3679
+ def dump(scope, r=[CRenderString.new], dep=[])
3531
3680
  if name
3532
3681
  r.last << @qualifier.map { |q| q.to_s << ' ' }.join if qualifier
3533
3682
  r.last << self.class.name.downcase[/(?:.*::)?(.*)/, 1] << ' ' << @name
@@ -3538,26 +3687,26 @@ EOH
3538
3687
  end
3539
3688
  end
3540
3689
 
3541
- def dump_def(scope, r=[''], dep=[])
3542
- r << ''
3690
+ def dump_def(scope, r=[CRenderString.new], dep=[])
3691
+ r << CRenderString.new
3543
3692
  r.last << @qualifier.map { |q| q.to_s << ' ' }.join if qualifier
3544
3693
  r.last << self.class.name.downcase[/(?:.*::)?(.*)/, 1]
3545
3694
  r.last << ' ' << @name if name
3546
3695
  if members
3547
3696
  r.last << ' {'
3548
3697
  @members.each_with_index { |m,i|
3549
- tr, dep = m.dump_def(scope, [''], dep)
3698
+ tr, dep = m.dump_def(scope, [CRenderString.new], dep)
3550
3699
  tr.last << ':' << @bits[i].to_s if bits and @bits[i]
3551
3700
  tr.last << ';'
3552
- r.concat tr.map { |s| "\t" << s }
3701
+ r.concat tr.map { |s| CRenderString.new << "\t" << s }
3553
3702
  }
3554
- r << '}'
3703
+ r << CRenderString.new('}')
3555
3704
  end
3556
3705
  r.last << dump_attributes
3557
3706
  [r, dep]
3558
3707
  end
3559
3708
 
3560
- def dump_initializer(init, scope, r=[''], dep=[])
3709
+ def dump_initializer(init, scope, r=[CRenderString.new], dep=[])
3561
3710
  return super(init, scope, r, dep) if not init.kind_of? ::Array
3562
3711
  r.last << '{ '
3563
3712
  showname = false
@@ -3567,21 +3716,21 @@ EOH
3567
3716
  next
3568
3717
  end
3569
3718
  r.last << ', ' if r.last[-2, 2] != '{ '
3570
- rt = ['']
3719
+ rt = [CRenderString.new]
3571
3720
  if showname
3572
3721
  showname = false
3573
3722
  rt << ".#{m.name} = "
3574
3723
  end
3575
3724
  rt, dep = m.type.dump_initializer(i, scope, rt, dep)
3576
3725
  r.last << rt.shift
3577
- r.concat rt.map { |s| "\t" << s }
3726
+ r.concat rt.map { |s| CRenderString.new << "\t" << s }
3578
3727
  }
3579
3728
  r.last << ' }'
3580
3729
  [r, dep]
3581
3730
  end
3582
3731
  end
3583
3732
  class Struct
3584
- def dump_def(scope, r=[''], dep=[])
3733
+ def dump_def(scope, r=[CRenderString.new], dep=[])
3585
3734
  if pack
3586
3735
  r, dep = super(scope, r, dep)
3587
3736
  r.last <<
@@ -3595,7 +3744,7 @@ EOH
3595
3744
  end
3596
3745
  end
3597
3746
  class Enum
3598
- def dump(scope, r=[''], dep=[])
3747
+ def dump(scope, r=[CRenderString.new], dep=[])
3599
3748
  if name
3600
3749
  r.last << @qualifier.map { |q| q.to_s << ' ' }.join if qualifier
3601
3750
  r.last << 'enum ' << @name
@@ -3606,7 +3755,7 @@ EOH
3606
3755
  end
3607
3756
  end
3608
3757
 
3609
- def dump_def(scope, r=[''], dep=[])
3758
+ def dump_def(scope, r=[CRenderString.new], dep=[])
3610
3759
  r.last << @qualifier.map { |q| q.to_s << ' ' }.join if qualifier
3611
3760
  r.last << 'enum'
3612
3761
  r.last << ' ' << @name if name
@@ -3626,7 +3775,7 @@ EOH
3626
3775
  [r, dep]
3627
3776
  end
3628
3777
 
3629
- def dump_initializer(init, scope, r=[''], dep=[])
3778
+ def dump_initializer(init, scope, r=[CRenderString.new], dep=[])
3630
3779
  if members and (
3631
3780
  k = @members.index(init) or
3632
3781
  (init.kind_of? CExpression and not init.op and k = @members.index(init.rexpr))
@@ -3639,14 +3788,14 @@ EOH
3639
3788
  end
3640
3789
  end
3641
3790
  class If
3642
- def dump(scope, r=[''], dep=[])
3643
- r.last << 'if ('
3791
+ def dump(scope, r=[CRenderString.new], dep=[])
3792
+ r.last << CRenderString.new(self, 'if (')
3644
3793
  r, dep = CExpression.dump(@test, scope, r, dep)
3645
3794
  r.last << ')'
3646
3795
  r, dep = Statement.dump(@bthen, scope, r, dep)
3647
3796
  if belse
3648
- @bthen.kind_of?(Block) ? (r.last << ' else') : (r << 'else')
3649
- if @belse.kind_of? If
3797
+ @bthen.kind_of?(Block) ? (r.last << CRenderString.new(' else')) : (r << CRenderString.new(self, 'else'))
3798
+ if @belse.kind_of?(If)
3650
3799
  # skip indent
3651
3800
  r.last << ' '
3652
3801
  r, dep = @belse.dump(scope, r, dep)
@@ -3658,9 +3807,9 @@ EOH
3658
3807
  end
3659
3808
  end
3660
3809
  class For
3661
- def dump(scope, r=[''], dep=[])
3662
- r.last << 'for ('
3663
- if @init.kind_of? Block
3810
+ def dump(scope, r=[CRenderString.new], dep=[])
3811
+ r.last << CRenderString.new(self, 'for (')
3812
+ if @init.kind_of?(Block)
3664
3813
  scope = @init
3665
3814
  skiptype = false
3666
3815
  @init.symbol.each_value { |s|
@@ -3684,56 +3833,57 @@ EOH
3684
3833
  end
3685
3834
  end
3686
3835
  class While
3687
- def dump(scope, r=[''], dep=[])
3688
- r.last << 'while ('
3836
+ def dump(scope, r=[CRenderString.new], dep=[])
3837
+ r.last << CRenderString.new(self, 'while (')
3689
3838
  r, dep = CExpression.dump(@test, scope, r, dep)
3690
3839
  r.last << ')'
3691
3840
  Statement.dump(@body, scope, r, dep)
3692
3841
  end
3693
3842
  end
3694
3843
  class DoWhile
3695
- def dump(scope, r=[''], dep=[])
3696
- r.last << 'do'
3844
+ def dump(scope, r=[CRenderString.new], dep=[])
3845
+ r.last << CRenderString.new(self, 'do')
3697
3846
  r, dep = Statement.dump(@body, scope, r, dep)
3698
- @body.kind_of?(Block) ? (r.last << ' while (') : (r << 'while (')
3847
+ r << CRenderString.new if not @body.kind_of?(Block)
3848
+ r.last << CRenderString.new(self, ' while (')
3699
3849
  r, dep = CExpression.dump(@test, scope, r, dep)
3700
3850
  r.last << ');'
3701
3851
  [r, dep]
3702
3852
  end
3703
3853
  end
3704
3854
  class Switch
3705
- def dump(scope, r=[''], dep=[])
3706
- r.last << 'switch ('
3855
+ def dump(scope, r=[CRenderString.new], dep=[])
3856
+ r.last << CRenderString.new(self, 'switch (')
3707
3857
  r, dep = CExpression.dump(@test, scope, r, dep)
3708
3858
  r.last << ')'
3709
- r.last << ' {' if @body.kind_of? Block
3710
- tr, dep = @body.dump(scope, [''], dep)
3859
+ r.last << ' {' if @body.kind_of?(Block)
3860
+ tr, dep = @body.dump(scope, [CRenderString.new], dep)
3711
3861
  r.concat tr.map { |s| Case.dump_indent(s, true) }
3712
- r << '}' if @body.kind_of? Block
3862
+ r << CRenderString.new('}') if @body.kind_of? Block
3713
3863
  [r, dep]
3714
3864
  end
3715
3865
  end
3716
3866
  class Continue
3717
- def dump(scope, r=[''], dep=[])
3718
- r.last << 'continue;'
3867
+ def dump(scope, r=[CRenderString.new], dep=[])
3868
+ r.last << CRenderString.new(self, 'continue;')
3719
3869
  [r, dep]
3720
3870
  end
3721
3871
  end
3722
3872
  class Break
3723
- def dump(scope, r=[''], dep=[])
3724
- r.last << 'break;'
3873
+ def dump(scope, r=[CRenderString.new], dep=[])
3874
+ r.last << CRenderString.new(self, 'break;')
3725
3875
  [r, dep]
3726
3876
  end
3727
3877
  end
3728
3878
  class Goto
3729
- def dump(scope, r=[''], dep=[])
3730
- r.last << "goto #@target;"
3879
+ def dump(scope, r=[CRenderString.new], dep=[])
3880
+ r.last << CRenderString.new(self, "goto #@target;")
3731
3881
  [r, dep]
3732
3882
  end
3733
3883
  end
3734
3884
  class Return
3735
- def dump(scope, r=[''], dep=[])
3736
- r.last << 'return '
3885
+ def dump(scope, r=[CRenderString.new], dep=[])
3886
+ r.last << CRenderString.new(self, 'return ')
3737
3887
  r, dep = CExpression.dump(@value, scope, r, dep)
3738
3888
  r.last.chop! if r.last[-1] == ?\ # the space character
3739
3889
  r.last << ';'
@@ -3741,12 +3891,12 @@ EOH
3741
3891
  end
3742
3892
  end
3743
3893
  class Case
3744
- def dump(scope, r=[''], dep=[])
3894
+ def dump(scope, r=[CRenderString.new], dep=[])
3745
3895
  case @expr
3746
3896
  when 'default'
3747
3897
  r.last << @expr
3748
3898
  else
3749
- r.last << 'case '
3899
+ r.last << CRenderString.new(self, 'case ')
3750
3900
  r, dep = CExpression.dump(@expr, scope, r, dep)
3751
3901
  if exprup
3752
3902
  r.last << ' ... '
@@ -3759,35 +3909,35 @@ EOH
3759
3909
 
3760
3910
  def self.dump_indent(s, short=false)
3761
3911
  case s
3762
- when /^(case|default)\W/; (short ? ' ' : "\t") << s
3763
- when /^\s+(case|default)\W/; "\t" << s
3912
+ when /^(case|default)\W/; CRenderString.new(short ? ' ' : "\t") << s
3913
+ when /^\s+(case|default)\W/; CRenderString.new("\t") << s
3764
3914
  when /:$/; s
3765
- else "\t" << s
3915
+ else CRenderString.new("\t") << s
3766
3916
  end
3767
3917
  end
3768
3918
  end
3769
3919
  class Label
3770
- def dump(scope, r=[''], dep=[])
3771
- r.last << @name << ':'
3920
+ def dump(scope, r=[CRenderString.new], dep=[])
3921
+ r.last << CRenderString.new(self, @name) << ':'
3772
3922
  dump_inner(scope, r, dep)
3773
3923
  end
3774
- def dump_inner(scope, r=[''], dep=[])
3924
+ def dump_inner(scope, r=[CRenderString.new], dep=[])
3775
3925
  if not @statement; [r, dep]
3776
- elsif @statement.kind_of? Block; Statement.dump(@statement, scope, r, dep)
3777
- else @statement.dump(scope, r << '', dep)
3926
+ elsif @statement.kind_of?(Block); Statement.dump(@statement, scope, r, dep)
3927
+ else @statement.dump(scope, r << CRenderString.new, dep)
3778
3928
  end
3779
3929
  end
3780
3930
  end
3781
3931
  class Asm
3782
- def dump(scope, r=[''], dep=[])
3783
- r.last << 'asm '
3932
+ def dump(scope, r=[CRenderString.new], dep=[])
3933
+ r.last << CRenderString.new(self, 'asm ')
3784
3934
  r.last << 'volatile ' if @volatile
3785
3935
  r.last << '('
3786
- r.last << @body.inspect
3936
+ r.last << CRenderString.new(self, CExpression.string_inspect(@body))
3787
3937
  if @output or @input or @clobber
3788
3938
  if @output and @output != []
3789
3939
  # TODO
3790
- r << ': /* todo */'
3940
+ r << CRenderString.new(': /* todo */')
3791
3941
  elsif (@input and @input != []) or (@clobber and @clobber != [])
3792
3942
  r.last << ' :'
3793
3943
  end
@@ -3795,51 +3945,60 @@ EOH
3795
3945
  if @input or @clobber
3796
3946
  if @input and @input != []
3797
3947
  # TODO
3798
- r << ': /* todo */'
3948
+ r << CRenderString.new(': /* todo */')
3799
3949
  elsif @clobber and @clobber != []
3800
3950
  r.last << ' :'
3801
3951
  end
3802
3952
  end
3803
3953
  if @clobber and @clobber != []
3804
- r << (': ' << @clobber.map { |c| c.inspect }.join(', '))
3954
+ r << (CRenderString.new(': ') << @clobber.map { |c| CExpression.string_inspect(c) }.join(', '))
3805
3955
  end
3806
3956
  r.last << ');'
3807
3957
  [r, dep]
3808
3958
  end
3809
3959
  end
3810
3960
  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)
3961
+ def self.string_inspect(s)
3962
+ # keep all ascii printable except \ and "
3963
+ '"' + s.gsub(/[^ !\x23-\x5b\x5d-\x7e]/) { |o|
3964
+ case hex = o.unpack('H*').first.downcase
3965
+ when '00'; '\\0'
3966
+ when '0a'; '\\n'
3967
+ when '0d'; '\\r'
3968
+ when '1b'; '\\e'
3969
+ when '22'; '\\"'
3970
+ when '5c'; '\\\\'
3971
+ else "\\x#{hex}"
3817
3972
  end
3818
- r.last << '('
3819
- end
3973
+ } + '"'
3974
+ end
3975
+
3976
+ def self.dump(e, scope, r=[CRenderString.new], dep=[], brace = false)
3820
3977
  r, dep = \
3821
3978
  case e
3822
3979
  when ::Numeric; r.last << e.to_s ; [r, dep]
3823
- when ::String; r.last << e.inspect ; [r, dep]
3980
+ when ::String; r.last << string_inspect(e) ; [r, dep]
3824
3981
  when CExpression; e.dump_inner(scope, r, dep, brace)
3825
3982
  when Variable; e.dump(scope, r, dep)
3826
3983
  when nil; [r, dep]
3827
3984
  else raise 'wtf?' + e.inspect
3828
3985
  end
3829
- if $DEBUG
3830
- r.last << ')'
3831
- end
3832
3986
  [r, dep]
3833
3987
  end
3834
3988
 
3835
- def dump(scope, r=[''], dep=[])
3989
+ def dump(scope, r=[CRenderString.new], dep=[])
3836
3990
  r, dep = dump_inner(scope, r, dep)
3837
- r.last << ';'
3991
+ r.last << CRenderString.new(self, ';')
3838
3992
  [r, dep]
3839
3993
  end
3840
3994
 
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)
3995
+ def dump_inner(scope, r=[CRenderString.new], dep=[], brace = false)
3996
+ r.last << CRenderString.new(self)
3997
+ if misc and misc[:custom_display]
3998
+ r.last << misc[:custom_display]
3999
+ return [r, dep]
4000
+ end
4001
+ r.last << '(' if brace and @op != :'->' and @op != :'.' and @op != :'[]' and (@op or @rexpr.kind_of?(CExpression))
3843
4002
  if not @lexpr
3844
4003
  if not @op
3845
4004
  case @rexpr
@@ -3855,7 +4014,7 @@ EOH
3855
4014
  else
3856
4015
  r.last << re.to_s
3857
4016
  end
3858
- if @type.kind_of? BaseType
4017
+ if @type.kind_of?(BaseType)
3859
4018
  r.last << 'U' if @type.specifier == :unsigned
3860
4019
  case @type.name
3861
4020
  when :longlong, :__int64; r.last << 'LL'
@@ -3864,8 +4023,8 @@ EOH
3864
4023
  end
3865
4024
  end
3866
4025
  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
4026
+ r.last << 'L' if @type.kind_of?(Pointer) and @type.type.kind_of?(BaseType) and @type.type.name == :short
4027
+ r.last << CExpression.string_inspect(@rexpr)
3869
4028
  when CExpression # cast
3870
4029
  r, dep = @type.dump_cast(scope, r, dep)
3871
4030
  r, dep = CExpression.dump(@rexpr, scope, r, dep, true)
@@ -3877,11 +4036,11 @@ EOH
3877
4036
  r.last << ' )'
3878
4037
  when Label
3879
4038
  r.last << '&&' << @rexpr.name
3880
- else raise "wtf? #{inspect}"
4039
+ else raise "(wtf? #{inspect})"
3881
4040
  end
3882
4041
  else
3883
4042
  r.last << @op.to_s
3884
- r, dep = CExpression.dump(@rexpr, scope, r, dep, (@rexpr.kind_of? C::CExpression and @rexpr.lexpr))
4043
+ r, dep = CExpression.dump(@rexpr, scope, r, dep, (@rexpr.kind_of?(C::CExpression) and @rexpr.lexpr))
3885
4044
  end
3886
4045
  elsif not @rexpr
3887
4046
  r, dep = CExpression.dump(@lexpr, scope, r, dep)
@@ -3890,16 +4049,16 @@ EOH
3890
4049
  case @op
3891
4050
  when :'->', :'.'
3892
4051
  r, dep = CExpression.dump(@lexpr, scope, r, dep, true)
3893
- r.last << @op.to_s << @rexpr
4052
+ r.last << CRenderString.new(self, @op.to_s) << @rexpr
3894
4053
  when :'[]'
3895
4054
  r, dep = CExpression.dump(@lexpr, scope, r, dep, true)
3896
4055
  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 == :'->'
4056
+ l = lexpr if lexpr.kind_of?(Variable)
4057
+ l = lexpr.lexpr.type.untypedef.findmember(lexpr.rexpr) if lexpr.kind_of?(CExpression) and lexpr.op == :'.'
4058
+ l = lexpr.lexpr.type.pointed.untypedef.findmember(lexpr.rexpr) if lexpr.kind_of?(CExpression) and lexpr.op == :'->'
3900
4059
  # 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)
4060
+ if l and l.attributes and rexpr.kind_of?(CExpression) and not rexpr.op and rexpr.rexpr.kind_of?(::Integer) and
4061
+ n = l.has_attribute_var('indexenum') and enum = scope.struct_ancestors[n] and i = enum.members.index(rexpr.rexpr)
3903
4062
  r.last << i
3904
4063
  dep |= [enum]
3905
4064
  else
@@ -3911,22 +4070,22 @@ EOH
3911
4070
  r.last << '('
3912
4071
  @rexpr.each { |arg|
3913
4072
  r.last << ', ' if r.last[-1] != ?(
3914
- r, dep = CExpression.dump(arg, scope, r, dep)
4073
+ r, dep = CExpression.dump(arg, scope, r, dep, (arg.kind_of?(CExpression) and arg.op == :','))
3915
4074
  }
3916
4075
  r.last << ')'
3917
4076
  when :'?:'
3918
4077
  r, dep = CExpression.dump(@lexpr, scope, r, dep, true)
3919
- r.last << ' ? '
4078
+ r.last << CRenderString.new(self, ' ? ')
3920
4079
  r, dep = CExpression.dump(@rexpr[0], scope, r, dep, true)
3921
- r.last << ' : '
4080
+ r.last << CRenderString.new(self, ' : ')
3922
4081
  r, dep = CExpression.dump(@rexpr[1], scope, r, dep, true)
3923
4082
  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))
4083
+ r, dep = CExpression.dump(@lexpr, scope, r, dep, (@lexpr.kind_of?(CExpression) and @lexpr.lexpr and @lexpr.op != @op and @lexpr.op != :funcall))
4084
+ r.last << CRenderString.new(self, ' ' << @op.to_s << ' ')
4085
+ r, dep = CExpression.dump(@rexpr, scope, r, dep, (@rexpr.kind_of?(CExpression) and @rexpr.lexpr and @rexpr.op != @op and @rexpr.op != :funcall and @op != :'='))
3927
4086
  end
3928
4087
  end
3929
- r.last << ')' if brace and @op != :'->' and @op != :'.' and @op != :'[]' and (@op or @rexpr.kind_of? CExpression)
4088
+ r.last << ')' if brace and @op != :'->' and @op != :'.' and @op != :'[]' and (@op or @rexpr.kind_of?(CExpression))
3930
4089
  [r, dep]
3931
4090
  end
3932
4091