Benjamin Peterson | 90f5ba5 | 2010-03-11 22:53:45 +0000 | [diff] [blame] | 1 | #! /usr/bin/env python3 |
Guido van Rossum | 2ba9f30 | 1992-03-02 16:20:32 +0000 | [diff] [blame] | 2 | |
Guido van Rossum | 07c9645 | 1994-10-03 16:45:35 +0000 | [diff] [blame] | 3 | # Read #define's and translate to Python code. |
| 4 | # Handle #include statements. |
| 5 | # Handle #define macros with one argument. |
| 6 | # Anything that isn't recognized or doesn't translate into valid |
| 7 | # Python is ignored. |
| 8 | |
| 9 | # Without filename arguments, acts as a filter. |
Guido van Rossum | 09336f9 | 1994-05-03 14:37:30 +0000 | [diff] [blame] | 10 | # If one or more filenames are given, output is written to corresponding |
| 11 | # filenames in the local directory, translated to all uppercase, with |
| 12 | # the extension replaced by ".py". |
Guido van Rossum | 07c9645 | 1994-10-03 16:45:35 +0000 | [diff] [blame] | 13 | |
Guido van Rossum | 01f5f62 | 1994-05-17 09:05:54 +0000 | [diff] [blame] | 14 | # By passing one or more options of the form "-i regular_expression" |
| 15 | # you can specify additional strings to be ignored. This is useful |
| 16 | # e.g. to ignore casts to u_long: simply specify "-i '(u_long)'". |
Guido van Rossum | 2ba9f30 | 1992-03-02 16:20:32 +0000 | [diff] [blame] | 17 | |
| 18 | # XXX To do: |
Guido van Rossum | 2ba9f30 | 1992-03-02 16:20:32 +0000 | [diff] [blame] | 19 | # - turn trailing C comments into Python comments |
Guido van Rossum | 2ba9f30 | 1992-03-02 16:20:32 +0000 | [diff] [blame] | 20 | # - turn C Boolean operators "&& || !" into Python "and or not" |
| 21 | # - what to do about #if(def)? |
Guido van Rossum | 07c9645 | 1994-10-03 16:45:35 +0000 | [diff] [blame] | 22 | # - what to do about macros with multiple parameters? |
Guido van Rossum | 2ba9f30 | 1992-03-02 16:20:32 +0000 | [diff] [blame] | 23 | |
Martin v. Löwis | 4f85bf3 | 2001-08-09 12:24:38 +0000 | [diff] [blame] | 24 | import sys, re, getopt, os |
Guido van Rossum | 2ba9f30 | 1992-03-02 16:20:32 +0000 | [diff] [blame] | 25 | |
Martin v. Löwis | 4f85bf3 | 2001-08-09 12:24:38 +0000 | [diff] [blame] | 26 | p_define = re.compile('^[\t ]*#[\t ]*define[\t ]+([a-zA-Z0-9_]+)[\t ]+') |
Guido van Rossum | 2ba9f30 | 1992-03-02 16:20:32 +0000 | [diff] [blame] | 27 | |
Martin v. Löwis | 4f85bf3 | 2001-08-09 12:24:38 +0000 | [diff] [blame] | 28 | p_macro = re.compile( |
Guido van Rossum | 6100d91 | 1996-08-22 23:12:23 +0000 | [diff] [blame] | 29 | '^[\t ]*#[\t ]*define[\t ]+' |
Martin v. Löwis | 4f85bf3 | 2001-08-09 12:24:38 +0000 | [diff] [blame] | 30 | '([a-zA-Z0-9_]+)\(([_a-zA-Z][_a-zA-Z0-9]*)\)[\t ]+') |
Guido van Rossum | 07c9645 | 1994-10-03 16:45:35 +0000 | [diff] [blame] | 31 | |
Serhiy Storchaka | b9c04db | 2015-05-03 15:35:14 +0300 | [diff] [blame] | 32 | p_include = re.compile('^[\t ]*#[\t ]*include[\t ]+<([^>\n]+)>') |
Guido van Rossum | 07c9645 | 1994-10-03 16:45:35 +0000 | [diff] [blame] | 33 | |
Martin v. Löwis | 4f85bf3 | 2001-08-09 12:24:38 +0000 | [diff] [blame] | 34 | p_comment = re.compile(r'/\*([^*]+|\*+[^/])*(\*+/)?') |
| 35 | p_cpp_comment = re.compile('//.*') |
Guido van Rossum | 2ba9f30 | 1992-03-02 16:20:32 +0000 | [diff] [blame] | 36 | |
Guido van Rossum | 9189bda | 1997-08-14 20:14:29 +0000 | [diff] [blame] | 37 | ignores = [p_comment, p_cpp_comment] |
Guido van Rossum | 01f5f62 | 1994-05-17 09:05:54 +0000 | [diff] [blame] | 38 | |
Martin v. Löwis | 4f85bf3 | 2001-08-09 12:24:38 +0000 | [diff] [blame] | 39 | p_char = re.compile(r"'(\\.[^\\]*|[^\\])'") |
Guido van Rossum | 07c9645 | 1994-10-03 16:45:35 +0000 | [diff] [blame] | 40 | |
Martin v. Löwis | dab3bc0 | 2002-11-23 12:08:10 +0000 | [diff] [blame] | 41 | p_hex = re.compile(r"0x([0-9a-fA-F]+)L?") |
| 42 | |
Guido van Rossum | 07c9645 | 1994-10-03 16:45:35 +0000 | [diff] [blame] | 43 | filedict = {} |
Martin v. Löwis | 4f85bf3 | 2001-08-09 12:24:38 +0000 | [diff] [blame] | 44 | importable = {} |
Guido van Rossum | 07c9645 | 1994-10-03 16:45:35 +0000 | [diff] [blame] | 45 | |
Guido van Rossum | 514d351 | 1995-01-17 17:01:40 +0000 | [diff] [blame] | 46 | try: |
Guido van Rossum | e51c3f5 | 2001-12-06 03:24:30 +0000 | [diff] [blame] | 47 | searchdirs=os.environ['include'].split(';') |
Guido van Rossum | 514d351 | 1995-01-17 17:01:40 +0000 | [diff] [blame] | 48 | except KeyError: |
Tim Peters | 70c4378 | 2001-01-17 08:48:39 +0000 | [diff] [blame] | 49 | try: |
Guido van Rossum | e51c3f5 | 2001-12-06 03:24:30 +0000 | [diff] [blame] | 50 | searchdirs=os.environ['INCLUDE'].split(';') |
Tim Peters | 70c4378 | 2001-01-17 08:48:39 +0000 | [diff] [blame] | 51 | except KeyError: |
Antoine Pitrou | 6103ab1 | 2009-10-24 20:11:21 +0000 | [diff] [blame] | 52 | searchdirs=['/usr/include'] |
doko@python.org | 3e6e2ac | 2013-01-25 13:12:29 +0100 | [diff] [blame] | 53 | try: |
| 54 | searchdirs.insert(0, os.path.join('/usr/include', |
| 55 | os.environ['MULTIARCH'])) |
| 56 | except KeyError: |
| 57 | pass |
Guido van Rossum | 514d351 | 1995-01-17 17:01:40 +0000 | [diff] [blame] | 58 | |
Guido van Rossum | 2ba9f30 | 1992-03-02 16:20:32 +0000 | [diff] [blame] | 59 | def main(): |
Tim Peters | 70c4378 | 2001-01-17 08:48:39 +0000 | [diff] [blame] | 60 | global filedict |
| 61 | opts, args = getopt.getopt(sys.argv[1:], 'i:') |
| 62 | for o, a in opts: |
| 63 | if o == '-i': |
Martin v. Löwis | 4f85bf3 | 2001-08-09 12:24:38 +0000 | [diff] [blame] | 64 | ignores.append(re.compile(a)) |
Tim Peters | 70c4378 | 2001-01-17 08:48:39 +0000 | [diff] [blame] | 65 | if not args: |
| 66 | args = ['-'] |
| 67 | for filename in args: |
| 68 | if filename == '-': |
| 69 | sys.stdout.write('# Generated by h2py from stdin\n') |
| 70 | process(sys.stdin, sys.stdout) |
| 71 | else: |
| 72 | fp = open(filename, 'r') |
| 73 | outfile = os.path.basename(filename) |
Martin v. Löwis | 4f85bf3 | 2001-08-09 12:24:38 +0000 | [diff] [blame] | 74 | i = outfile.rfind('.') |
Tim Peters | 70c4378 | 2001-01-17 08:48:39 +0000 | [diff] [blame] | 75 | if i > 0: outfile = outfile[:i] |
Martin v. Löwis | 4f85bf3 | 2001-08-09 12:24:38 +0000 | [diff] [blame] | 76 | modname = outfile.upper() |
| 77 | outfile = modname + '.py' |
Tim Peters | 70c4378 | 2001-01-17 08:48:39 +0000 | [diff] [blame] | 78 | outfp = open(outfile, 'w') |
| 79 | outfp.write('# Generated by h2py from %s\n' % filename) |
| 80 | filedict = {} |
| 81 | for dir in searchdirs: |
| 82 | if filename[:len(dir)] == dir: |
| 83 | filedict[filename[len(dir)+1:]] = None # no '/' trailing |
Martin v. Löwis | 4f85bf3 | 2001-08-09 12:24:38 +0000 | [diff] [blame] | 84 | importable[filename[len(dir)+1:]] = modname |
Tim Peters | 70c4378 | 2001-01-17 08:48:39 +0000 | [diff] [blame] | 85 | break |
| 86 | process(fp, outfp) |
| 87 | outfp.close() |
| 88 | fp.close() |
Guido van Rossum | 2ba9f30 | 1992-03-02 16:20:32 +0000 | [diff] [blame] | 89 | |
Martin v. Löwis | dab3bc0 | 2002-11-23 12:08:10 +0000 | [diff] [blame] | 90 | def pytify(body): |
| 91 | # replace ignored patterns by spaces |
| 92 | for p in ignores: |
| 93 | body = p.sub(' ', body) |
| 94 | # replace char literals by ord(...) |
Georg Brandl | 9c14f2f | 2010-10-21 13:29:10 +0000 | [diff] [blame] | 95 | body = p_char.sub("ord('\\1')", body) |
Martin v. Löwis | dab3bc0 | 2002-11-23 12:08:10 +0000 | [diff] [blame] | 96 | # Compute negative hexadecimal constants |
| 97 | start = 0 |
Christian Heimes | a37d4c6 | 2007-12-04 23:02:19 +0000 | [diff] [blame] | 98 | UMAX = 2*(sys.maxsize+1) |
Martin v. Löwis | dab3bc0 | 2002-11-23 12:08:10 +0000 | [diff] [blame] | 99 | while 1: |
| 100 | m = p_hex.search(body, start) |
| 101 | if not m: break |
| 102 | s,e = m.span() |
Georg Brandl | 8efadf5 | 2008-05-16 15:23:30 +0000 | [diff] [blame] | 103 | val = int(body[slice(*m.span(1))], 16) |
Christian Heimes | a37d4c6 | 2007-12-04 23:02:19 +0000 | [diff] [blame] | 104 | if val > sys.maxsize: |
Martin v. Löwis | dab3bc0 | 2002-11-23 12:08:10 +0000 | [diff] [blame] | 105 | val -= UMAX |
| 106 | body = body[:s] + "(" + str(val) + ")" + body[e:] |
| 107 | start = s + 1 |
| 108 | return body |
| 109 | |
Guido van Rossum | 07c9645 | 1994-10-03 16:45:35 +0000 | [diff] [blame] | 110 | def process(fp, outfp, env = {}): |
Tim Peters | 70c4378 | 2001-01-17 08:48:39 +0000 | [diff] [blame] | 111 | lineno = 0 |
| 112 | while 1: |
| 113 | line = fp.readline() |
| 114 | if not line: break |
| 115 | lineno = lineno + 1 |
Martin v. Löwis | 4f85bf3 | 2001-08-09 12:24:38 +0000 | [diff] [blame] | 116 | match = p_define.match(line) |
| 117 | if match: |
Tim Peters | 70c4378 | 2001-01-17 08:48:39 +0000 | [diff] [blame] | 118 | # gobble up continuation lines |
| 119 | while line[-2:] == '\\\n': |
| 120 | nextline = fp.readline() |
| 121 | if not nextline: break |
| 122 | lineno = lineno + 1 |
| 123 | line = line + nextline |
Martin v. Löwis | 4f85bf3 | 2001-08-09 12:24:38 +0000 | [diff] [blame] | 124 | name = match.group(1) |
| 125 | body = line[match.end():] |
Martin v. Löwis | dab3bc0 | 2002-11-23 12:08:10 +0000 | [diff] [blame] | 126 | body = pytify(body) |
Tim Peters | 70c4378 | 2001-01-17 08:48:39 +0000 | [diff] [blame] | 127 | ok = 0 |
Martin v. Löwis | dab3bc0 | 2002-11-23 12:08:10 +0000 | [diff] [blame] | 128 | stmt = '%s = %s\n' % (name, body.strip()) |
Tim Peters | 70c4378 | 2001-01-17 08:48:39 +0000 | [diff] [blame] | 129 | try: |
Georg Brandl | 7cae87c | 2006-09-06 06:51:57 +0000 | [diff] [blame] | 130 | exec(stmt, env) |
Tim Peters | 70c4378 | 2001-01-17 08:48:39 +0000 | [diff] [blame] | 131 | except: |
| 132 | sys.stderr.write('Skipping: %s' % stmt) |
| 133 | else: |
| 134 | outfp.write(stmt) |
Martin v. Löwis | 4f85bf3 | 2001-08-09 12:24:38 +0000 | [diff] [blame] | 135 | match = p_macro.match(line) |
| 136 | if match: |
| 137 | macro, arg = match.group(1, 2) |
| 138 | body = line[match.end():] |
Martin v. Löwis | dab3bc0 | 2002-11-23 12:08:10 +0000 | [diff] [blame] | 139 | body = pytify(body) |
Tim Peters | 70c4378 | 2001-01-17 08:48:39 +0000 | [diff] [blame] | 140 | stmt = 'def %s(%s): return %s\n' % (macro, arg, body) |
| 141 | try: |
Georg Brandl | 7cae87c | 2006-09-06 06:51:57 +0000 | [diff] [blame] | 142 | exec(stmt, env) |
Tim Peters | 70c4378 | 2001-01-17 08:48:39 +0000 | [diff] [blame] | 143 | except: |
| 144 | sys.stderr.write('Skipping: %s' % stmt) |
| 145 | else: |
| 146 | outfp.write(stmt) |
Martin v. Löwis | 4f85bf3 | 2001-08-09 12:24:38 +0000 | [diff] [blame] | 147 | match = p_include.match(line) |
| 148 | if match: |
| 149 | regs = match.regs |
Tim Peters | 70c4378 | 2001-01-17 08:48:39 +0000 | [diff] [blame] | 150 | a, b = regs[1] |
| 151 | filename = line[a:b] |
Georg Brandl | 8efadf5 | 2008-05-16 15:23:30 +0000 | [diff] [blame] | 152 | if filename in importable: |
Martin v. Löwis | f2f8c51 | 2001-08-09 12:32:10 +0000 | [diff] [blame] | 153 | outfp.write('from %s import *\n' % importable[filename]) |
Georg Brandl | 8efadf5 | 2008-05-16 15:23:30 +0000 | [diff] [blame] | 154 | elif filename not in filedict: |
Tim Peters | 70c4378 | 2001-01-17 08:48:39 +0000 | [diff] [blame] | 155 | filedict[filename] = None |
| 156 | inclfp = None |
| 157 | for dir in searchdirs: |
| 158 | try: |
Martin v. Löwis | 4f85bf3 | 2001-08-09 12:24:38 +0000 | [diff] [blame] | 159 | inclfp = open(dir + '/' + filename) |
Tim Peters | 70c4378 | 2001-01-17 08:48:39 +0000 | [diff] [blame] | 160 | break |
| 161 | except IOError: |
| 162 | pass |
| 163 | if inclfp: |
| 164 | outfp.write( |
| 165 | '\n# Included from %s\n' % filename) |
| 166 | process(inclfp, outfp, env) |
| 167 | else: |
Guido van Rossum | 436fd75 | 2001-12-06 03:28:17 +0000 | [diff] [blame] | 168 | sys.stderr.write('Warning - could not find file %s\n' % |
| 169 | filename) |
Guido van Rossum | 07c9645 | 1994-10-03 16:45:35 +0000 | [diff] [blame] | 170 | |
Andrew M. Kuchling | e236b38 | 2004-08-09 17:27:55 +0000 | [diff] [blame] | 171 | if __name__ == '__main__': |
| 172 | main() |