PageRenderTime 46ms CodeModel.GetById 16ms RepoModel.GetById 1ms app.codeStats 0ms

/Core/Dependencies/Havok/Tools/Serialize/havokDomClass/headerToDom.py

https://bitbucket.org/barakianc/nvidia-physx-and-apex-in-gge
Python | 679 lines | 614 code | 37 blank | 28 comment | 93 complexity | c775f75c181b78cb77127af2add9ed9e MD5 | raw file
  1. #
  2. # Confidential Information of Telekinesys Research Limited (t/a Havok). Not for disclosure or distribution without Havok's
  3. # prior written consent. This software contains code, techniques and know-how which is confidential and proprietary to Havok.
  4. # Level 2 and Level 3 source code contains trade secrets of Havok. Havok Software (C) Copyright 1999-2011 Telekinesys Research Limited t/a Havok. All Rights Reserved. Use of this software is subject to the terms of an end user license agreement.
  5. #
  6. #! /usr/bin/env python
  7. ###
  8. ### This script is used to extract an hkClass definition from a c++ header file.
  9. ###
  10. ### This script can be either be executed directly or imported
  11. ###
  12. import re
  13. import sys
  14. import hkcToDom
  15. import string
  16. import util
  17. def _readExtraTypes():
  18. import os
  19. fname = os.path.abspath( os.path.join( __file__, "..", "typeMapping.txt") )
  20. ret = {}
  21. try:
  22. for line in open(fname).read().split():
  23. key, value = [ x.strip() for x in line.split(":") ]
  24. ret[ key ] = value
  25. except IOError:
  26. pass
  27. return fname, ret
  28. extraTypesFile, globalTypeFromLocal = _readExtraTypes()
  29. def applyAttr(target, attrname, value):
  30. try:
  31. curval = getattr( target, attrname )
  32. except AttributeError:
  33. assert attrname.rsplit(".",1)[-1][0] in string.uppercase, "Misspelled attribute. If '%s' is a custom identifier, it must begin with upper case." % attrname
  34. target.attributes[attrname] = value
  35. else:
  36. if curval == None:
  37. newval = value
  38. elif type(curval) == bool:
  39. newval = value.strip().lower() in ["1", "true"]
  40. else:
  41. newval = type(curval)(value)
  42. setattr( target, attrname, newval )
  43. class TextMatcher:
  44. def __init__(self, name, rules):
  45. self.name = name
  46. self.rules = rules
  47. def run(self, txt):
  48. #print "*** %i '%s'"%( len(txt), txt[-10:])
  49. bestMatch = None
  50. bestRule = None
  51. for rule in self.rules:
  52. match = rule.search(txt)
  53. if match:
  54. if bestMatch==None or match.start() < bestMatch.start():
  55. bestMatch = match
  56. bestRule = rule
  57. if bestMatch == None:
  58. return None, None
  59. matchRange = bestMatch.span()
  60. skipped = txt[:matchRange[0]].strip()
  61. if len(skipped):
  62. print >>sys.stderr, "-- When parsing '%s' UNPARSED '%s' at '%s...'" % (self.name, skipped, txt[:100])
  63. return bestRule, bestMatch
  64. def killwhitespace(s):
  65. return s.replace("\t","").replace("\n","").replace("\r","").replace(" ","")
  66. class CppParser:
  67. re_commentAttribute = re.compile( r"//\s*(\+.+)" )
  68. re_docsComment = re.compile( "^(\s*///.*\n)+", re.M )
  69. re_cComment = re.compile( r"/\*[^*]*\*+([^/*][^*]*\*+)*/" )
  70. re_cppComment = re.compile( r"\s*//.*" )
  71. re_whitespace = re.compile( r"\s+" )
  72. re_whitespaceInArray = re.compile(r"\s*\[\s*(\S+)\s*\]")
  73. re_constInDecl = re.compile(r"\s*\bconst\b\s*")
  74. re_preproc = re.compile( r"\s*#\s*(pragma|error|undef|define|ifdef|ifndef|if|elif|else|endif).*")
  75. re_classAlign = re.compile( r"HK_CLASSALIGN(?:\d*)\s*\(([^,)]+)(?:,\s*\d+\s*)?\s*\)")
  76. re_align = re.compile( r"HK_ALIGN(\d*)\s*\(([^,\)]+)(?:,\s*(\d+)\s*)?\s*\)\s*;")
  77. re_substmacros = re.compile( r"\s*(HKP_SHAPE_VIRTUAL_CONST|HKP_SHAPE_VIRTUAL_THIS|HKP_SHAPE_VIRTUAL|HCL_SHAPE_VIRTUAL)\s*" ) ### macros to substitude
  78. re_refPtr = re.compile( r"hkRefPtr<\s*([^>]+)\s*>" )
  79. re_refVariant = re.compile( r"([\s*<])hkRefVariant([\s*>])" )
  80. re_junkymacros = re.compile( r"\s*HK_(CPU_PTR|PAD_ON_SPU|THREAD_LOCAL|INIT_FUNCTION)\((.*?)\)" ) ### leave group(2) in place
  81. re_memDeclaration = re.compile(r"\s*((HK_DECLARE_(CLASS|NONVIRTUAL_CLASS|SYSTEM)_ALLOCATOR)[^\s\(]*)", re.M)
  82. re_overideDestination = re.compile(r'^\s*HK_REFLECTION_CLASSFILE_DESTINATION\s*\(\s*"([^"]*)"\s*\)\s*;', re.M)
  83. re_classStart = re.compile( r"(?P<type>struct|class)\s+(?P<namespace>(::)?(\w+::)*)(?P<name>\w+)(\s*:(?!:)\s*(?P<parents>[^;{]+))?\s*(?P<decltype>[{;])" )
  84. re_enumStart = re.compile( r"enum\s*(?P<name>\w*)\s*(?P<decltype>[{;])" )
  85. re_unionStart = re.compile( r"union\s*(?P<name>\w*)\s*(?P<decltype>[{;])" )
  86. re_namespaceStart = re.compile( r"namespace\s*(?P<name>\w*)\s*(?P<decltype>[{;])" )
  87. re_taggedUnionStart = re.compile( r"hkTaggedUnion\s*(?P<name>\w*)\s*(?P<decltype>[{;])" )
  88. re_typedef = re.compile( r"typedef\s*[^;]+;" )
  89. re_attributesPlaceholder = re.compile( r"\001ATT([^\002]+)\002;" )
  90. re_attributes = re.compile(r"\+([\w\.]+)(?:\(([^\)]+)\))?")
  91. re_externVariable = re.compile( r"((extern|static)\s+)?(const\s+)?((class|struct)\s+)?(?P<type>[\w\*]+)\s+(?P<name>\w+)\s*(?P<value>=[^;]+)?;" )
  92. re_functionDefinition = re.compile( r"(?P<method>[\w~][^;\(]+)\s*\((?P<params>[^\)]*)\)\s*(?P<qualifiers>[^{;]*)(?P<decltype>[{;])" )
  93. re_spuriousSemicolon = re.compile( "^\s*;" )
  94. re_externCstart = re.compile( r"extern\s*\"C\"\s+[^{;]*(?P<decltype>[{;])" )
  95. re_hashInclude = re.compile( r'#\s*include\s*["<](?P<path>[^">]+)[>"]' )
  96. re_templateStart = re.compile( r"template\s*<" )
  97. re_enumItem = re.compile( r"(?P<name>\w+)\s*(=\s*(?P<value>[^\s,]+))?,?" )
  98. re_taggedUnionItem = re.compile( r"hkTaggedUnionItem\s*\(\s*(?P<name>\w+)\s*(=\s*(?P<value>[^\s,]+)\s*)?,\s*(?P<class>[^\s\)]+)\s*\)\s*,?" )
  99. re_accessControl = re.compile( r"(public|protected|private):" )
  100. re_classMethod = re.compile( r"(?P<method>[\w~][^;\(]+)\s*\((?P<params>[^\)]*)\)\s*(?P<qualifiers>[^\]{;]*)(?P<decltype>[{;])" )
  101. re_classMember = re.compile( r"(?P<member>\w[^{;\(]+);" )
  102. re_functionPointer = re.compile( r"\([^\*]*\*[^\)]+\)\s*\([^\)]*\)" )
  103. def __init__(self):
  104. self.debug = lambda x : sys.stdout.write(x+"\n")
  105. self.debug = lambda x : None
  106. self.globalMatcher = TextMatcher( "global", [
  107. self.re_overideDestination,
  108. self.re_templateStart,
  109. self.re_hashInclude,
  110. self.re_classStart,
  111. self.re_enumStart,
  112. self.re_unionStart,
  113. self.re_namespaceStart,
  114. self.re_taggedUnionStart,
  115. self.re_externCstart,
  116. self.re_typedef,
  117. self.re_externVariable,
  118. self.re_functionDefinition,
  119. self.re_attributesPlaceholder,
  120. self.re_spuriousSemicolon,
  121. ] )
  122. self.classMatcher = TextMatcher( "class", [
  123. self.re_accessControl,
  124. self.re_classStart,
  125. self.re_enumStart,
  126. self.re_unionStart,
  127. self.re_typedef,
  128. self.re_attributesPlaceholder,
  129. self.re_classMethod,
  130. self.re_classMember,
  131. self.re_spuriousSemicolon,
  132. ] )
  133. self.enumMatcher = TextMatcher( "enum", [
  134. self.re_attributesPlaceholder,
  135. self.re_enumItem,
  136. ] )
  137. self.taggedUnionMatcher = TextMatcher( "tagged", [
  138. self.re_taggedUnionItem,
  139. ] )
  140. self.current_filename = None
  141. def findEndBrace(self, txt, start, braces="{}"):
  142. cur = start
  143. lparens = 1
  144. while lparens:
  145. rp = txt.index(braces[1], cur)
  146. lparens -= 1
  147. lparens += txt[cur:rp].count(braces[0])
  148. cur = rp+1
  149. return cur
  150. def warn(self, match, txt):
  151. span = match.span()
  152. self.debug( "WARN (%s) (%s)" % (txt[:span[0]], txt[span[0]:span[1]]) )
  153. def location_of(self, what):
  154. if self.current_filename:
  155. txt = open(self.current_filename).read()
  156. try:
  157. if isinstance(what, basestring):
  158. cidx = txt.find(what)
  159. else:
  160. cidx = what.search(txt).start() + 1
  161. except:
  162. cidx = 0 # failsafe
  163. return "%s:%i" % (self.current_filename, txt[:cidx].count("\n") + 1)
  164. else:
  165. return "unknown_location:0"
  166. def parseAccessControl(self, match, txt):
  167. self.debug("ACCESS %s"% match.group())
  168. def _parseEnumOrTaggedUnion(self, match, txt, Defn, Item, Matcher):
  169. if match.group("decltype") == "{":
  170. self.debug("%s(%s)" % (Defn.__name__.upper(), match.group()))
  171. name = match.group("name")
  172. span = match.span()
  173. defnEnd = self.findEndBrace(txt, span[1] )
  174. if name:
  175. defn = Defn()
  176. defn.name = name
  177. body = txt[span[1]:defnEnd-1]
  178. seen_values = {}
  179. while 1:
  180. item, match = Matcher.run( body )
  181. if match == None:
  182. break
  183. elif item == self.re_attributesPlaceholder:
  184. newbody, attrs = self.parseAttributes(match, body)
  185. for k,v in attrs:
  186. applyAttr(defn, k, v)
  187. elif item in [ self.re_enumItem, self.re_taggedUnionItem ]:
  188. i = Item()
  189. i.name = match.group("name")
  190. i.initializer = match.group("value")
  191. try: i.klass = match.group("class")
  192. except IndexError: pass
  193. if i.initializer == None:
  194. if len(defn.item):
  195. i.value = defn.item[-1].value + 1
  196. else:
  197. i.value = 0
  198. else:
  199. try: i.value = int( eval( i.initializer, seen_values ) )
  200. except (SyntaxError, NameError):
  201. i.value = 0 ### This is only for non-reflected enums
  202. print >>sys.stderr, "---------------UNPARSED '%s' in '%s'" % (i.initializer,body)
  203. seen_values[i.name] = i.value
  204. defn.item.append(i)
  205. self.debug("%s(%s)"% (Item.__name__.upper(), hkcToDom.slot_values_as_keywords(i)) )
  206. else:
  207. self.debug("NO_ACTION %s %s"% (match.group(), item))
  208. oldBodyLength = len(body)
  209. body = body[match.span()[1]:]
  210. if len(body) >= oldBodyLength:
  211. raise ("*** Breaking from infinite loop ***\n" \
  212. "While parsing '%s'\n" \
  213. "'%s'" % (defn.name, body) )
  214. return txt[defnEnd:], defn
  215. return txt[defnEnd:], None
  216. return None, None
  217. def parseEnum(self, match, txt):
  218. return self._parseEnumOrTaggedUnion(match, txt, hkcToDom.Enum, hkcToDom.EnumItem, self.enumMatcher)
  219. def parseTaggedUnion(self, match, txt):
  220. return self._parseEnumOrTaggedUnion(match, txt, hkcToDom.TaggedUnion, hkcToDom.TaggedUnionItem, self.taggedUnionMatcher)
  221. def parseUnion(self, match, txt):
  222. if match.group("decltype") == "{":
  223. self.debug("UNION %s"% match.group())
  224. span = match.span()
  225. end = self.findEndBrace(txt, span[1] )
  226. return txt[end:], None
  227. return None, None
  228. def parseAttributes(self, match, txt):
  229. self.debug("ATTRIBUTES %s"% match.group(1))
  230. return None, self.re_attributes.findall(match.group())
  231. def parseExternC(self, match, txt):
  232. if match.group("decltype") == "{":
  233. span = match.span()
  234. end = self.findEndBrace(txt, span[1] )
  235. return txt[end:], None
  236. return None, None
  237. def parseNamespace(self, match, txt):
  238. if match.group("decltype") == "{":
  239. span = match.span()
  240. brace = self.findEndBrace(txt, span[1] ) - 1
  241. return txt[span[1]:brace] + txt[brace+1:], None # remove matching }
  242. #return txt[end:], None # ignore namespace block
  243. return None, None
  244. def parseFunction(self, match, txt):
  245. if match.group("decltype") == "{":
  246. span = match.span()
  247. end = self.findEndBrace(txt, span[1] )
  248. return txt[end:], None
  249. return None, None
  250. def parseClass(self, match, txt, declaredscope):
  251. if match.group("decltype") == "{":
  252. self.debug("CLASS (%s) (%s) (%s) (%s)" % (match.group("type"), match.group("namespace"), match.group("name"), match.group("parents")))
  253. span = match.span()
  254. classEnd = self.findEndBrace(txt, span[1] )
  255. klass = hkcToDom.Class()
  256. klass.scope = declaredscope
  257. klass.fromheader = 1
  258. klass.name = match.group("name")
  259. parents = match.group("parents")
  260. if parents:
  261. getparentname = lambda x : x[len(x) > 1 and 1 or 0]
  262. parents = [getparentname(x.split()).split("<")[0].strip() for x in parents.split(",")]
  263. klass.parent = parents[0]
  264. for iname in parents[1:]:
  265. ic = hkcToDom.Interface()
  266. ic.name = iname
  267. klass.interface.append( ic )
  268. body = txt[span[1]:classEnd-1]
  269. if match.group("type") == "class":
  270. currentAccess = "private"
  271. else:
  272. currentAccess = "public"
  273. def appendMember(mname, mtype, mvis, msrc, mflags=""):
  274. assert len(mname)
  275. if len(mtype) == 0:
  276. print >>sys.stderr, "Error: MISSING STRING AFTER '%s'" % (mname)
  277. assert len(mtype)
  278. if klass.reflected:
  279. assert mname.startswith(klass.memberprefix), "Member '%s::%s' does not start with '%s'\n" \
  280. "Either add the prefix or add a //+memberprefix declaration to the class" % (
  281. klass.name, mname, klass.memberprefix)
  282. if mname.startswith(klass.memberprefix):
  283. mname = mname[len(klass.memberprefix):]
  284. # check for synthetic member types
  285. if len(klass.member) >= 1:
  286. prev = klass.member[-1]
  287. prev2 = klass.member[-2] if len(klass.member) >= 2 else None
  288. if mname.startswith("num") and mname[3:].lower() == prev.name.lower():
  289. errPrefix = "%s::%s " % (klass.name, mname)
  290. if prev2 and prev2.name.startswith(prev.name) and prev2.name.endswith("Class"):
  291. assert prev.type == "void*"
  292. assert prev2.type == "hkClass*"
  293. prev2.name = prev.name
  294. prev2.type = "hkHomogeneousArray"
  295. assert prev2.visibility == mvis and prev.visibility == mvis, errPrefix + "homogeneous parts have differing visibility"
  296. assert prev2.flags == "" and prev.flags == "", errPrefix + "homogeneous array attributes should go on last member"
  297. prev2.flags = mflags
  298. prev2.sourcecode += prev.sourcecode + msrc
  299. klass.member.pop()
  300. return
  301. elif prev.type.endswith("*"):
  302. prev.type = "hkSimpleArray<%s>" % prev.type.rsplit("*",1)[0].rstrip()
  303. assert prev.visibility == mvis, errPrefix + "simplearray parts have differing visibility"
  304. assert prev.flags == "", errPrefix + "simplearray attributes should apply to last member"
  305. prev.flags = mflags
  306. prev.sourcecode += msrc
  307. return
  308. elif mname.endswith("Class") and prev.name==mname[:-5] \
  309. and mtype=="hkClass*" and prev.type=="void*":
  310. prev.type = "hkVariant"
  311. return
  312. member = hkcToDom.Member()
  313. member.name = mname
  314. member.type = mtype
  315. member.visibility = mvis
  316. member.flags = mflags
  317. member.sourcecode = msrc
  318. klass.member.append(member)
  319. def appendMethod(mtxt, parameters, qualifiers, visibility):
  320. if 0 not in [ mtxt.find(ignore) == -1 for ignore in "HK_DECLARE HK_ALIGN HK_SPU_VIRTUAL_DECLSPEC".split() ]:
  321. def extract(txt, reg):
  322. out = re.sub(reg, "", txt)
  323. return out, txt!=out
  324. method = hkcToDom.Method()
  325. method.description = "%s(%s)%s" % (mtxt,parameters,qualifiers)
  326. method.visibility = visibility
  327. mtxt, method.inline = extract(mtxt, r"\b(inline|HK_FORCE_INLINE)\b")
  328. mtxt, method.virtual = extract(mtxt, r"\bvirtual\b")
  329. mtxt, method.static = extract(mtxt, r"\bstatic\b")
  330. mtxt, constness = extract(mtxt, r"\b(const|explicit)\b")
  331. qualifiers, method.const = extract(qualifiers, r"\bconst\b")
  332. qualifiers, method.purevirtual = extract(qualifiers, "=\s*0")
  333. qualifiers, initializers = extract(qualifiers, r"([:,]\s*\w+\s*\([^\)]*\))+")
  334. if qualifiers.replace(")","").strip() != "":
  335. print >>sys.stderr, "---------------UNPARSED '%s' in '%s'" % (qualifiers,mtxt)
  336. method.name = mtxt.split()[-1]
  337. if killwhitespace(parameters):
  338. for i, x in enumerate(parameters.split(",")):
  339. param = hkcToDom.Parameter()
  340. param.description = x
  341. valuelist = x.split("=")
  342. if len(valuelist) == 2:
  343. param.default = valuelist[-1].lstrip()
  344. plist = valuelist[0].split()
  345. if len([v for v in plist if v != "const"]) > 1 \
  346. and plist[-1] not in [">", "*", "&"]:
  347. param.name = plist[-1]
  348. param.type = " ".join(v for v in plist[:-1] if v != "const")
  349. else:
  350. param.type = " ".join(v for v in plist if v != "const")
  351. param.name = "noname_"+str(i)
  352. method.parameter.append(param)
  353. if klass.name == method.name:
  354. self.debug("CONSTRUCTOR(%s,%s)" % (method.name, parameters))
  355. assert len(mtxt.split()) == 1
  356. klass.method.append( method )
  357. elif "~"+klass.name == method.name:
  358. self.debug("DESTRUCTOR(%s)" % (method.name))
  359. assert len(mtxt.split()) == 1
  360. assert len(method.parameter) == 0
  361. else:
  362. method.returns = " ".join( mtxt.split()[:-1] )
  363. self.debug("METHOD(%s,%s::%s,%s)" % (method.returns, klass.name, method.name, parameters))
  364. klass.method.append( method )
  365. lastParsed = None
  366. while 1:
  367. item, match = self.classMatcher.run(body)
  368. if match == None:
  369. break
  370. newbody = None
  371. if item == self.re_accessControl:
  372. currentAccess = match.group(1)
  373. item = lastParsed # don't affect lastParsed
  374. elif item == self.re_classStart:
  375. newbody, k = self.parseClass(match, body, klass)
  376. if k:
  377. klass._class.append(k)
  378. elif item == self.re_enumStart:
  379. newbody, enum = self.parseEnum(match, body)
  380. if enum:
  381. enum.scope = klass
  382. klass.enum.append(enum)
  383. elif item == self.re_unionStart:
  384. newbody, union = self.parseUnion(match, body)
  385. elif item == self.re_attributesPlaceholder:
  386. newbody, attrs = self.parseAttributes(match, body)
  387. if lastParsed == None:
  388. target = klass
  389. elif lastParsed == self.re_classMember:
  390. if klass.member:
  391. target = klass.member[-1]
  392. else:
  393. target = None
  394. elif lastParsed == self.re_typedef:
  395. target = None # ignore attrs on typedefs for now
  396. else:
  397. raise "Unhandled case for attributes, don't know how to apply '%s' to previous item in '%s'" % (attrs, klass.name)
  398. if target:
  399. nosaveflag = False # apply nosave at end
  400. for k,v in attrs:
  401. if k=="nosave":
  402. target.serialized = False
  403. nosaveflag = True
  404. else:
  405. applyAttr(target, k, v)
  406. if nosaveflag:
  407. t = target.overridetype or target.type
  408. if t.endswith("*"):
  409. target.overridetype = "void*"
  410. else:
  411. partial = re.match("(hkArray|hkSimpleArray|hkEnum|hkFlags)\s*<\s*([^>,]+)\s*(,[^>]+)?\s*>", t)
  412. if partial:
  413. stem, c, sz = partial.groups()
  414. target.overridetype = stem + ("<void*" if c.strip().endswith("*") else "<void") + (sz or "") + ">"
  415. item = lastParsed # don't affect lastParsed
  416. elif item == self.re_classMethod:
  417. span = match.span()
  418. # actually a function pointer
  419. if self.re_functionPointer.search(match.group()):
  420. mtype = "void*"
  421. mname = match.group().split("(")[1].split("*")[1].split(")")[0].split()[-1]
  422. self.debug("MEMBER (%s)" % match.group())
  423. appendMember(mname, mtype, currentAccess, match.group() )
  424. if util.hasReflectionDeclaration(match.group()):
  425. self.debug(match.group())
  426. klass.reflected = True
  427. elif self.re_memDeclaration.search(match.group()):
  428. assert 0, "Memory declaration macros should be expanded at this point"
  429. klass.memory_declaration = (currentAccess, match.group())
  430. self.debug("%s (%s)" % (match.group(), currentAccess))
  431. else:
  432. if not klass.abstract and killwhitespace(match.group("qualifiers")).find("=0") != -1:
  433. self.debug("ABSTRACT")
  434. klass.abstract = True
  435. elif not klass.vtable and "virtual" in match.group().split():
  436. self.debug("VIRTUAL")
  437. klass.vtable = True
  438. appendMethod(match.group("method"), match.group("params"), match.group("qualifiers"), currentAccess )
  439. if match.group("decltype") == "{":
  440. methodEnd = self.findEndBrace(body, span[1] )
  441. newbody = body[methodEnd:]
  442. elif item == self.re_classMember:
  443. bits = self.re_constInDecl.sub(" ", match.group().rstrip(";"))
  444. bits = self.re_whitespaceInArray.sub(r"[\1]", bits)
  445. bits = re.sub("\s*\*\s*", "* ", bits).split()
  446. if bits[0] not in ("friend", "static", "typedef"):
  447. mtype, mname = " ".join(bits[:-1]), bits[-1]
  448. k = klass #todo: should lookup parent first, but often don't have definition
  449. while k: # look at enclosing scopes too
  450. mtype = k.typedef.get(mtype, mtype)
  451. k = k.scope
  452. mflags = ""
  453. if bits[0] == "enum":
  454. print "%s:Implicitly sized enum is not portable (%s). Use hkEnum<> instead." % (self.location_of(re.compile("^\s*enum[^;]*"+bits[2],re.M)), " ".join(bits))
  455. arrayBegin = mname.find("[")
  456. if arrayBegin != -1:
  457. mtype += mname[arrayBegin:]
  458. mname = mname[:arrayBegin]
  459. self.debug("MEMBER (%s)" % match.group())
  460. appendMember(mname, mtype, currentAccess, match.group(), mflags)
  461. elif item == self.re_typedef:
  462. bits = [b for b in match.group()[:-1].split(" ") if b]
  463. klass.typedef[bits[-1]] = " ".join(bits[1:-1])
  464. elif item == self.re_spuriousSemicolon:
  465. pass
  466. else:
  467. self.debug("NO_ACTION %s %s"% (match.group(), item))
  468. lastParsed = item
  469. oldBodyLength = len(body)
  470. if newbody:
  471. body = newbody
  472. else:
  473. body = body[match.span()[1]:]
  474. if len(body) >= oldBodyLength:
  475. raise ("*** Breaking from infinite loop ***\n" \
  476. "While parsing '%s'\n" \
  477. "'%s'" % (klass.name, body) )
  478. return txt[classEnd:], klass
  479. else:
  480. self.debug("FORWARD (%s) (%s) (%s) (%s)" % (match.group("type"), match.group("namespace"), match.group("name"), match.group("parents")))
  481. return None, None
  482. def parseTemplate(self, match, txt):
  483. span = match.span()
  484. end = self.findEndBrace(txt, span[1], "<>")
  485. tend = len(txt)
  486. decl = txt.find(";", end)
  487. if decl != -1 and decl < tend:
  488. tend = decl
  489. defn = txt.find("{", end)
  490. if defn != -1 and defn < tend:
  491. classdecl = txt[end:defn].split(":")[0] # get class declaration and cut inheritance declaration
  492. if classdecl.find("<") == -1 and classdecl.find(">") == -1:
  493. ### just skip "template" and let to process found class as normal
  494. #print "---CHECK:",txt[end:defn]
  495. return txt[end:], None
  496. self.debug("TEMPLATE %s" % txt[:defn])
  497. tend = self.findEndBrace(txt, defn+1 )
  498. else:
  499. self.debug("TEMPLATE %s" % txt[:decl])
  500. return txt[tend:], None
  501. def parseString(self, txt):
  502. document = hkcToDom.Document(self.current_filename)
  503. document.file = hkcToDom.File()
  504. for key, value in util.extract_tkbms(txt).items():
  505. setattr(document.file,key,value)
  506. txt = self.re_classAlign.sub(r"\1", txt) # HK_CLASSALIGN(class,8) -> class
  507. def do_align(match):
  508. return "%s; //+align(%s)\n" % (match.group(2), match.group(1) or match.group(3))
  509. txt = self.re_align.sub(do_align, txt) # HK_ALIGN(int foo,8); -> int foo; //+align(8)
  510. txt = re.sub("(?m)^\s*$\n","",txt) # delete blank lines
  511. def docstring_join(match):
  512. s,e = match.span()
  513. lines = match.string[s:e].split("\n")[:-1]
  514. lines = ( l[l.index("///")+3:].strip() for l in lines )
  515. return '//@hk.DocString("%s")\n' % " ".join(lines)
  516. # txt = self.re_docsComment.sub(docstring_join, txt) # join adjacent docstring lines
  517. txt = self.re_commentAttribute.sub(r"\001ATT\1\002;", txt) # save attributes, use unused char delimeters
  518. txt = self.re_cComment.sub("", txt) # remove c comments
  519. txt = self.re_cppComment.sub("", txt) # c++ comments too
  520. txt = txt.replace("\\\n", " ") # do preproc line joining
  521. txt = self.re_preproc.sub("", txt) # remove preprocessor
  522. txt = self.re_whitespace.sub(" ", txt) # and all whitespace
  523. def do_hkp_macros(match):
  524. substmacros = { "HCL_SHAPE_VIRTUAL": " virtual ",
  525. "HKP_SHAPE_VIRTUAL": " virtual ",
  526. "HKP_SHAPE_VIRTUAL_CONST": " const ",
  527. "HKP_SHAPE_VIRTUAL_THIS" : " "
  528. }
  529. return substmacros[match.group(1)]
  530. txt = self.re_refPtr.sub(r"\1*", txt) # hkRefPtr<T> -> T*
  531. txt = self.re_refVariant.sub(r"\1hkReferencedObject*\2", txt) # hkRefVariant -> hkReferencedObject*
  532. txt = self.re_substmacros.sub(do_hkp_macros, txt) # substitude HKP_SHAPE_VIRTUAL, HKP_SHAPE_VIRTUAL_CONST and HKP_SHAPE_VIRTUAL_THIS macros
  533. txt = self.re_junkymacros.sub(r"\2 ", txt) # remove HK_CPU_PTR(\2), HK_PAD_ON_SPU(\2) and HK_THREAD_LOCAL(\2) macros
  534. while 1:
  535. item, match = self.globalMatcher.run(txt)
  536. if match == None:
  537. break
  538. newtxt = None
  539. if item == self.re_overideDestination:
  540. document.file.overridedestination = match.group(1)
  541. elif item == self.re_templateStart:
  542. newtxt, junk = self.parseTemplate(match, txt)
  543. elif item == self.re_hashInclude:
  544. self.debug("INCLUDE %s"% match.group("path"))
  545. document.file.includeheaders += "#include <%s>\n" % match.group("path")
  546. elif item == self.re_classStart:
  547. newtxt, klass = self.parseClass(match, txt, None)
  548. if klass:
  549. document.file._class.append(klass)
  550. elif item == self.re_enumStart:
  551. newtxt, enum = self.parseEnum(match, txt)
  552. if enum:
  553. document.file.enum.append(enum)
  554. elif item == self.re_unionStart:
  555. newtxt, union = self.parseUnion(match, txt)
  556. elif item == self.re_namespaceStart:
  557. newtxt, junk = self.parseNamespace(match, txt)
  558. elif item == self.re_taggedUnionStart:
  559. newtxt, union = self.parseTaggedUnion(match, txt)
  560. if union:
  561. document.file.taggedunion.append(union)
  562. elif item == self.re_externCstart:
  563. newtxt, junk = self.parseExternC(match, txt)
  564. elif item == self.re_typedef:
  565. pass
  566. elif item == self.re_externVariable:
  567. pass
  568. elif item == self.re_functionDefinition:
  569. newtxt, junk = self.parseFunction(match, txt)
  570. elif item == self.re_attributesPlaceholder:
  571. pass # ignore attributes on e.g typedef or global
  572. elif item == self.re_spuriousSemicolon:
  573. pass
  574. else:
  575. print "NO_ACTION", match.group(), item
  576. print "***", txt
  577. oldTxtLength = len(txt)
  578. if newtxt:
  579. txt = newtxt
  580. else:
  581. txt = txt[match.span()[1]:]
  582. if len(txt) >= oldTxtLength:
  583. raise ("*** Breaking from infinite loop ***\n" \
  584. "While parsing '%s'\n" \
  585. "'%s'" % (self.current_filename, txt) )
  586. return document
  587. def parseFile(self, filename):
  588. self.debug("*************************\n*** %s\n*************************" % filename)
  589. self.current_filename = filename
  590. txt = open(filename).read()
  591. document = self.parseString(txt)
  592. self.current_filename = None
  593. return document
  594. def headerToDom(filename):
  595. return CppParser().parseFile( filename )
  596. def usage():
  597. import os
  598. print 'Usage: %s <filename.h>\n' % os.path.basename(sys.argv[0])
  599. print 'Generate a class dom from the specified header file'
  600. print 'Options:'
  601. print ' -h --help print this help text'
  602. def main():
  603. args = sys.argv[1:]
  604. if ("-h" in args) or ("--help" in args):
  605. usage()
  606. sys.exit(0)
  607. if len(args) < 1:
  608. usage()
  609. sys.exit(1)
  610. for arg in args:
  611. document = CppParser().parseFile( arg )
  612. import bindingToXml
  613. print bindingToXml.bindingToXml("doc", document)
  614. if __name__=="__main__":
  615. main()
  616. #
  617. # Havok SDK - NO SOURCE PC DOWNLOAD, BUILD(#20110914)
  618. #
  619. # Confidential Information of Havok. (C) Copyright 1999-2011
  620. # Telekinesys Research Limited t/a Havok. All Rights Reserved. The Havok
  621. # Logo, and the Havok buzzsaw logo are trademarks of Havok. Title, ownership
  622. # rights, and intellectual property rights in the Havok software remain in
  623. # Havok and/or its suppliers.
  624. #
  625. # Use of this software for evaluation purposes is subject to and indicates
  626. # acceptance of the End User licence Agreement for this product. A copy of
  627. # the license is included with this software and is also available at www.havok.com/tryhavok.
  628. #
  629. #