gen_header.py 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343
  1. #!/usr/bin/python
  2. #
  3. # gen_header.py - generate portable header
  4. #
  5. # Copyright (C) 2013 Matthew R. Wette
  6. # mwette@alumni.caltech.edu
  7. #
  8. # This program is free software; you can redistribute it and/or
  9. # modify it under the terms of the GNU General Public License as
  10. # published by the Free Software Foundation; either version 2 of the
  11. # License, or (at your option) any later version.
  12. #
  13. # This program is distributed in the hope that it will be useful, but
  14. # WITHOUT ANY WARRANTY; without even the implied warranty of
  15. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  16. # General Public License for more details.
  17. #
  18. # You should have received a copy of the GNU General Public License
  19. # along with this program; if not, write to the Free Software
  20. # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
  21. # 02111-1307, USA.
  22. #
  23. # The GNU General Public License is contained in the file COPYING.
  24. #
  25. # v130608a
  26. import sys, os, re, difflib
  27. import pdb
  28. from gen_utils import replace_in_code, move_if_changed, write_w_fill
  29. defcombos = [
  30. ('and', "__APPLE__", "__i386__"),
  31. ('and', "__APPLE__", "__x86_64__"),
  32. ('or', "__MINGW32__", "__CYGWIN32__", ('and', "_WIN32", "_M_IX86")),
  33. ('and', "__linux__", "__i386__"),
  34. ('and', "__linux__", "__x86_64__"),
  35. ('and', "__linux__", "__powerpc__", ('not', "__powerpc64__")),
  36. ('and', "__linux__", "__powerpc__", "__powerpc64__"),
  37. ('and', "__linux__", "__arm__"),
  38. ('and', "__linux__", "__x390__", "__s390x__"),
  39. ('and', "__linux__", "__mips__"),
  40. ]
  41. rx1 = re.compile(r' *(VG_USERREQ_\w+).*')
  42. rx2 = re.compile(r'#define (\w+)(.*)')
  43. def slurp(filename):
  44. """
  45. Read header file and return list of enums and #defines for user codes.
  46. This will raise exception if file has no enums or defs
  47. """
  48. # Skip to enum, then read enum-guts.
  49. enums = []
  50. f0 = open(filename, 'r')
  51. l0 = f0.readline()
  52. while l0:
  53. if l0.startswith(" enum {"): break
  54. l0 = f0.readline()
  55. l0 = f0.readline()
  56. while l0:
  57. m = rx1.match(l0)
  58. if not m: break
  59. enums.append(m.group(1).strip())
  60. l0 = f0.readline()
  61. # Now process defs.
  62. defs = []
  63. while l0:
  64. if not l0.startswith("#define"):
  65. l0 = f0.readline()
  66. continue
  67. defn = l0
  68. while defn.endswith("\\\n"):
  69. defn = defn.rstrip(" \t\\\n")
  70. defn += " " + f0.readline().lstrip()
  71. if defn.find("VALGRIND_DO_CLIENT_REQUEST") >= 0:
  72. defs.append(defn)
  73. l0 = f0.readline()
  74. f0.close()
  75. return [enums,defs]
  76. def get_enum_values(filename, enumnames):
  77. """
  78. For enums that exist int the provided header file return a dict that
  79. gives values for each enum.
  80. """
  81. f1 = open("_z1.c", 'w')
  82. f1.write("#include <stdio.h>\n")
  83. f1.write("#include \"%s\"\n" % (filename,))
  84. f1.write("int main() {\n")
  85. for e in enumnames:
  86. f1.write(" printf(\"enumd['%s'] = \\\"0x%%x\\\"\\n\", %s);\n" % (e,e))
  87. f1.write("}\n")
  88. f1.close()
  89. # run code and collect
  90. os.system("gcc -I../include -o _z1 _z1.c")
  91. f2 = os.popen("./_z1", 'r')
  92. enumd = {}
  93. l = f2.readline()
  94. while l:
  95. exec(l)
  96. l = f2.readline()
  97. f2.close()
  98. os.system("rm _z1 _z1.c")
  99. return enumd
  100. rx3 = re.compile(r"#define\s+([A-Z0-9_]+)\s*(\(.*)")
  101. rx4 = re.compile(r"#define\s+([A-Za-z0-9_]+)(\([A-Za-z0-9_, ]*\))\s*(.*)$")
  102. def massage_defs(defs, enumd):
  103. """
  104. Given an array of defs, replace lval names and expand enum vals.
  105. """
  106. newdefs = []
  107. enuml = enumd.keys()
  108. for d0 in defs:
  109. m = rx4.match(d0)
  110. if not m:
  111. raise Exception, "can't handle " + d0
  112. if m.group(1).startswith("XPROF_"):
  113. lval = "#define " \
  114. + re.sub("XPROF_", "XPROF_", m.group(1)) + m.group(2)
  115. elif m.group(1).startswith("XP_"):
  116. lval = "#define " \
  117. + re.sub("XP_", "XP_", m.group(1)) + m.group(2)
  118. else:
  119. lval = "#define " + m.group(1) + m.group(2)
  120. rval = m.group(3)
  121. for e in enuml:
  122. if rval.find(e) >= 0:
  123. rval = rval.replace(e, enumd[e])
  124. newdefs.append(lval + " " + rval)
  125. return newdefs
  126. def qr_mindefs(rule, defs=[]):
  127. """
  128. Generate min list of defs to satisfy rule.
  129. Example: ('and', "_x_", "_y_") -> ["_x_", "_y_"]
  130. """
  131. def x_leaf(arg):
  132. return [arg]
  133. def x_and(args):
  134. res = []
  135. for a in args:
  136. res.extend(qr_mindefs(a))
  137. return res
  138. def x_or(args):
  139. return qr_mindefs(args[1])
  140. def x_not(args):
  141. return []
  142. if isinstance(rule, tuple):
  143. if rule[0] == 'and':
  144. return x_and(rule[1:])
  145. elif rule[0] == 'or':
  146. return x_or(rule[1:])
  147. elif rule[0] == 'not':
  148. return x_not(rule[1:])
  149. else:
  150. return x_leaf(rule)
  151. def qr_expand(rule):
  152. """
  153. Expand qualifier to cpp code.
  154. Example: ('and', "_x_", "_y_") -> (defined(_x_) && defined(_y_))
  155. """
  156. def x_leaf(arg):
  157. return "defined(" + arg + ")"
  158. def x_and(args):
  159. res = qr_expand(args[0])
  160. for a in args[1:]:
  161. res = res + " && " + qr_expand(a)
  162. return "(" + res + ")"
  163. def x_or(args):
  164. res = qr_expand(args[0])
  165. for a in args[1:]:
  166. res = res + " || " + qr_expand(a)
  167. return "(" + res + ")"
  168. def x_not(args):
  169. return "!" + qr_expand(args[0])
  170. if isinstance(rule, tuple):
  171. if rule[0] == 'and':
  172. return x_and(rule[1:])
  173. elif rule[0] == 'or':
  174. return x_or(rule[1:])
  175. elif rule[0] == 'not':
  176. return x_not(rule[1:])
  177. else:
  178. return x_leaf(rule)
  179. def collect_qdefs(rexpr, defs):
  180. """
  181. Given all defrules return list of symbols used.
  182. """
  183. if isinstance(rexpr, tuple):
  184. for e in rexpr[1:]:
  185. collect_qdefs(e, defs)
  186. else:
  187. if not rexpr in defs:
  188. defs.append(rexpr)
  189. def expand_defs(defs, qc, aq):
  190. """
  191. defs = #define we want to expand
  192. qc = qualifier combo (needs expand by qr_expand).
  193. aq = all qualifiers
  194. """
  195. f1 = open("_z1.c", 'w')
  196. for q in aq:
  197. f1.write("#undef " + q + "\n")
  198. for q in qr_mindefs(qc):
  199. f1.write("#define " + q + "\n")
  200. f1.write("#include \"valgrind.h\"\n")
  201. #
  202. f1.write('=== BEG ===\n')
  203. for d in defs:
  204. f1.write(re.sub("#define", "Edefine", d) + "\n")
  205. f1.write('=== END ===\n')
  206. f1.close()
  207. #
  208. cc_cmd = "cc"
  209. os.system(cc_cmd + " -E -I../include _z1.c >_z1.E")
  210. #
  211. f2 = open("_z1.E", 'r')
  212. xdefs = []
  213. l0 = f2.readline()
  214. while l0:
  215. if l0.startswith("=== BEG ==="):
  216. l0 = f2.readline()
  217. break
  218. l0 = f2.readline()
  219. while l0:
  220. if l0.startswith('=== END ==='):
  221. break
  222. if l0.startswith('Edefine'):
  223. # clean up ...
  224. l = l0
  225. l = re.sub('Edefine ', '#define ', l)
  226. #l = re.sub('_zzq', '', l)
  227. #l = re.sub('_qzz', '', l)
  228. xdefs.append(l)
  229. l0 = f2.readline()
  230. f2.close()
  231. os.system("rm -f _z1.c _z1.E")
  232. return xdefs
  233. def genxhdr1(stuff, f1):
  234. """
  235. called by fill_in_xxx
  236. """
  237. qcl, xdefd = stuff
  238. nqc = len(qcl)
  239. defl = []
  240. el = ""
  241. for ix in range(nqc):
  242. qcstr = qr_expand(qcl[ix])[1:-1]
  243. xdefs = xdefd[ix]
  244. f1.write("#" + el + "if")
  245. col = 4
  246. parts = qcstr.split()
  247. for p in parts:
  248. col = write_w_fill(f1, col, " " + p, leader = "\t", cc = " \\")
  249. f1.write("\n\n")
  250. el = "el"
  251. for xdef in xdefs:
  252. m = rx4.match(xdef)
  253. if not m: raise Exception, "NO MATCH"
  254. lval = "#define " + m.group(1) + m.group(2)
  255. if ix == 0: defl.append(lval)
  256. f1.write(lval + "\t\\\n")
  257. lines = chopup(m.group(3), 60)
  258. n = len(lines)
  259. for i in range(n):
  260. f1.write("\t")
  261. f1.write(lines[i])
  262. if i < n -1: f1.write(" \\")
  263. f1.write("\n")
  264. f1.write("\n")
  265. f1.write("#else\n")
  266. for d in defl:
  267. #f1.write(d + " /* */\n")
  268. f1.write(d + " 0\n")
  269. f1.write('#endif\n')
  270. def chopup(line, mx = 60):
  271. """
  272. Chop up into lines of max length mx (default 60).
  273. Deals with double-quotes.
  274. """
  275. lines = []
  276. ln = len(line)
  277. st = 0
  278. nd = st
  279. while nd < ln:
  280. if st + mx > ln:
  281. lines.append(line[st:])
  282. return lines
  283. nd = st + 60
  284. while line[nd-1] != " ":
  285. nd = nd - 1
  286. if nd == st:
  287. raise Exception, "can't handle no spaces"
  288. while line[nd-1] == " ": nd = nd - 1 # back up to no spaces
  289. if line.count("\"", st, nd) % 2 != 0:
  290. #pdb.set_trace()
  291. ix = line.rfind("\"", st, nd)
  292. if ix < 0: raise Exception, "chopup: bad line"
  293. if st + ix > mx/2:
  294. nd = ix
  295. else:
  296. # \fix should split quote
  297. nd = ix
  298. lines.append(line[st:nd])
  299. while nd < ln and line[nd] == " ": nd = nd + 1
  300. st = nd
  301. return lines
  302. if True:
  303. enums,defs = slurp("cputildefs.h")
  304. enumd = get_enum_values("cputildefs.h", enums)
  305. defs = massage_defs(defs, enumd)
  306. #
  307. alldefs = []
  308. for r in defcombos:
  309. collect_qdefs(r, alldefs)
  310. #
  311. n = len(defcombos)
  312. xdefd = {}
  313. for i in range(n):
  314. dc = defcombos[i]
  315. xdefs = expand_defs(defs, dc, alldefs)
  316. xdefd[i] = xdefs
  317. fname = "cputil.h"
  318. replace_in_code((defcombos,xdefd), fname, "autocoding", genxhdr1)
  319. move_if_changed(fname)
  320. if False:
  321. for qc in defcombos:
  322. #v = qr_expand(qc)[1:-1]
  323. v = qr_mindefs(qc)
  324. print v
  325. # --- last line of gen_header.py ---