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.

167 lines
5.3 KiB

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