c_generator.py 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444
  1. #------------------------------------------------------------------------------
  2. # pycparser: c_generator.py
  3. #
  4. # C code generator from pycparser AST nodes.
  5. #
  6. # Eli Bendersky [https://eli.thegreenplace.net/]
  7. # License: BSD
  8. #------------------------------------------------------------------------------
  9. from . import c_ast
  10. class CGenerator(object):
  11. """ Uses the same visitor pattern as c_ast.NodeVisitor, but modified to
  12. return a value from each visit method, using string accumulation in
  13. generic_visit.
  14. """
  15. def __init__(self):
  16. # Statements start with indentation of self.indent_level spaces, using
  17. # the _make_indent method
  18. #
  19. self.indent_level = 0
  20. def _make_indent(self):
  21. return ' ' * self.indent_level
  22. def visit(self, node):
  23. method = 'visit_' + node.__class__.__name__
  24. return getattr(self, method, self.generic_visit)(node)
  25. def generic_visit(self, node):
  26. #~ print('generic:', type(node))
  27. if node is None:
  28. return ''
  29. else:
  30. return ''.join(self.visit(c) for c_name, c in node.children())
  31. def visit_Constant(self, n):
  32. return n.value
  33. def visit_ID(self, n):
  34. return n.name
  35. def visit_Pragma(self, n):
  36. ret = '#pragma'
  37. if n.string:
  38. ret += ' ' + n.string
  39. return ret
  40. def visit_ArrayRef(self, n):
  41. arrref = self._parenthesize_unless_simple(n.name)
  42. return arrref + '[' + self.visit(n.subscript) + ']'
  43. def visit_StructRef(self, n):
  44. sref = self._parenthesize_unless_simple(n.name)
  45. return sref + n.type + self.visit(n.field)
  46. def visit_FuncCall(self, n):
  47. fref = self._parenthesize_unless_simple(n.name)
  48. return fref + '(' + self.visit(n.args) + ')'
  49. def visit_UnaryOp(self, n):
  50. operand = self._parenthesize_unless_simple(n.expr)
  51. if n.op == 'p++':
  52. return '%s++' % operand
  53. elif n.op == 'p--':
  54. return '%s--' % operand
  55. elif n.op == 'sizeof':
  56. # Always parenthesize the argument of sizeof since it can be
  57. # a name.
  58. return 'sizeof(%s)' % self.visit(n.expr)
  59. else:
  60. return '%s%s' % (n.op, operand)
  61. def visit_BinaryOp(self, n):
  62. lval_str = self._parenthesize_if(n.left,
  63. lambda d: not self._is_simple_node(d))
  64. rval_str = self._parenthesize_if(n.right,
  65. lambda d: not self._is_simple_node(d))
  66. return '%s %s %s' % (lval_str, n.op, rval_str)
  67. def visit_Assignment(self, n):
  68. rval_str = self._parenthesize_if(
  69. n.rvalue,
  70. lambda n: isinstance(n, c_ast.Assignment))
  71. return '%s %s %s' % (self.visit(n.lvalue), n.op, rval_str)
  72. def visit_IdentifierType(self, n):
  73. return ' '.join(n.names)
  74. def _visit_expr(self, n):
  75. if isinstance(n, c_ast.InitList):
  76. return '{' + self.visit(n) + '}'
  77. elif isinstance(n, c_ast.ExprList):
  78. return '(' + self.visit(n) + ')'
  79. else:
  80. return self.visit(n)
  81. def visit_Decl(self, n, no_type=False):
  82. # no_type is used when a Decl is part of a DeclList, where the type is
  83. # explicitly only for the first declaration in a list.
  84. #
  85. s = n.name if no_type else self._generate_decl(n)
  86. if n.bitsize: s += ' : ' + self.visit(n.bitsize)
  87. if n.init:
  88. s += ' = ' + self._visit_expr(n.init)
  89. return s
  90. def visit_DeclList(self, n):
  91. s = self.visit(n.decls[0])
  92. if len(n.decls) > 1:
  93. s += ', ' + ', '.join(self.visit_Decl(decl, no_type=True)
  94. for decl in n.decls[1:])
  95. return s
  96. def visit_Typedef(self, n):
  97. s = ''
  98. if n.storage: s += ' '.join(n.storage) + ' '
  99. s += self._generate_type(n.type)
  100. return s
  101. def visit_Cast(self, n):
  102. s = '(' + self._generate_type(n.to_type, emit_declname=False) + ')'
  103. return s + ' ' + self._parenthesize_unless_simple(n.expr)
  104. def visit_ExprList(self, n):
  105. visited_subexprs = []
  106. for expr in n.exprs:
  107. visited_subexprs.append(self._visit_expr(expr))
  108. return ', '.join(visited_subexprs)
  109. def visit_InitList(self, n):
  110. visited_subexprs = []
  111. for expr in n.exprs:
  112. visited_subexprs.append(self._visit_expr(expr))
  113. return ', '.join(visited_subexprs)
  114. def visit_Enum(self, n):
  115. return self._generate_struct_union_enum(n, name='enum')
  116. def visit_Enumerator(self, n):
  117. if not n.value:
  118. return '{indent}{name},\n'.format(
  119. indent=self._make_indent(),
  120. name=n.name,
  121. )
  122. else:
  123. return '{indent}{name} = {value},\n'.format(
  124. indent=self._make_indent(),
  125. name=n.name,
  126. value=self.visit(n.value),
  127. )
  128. def visit_FuncDef(self, n):
  129. decl = self.visit(n.decl)
  130. self.indent_level = 0
  131. body = self.visit(n.body)
  132. if n.param_decls:
  133. knrdecls = ';\n'.join(self.visit(p) for p in n.param_decls)
  134. return decl + '\n' + knrdecls + ';\n' + body + '\n'
  135. else:
  136. return decl + '\n' + body + '\n'
  137. def visit_FileAST(self, n):
  138. s = ''
  139. for ext in n.ext:
  140. if isinstance(ext, c_ast.FuncDef):
  141. s += self.visit(ext)
  142. elif isinstance(ext, c_ast.Pragma):
  143. s += self.visit(ext) + '\n'
  144. else:
  145. s += self.visit(ext) + ';\n'
  146. return s
  147. def visit_Compound(self, n):
  148. s = self._make_indent() + '{\n'
  149. self.indent_level += 2
  150. if n.block_items:
  151. s += ''.join(self._generate_stmt(stmt) for stmt in n.block_items)
  152. self.indent_level -= 2
  153. s += self._make_indent() + '}\n'
  154. return s
  155. def visit_CompoundLiteral(self, n):
  156. return '(' + self.visit(n.type) + '){' + self.visit(n.init) + '}'
  157. def visit_EmptyStatement(self, n):
  158. return ';'
  159. def visit_ParamList(self, n):
  160. return ', '.join(self.visit(param) for param in n.params)
  161. def visit_Return(self, n):
  162. s = 'return'
  163. if n.expr: s += ' ' + self.visit(n.expr)
  164. return s + ';'
  165. def visit_Break(self, n):
  166. return 'break;'
  167. def visit_Continue(self, n):
  168. return 'continue;'
  169. def visit_TernaryOp(self, n):
  170. s = '(' + self._visit_expr(n.cond) + ') ? '
  171. s += '(' + self._visit_expr(n.iftrue) + ') : '
  172. s += '(' + self._visit_expr(n.iffalse) + ')'
  173. return s
  174. def visit_If(self, n):
  175. s = 'if ('
  176. if n.cond: s += self.visit(n.cond)
  177. s += ')\n'
  178. s += self._generate_stmt(n.iftrue, add_indent=True)
  179. if n.iffalse:
  180. s += self._make_indent() + 'else\n'
  181. s += self._generate_stmt(n.iffalse, add_indent=True)
  182. return s
  183. def visit_For(self, n):
  184. s = 'for ('
  185. if n.init: s += self.visit(n.init)
  186. s += ';'
  187. if n.cond: s += ' ' + self.visit(n.cond)
  188. s += ';'
  189. if n.next: s += ' ' + self.visit(n.next)
  190. s += ')\n'
  191. s += self._generate_stmt(n.stmt, add_indent=True)
  192. return s
  193. def visit_While(self, n):
  194. s = 'while ('
  195. if n.cond: s += self.visit(n.cond)
  196. s += ')\n'
  197. s += self._generate_stmt(n.stmt, add_indent=True)
  198. return s
  199. def visit_DoWhile(self, n):
  200. s = 'do\n'
  201. s += self._generate_stmt(n.stmt, add_indent=True)
  202. s += self._make_indent() + 'while ('
  203. if n.cond: s += self.visit(n.cond)
  204. s += ');'
  205. return s
  206. def visit_Switch(self, n):
  207. s = 'switch (' + self.visit(n.cond) + ')\n'
  208. s += self._generate_stmt(n.stmt, add_indent=True)
  209. return s
  210. def visit_Case(self, n):
  211. s = 'case ' + self.visit(n.expr) + ':\n'
  212. for stmt in n.stmts:
  213. s += self._generate_stmt(stmt, add_indent=True)
  214. return s
  215. def visit_Default(self, n):
  216. s = 'default:\n'
  217. for stmt in n.stmts:
  218. s += self._generate_stmt(stmt, add_indent=True)
  219. return s
  220. def visit_Label(self, n):
  221. return n.name + ':\n' + self._generate_stmt(n.stmt)
  222. def visit_Goto(self, n):
  223. return 'goto ' + n.name + ';'
  224. def visit_EllipsisParam(self, n):
  225. return '...'
  226. def visit_Struct(self, n):
  227. return self._generate_struct_union_enum(n, 'struct')
  228. def visit_Typename(self, n):
  229. return self._generate_type(n.type)
  230. def visit_Union(self, n):
  231. return self._generate_struct_union_enum(n, 'union')
  232. def visit_NamedInitializer(self, n):
  233. s = ''
  234. for name in n.name:
  235. if isinstance(name, c_ast.ID):
  236. s += '.' + name.name
  237. else:
  238. s += '[' + self.visit(name) + ']'
  239. s += ' = ' + self._visit_expr(n.expr)
  240. return s
  241. def visit_FuncDecl(self, n):
  242. return self._generate_type(n)
  243. def visit_ArrayDecl(self, n):
  244. return self._generate_type(n, emit_declname=False)
  245. def visit_TypeDecl(self, n):
  246. return self._generate_type(n, emit_declname=False)
  247. def visit_PtrDecl(self, n):
  248. return self._generate_type(n, emit_declname=False)
  249. def _generate_struct_union_enum(self, n, name):
  250. """ Generates code for structs, unions, and enums. name should be
  251. 'struct', 'union', or 'enum'.
  252. """
  253. if name in ('struct', 'union'):
  254. members = n.decls
  255. body_function = self._generate_struct_union_body
  256. else:
  257. assert name == 'enum'
  258. members = None if n.values is None else n.values.enumerators
  259. body_function = self._generate_enum_body
  260. s = name + ' ' + (n.name or '')
  261. if members is not None:
  262. # None means no members
  263. # Empty sequence means an empty list of members
  264. s += '\n'
  265. s += self._make_indent()
  266. self.indent_level += 2
  267. s += '{\n'
  268. s += body_function(members)
  269. self.indent_level -= 2
  270. s += self._make_indent() + '}'
  271. return s
  272. def _generate_struct_union_body(self, members):
  273. return ''.join(self._generate_stmt(decl) for decl in members)
  274. def _generate_enum_body(self, members):
  275. # `[:-2] + '\n'` removes the final `,` from the enumerator list
  276. return ''.join(self.visit(value) for value in members)[:-2] + '\n'
  277. def _generate_stmt(self, n, add_indent=False):
  278. """ Generation from a statement node. This method exists as a wrapper
  279. for individual visit_* methods to handle different treatment of
  280. some statements in this context.
  281. """
  282. typ = type(n)
  283. if add_indent: self.indent_level += 2
  284. indent = self._make_indent()
  285. if add_indent: self.indent_level -= 2
  286. if typ in (
  287. c_ast.Decl, c_ast.Assignment, c_ast.Cast, c_ast.UnaryOp,
  288. c_ast.BinaryOp, c_ast.TernaryOp, c_ast.FuncCall, c_ast.ArrayRef,
  289. c_ast.StructRef, c_ast.Constant, c_ast.ID, c_ast.Typedef,
  290. c_ast.ExprList):
  291. # These can also appear in an expression context so no semicolon
  292. # is added to them automatically
  293. #
  294. return indent + self.visit(n) + ';\n'
  295. elif typ in (c_ast.Compound,):
  296. # No extra indentation required before the opening brace of a
  297. # compound - because it consists of multiple lines it has to
  298. # compute its own indentation.
  299. #
  300. return self.visit(n)
  301. else:
  302. return indent + self.visit(n) + '\n'
  303. def _generate_decl(self, n):
  304. """ Generation from a Decl node.
  305. """
  306. s = ''
  307. if n.funcspec: s = ' '.join(n.funcspec) + ' '
  308. if n.storage: s += ' '.join(n.storage) + ' '
  309. s += self._generate_type(n.type)
  310. return s
  311. def _generate_type(self, n, modifiers=[], emit_declname = True):
  312. """ Recursive generation from a type node. n is the type node.
  313. modifiers collects the PtrDecl, ArrayDecl and FuncDecl modifiers
  314. encountered on the way down to a TypeDecl, to allow proper
  315. generation from it.
  316. """
  317. typ = type(n)
  318. #~ print(n, modifiers)
  319. if typ == c_ast.TypeDecl:
  320. s = ''
  321. if n.quals: s += ' '.join(n.quals) + ' '
  322. s += self.visit(n.type)
  323. nstr = n.declname if n.declname and emit_declname else ''
  324. # Resolve modifiers.
  325. # Wrap in parens to distinguish pointer to array and pointer to
  326. # function syntax.
  327. #
  328. for i, modifier in enumerate(modifiers):
  329. if isinstance(modifier, c_ast.ArrayDecl):
  330. if (i != 0 and
  331. isinstance(modifiers[i - 1], c_ast.PtrDecl)):
  332. nstr = '(' + nstr + ')'
  333. nstr += '['
  334. if modifier.dim_quals:
  335. nstr += ' '.join(modifier.dim_quals) + ' '
  336. nstr += self.visit(modifier.dim) + ']'
  337. elif isinstance(modifier, c_ast.FuncDecl):
  338. if (i != 0 and
  339. isinstance(modifiers[i - 1], c_ast.PtrDecl)):
  340. nstr = '(' + nstr + ')'
  341. nstr += '(' + self.visit(modifier.args) + ')'
  342. elif isinstance(modifier, c_ast.PtrDecl):
  343. if modifier.quals:
  344. nstr = '* %s%s' % (' '.join(modifier.quals),
  345. ' ' + nstr if nstr else '')
  346. else:
  347. nstr = '*' + nstr
  348. if nstr: s += ' ' + nstr
  349. return s
  350. elif typ == c_ast.Decl:
  351. return self._generate_decl(n.type)
  352. elif typ == c_ast.Typename:
  353. return self._generate_type(n.type, emit_declname = emit_declname)
  354. elif typ == c_ast.IdentifierType:
  355. return ' '.join(n.names) + ' '
  356. elif typ in (c_ast.ArrayDecl, c_ast.PtrDecl, c_ast.FuncDecl):
  357. return self._generate_type(n.type, modifiers + [n],
  358. emit_declname = emit_declname)
  359. else:
  360. return self.visit(n)
  361. def _parenthesize_if(self, n, condition):
  362. """ Visits 'n' and returns its string representation, parenthesized
  363. if the condition function applied to the node returns True.
  364. """
  365. s = self._visit_expr(n)
  366. if condition(n):
  367. return '(' + s + ')'
  368. else:
  369. return s
  370. def _parenthesize_unless_simple(self, n):
  371. """ Common use case for _parenthesize_if
  372. """
  373. return self._parenthesize_if(n, lambda d: not self._is_simple_node(d))
  374. def _is_simple_node(self, n):
  375. """ Returns True for nodes that are "simple" - i.e. nodes that always
  376. have higher precedence than operators.
  377. """
  378. return isinstance(n, (c_ast.Constant, c_ast.ID, c_ast.ArrayRef,
  379. c_ast.StructRef, c_ast.FuncCall))