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.

172 lines
5.5 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 python3
  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. searchdirs=['/usr/include']
  39. try:
  40. searchdirs.insert(0, os.path.join('/usr/include',
  41. os.environ['MULTIARCH']))
  42. except KeyError:
  43. pass
  44. def main():
  45. global filedict
  46. opts, args = getopt.getopt(sys.argv[1:], 'i:')
  47. for o, a in opts:
  48. if o == '-i':
  49. ignores.append(re.compile(a))
  50. if not args:
  51. args = ['-']
  52. for filename in args:
  53. if filename == '-':
  54. sys.stdout.write('# Generated by h2py from stdin\n')
  55. process(sys.stdin, sys.stdout)
  56. else:
  57. fp = open(filename, 'r')
  58. outfile = os.path.basename(filename)
  59. i = outfile.rfind('.')
  60. if i > 0: outfile = outfile[:i]
  61. modname = outfile.upper()
  62. outfile = modname + '.py'
  63. outfp = open(outfile, 'w')
  64. outfp.write('# Generated by h2py from %s\n' % filename)
  65. filedict = {}
  66. for dir in searchdirs:
  67. if filename[:len(dir)] == dir:
  68. filedict[filename[len(dir)+1:]] = None # no '/' trailing
  69. importable[filename[len(dir)+1:]] = modname
  70. break
  71. process(fp, outfp)
  72. outfp.close()
  73. fp.close()
  74. def pytify(body):
  75. # replace ignored patterns by spaces
  76. for p in ignores:
  77. body = p.sub(' ', body)
  78. # replace char literals by ord(...)
  79. body = p_char.sub("ord('\\1')", body)
  80. # Compute negative hexadecimal constants
  81. start = 0
  82. UMAX = 2*(sys.maxsize+1)
  83. while 1:
  84. m = p_hex.search(body, start)
  85. if not m: break
  86. s,e = m.span()
  87. val = int(body[slice(*m.span(1))], 16)
  88. if val > sys.maxsize:
  89. val -= UMAX
  90. body = body[:s] + "(" + str(val) + ")" + body[e:]
  91. start = s + 1
  92. return body
  93. def process(fp, outfp, env = {}):
  94. lineno = 0
  95. while 1:
  96. line = fp.readline()
  97. if not line: break
  98. lineno = lineno + 1
  99. match = p_define.match(line)
  100. if match:
  101. # gobble up continuation lines
  102. while line[-2:] == '\\\n':
  103. nextline = fp.readline()
  104. if not nextline: break
  105. lineno = lineno + 1
  106. line = line + nextline
  107. name = match.group(1)
  108. body = line[match.end():]
  109. body = pytify(body)
  110. ok = 0
  111. stmt = '%s = %s\n' % (name, body.strip())
  112. try:
  113. exec(stmt, env)
  114. except:
  115. sys.stderr.write('Skipping: %s' % stmt)
  116. else:
  117. outfp.write(stmt)
  118. match = p_macro.match(line)
  119. if match:
  120. macro, arg = match.group(1, 2)
  121. body = line[match.end():]
  122. body = pytify(body)
  123. stmt = 'def %s(%s): return %s\n' % (macro, arg, body)
  124. try:
  125. exec(stmt, env)
  126. except:
  127. sys.stderr.write('Skipping: %s' % stmt)
  128. else:
  129. outfp.write(stmt)
  130. match = p_include.match(line)
  131. if match:
  132. regs = match.regs
  133. a, b = regs[1]
  134. filename = line[a:b]
  135. if filename in importable:
  136. outfp.write('from %s import *\n' % importable[filename])
  137. elif filename not in filedict:
  138. filedict[filename] = None
  139. inclfp = None
  140. for dir in searchdirs:
  141. try:
  142. inclfp = open(dir + '/' + filename)
  143. break
  144. except IOError:
  145. pass
  146. if inclfp:
  147. outfp.write(
  148. '\n# Included from %s\n' % filename)
  149. process(inclfp, outfp, env)
  150. else:
  151. sys.stderr.write('Warning - could not find file %s\n' %
  152. filename)
  153. if __name__ == '__main__':
  154. main()