PageRenderTime 61ms CodeModel.GetById 13ms RepoModel.GetById 0ms app.codeStats 1ms

/lib/metasm/metasm/parse_c.rb

https://github.com/Jonono2/metasploit-framework
Ruby | 4043 lines | 3600 code | 229 blank | 214 comment | 1162 complexity | c00ccb6d0a1677da4a9e23c86e7331a8 MD5 | raw file
Possible License(s): BSD-3-Clause, Apache-2.0, GPL-3.0, LGPL-2.1, GPL-2.0

Large files files are truncated, but you can click here to view the full file

  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. require 'metasm/main'
  6. require 'metasm/preprocessor'
  7. module Metasm
  8. # c parser
  9. # inspired from http://www.math.grin.edu/~stone/courses/languages/C-syntax.xhtml
  10. module C
  11. Keyword = %w[struct union enum if else for while do switch goto
  12. register extern auto static typedef const volatile
  13. void int float double char signed unsigned long short
  14. case continue break return default __attribute__
  15. asm __asm __asm__ sizeof typeof
  16. __declspec __cdecl __stdcall __fastcall __noreturn
  17. inline __inline __inline__ __volatile__
  18. __int8 __int16 __int32 __int64
  19. __builtin_offsetof
  20. ].inject({}) { |h, w| h.update w => true }
  21. class Statement
  22. end
  23. module Typed # allows quick testing whether an object is an CExpr or a Variable
  24. end
  25. class Block < Statement
  26. attr_accessor :symbol # hash name => Type/Variable/enum value
  27. attr_accessor :struct # hash name => Struct/Union/Enum
  28. attr_accessor :outer # parent block
  29. attr_accessor :statements # array of Statement/Declaration
  30. attr_accessor :anonymous_enums # array of anonymous Enum
  31. def initialize(outer, statements=[], symbol={}, struct={})
  32. @outer = outer
  33. @statements = statements
  34. @symbol = symbol
  35. @struct = struct
  36. end
  37. def struct_ancestors
  38. @outer ? @outer.struct_ancestors.merge(@struct) : @struct
  39. end
  40. def symbol_ancestors
  41. @outer ? @outer.symbol_ancestors.merge(@symbol) : @symbol
  42. end
  43. end
  44. module Attributes
  45. attr_accessor :attributes
  46. DECLSPECS = %w[cdecl stdcall fastcall inline naked thiscall noreturn]
  47. # parses a sequence of __attribute__((anything)) into self.attributes (array of string)
  48. def parse_attributes(parser, allow_declspec = false)
  49. while tok = parser.skipspaces and tok.type == :string
  50. case keyword = tok.raw
  51. when '__attribute__', '__declspec' # synonymous: __attribute__((foo)) == __declspec(foo)
  52. raise tok || parser if not tok = parser.skipspaces or tok.type != :punct or tok.raw != '('
  53. raise tok || parser if keyword == '__attribute__' and (not tok = parser.skipspaces or tok.type != :punct or tok.raw != '(')
  54. nest = 0
  55. attrib = ''
  56. loop do
  57. raise parser if not tok = parser.skipspaces
  58. if tok.type == :punct and tok.raw == ')'
  59. if nest == 0
  60. raise tok || parser if keyword == '__attribute__' and (not tok = parser.skipspaces or tok.type != :punct or tok.raw != ')')
  61. break
  62. else
  63. nest -= 1
  64. end
  65. elsif tok.type == :punct and tok.raw == '('
  66. nest += 1
  67. elsif nest == 0 and tok.type == :punct and tok.raw == ','
  68. raise tok || parser if not allow_declspec and DECLSPECS.include? attrib
  69. add_attribute attrib
  70. attrib = ''
  71. next
  72. end
  73. attrib << tok.raw
  74. end
  75. raise tok || parser, "attr #{attrib.inspect} not allowed here" if not allow_declspec and DECLSPECS.include? attrib
  76. else
  77. if allow_declspec and DECLSPECS.include? keyword.gsub('_', '')
  78. attrib = keyword.gsub('_', '')
  79. else break
  80. end
  81. end
  82. add_attribute(attrib)
  83. end
  84. parser.unreadtok tok
  85. end
  86. # checks if the object has an attribute in its attribute list
  87. def has_attribute(attr)
  88. attributes.to_a.include? attr
  89. end
  90. # adds an attribute to the object attribute list if it is not already in it
  91. def add_attribute(attr)
  92. (@attributes ||= []) << attr if not has_attribute(attr)
  93. end
  94. # checks if the object has an attributes a la __attribute__((attr(stuff))), returns 'stuff' (raw, no split on ',' or anything)
  95. def has_attribute_var(attr)
  96. $1 if attributes.to_a.find { |a| a =~ /^#{attr}\((.*)\)$/ }
  97. end
  98. end
  99. class Type
  100. include Attributes
  101. attr_accessor :qualifier # const volatile
  102. def pointer? ; false end
  103. def arithmetic? ; false end
  104. def integral? ; false end
  105. def float? ; false end
  106. def void? ; false end
  107. def base ; self end
  108. def untypedef ; self end
  109. def parse_initializer(parser, scope)
  110. raise parser, 'expr expected' if not ret = CExpression.parse(parser, scope, false)
  111. p, i = pointer?, integral?
  112. r = ret.reduce(parser) if p or i
  113. if (not p and not i) or (i and not r.kind_of? ::Integer) or (p and r != 0)
  114. parser.check_compatible_type(parser, ret.type, self)
  115. end
  116. ret
  117. end
  118. def parse_initializer_designator(parser, scope, value, idx, root=true)
  119. if not root and (not nt = parser.skipspaces or nt.type != :punct or nt.raw != '=')
  120. raise nt || parser, '"=" expected'
  121. end
  122. value[idx] = parse_initializer(parser, scope)
  123. idx + 1
  124. end
  125. end
  126. class BaseType < Type
  127. attr_accessor :name # :int :long :longlong :short :double :longdouble :float :char :void :__int8/16/32/64
  128. attr_accessor :specifier # sign specifier only
  129. def arithmetic? ; @name != :void end
  130. def integral? ; [:char, :short, :int, :long, :longlong, :ptr,
  131. :__int8, :__int16, :__int32, :__int64].include? @name end
  132. def signed? ; specifier != :unsigned end
  133. def float? ; [:float, :double, :longdouble].include? @name end
  134. def void? ; @name == :void end
  135. def align(parser) @name == :double ? 4 : parser.typesize[@name] end
  136. def initialize(name, *specs)
  137. @name = name
  138. specs.each { |s|
  139. case s
  140. when :const, :volatile; (@qualifier ||= []) << s
  141. when :signed, :unsigned; @specifier = s
  142. when nil
  143. else raise "internal error, got #{name.inspect} #{specs.inspect}"
  144. end
  145. }
  146. end
  147. def ==(o)
  148. o.object_id == self.object_id or
  149. (o.class == self.class and o.name == self.name and o.specifier == self.specifier and o.attributes == self.attributes)
  150. end
  151. end
  152. class TypeDef < Type
  153. attr_accessor :name
  154. attr_accessor :type
  155. attr_accessor :backtrace
  156. def initialize(name, type, backtrace)
  157. @name, @type, @backtrace = name, type, backtrace
  158. end
  159. def parse_initializer(parser, scope)
  160. @type.parse_initializer(parser, scope)
  161. end
  162. def pointer? ; @type.pointer? end
  163. def arithmetic? ; @type.arithmetic? end
  164. def integral? ; @type.integral? end
  165. def signed? ; @type.signed? end # relevant only if integral? returns true
  166. def float? ; @type.float? end
  167. def void? ; @type.void? end
  168. def untypedef ; @type.untypedef end
  169. def align(parser) @type.align(parser) end # XXX __attribute__ ?
  170. def pointed ; @type.pointed end
  171. end
  172. class Function < Type
  173. attr_accessor :type # return type
  174. attr_accessor :args # [name, Variable]
  175. attr_accessor :varargs # true/false
  176. def initialize(type=nil, args=nil)
  177. @type = type
  178. @args = args if args
  179. end
  180. def base ; @type.base ; end
  181. end
  182. class Union < Type
  183. attr_accessor :members # [Variable]
  184. attr_accessor :bits # [bits] or nil
  185. attr_accessor :name
  186. attr_accessor :backtrace
  187. attr_accessor :fldoffset, :fldbitoffset, :fldlist
  188. def align(parser) @members.to_a.map { |m| m.type.align(parser) }.max end
  189. # there is only one instance of a given named struct per parser
  190. # so we just compare struct names here
  191. # for comparison between parsers, see #compare_deep
  192. def ==(o)
  193. o.object_id == self.object_id or
  194. (o.class == self.class and o.name == self.name and ((o.name and true) or compare_deep(o)))
  195. end
  196. # compare to another structure, comparing members recursively (names and type)
  197. # returns true if the self is same as o
  198. def compare_deep(o, seen = [])
  199. return true if o.object_id == self.object_id
  200. return if o.class != self.class or o.name != self.name or o.attributes != self.attributes
  201. o.members.to_a.zip(self.members.to_a).each { |om, sm|
  202. return if om.name != sm.name
  203. return if om.type != sm.type
  204. if om.type.pointer?
  205. ot = om.type
  206. st = sm.type
  207. 500.times { # limit for selfpointers (shouldnt happen)
  208. break if not ot.pointer?
  209. ot = ot.pointed.untypedef
  210. st = st.pointed.untypedef
  211. }
  212. if ot.kind_of?(C::Union) and ot.name and not seen.include?(ot)
  213. return if not st.compare_deep(ot, seen+[ot])
  214. end
  215. end
  216. }
  217. true
  218. end
  219. def findmember(name, igncase=false)
  220. raise 'undefined structure' if not members
  221. return @fldlist[name] if fldlist and @fldlist[name]
  222. name = name.downcase if igncase
  223. if m = @members.find { |m_| (n = m_.name) and (igncase ? n.downcase : n) == name }
  224. return m
  225. else
  226. @members.each { |m_|
  227. if t = m_.type.untypedef and t.kind_of? Union and mm = t.findmember(name, igncase)
  228. return mm
  229. end
  230. }
  231. end
  232. nil
  233. end
  234. def offsetof(parser, name)
  235. raise parser, 'undefined structure' if not members
  236. update_member_cache(parser) if not fldlist
  237. return 0 if @fldlist[name]
  238. if name.kind_of?(Variable)
  239. return 0 if @members.include? name
  240. raise ParseError, 'unknown union member'
  241. end
  242. raise parser, 'unknown union member' if not findmember(name)
  243. @members.find { |m|
  244. m.type.untypedef.kind_of? Union and m.type.untypedef.findmember(name)
  245. }.type.untypedef.offsetof(parser, name)
  246. end
  247. def bitoffsetof(parser, name)
  248. raise parser, 'undefined structure' if not members
  249. update_member_cache(parser) if not fldlist
  250. return if @fldlist[name] or @members.include?(name)
  251. raise parser, 'undefined union' if not @members
  252. raise parser, 'unknown union member' if not findmember(name)
  253. @members.find { |m|
  254. m.type.untypedef.kind_of? Union and m.type.untypedef.findmember(name)
  255. }.type.untypedef.bitoffsetof(parser, name)
  256. end
  257. def parse_members(parser, scope)
  258. @fldlist = nil if fldlist # invalidate fld offset cache
  259. @members = []
  260. # parse struct/union members in definition
  261. loop do
  262. raise parser if not tok = parser.skipspaces
  263. break if tok.type == :punct and tok.raw == '}'
  264. parser.unreadtok tok
  265. raise tok, 'invalid struct member type' if not basetype = Variable.parse_type(parser, scope)
  266. loop do
  267. member = basetype.dup
  268. member.parse_declarator(parser, scope)
  269. member.type.length ||= 0 if member.type.kind_of?(Array) # struct { char blarg[]; };
  270. raise member.backtrace, 'member redefinition' if member.name and @members.find { |m| m.name == member.name }
  271. @members << member
  272. raise tok || parser if not tok = parser.skipspaces or tok.type != :punct
  273. if tok.raw == ':' # bits
  274. raise tok, 'bad type for bitslice' if not member.type.integral?
  275. bits = nil
  276. raise tok, "bad bit count #{bits.inspect}" if not bits = CExpression.parse(parser, scope, false) or
  277. not bits.constant? or !(bits = bits.reduce(parser)).kind_of? ::Integer
  278. #raise tok, 'need more bits' if bits > 8*parser.sizeof(member)
  279. # WORD wReserved:17; => yay windows.h
  280. (@bits ||= [])[@members.length-1] = bits
  281. raise tok || parser, '"," or ";" expected' if not tok = parser.skipspaces or tok.type != :punct
  282. end
  283. case tok.raw
  284. when ';'; break
  285. when ','
  286. when '}'; parser.unreadtok(tok); break
  287. else raise tok, '"," or ";" expected'
  288. end
  289. end
  290. end
  291. parse_attributes(parser)
  292. end
  293. # updates the @fldoffset / @fldbitoffset hash storing the offset of members
  294. def update_member_cache(parser)
  295. @fldlist = {}
  296. @members.to_a.each { |m|
  297. @fldlist[m.name] = m if m.name
  298. }
  299. end
  300. def parse_initializer(parser, scope)
  301. if tok = parser.skipspaces and tok.type == :punct and tok.raw == '{'
  302. # struct x toto = { 1, .4, .member[0][6].bla = 12 };
  303. raise tok, 'undefined struct' if not @members
  304. ret = []
  305. if tok = parser.skipspaces and (tok.type != :punct or tok.raw != '}')
  306. parser.unreadtok tok
  307. idx = 0
  308. loop do
  309. idx = parse_initializer_designator(parser, scope, ret, idx, true)
  310. raise tok || parser, '"," or "}" expected' if not tok = parser.skipspaces or tok.type != :punct or (tok.raw != '}' and tok.raw != ',')
  311. break if tok.raw == '}'
  312. raise tok, 'struct is smaller than that' if idx >= @members.length
  313. end
  314. end
  315. ret
  316. else
  317. parser.unreadtok tok
  318. super(parser, scope)
  319. end
  320. end
  321. # parses a designator+initializer eg '.toto = 4' or '.tutu[42][12].bla = 16' or (root ? '4' : '=4')
  322. def parse_initializer_designator(parser, scope, value, idx, root=true)
  323. if nt = parser.skipspaces and nt.type == :punct and nt.raw == '.' and
  324. nnt = parser.skipspaces and nnt.type == :string and
  325. findmember(nnt.raw)
  326. raise nnt, 'unhandled indirect initializer' if not nidx = @members.index(@members.find { |m| m.name == nnt.raw }) # TODO
  327. if not root
  328. value[idx] ||= [] # AryRecorder may change [] to AryRec.new, can't do v = v[i] ||= []
  329. value = value[idx]
  330. end
  331. idx = nidx
  332. @members[idx].type.untypedef.parse_initializer_designator(parser, scope, value, idx, false)
  333. else
  334. parser.unreadtok nnt
  335. if root
  336. parser.unreadtok nt
  337. value[idx] = @members[idx].type.parse_initializer(parser, scope)
  338. else
  339. raise nt || parser, '"=" expected' if not nt or nt.type != :punct or nt.raw != '='
  340. value[idx] = parse_initializer(parser, scope)
  341. end
  342. end
  343. idx + 1
  344. end
  345. # resolve structptr + offset into 'str.membername'
  346. # handles 'var.substruct1.array[12].foo'
  347. # updates str
  348. # returns the final member type itself
  349. # works for Struct/Union/Array
  350. def expand_member_offset(c_parser, off, str)
  351. # XXX choose in members, check sizeof / prefer structs
  352. m = @members.first
  353. str << '.' << m.name if m.name
  354. if m.type.respond_to?(:expand_member_offset)
  355. m.type.expand_member_offset(c_parser, off, str)
  356. else
  357. m.type
  358. end
  359. end
  360. end
  361. class Struct < Union
  362. attr_accessor :pack
  363. def align(parser) [@members.to_a.map { |m| m.type.align(parser) }.max || 1, (pack || 8)].min end
  364. def offsetof(parser, name)
  365. raise parser, 'undefined structure' if not members
  366. update_member_cache(parser) if not fldlist
  367. return @fldoffset[name] if @fldoffset[name]
  368. return @fldoffset[name.name] if name.respond_to?(:name) and @fldoffset[name.name]
  369. # this is almost never reached, only for <struct>.offsetof(anonymoussubstructmembername)
  370. raise parser, 'unknown structure member' if (name.kind_of?(::String) ? !findmember(name) : !@members.include?(name))
  371. indirect = true if name.kind_of?(::String) and not @fldlist[name]
  372. al = align(parser)
  373. off = 0
  374. bit_off = 0
  375. isz = nil
  376. @members.each_with_index { |m, i|
  377. if bits and b = @bits[i]
  378. if not isz
  379. mal = [m.type.align(parser), al].min
  380. off = (off + mal - 1) / mal * mal
  381. end
  382. isz = parser.sizeof(m)
  383. if b == 0 or (bit_off > 0 and bit_off + b > 8*isz)
  384. bit_off = 0
  385. mal = [m.type.align(parser), al].min
  386. off = (off + isz + mal - 1) / mal * mal
  387. end
  388. break if m.name == name or m == name
  389. bit_off += b
  390. else
  391. if isz
  392. off += isz
  393. bit_off = 0
  394. isz = nil
  395. end
  396. mal = [m.type.align(parser), al].min
  397. off = (off + mal - 1) / mal * mal
  398. if m.name == name or m == name
  399. break
  400. elsif indirect and m.type.untypedef.kind_of? Union and m.type.untypedef.findmember(name)
  401. off += m.type.untypedef.offsetof(parser, name)
  402. break
  403. else
  404. off += parser.sizeof(m)
  405. end
  406. end
  407. }
  408. off
  409. end
  410. # returns the [bitoffset, bitlength] of the field if it is a bitfield
  411. # this should be added to the offsetof(field)
  412. def bitoffsetof(parser, name)
  413. raise parser, 'undefined structure' if not members
  414. update_member_cache(parser) if not fldlist
  415. return @fldbitoffset[name] if fldbitoffset and @fldbitoffset[name]
  416. return @fldbitoffset[name.name] if fldbitoffset and name.respond_to?(:name) and @fldbitoffset[name.name]
  417. return if @fldlist[name] or @members.include?(name)
  418. raise parser, 'undefined union' if not @members
  419. raise parser, 'unknown union member' if not findmember(name)
  420. @members.find { |m|
  421. m.type.untypedef.kind_of?(Union) and m.type.untypedef.findmember(name)
  422. }.type.untypedef.bitoffsetof(parser, name)
  423. end
  424. # returns the @member element that has offsetof(m) == off
  425. def findmember_atoffset(parser, off)
  426. return if not members
  427. update_member_cache(parser) if not fldlist
  428. if m = @fldoffset.index(off)
  429. @fldlist[m]
  430. end
  431. end
  432. def parse_members(parser, scope)
  433. super(parser, scope)
  434. if has_attribute 'packed'
  435. @pack = 1
  436. elsif p = has_attribute_var('pack')
  437. @pack = p[/\d+/].to_i
  438. raise parser, "illegal struct pack(#{p})" if @pack == 0
  439. end
  440. end
  441. # updates the @fldoffset / @fldbitoffset hash storing the offset of members
  442. def update_member_cache(parser)
  443. super(parser)
  444. @fldoffset = {}
  445. @fldbitoffset = {} if fldbitoffset
  446. al = align(parser)
  447. off = 0
  448. bit_off = 0
  449. isz = nil
  450. @members.each_with_index { |m, i|
  451. if bits and b = @bits[i]
  452. if not isz
  453. mal = [m.type.align(parser), al].min
  454. off = (off + mal - 1) / mal * mal
  455. end
  456. isz = parser.sizeof(m)
  457. if b == 0 or (bit_off > 0 and bit_off + b > 8*isz)
  458. bit_off = 0
  459. mal = [m.type.align(parser), al].min
  460. off = (off + isz + mal - 1) / mal * mal
  461. end
  462. if m.name
  463. @fldoffset[m.name] = off
  464. @fldbitoffset ||= {}
  465. @fldbitoffset[m.name] = [bit_off, b]
  466. end
  467. bit_off += b
  468. else
  469. if isz
  470. off += isz
  471. bit_off = 0
  472. isz = nil
  473. end
  474. mal = [m.type.align(parser), al].min
  475. off = (off + mal - 1) / mal * mal
  476. @fldoffset[m.name] = off if m.name
  477. off += parser.sizeof(m)
  478. end
  479. }
  480. end
  481. # see Union#expand_member_offset
  482. def expand_member_offset(c_parser, off, str)
  483. members.to_a.each { |m|
  484. mo = offsetof(c_parser, m)
  485. if mo == off or mo + c_parser.sizeof(m) > off
  486. if bitoffsetof(c_parser, m)
  487. # ignore bitfields
  488. str << "+#{off}" if off > 0
  489. return self
  490. end
  491. str << '.' << m.name if m.name
  492. if m.type.respond_to?(:expand_member_offset)
  493. return m.type.expand_member_offset(c_parser, off-mo, str)
  494. else
  495. return m.type
  496. end
  497. elsif mo > off
  498. break
  499. end
  500. }
  501. # XXX that works only for pointer-style str
  502. str << "+#{off}" if off > 0
  503. nil
  504. end
  505. end
  506. class Enum < Type
  507. # name => value
  508. attr_accessor :members
  509. attr_accessor :name
  510. attr_accessor :backtrace
  511. def align(parser) BaseType.new(:int).align(parser) end
  512. def arithmetic?; true end
  513. def integral?; true end
  514. def signed?; false end
  515. def parse_members(parser, scope)
  516. val = -1
  517. @members = {}
  518. loop do
  519. raise parser if not tok = parser.skipspaces
  520. break if tok.type == :punct and tok.raw == '}'
  521. name = tok.raw
  522. raise tok, 'bad enum name' if tok.type != :string or Keyword[name] or (?0..?9).include?(name[0])
  523. raise parser if not tok = parser.skipspaces
  524. if tok.type == :punct and tok.raw == '='
  525. raise tok || parser if not val = CExpression.parse(parser, scope, false) or not val = val.reduce(parser) or not tok = parser.skipspaces
  526. else
  527. val += 1
  528. end
  529. raise tok, "enum value #{name} redefinition" if scope.symbol[name] and scope.symbol[name] != val
  530. @members[name] = val
  531. scope.symbol[name] = val
  532. if tok.type == :punct and tok.raw == '}'
  533. break
  534. elsif tok.type == :punct and tok.raw == ','
  535. else raise tok, '"," or "}" expected'
  536. end
  537. end
  538. parse_attributes(parser)
  539. end
  540. def compare_deep(o)
  541. return true if o.object_id == self.object_id
  542. return if o.class != self.class or o.name != self.name or o.attributes != self.attributes
  543. members == o.members
  544. end
  545. end
  546. class Pointer < Type
  547. attr_accessor :type
  548. def initialize(type=nil)
  549. @type = type
  550. end
  551. def pointer? ; true ; end
  552. def arithmetic? ; true ; end
  553. def base ; @type.base ; end
  554. def align(parser) BaseType.new(:ptr).align(parser) end
  555. def pointed ; @type end
  556. def ==(o)
  557. o.class == self.class and o.type == self.type
  558. end
  559. end
  560. class Array < Pointer
  561. attr_accessor :length
  562. def initialize(type=nil, length=nil)
  563. super(type)
  564. @length = length if length
  565. end
  566. def align(parser) @type.align(parser) end
  567. def parse_initializer(parser, scope)
  568. raise parser, 'cannot initialize dynamic array' if @length.kind_of? CExpression
  569. if tok = parser.skipspaces and tok.type == :punct and tok.raw == '{'
  570. # struct x foo[] = { { 4 }, [12].tutu = 2 };
  571. ret = []
  572. if tok = parser.skipspaces and (tok.type != :punct or tok.raw != '}')
  573. parser.unreadtok tok
  574. idx = 0
  575. loop do
  576. idx = parse_initializer_designator(parser, scope, ret, idx, true)
  577. raise tok || parser, '"," or "}" expected' if not tok = parser.skipspaces or tok.type != :punct or (tok.raw != '}' and tok.raw != ',')
  578. break if tok.raw == '}'
  579. # allow int x[] = {1, 2, 3, };
  580. break if tok = parser.skipspaces and tok.type == :punct and tok.raw == '}'
  581. parser.unreadtok tok
  582. raise tok, 'array is smaller than that' if length and idx >= @length
  583. end
  584. end
  585. ret
  586. else
  587. parser.unreadtok tok
  588. i = super(parser, scope)
  589. if i.kind_of? CExpression and not i.op and i.rexpr.kind_of? String and @length and i.rexpr.length > @length
  590. puts tok.exception("initializer is too long (#{i.rexpr.length} for #@length)").message if $VERBOSE
  591. i.rexpr = i.rexpr[0, @length]
  592. end
  593. i
  594. end
  595. end
  596. # this class is a hack to support [1 ... 4] array initializer
  597. # it stores the effects of subsequent initializers (eg [1 ... 4].toto[48].bla[2 ... 57] = 12)
  598. # which are later played back on the range
  599. class AryRecorder
  600. attr_accessor :log
  601. def initialize
  602. @log = []
  603. end
  604. def []=(idx, val)
  605. val = self.class.new if val == []
  606. @log[idx] = val
  607. end
  608. def [](idx)
  609. @log[idx]
  610. end
  611. def playback_idx(i)
  612. case v = @log[i]
  613. when self.class; v.playback
  614. else v
  615. end
  616. end
  617. def playback(ary=[])
  618. @log.each_with_index { |v, i| ary[i] = playback_idx(i) }
  619. ary
  620. end
  621. end
  622. # parses a designator+initializer eg '[12] = 4' or '[42].bla = 16' or '[3 ... 8] = 28'
  623. def parse_initializer_designator(parser, scope, value, idx, root=true)
  624. # root = true for 1st invocation (x = { 4 }) => immediate value allowed
  625. # or false for recursive invocations (x = { .y = 4 }) => need '=' sign before immediate
  626. if nt = parser.skipspaces and nt.type == :punct and nt.raw == '['
  627. if not root
  628. value[idx] ||= [] # AryRecorder may change [] to AryRec.new, can't do v = v[i] ||= []
  629. value = value[idx]
  630. end
  631. 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
  632. nt = parser.skipspaces
  633. if nt and nt.type == :punct and nt.raw == '.' # range
  634. raise nt || parser, '".." expected' if not nt = parser.skipspaces or nt.type != :punct or nt.raw != '.'
  635. raise nt || parser, '"." expected' if not nt = parser.skipspaces or nt.type != :punct or nt.raw != '.'
  636. 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
  637. raise nt, 'bad range' if eidx < idx
  638. nt = parser.skipspaces
  639. realvalue = value
  640. value = AryRecorder.new
  641. end
  642. raise nt || parser, '"]" expected' if not nt or nt.type != :punct or nt.raw != ']'
  643. raise nt, 'array is smaller than that' if length and (eidx||idx) >= @length
  644. @type.untypedef.parse_initializer_designator(parser, scope, value, idx, false)
  645. if eidx
  646. (idx..eidx).each { |i| realvalue[i] = value.playback_idx(idx) }
  647. idx = eidx # next default value = eidx+1 (eg int x[] = { [1 ... 3] = 4, 5 } => x[4] = 5)
  648. end
  649. else
  650. if root
  651. parser.unreadtok nt
  652. value[idx] = @type.parse_initializer(parser, scope)
  653. else
  654. raise nt || parser, '"=" expected' if not nt or nt.type != :punct or nt.raw != '='
  655. value[idx] = parse_initializer(parser, scope)
  656. end
  657. end
  658. idx + 1
  659. end
  660. # see Union#expand_member_offset
  661. def expand_member_offset(c_parser, off, str)
  662. tsz = c_parser.sizeof(@type)
  663. str << "[#{off/tsz}]"
  664. if @type.respond_to?(:expand_member_offset)
  665. @type.expand_member_offset(c_parser, off%tsz, str)
  666. else
  667. @type
  668. end
  669. end
  670. end
  671. class Variable
  672. include Attributes
  673. include Typed
  674. attr_accessor :type
  675. attr_accessor :initializer # CExpr / Block (for Functions)
  676. attr_accessor :name
  677. attr_accessor :storage # auto register static extern typedef
  678. attr_accessor :backtrace # definition backtrace info (the name token)
  679. def initialize(name=nil, type=nil)
  680. @name, @type = name, type
  681. end
  682. end
  683. # found in a block's Statements, used to know the initialization order
  684. # eg { int i; i = 4; struct foo { int k; } toto = {i}; }
  685. class Declaration
  686. attr_accessor :var
  687. def initialize(var)
  688. @var = var
  689. end
  690. end
  691. class If < Statement
  692. attr_accessor :test # expression
  693. attr_accessor :bthen, :belse # statements
  694. def initialize(test, bthen, belse=nil)
  695. @test = test
  696. @bthen = bthen
  697. @belse = belse if belse
  698. end
  699. def self.parse(parser, scope, nest)
  700. tok = nil
  701. raise tok || self, '"(" expected' if not tok = parser.skipspaces or tok.type != :punct or tok.raw != '('
  702. raise tok, 'expr expected' if not expr = CExpression.parse(parser, scope) or not expr.type.arithmetic?
  703. raise tok || self, '")" expected' if not tok = parser.skipspaces or tok.type != :punct or tok.raw != ')'
  704. bthen = parser.parse_statement scope, nest
  705. if tok = parser.skipspaces and tok.type == :string and tok.raw == 'else'
  706. belse = parser.parse_statement scope, nest
  707. else
  708. parser.unreadtok tok
  709. end
  710. new expr, bthen, belse
  711. end
  712. end
  713. class For < Statement
  714. attr_accessor :init, :test, :iter # CExpressions, init may be Block
  715. attr_accessor :body
  716. def initialize(init, test, iter, body)
  717. @init, @test, @iter, @body = init, test, iter, body
  718. end
  719. def self.parse(parser, scope, nest)
  720. tok = nil
  721. raise tok || parser, '"(" expected' if not tok = parser.skipspaces or tok.type != :punct or tok.raw != '('
  722. init = forscope = Block.new(scope)
  723. if not parser.parse_definition(forscope)
  724. forscope = scope
  725. init = CExpression.parse(parser, forscope)
  726. raise tok || parser, '";" expected' if not tok = parser.skipspaces or tok.type != :punct or tok.raw != ';'
  727. end
  728. test = CExpression.parse(parser, forscope)
  729. raise tok || parser, '";" expected' if not tok = parser.skipspaces or tok.type != :punct or tok.raw != ';'
  730. raise tok, 'bad test expression in for loop' if test and not test.type.arithmetic?
  731. iter = CExpression.parse(parser, forscope)
  732. raise tok || parser, '")" expected' if not tok = parser.skipspaces or tok.type != :punct or tok.raw != ')'
  733. new init, test, iter, parser.parse_statement(forscope, nest + [:loop])
  734. end
  735. end
  736. class While < Statement
  737. attr_accessor :test
  738. attr_accessor :body
  739. def initialize(test, body)
  740. @test = test
  741. @body = body
  742. end
  743. def self.parse(parser, scope, nest)
  744. tok = nil
  745. raise tok || parser, '"(" expected' if not tok = parser.skipspaces or tok.type != :punct or tok.raw != '('
  746. raise tok, 'expr expected' if not expr = CExpression.parse(parser, scope) or not expr.type.arithmetic?
  747. raise tok || parser, '")" expected' if not tok = parser.skipspaces or tok.type != :punct or tok.raw != ')'
  748. new expr, parser.parse_statement(scope, nest + [:loop])
  749. end
  750. end
  751. class DoWhile < While
  752. def self.parse(parser, scope, nest)
  753. body = parser.parse_statement(scope, nest + [:loop])
  754. tok = nil
  755. raise tok || parser, '"while" expected' if not tok = parser.skipspaces or tok.type != :string or tok.raw != 'while'
  756. raise tok || parser, '"(" expected' if not tok = parser.skipspaces or tok.type != :punct or tok.raw != '('
  757. raise tok, 'expr expected' if not expr = CExpression.parse(parser, scope) or not expr.type.arithmetic?
  758. raise tok || parser, '")" expected' if not tok = parser.skipspaces or tok.type != :punct or tok.raw != ')'
  759. parser.checkstatementend(tok)
  760. new expr, body
  761. end
  762. end
  763. class Switch < Statement
  764. attr_accessor :test, :body
  765. def initialize(test, body)
  766. @test = test
  767. @body = body
  768. end
  769. def self.parse(parser, scope, nest)
  770. raise tok || parser, '"(" expected' if not tok = parser.skipspaces or tok.type != :punct or tok.raw != '('
  771. raise tok, 'expr expected' if not expr = CExpression.parse(parser, scope) or not expr.type.integral?
  772. raise tok || parser, '")" expected' if not tok = parser.skipspaces or tok.type != :punct or tok.raw != ')'
  773. new expr, parser.parse_statement(scope, nest + [:switch])
  774. end
  775. end
  776. class Continue < Statement
  777. end
  778. class Break < Statement
  779. end
  780. class Goto < Statement
  781. attr_accessor :target
  782. def initialize(target)
  783. @target = target
  784. end
  785. end
  786. class Return < Statement
  787. attr_accessor :value
  788. def initialize(value)
  789. @value = value
  790. end
  791. end
  792. class Label < Statement
  793. attr_accessor :name
  794. attr_accessor :statement
  795. def initialize(name, statement=nil)
  796. @name, @statement = name, statement
  797. end
  798. end
  799. class Case < Label
  800. attr_accessor :expr, :exprup # exprup if range, expr may be 'default'
  801. def initialize(expr, exprup, statement)
  802. @expr, @statement = expr, statement
  803. @exprup = exprup if exprup
  804. end
  805. def self.parse(parser, scope, nest)
  806. raise parser, 'invalid case' if not expr = CExpression.parse(parser, scope) or not expr.constant? or not expr.type.integral?
  807. raise tok || parser, '":" or "..." expected' if not tok = parser.skipspaces or tok.type != :punct or (tok.raw != ':' and tok.raw != '.')
  808. if tok.raw == '.'
  809. raise tok || parser, '".." expected' if not tok = parser.skipspaces or tok.type != :punct or tok.raw != '.'
  810. raise tok || parser, '"." expected' if not tok = parser.skipspaces or tok.type != :punct or tok.raw != '.'
  811. raise tok, 'invalid case range' if not exprup = CExpression.parse(parser, scope) or not exprup.constant? or not exprup.type.integral?
  812. raise tok || parser, '":" expected' if not tok = parser.skipspaces or tok.type != :punct or tok.raw != ':'
  813. end
  814. body = parser.parse_statement scope, nest
  815. new expr, exprup, body
  816. end
  817. end
  818. # inline asm statement
  819. class Asm < Statement
  820. include Attributes
  821. attr_accessor :body # asm source (::String)
  822. attr_accessor :output, :input, :clobber # I/O, gcc-style (::Array)
  823. attr_accessor :backtrace # body Token
  824. attr_accessor :volatile
  825. def initialize(body, backtrace, output=nil, input=nil, clobber=nil, volatile=nil)
  826. @body, @backtrace, @output, @input, @clobber, @volatile = body, backtrace, output, input, clobber, volatile
  827. end
  828. def self.parse(parser, scope)
  829. if tok = parser.skipspaces and tok.type == :string and (tok.raw == 'volatile' or tok.raw == '__volatile__')
  830. volatile = true
  831. tok = parser.skipspaces
  832. end
  833. if not tok or tok.type != :punct or tok.raw != '('
  834. # detect MS-style inline asm: "__asm .* __asm .*" or "asm { [\s.]* }"
  835. ftok = tok
  836. body = ''
  837. if tok.type == :punct and tok.raw == '{'
  838. loop do
  839. raise ftok, 'unterminated asm block' if not tok = parser.lexer.readtok
  840. break if tok.type == :punct and tok.raw == '}'
  841. case tok.type
  842. when :space; body << ' '
  843. when :eol; body << "\n"
  844. when :punct; body << tok.raw
  845. when :quoted; body << CExpression.string_inspect(tok.value) # concat adjacent c strings
  846. when :string
  847. body << \
  848. case tok.raw
  849. when 'asm', '__asm', '__asm__'; "\n"
  850. when '_emit'; 'db'
  851. else tok.raw
  852. end
  853. end
  854. end
  855. # allow shell-style heredoc: asm <<EOS\n<asm>\nEOS
  856. elsif tok.type == :punct and tok.raw == '<'
  857. raise ftok, 'bad asm heredoc' if not tok = parser.lexer.readtok or tok.type != :punct or tok.raw != '<'
  858. delimiter = parser.lexer.readtok
  859. if delimiter.type == :punct and delimiter.raw == '-'
  860. skipspc = true
  861. delimiter = parser.lexer.readtok
  862. end
  863. raise ftok, 'bad asm heredoc delim' if delimiter.type != :string or not tok = parser.lexer.readtok or tok.type != :eol
  864. nl = true
  865. loop do
  866. raise ftok, 'unterminated heredoc' if not tok = parser.lexer.readtok
  867. break if nl and tok.raw == delimiter.raw
  868. raw = tok.raw
  869. raw = "\n" if skipspc and tok.type == :eol
  870. body << raw
  871. nl = (tok.type == :eol and (raw[-1] == ?\n or raw[-1] == ?\r))
  872. end
  873. # MS single-instr: asm inc eax;
  874. # also allow asm "foo bar\nbaz";
  875. else
  876. parser.lexer.unreadtok tok
  877. loop do
  878. break if not tok = parser.lexer.readtok or tok.type == :eol
  879. case tok.type
  880. when :space; body << ' '
  881. when :punct
  882. case tok.raw
  883. when '}'
  884. parser.lexer.unreadtok tok
  885. break
  886. else body << tok.raw
  887. end
  888. when :quoted; body << (body.empty? ? tok.value : CExpression.string_inspect(tok.value)) # asm "pop\nret" VS asm add al, 'z'
  889. when :string
  890. body << \
  891. case tok.raw
  892. when 'asm', '__asm', '__asm__'; "\n"
  893. when '_emit'; 'db'
  894. else tok.raw
  895. end
  896. end
  897. end
  898. end
  899. return new(body, ftok, nil, nil, nil, volatile)
  900. end
  901. raise tok || parser, '"(" expected' if not tok or tok.type != :punct or tok.raw != '('
  902. raise tok || parser, 'qstring expected' if not tok = parser.skipspaces or tok.type != :quoted
  903. body = tok
  904. ret = new body.value, body
  905. tok = parser.skipspaces
  906. raise tok || parser, '":" or ")" expected' if not tok or tok.type != :punct or (tok.raw != ':' and tok.raw != ')')
  907. if tok.raw == ':'
  908. ret.output = []
  909. raise parser if not tok = parser.skipspaces
  910. while tok.type == :quoted
  911. type = tok.value
  912. raise tok, 'expr expected' if not var = CExpression.parse_value(parser, scope)
  913. ret.output << [type, var]
  914. raise tok || parser, '":" or "," or ")" expected' if not tok = parser.skipspaces or tok.type != :punct or (tok.raw != ',' and tok.raw != ')' and tok.raw != ':')
  915. break if tok.raw == ':' or tok.raw == ')'
  916. raise tok || parser, 'qstring expected' if not tok = parser.skipspaces or tok.type != :quoted
  917. end
  918. end
  919. if tok.raw == ':'
  920. ret.input = []
  921. raise parser if not tok = parser.skipspaces
  922. while tok.type == :quoted
  923. type = tok.value
  924. raise tok, 'expr expected' if not var = CExpression.parse_value(parser, scope)
  925. ret.input << [type, var]
  926. raise tok || parser, '":" or "," or ")" expected' if not tok = parser.skipspaces or tok.type != :punct or (tok.raw != ',' and tok.raw != ')' and tok.raw != ':')
  927. break if tok.raw == ':' or tok.raw == ')'
  928. raise tok || parser, 'qstring expected' if not tok = parser.skipspaces or tok.type != :quoted
  929. end
  930. end
  931. if tok.raw == ':'
  932. ret.clobber = []
  933. raise parser if not tok = parser.skipspaces
  934. while tok.type == :quoted
  935. ret.clobber << tok.value
  936. raise tok || parser, '"," or ")" expected' if not tok = parser.skipspaces or tok.type != :punct or (tok.raw != ',' and tok.raw != ')')
  937. break if tok.raw == ')'
  938. raise tok || parser, 'qstring expected' if not tok = parser.skipspaces or tok.type != :quoted
  939. end
  940. end
  941. raise tok || parser, '")" expected' if not tok or tok.type != :punct or tok.raw != ')'
  942. ret.parse_attributes(parser)
  943. parser.checkstatementend(tok)
  944. ret
  945. end
  946. end
  947. class CExpression < Statement
  948. include Typed
  949. # may be :,, :., :'->', :funcall (function, [arglist]), :[] (array indexing), nil (cast)
  950. attr_accessor :op
  951. # nil/CExpr/Variable/Label/::String( = :quoted/struct member name)/::Integer/::Float/Block
  952. attr_accessor :lexpr, :rexpr
  953. # a Type
  954. attr_accessor :type
  955. def initialize(l, o, r, t)
  956. raise "invalid CExpr #{[l, o, r, t].inspect}" if (o and not o.kind_of? ::Symbol) or not t.kind_of? Type
  957. @lexpr, @op, @rexpr, @type = l, o, r, t
  958. end
  959. # overwrites @lexpr @op @rexpr @type from the arg
  960. def replace(o)
  961. @lexpr, @op, @rexpr, @type = o.lexpr, o.op, o.rexpr, o.type
  962. self
  963. end
  964. # deep copy of the object
  965. # recurses only within CExpressions, anything else is copied by reference
  966. def deep_dup
  967. n = dup
  968. n.lexpr = n.lexpr.deep_dup if n.lexpr.kind_of? CExpression
  969. n.rexpr = n.rexpr.deep_dup if n.rexpr.kind_of? CExpression
  970. n.rexpr = n.rexpr.map { |e| e.kind_of?(CExpression) ? e.deep_dup : e } if n.rexpr.kind_of? ::Array
  971. n
  972. end
  973. # recursive constructor with automatic type inference
  974. # e.g. CExpression[foo, :+, [:*, bar]]
  975. # assumes root args are correctly typed (eg *foo => foo must be a pointer)
  976. # take care to use [int] with immediates, e.g. CExpression[foo, :+, [2]]
  977. # CExpr[some_cexpr] returns some_cexpr
  978. def self.[](*args)
  979. # sub-arrays in args are to be passed to self.[] recursively (syntaxic sugar)
  980. splat = lambda { |e| e.kind_of?(::Array) ? self[*e] : e }
  981. args.shift while args.first == nil # CExpr[nil, :&, bla] => CExpr[:&, bla]
  982. case args.length
  983. when 4
  984. op = args[1]
  985. if op == :funcall or op == :'?:'
  986. x2 = args[2].map { |a| splat[a] } if args[2]
  987. else
  988. x2 = splat[args[2]]
  989. end
  990. new(splat[args[0]], op, x2, args[3])
  991. when 3
  992. op = args[1]
  993. x1 = splat[args[0]]
  994. if op == :funcall or op == :'?:'
  995. x2 = args[2].map { |a| splat[a] } if args[2]
  996. else
  997. x2 = splat[args[2]]
  998. end
  999. case op
  1000. when :funcall
  1001. rt = x1.type.untypedef
  1002. rt = rt.type.untypedef if rt.pointer?
  1003. new(x1, op, x2, rt.type)
  1004. when :[]; new(x1, op, x2, x1.type.untypedef.type)
  1005. when :+; new(x1, op, x2, (x2.type.pointer? ? x2.type : x1.type))
  1006. when :-; new(x1, op, x2, ((x1.type.pointer? and x2.type.pointer?) ? BaseType.new(:int) : x2.type.pointer? ? x2.type : x1.type))
  1007. when :'&&', :'||', :==, :'!=', :>, :<, :<=, :>=; new(x1, op, x2, BaseType.new(:int))
  1008. when :'.', :'->'
  1009. t = x1.type.untypedef
  1010. t = t.type.untypedef if op == :'->' and x1.type.pointer?
  1011. raise "parse error: #{t} has no member #{x2}" if not t.kind_of? Union or not m = t.findmember(x2)
  1012. new(x1, op, x2, m.type)
  1013. when :'?:'; new(x1, op, x2, x2[0].type)
  1014. when :','; new(x1, op, x2, x2.type)
  1015. else new(x1, op, x2, x1.type)
  1016. end
  1017. when 2
  1018. x0 = splat[args[0]]
  1019. x1 = splat[args[1]]
  1020. x0, x1 = x1, x0 if x0.kind_of? Type
  1021. if x1.kind_of? Type; new(nil, nil, x0, x1) # (cast)r
  1022. elsif x0 == :*; new(nil, x0, x1, x1.type.untypedef.type) # *r
  1023. elsif x0 == :& and x1.kind_of? CExpression and x1.type.kind_of? C::Array; new(nil, nil, x1, Pointer.new(x1.type.type))
  1024. elsif x0 == :&; new(nil, x0, x1, Pointer.new(x1.type)) # &r
  1025. elsif x0 == :'!'; new(nil, x0, x1, BaseType.new(:int)) # &r
  1026. elsif x1.kind_of? ::Symbol; new(x0, x1, nil, x0.type) # l++
  1027. else new(nil, x0, x1, x1.type) # +r
  1028. end
  1029. when 1
  1030. x = splat[args[0]]
  1031. case x
  1032. when CExpression; x
  1033. when ::Integer; new(nil, nil, x, BaseType.new(:int)) # XXX range => __int64 ?
  1034. when ::Float; new(nil, nil, x, BaseType.new(:double))
  1035. when ::String; new(nil, nil, x, Pointer.new(BaseType.new(:char)))
  1036. else new(nil, nil, x, x.type)
  1037. end
  1038. else raise "parse error CExpr[*#{args.inspect}]"
  1039. end
  1040. end
  1041. end
  1042. class Parser
  1043. # creates a new CParser, parses all top-level statements
  1044. def self.parse(text)
  1045. new.parse text
  1046. end
  1047. # parses the current lexer content (or the text arg) for toplevel definitions
  1048. def parse(text=nil, filename='<unk>', lineno=1)
  1049. @lexer.feed text, filename, lineno if text
  1050. nil while not @lexer.eos? and (parse_definition(@toplevel) or parse_toplevel_statement(@toplevel))
  1051. raise @lexer.readtok || self, 'invalid definition' if not @lexer.eos?
  1052. sanity_checks
  1053. self
  1054. end
  1055. # parses a C file
  1056. def parse_file(file)
  1057. parse(File.read(file), file)
  1058. end
  1059. attr_accessor :lexer, :toplevel, :typesize, :pragma_pack
  1060. attr_accessor :endianness
  1061. attr_accessor :allow_bad_c
  1062. attr_accessor :program
  1063. # allowed arguments: ExeFormat, CPU, Preprocessor, Symbol (for the data model)
  1064. def initialize(*args)
  1065. model = args.grep(Symbol).first || :ilp32
  1066. lexer = args.grep(Preprocessor).first || Preprocessor.new
  1067. @program = args.grep(ExeFormat).first
  1068. cpu = args.grep(CPU).first
  1069. cpu ||= @program.cpu if @program
  1070. @lexer = lexer
  1071. @prev_pragma_callback = @lexer.pragma_callback
  1072. @lexer.pragma_callback = lambda { |tok| parse_pragma_callback(tok) }
  1073. @toplevel = Block.new(nil)
  1074. @unreadtoks = []
  1075. @endianness = cpu ? cpu.endianness : :big
  1076. @typesize = { :void => 1, :__int8 => 1, :__int16 => 2, :__int32 => 4, :__int64 => 8,
  1077. :char => 1, :float => 4, :double => 8, :longdouble => 12 }
  1078. send model
  1079. cpu.tune_cparser(self) if cpu
  1080. @program.tune_cparser(self) if @program
  1081. end
  1082. def ilp16
  1083. @typesize.update :short => 2, :ptr => 2,
  1084. :int => 2, :long => 4, :longlong => 4
  1085. end
  1086. def lp32
  1087. @typesize.update :short => 2, :ptr => 4,
  1088. :int => 2, :long => 4, :longlong => 8
  1089. end
  1090. def ilp32
  1091. @typesize.update :short => 2, :ptr => 4,
  1092. :int => 4, :long => 4, :longlong => 8
  1093. end
  1094. def llp64
  1095. @typesize.update :short => 2, :ptr => 8,
  1096. :int => 4, :long => 4, :longlong => 8
  1097. end
  1098. def lp64
  1099. @typesize.update :short => 2, :ptr => 8,
  1100. :int => 4, :long => 8, :longlong => 8
  1101. end
  1102. def ilp64
  1103. @typesize.update :short => 2, :ptr => 8,
  1104. :int => 8, :long => 8, :longlong => 8
  1105. end
  1106. def parse_pragma_callback(otok)
  1107. case otok.raw
  1108. when 'pack'
  1109. nil while lp = @lexer.readtok and lp.type == :space
  1110. nil while rp = @lexer.readtok and rp.type == :space
  1111. if not rp or rp.type != :punct or rp.raw != ')'
  1112. v1 = rp
  1113. nil while rp = @lexer.readtok and rp.type == :space
  1114. end
  1115. if rp and rp.type == :punct and rp.raw == ','
  1116. nil while v2 = @lexer.readtok and v2.type == :space
  1117. nil while rp = @lexer.readtok and rp.type == :space
  1118. end
  1119. raise otok if not rp or lp.type != :punct or rp.type != :punct or lp.raw != '(' or rp.raw != ')'
  1120. raise otok if (v1 and v1.type != :string) or (v2 and (v2.type != :string or v2.raw =~ /[^\d]/))
  1121. if not v1
  1122. @pragma_pack = nil
  1123. elsif v1.raw == 'push'
  1124. @pragma_pack_stack ||= []
  1125. @pragma_pack_stack << pragma_pack
  1126. @pragma_pack = v2.raw.to_i if v2
  1127. raise v2, 'bad pack value' if pragma_pack == 0
  1128. elsif v1.raw == 'pop'
  1129. @pragma_pack_stack ||= []
  1130. raise v1, 'pack stack empty' if @pragma_pack_stack.empty?
  1131. @pragma_pack = @pragma_pack_stack.pop
  1132. @pragma_pack = v2.raw.to_i if v2 and v2.raw # #pragma pack(pop, 4) => pop stack, but use 4 as pack value (imho)
  1133. raise v2, 'bad pack value' if @pragma_pack == 0
  1134. elsif v1.raw =~ /^\d+$/
  1135. raise v2, '2nd arg unexpected' if v2
  1136. @pragma_pack = v1.raw.to_i
  1137. raise v1, 'bad pack value' if @pragma_pack == 0
  1138. else raise otok
  1139. end
  1140. # the caller checks for :eol
  1141. when 'warning'
  1142. if $DEBUG
  1143. @prev_pragma_callback[otok]
  1144. else
  1145. # silent discard
  1146. nil while tok = @lexer.readtok_nopp and tok.type != :eol
  1147. @lexer.unreadtok tok
  1148. end
  1149. when 'prepare_visualstudio'
  1150. prepare_visualstudio
  1151. when 'prepare_gcc'
  1152. prepare_gcc
  1153. when 'data_model' # XXX use carefully, should be the very first thing parsed
  1154. nil while lp = @lexer.readtok and lp.type == :space
  1155. if lp.type != :string or lp.raw !~ /^s?[il]?lp(16|32|64)$/ or not respond_to? lp.raw
  1156. raise lp, "invalid data model (use lp32/lp64/llp64/ilp64)"
  1157. else
  1158. send lp.raw
  1159. end
  1160. else @prev_pragma_callback[otok]
  1161. end
  1162. end
  1163. def prepare_visualstudio
  1164. @lexer.define_weak('_WIN32')
  1165. @lexer.define_weak('_WIN32_WINNT', 0x500)
  1166. @lexer.define_weak('_INTEGRAL_MAX_BITS', 64)
  1167. @lexer.define_weak('__w64')
  1168. @lexer.define_weak('_cdecl', '__cdecl') # typo ? seen in winreg.h
  1169. @lexer.define_weak('_fastcall', '__fastcall') # typo ? seen in ntddk.h
  1170. @lexer.define_weak('_MSC_VER', 1300) # handle '#pragma once' and _declspec(noreturn)
  1171. @lexer.define_weak('__forceinline', '__inline')
  1172. @lexer.define_weak('__ptr32') # needed with msc_ver 1300, don't understand their use
  1173. @lexer.define_weak('__ptr64')
  1174. end
  1175. def prepare_gcc
  1176. @lexer.define_weak('__GNUC__', 2) # otherwise __attribute__ is defined to void..
  1177. @lexer.define_weak('__STDC__')
  1178. @lexer.define_weak('__const', 'const')
  1179. @lexer.define_weak('__signed', 'signed')
  1180. @lexer.define_weak('__signed__', 'signed')
  1181. @lexer.define_weak('__volatile', 'volatile')
  1182. if not @lexer.definition['__builtin_constant_p']
  1183. # magic macro to check if its arg is an immediate value
  1184. @lexer.define_weak('__builtin_constant_p', '0')
  1185. @lexer.definition['__builtin_constant_p'].args = [Preprocessor::Token.new([])]
  1186. end
  1187. @lexer.nodefine_strong('alloca') # TODO __builtin_alloca
  1188. @lexer.hooked_include['stddef.h'] = <<EOH
  1189. /* simplified, define all at first invocation. may break things... */
  1190. #undef __need_ptrdiff_t
  1191. #undef __need_size_t
  1192. #undef __need_wint_t
  1193. #undef __need_wchar_t
  1194. #undef __need_NULL
  1195. #undef NULL
  1196. #if !defined (_STDDEF_H)
  1197. #define _STDDEF_H
  1198. #define __PTRDIFF_TYPE__ long int
  1199. typedef __PTRDIFF_TYPE__ ptrdiff_t;
  1200. #define __SIZE_TYPE__ long unsigned int
  1201. typedef __SIZE_TYPE__ size_t;
  1202. #define __WINT_TYPE__ unsigned int
  1203. typedef __WINT_TYPE__ wint_t;
  1204. #define __WCHAR_TYPE__ int
  1205. typedef __WCHAR_TYPE__ wchar_t;
  1206. #define NULL 0
  1207. #define offsetof(TYPE, MEMBER) __builtin_offsetof (TYPE, MEMBER)
  1208. #endif
  1209. EOH
  1210. # TODO va_args
  1211. @lexer.hooked_include['stdarg.h'] = <<EOH
  1212. // TODO
  1213. typedef void* __gnuc_va_list;
  1214. /*
  1215. typedef void* va_list;
  1216. #define va_start(v, l)
  1217. #define va_end(v)
  1218. #define va_arg(v, l)
  1219. #define va_copy(d, s)
  1220. */
  1221. EOH
  1222. @lexer.hooked_include['limits.h'] = <<EOH
  1223. #define CHAR_BIT 8
  1224. #define SCHAR_MIN (-128)
  1225. #define SCHAR_MAX 127
  1226. #define UCHAR_MAX 255
  1227. #ifdef __CHAR_UNSIGNED__
  1228. # define CHAR_MIN 0
  1229. # define CHAR_MAX UCHAR_MAX
  1230. #else
  1231. # define CHAR_MIN SCHAR_MIN
  1232. # define CHAR_MAX SCHAR_MAX
  1233. #endif
  1234. #define UINT_MAX #{(1 << (8*@typesize[:int]))-1}U
  1235. #define INT_MAX (UINT_MAX >> 1)
  1236. #define INT_MIN (-INT_MAX - 1)
  1237. #define ULONG_MAX #{(1 << (8*@typesize[:long]))-1}UL
  1238. #define LONG_MAX (ULONG_MAX >> 1L)
  1239. #define LONG_MIN (-LONG_MAX - 1L)
  1240. EOH
  1241. end
  1242. # C sanity checks
  1243. def sanity_checks
  1244. return if not $VERBOSE
  1245. # TODO
  1246. end
  1247. # checks that the types are compatible (variable predeclaration, function argument..)
  1248. # strict = false for func call/assignment (eg

Large files files are truncated, but you can click here to view the full file