Funktionierender Prototyp des Serious Games zur Vermittlung von Wissen zu Software-Engineering-Arbeitsmodellen.
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.

c_generator.py 17KB

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