You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

175 lines
5.6 KiB

35 years ago
35 years ago
35 years ago
35 years ago
35 years ago
35 years ago
35 years ago
35 years ago
  1. #! /usr/bin/env python
  2. # Read #define's and translate to Python code.
  3. # Handle #include statements.
  4. # Handle #define macros with one argument.
  5. # Anything that isn't recognized or doesn't translate into valid
  6. # Python is ignored.
  7. # Without filename arguments, acts as a filter.
  8. # If one or more filenames are given, output is written to corresponding
  9. # filenames in the local directory, translated to all uppercase, with
  10. # the extension replaced by ".py".
  11. # By passing one or more options of the form "-i regular_expression"
  12. # you can specify additional strings to be ignored. This is useful
  13. # e.g. to ignore casts to u_long: simply specify "-i '(u_long)'".
  14. # XXX To do:
  15. # - turn trailing C comments into Python comments
  16. # - turn C Boolean operators "&& || !" into Python "and or not"
  17. # - what to do about #if(def)?
  18. # - what to do about macros with multiple parameters?
  19. import sys, re, getopt, os
  20. p_define = re.compile('^[\t ]*#[\t ]*define[\t ]+([a-zA-Z0-9_]+)[\t ]+')
  21. p_macro = re.compile(
  22. '^[\t ]*#[\t ]*define[\t ]+'
  23. '([a-zA-Z0-9_]+)\(([_a-zA-Z][_a-zA-Z0-9]*)\)[\t ]+')
  24. p_include = re.compile('^[\t ]*#[\t ]*include[\t ]+<([a-zA-Z0-9_/\.]+)')
  25. p_comment = re.compile(r'/\*([^*]+|\*+[^/])*(\*+/)?')
  26. p_cpp_comment = re.compile('//.*')
  27. ignores = [p_comment, p_cpp_comment]
  28. p_char = re.compile(r"'(\\.[^\\]*|[^\\])'")
  29. p_hex = re.compile(r"0x([0-9a-fA-F]+)L?")
  30. filedict = {}
  31. importable = {}
  32. try:
  33. searchdirs=os.environ['include'].split(';')
  34. except KeyError:
  35. try:
  36. searchdirs=os.environ['INCLUDE'].split(';')
  37. except KeyError:
  38. try:
  39. if sys.platform.find("beos") == 0:
  40. searchdirs=os.environ['BEINCLUDES'].split(';')
  41. elif sys.platform.startswith("atheos"):
  42. searchdirs=os.environ['C_INCLUDE_PATH'].split(':')
  43. else:
  44. raise KeyError
  45. except KeyError:
  46. searchdirs=['/usr/include']
  47. def main():
  48. global filedict
  49. opts, args = getopt.getopt(sys.argv[1:], 'i:')
  50. for o, a in opts:
  51. if o == '-i':
  52. ignores.append(re.compile(a))
  53. if not args:
  54. args = ['-']
  55. for filename in args:
  56. if filename == '-':
  57. sys.stdout.write('# Generated by h2py from stdin\n')
  58. process(sys.stdin, sys.stdout)
  59. else:
  60. fp = open(filename, 'r')
  61. outfile = os.path.basename(filename)
  62. i = outfile.rfind('.')
  63. if i > 0: outfile = outfile[:i]
  64. modname = outfile.upper()
  65. outfile = modname + '.py'
  66. outfp = open(outfile, 'w')
  67. outfp.write('# Generated by h2py from %s\n' % filename)
  68. filedict = {}
  69. for dir in searchdirs:
  70. if filename[:len(dir)] == dir:
  71. filedict[filename[len(dir)+1:]] = None # no '/' trailing
  72. importable[filename[len(dir)+1:]] = modname
  73. break
  74. process(fp, outfp)
  75. outfp.close()
  76. fp.close()
  77. def pytify(body):
  78. # replace ignored patterns by spaces
  79. for p in ignores:
  80. body = p.sub(' ', body)
  81. # replace char literals by ord(...)
  82. body = p_char.sub("ord('\\1')", body)
  83. # Compute negative hexadecimal constants
  84. start = 0
  85. UMAX = 2*(sys.maxint+1)
  86. while 1:
  87. m = p_hex.search(body, start)
  88. if not m: break
  89. s,e = m.span()
  90. val = long(body[slice(*m.span(1))], 16)
  91. if val > sys.maxint:
  92. val -= UMAX
  93. body = body[:s] + "(" + str(val) + ")" + body[e:]
  94. start = s + 1
  95. return body
  96. def process(fp, outfp, env = {}):
  97. lineno = 0
  98. while 1:
  99. line = fp.readline()
  100. if not line: break
  101. lineno = lineno + 1
  102. match = p_define.match(line)
  103. if match:
  104. # gobble up continuation lines
  105. while line[-2:] == '\\\n':
  106. nextline = fp.readline()
  107. if not nextline: break
  108. lineno = lineno + 1
  109. line = line + nextline
  110. name = match.group(1)
  111. body = line[match.end():]
  112. body = pytify(body)
  113. ok = 0
  114. stmt = '%s = %s\n' % (name, body.strip())
  115. try:
  116. exec stmt in env
  117. except:
  118. sys.stderr.write('Skipping: %s' % stmt)
  119. else:
  120. outfp.write(stmt)
  121. match = p_macro.match(line)
  122. if match:
  123. macro, arg = match.group(1, 2)
  124. body = line[match.end():]
  125. body = pytify(body)
  126. stmt = 'def %s(%s): return %s\n' % (macro, arg, body)
  127. try:
  128. exec stmt in env
  129. except:
  130. sys.stderr.write('Skipping: %s' % stmt)
  131. else:
  132. outfp.write(stmt)
  133. match = p_include.match(line)
  134. if match:
  135. regs = match.regs
  136. a, b = regs[1]
  137. filename = line[a:b]
  138. if importable.has_key(filename):
  139. outfp.write('from %s import *\n' % importable[filename])
  140. elif not filedict.has_key(filename):
  141. filedict[filename] = None
  142. inclfp = None
  143. for dir in searchdirs:
  144. try:
  145. inclfp = open(dir + '/' + filename)
  146. break
  147. except IOError:
  148. pass
  149. if inclfp:
  150. outfp.write(
  151. '\n# Included from %s\n' % filename)
  152. process(inclfp, outfp, env)
  153. else:
  154. sys.stderr.write('Warning - could not find file %s\n' %
  155. filename)
  156. if __name__ == '__main__':
  157. main()