blob: 00a2592a3a0aea3d6f43874154dd4bab2b706e65 [file] [log] [blame]
eli.benderskyd5ba3452011-02-18 21:32:47 +02001#-----------------------------------------------------------------
2# pycparser: c-to-c.py
3#
eli.benderskyafcfaac2011-02-25 16:46:01 +02004# Example of a C code generator from pycparser AST nodes, serving
5# as a simplistic translator from C to AST and back to C.
eli.benderskyd5ba3452011-02-18 21:32:47 +02006#
7# Copyright (C) 2008-2011, Eli Bendersky
8# License: LGPL
9#-----------------------------------------------------------------
10from __future__ import print_function
11import sys
12
13# This is not required if you've installed pycparser into
14# your site-packages/ with setup.py
15#
16sys.path.insert(0, '..')
17
18from pycparser import c_parser, c_ast, parse_file
19
20
eli.benderskyafcfaac2011-02-25 16:46:01 +020021class CGenerator(object):
22 """ Uses the same visitor pattern as c_ast.NodeVisitor, but modified to
23 return a value from each visit method, using string accumulation in
24 generic_visit.
25 """
eli.benderskyd5ba3452011-02-18 21:32:47 +020026 def __init__(self):
27 self.output = ''
28
eli.bendersky3ae9f7a2011-02-27 07:19:41 +020029 # Statements start with indentation of self.indent_level spaces, using
30 # the _make_indent method
eli.benderskyafcfaac2011-02-25 16:46:01 +020031 #
32 self.indent_level = 0
33
eli.bendersky3ae9f7a2011-02-27 07:19:41 +020034 def _make_indent(self):
35 return ' ' * self.indent_level
36
eli.benderskyafcfaac2011-02-25 16:46:01 +020037 def visit(self, node):
38 method = 'visit_' + node.__class__.__name__
39 return getattr(self, method, self.generic_visit)(node)
40
41 def generic_visit(self, node):
eli.benderskydcb859c2011-03-05 17:02:43 +020042 #~ print('generic:', type(node))
eli.benderskyafcfaac2011-02-25 16:46:01 +020043 if node is None:
44 return ''
45 else:
46 return ''.join(self.visit(c) for c in node.children())
eli.benderskyd5ba3452011-02-18 21:32:47 +020047
48 def visit_Constant(self, n):
eli.benderskyafcfaac2011-02-25 16:46:01 +020049 return n.value
50
eli.benderskyd5ba3452011-02-18 21:32:47 +020051 def visit_ID(self, n):
eli.benderskyafcfaac2011-02-25 16:46:01 +020052 return n.name
eli.bendersky3ae9f7a2011-02-27 07:19:41 +020053
54 def visit_ArrayRef(self, n):
55 return self.visit(n.name) + '[' + self.visit(n.subscript) + ']'
56
eli.bendersky724b1cc2011-03-05 10:45:08 +020057 def visit_StructRef(self, n):
58 return self.visit(n.name) + n.type + self.visit(n.field)
59
60 def visit_FuncCall(self, n):
61 return self.visit(n.name) + '(' + self.visit(n.args) + ')'
62
eli.benderskyae36e962011-02-27 08:25:05 +020063 def visit_UnaryOp(self, n):
64 if n.op == 'p++':
65 return '%s++' % self.visit(n.expr)
66 else:
67 return '%s%s' % (n.op, self.visit(n.expr))
68
eli.bendersky3ae9f7a2011-02-27 07:19:41 +020069 def visit_BinaryOp(self, n):
eli.bendersky724b1cc2011-03-05 10:45:08 +020070 # To avoid operator precedence issues, parenthesize both operands unless
71 # they're "simple" nodes that have precedence over all binary ops.
72 #
73 simplenodes = (
74 c_ast.Constant, c_ast.ID, c_ast.ArrayRef, c_ast.StructRef,
75 c_ast.FuncCall)
76 isnotsimple = lambda n: not isinstance(n, simplenodes)
77 lval_str = self._parenthesize_if(n.left, isnotsimple)
78 rval_str = self._parenthesize_if(n.right, isnotsimple)
79 return '%s %s %s' % (lval_str, n.op, rval_str)
eli.bendersky3ae9f7a2011-02-27 07:19:41 +020080
81 def visit_Assignment(self, n):
eli.bendersky724b1cc2011-03-05 10:45:08 +020082 rval_str = self._parenthesize_if(
83 n.rvalue,
84 lambda n: isinstance(n, c_ast.Assignment))
85 return '%s %s %s' % (self.visit(n.lvalue), n.op, rval_str)
eli.benderskyd5ba3452011-02-18 21:32:47 +020086
87 def visit_IdentifierType(self, n):
eli.bendersky3ae9f7a2011-02-27 07:19:41 +020088 return ' '.join(n.names)
eli.benderskyd5ba3452011-02-18 21:32:47 +020089
eli.benderskyabb96e62011-03-05 16:30:05 +020090 def visit_Decl(self, n, no_type=False):
91 # no_type is used when a Decl is part of a DeclList, where the type is
92 # explicitly only for the first delaration in a list.
93 #
94 s = n.name if no_type else self._generate_decl(n)
eli.benderskyafcfaac2011-02-25 16:46:01 +020095 if n.bitsize: s += ' : ' + self.visit(n.bitsize)
eli.benderskydcb859c2011-03-05 17:02:43 +020096 if n.init:
97 if isinstance(n.init, c_ast.ExprList):
98 s += ' = {' + self.visit(n.init) + '}'
99 else:
100 s += ' = ' + self.visit(n.init)
eli.benderskyafcfaac2011-02-25 16:46:01 +0200101 return s
eli.benderskyd5ba3452011-02-18 21:32:47 +0200102
eli.benderskyabb96e62011-03-05 16:30:05 +0200103 def visit_DeclList(self, n):
104 s = self.visit(n.decls[0])
105 if len(n.decls) > 1:
106 s += ', ' + ', '.join(self.visit_Decl(decl, no_type=True)
107 for decl in n.decls[1:])
108 return s
109
eli.bendersky3ae9f7a2011-02-27 07:19:41 +0200110 def visit_Typedef(self, n):
111 s = ''
112 if n.storage: s += ' '.join(n.storage) + ' '
113 s += self._generate_type(n.type)
114 return s
115
116 def visit_Cast(self, n):
117 s = '(' + self.visit(n.to_type) + ')'
118 return s + ' ' + self.visit(n.expr)
119
eli.bendersky724b1cc2011-03-05 10:45:08 +0200120 def visit_ExprList(self, n):
121 return ', '.join(self.visit(expr) for expr in n.exprs)
122
eli.bendersky3ae9f7a2011-02-27 07:19:41 +0200123 def visit_Enum(self, n):
124 s = 'enum'
125 if n.name: s += ' ' + n.name
126 if n.values:
127 s += ' {'
128 for i, enumerator in enumerate(n.values.enumerators):
129 s += enumerator.name
130 if enumerator.value:
131 s += ' = ' + self.visit(enumerator.value)
132 if i != len(n.values.enumerators) - 1:
133 s += ', '
134 s += '}'
135 return s
136
137 def visit_Struct(self, n):
138 s = 'struct'
139 if n.name: s += ' ' + n.name
140 if n.decls:
141 s += ' { \n'
142 for decl in n.decls:
143 s += ' ' + self.visit(decl) + ';\n'
144 s += '}'
145 return s
146
eli.benderskyafcfaac2011-02-25 16:46:01 +0200147 def visit_FuncDef(self, n):
148 decl = self.visit(n.decl)
149 self.indent_level = 0
eli.bendersky3ae9f7a2011-02-27 07:19:41 +0200150 # The body is a Compound node
eli.benderskyafcfaac2011-02-25 16:46:01 +0200151 body = self.visit(n.body)
eli.bendersky3ae9f7a2011-02-27 07:19:41 +0200152 return decl + '\n' + body + '\n'
153
154 def visit_FileAST(self, n):
155 s = ''
156 for ext in n.ext:
157 if isinstance(ext, c_ast.FuncDef):
158 s += self.visit(ext)
159 else:
160 s += self.visit(ext) + ';\n'
161 return s
162
163 def visit_Compound(self, n):
164 s = self._make_indent() + '{\n'
165 self.indent_level += 2
166 s += ''.join(self._generate_stmt(stmt) for stmt in n.block_items)
167 self.indent_level -= 2
168 s += self._make_indent() + '}\n'
169 return s
170
171 def visit_ParamList(self, n):
172 return ', '.join(self.visit(param) for param in n.params)
173
174 def visit_Return(self, n):
175 s = 'return'
176 if n.expr: s += ' ' + self.visit(n.expr)
177 return s + ';'
178
eli.benderskyfc96e5e2011-03-04 09:51:23 +0200179 def visit_Break(self, n):
180 return 'break;'
181
182 def visit_Continue(self, n):
183 return 'continue;'
eli.bendersky724b1cc2011-03-05 10:45:08 +0200184
185 def visit_TernaryOp(self, n):
186 s = self.visit(n.cond) + ' ? '
187 s += self.visit(n.iftrue) + ' : '
188 s += self.visit(n.iffalse)
189 return s
190
eli.benderskye6ecb1a2011-03-05 10:58:46 +0200191 def visit_If(self, n):
192 s = 'if ('
193 if n.cond: s += self.visit(n.cond)
194 s += ')\n'
195 s += self._generate_stmt(n.iftrue, add_indent=True)
196 if n.iffalse:
197 s += self._make_indent() + 'else\n'
198 s += self._generate_stmt(n.iffalse, add_indent=True)
199 return s
200
eli.benderskyae36e962011-02-27 08:25:05 +0200201 def visit_For(self, n):
202 s = 'for ('
203 if n.init: s += self.visit(n.init)
204 s += ';'
205 if n.cond: s += ' ' + self.visit(n.cond)
206 s += ';'
207 if n.next: s += ' ' + self.visit(n.next)
208 s += ')\n'
209 s += self._generate_stmt(n.stmt, add_indent=True)
210 return s
211
eli.benderskyfc96e5e2011-03-04 09:51:23 +0200212 def visit_While(self, n):
213 s = 'while ('
214 if n.cond: s += self.visit(n.cond)
215 s += ')\n'
216 s += self._generate_stmt(n.stmt, add_indent=True)
217 return s
218
eli.benderskye6ecb1a2011-03-05 10:58:46 +0200219 def visit_DoWhile(self, n):
220 s = 'do\n'
221 s += self._generate_stmt(n.stmt, add_indent=True)
222 s += self._make_indent() + 'while ('
223 if n.cond: s += self.visit(n.cond)
224 s += ');'
225 return s
226
eli.benderskyabb96e62011-03-05 16:30:05 +0200227 def visit_Switch(self, n):
228 s = 'switch (' + self.visit(n.cond) + ')\n'
229 s += self._generate_stmt(n.stmt, add_indent=True)
230 return s
231
232 def visit_Case(self, n):
233 s = 'case ' + self.visit(n.expr) + ':\n'
234 s += self._generate_stmt(n.stmt, add_indent=True)
235 return s
236
237 def visit_Default(self, n):
238 return 'default:\n' + self._generate_stmt(n.stmt, add_indent=True)
239
240 def visit_Label(self, n):
241 return n.name + ':\n' + self._generate_stmt(n.stmt)
242
243 def visit_Goto(self, n):
244 return 'goto ' + n.name + ';'
245
eli.benderskye6ecb1a2011-03-05 10:58:46 +0200246 def visit_EllipsisParam(self, n):
247 return '...'
248
eli.benderskyabb96e62011-03-05 16:30:05 +0200249 def visit_Struct(self, n):
250 return self._generate_struct_union(n, 'struct')
251
252 def visit_Union(self, n):
253 return self._generate_struct_union(n, 'union')
254
eli.benderskydcb859c2011-03-05 17:02:43 +0200255 def visit_NamedInitializer(self, n):
256 s = ''
257 for name in n.name:
258 if isinstance(name, c_ast.ID):
259 s += '.' + name.name
260 elif isinstance(name, c_ast.Constant):
261 s += '[' + name.value + ']'
262 s += ' = ' + self.visit(n.expr)
263 return s
264
eli.benderskyabb96e62011-03-05 16:30:05 +0200265 def _generate_struct_union(self, n, name):
266 """ Generates code for structs and unions. name should be either
267 'struct' or union.
268 """
eli.benderskydcb859c2011-03-05 17:02:43 +0200269 s = name + ' ' + (n.name or '')
270 if n.decls:
271 s += '\n'
272 s += self._make_indent()
273 self.indent_level += 2
274 s += '{\n'
275 for decl in n.decls:
276 s += self._generate_stmt(decl)
277 self.indent_level -= 2
278 s += self._make_indent() + '}'
eli.benderskyabb96e62011-03-05 16:30:05 +0200279 return s
280
eli.benderskyae36e962011-02-27 08:25:05 +0200281 def _generate_stmt(self, n, add_indent=False):
eli.bendersky3ae9f7a2011-02-27 07:19:41 +0200282 """ Generation from a statement node. This method exists as a wrapper
283 for individual visit_* methods to handle different treatment of
284 some statements in this context.
285 """
286 typ = type(n)
eli.benderskyae36e962011-02-27 08:25:05 +0200287 if add_indent: self.indent_level += 2
eli.benderskyfc96e5e2011-03-04 09:51:23 +0200288 indent = self._make_indent()
eli.benderskyae36e962011-02-27 08:25:05 +0200289 if add_indent: self.indent_level -= 2
eli.bendersky3ae9f7a2011-02-27 07:19:41 +0200290
eli.bendersky724b1cc2011-03-05 10:45:08 +0200291 if typ in (
292 c_ast.Decl, c_ast.Assignment, c_ast.Cast, c_ast.UnaryOp,
293 c_ast.BinaryOp, c_ast.TernaryOp, c_ast.FuncCall):
eli.bendersky3ae9f7a2011-02-27 07:19:41 +0200294 # These can also appear in an expression context so no semicolon
295 # is added to them automatically
296 #
eli.benderskyfc96e5e2011-03-04 09:51:23 +0200297 return indent + self.visit(n) + ';\n'
eli.bendersky3ae9f7a2011-02-27 07:19:41 +0200298 elif typ in (c_ast.Compound,):
299 # No extra indentation required before the opening brace of a
300 # compound - because it consists of multiple lines it has to
301 # compute its own indentation.
302 #
eli.benderskyae36e962011-02-27 08:25:05 +0200303 return self.visit(n)
eli.bendersky3ae9f7a2011-02-27 07:19:41 +0200304 else:
eli.benderskyfc96e5e2011-03-04 09:51:23 +0200305 return indent + self.visit(n) + '\n'
eli.benderskyafcfaac2011-02-25 16:46:01 +0200306
eli.benderskyd5ba3452011-02-18 21:32:47 +0200307 def _generate_decl(self, n):
308 """ Generation from a Decl node.
309 """
eli.benderskyafcfaac2011-02-25 16:46:01 +0200310 s = ''
311 if n.funcspec: s = ' '.join(n.funcspec) + ' '
312 if n.storage: s += ' '.join(n.storage) + ' '
313 s += self._generate_type(n.type)
314 return s
eli.benderskyd5ba3452011-02-18 21:32:47 +0200315
316 def _generate_type(self, n, modifiers=[]):
317 """ Recursive generation from a type node. n is the type node.
eli.benderskyafcfaac2011-02-25 16:46:01 +0200318 modifiers collects the PtrDecl, ArrayDecl and FuncDecl modifiers
319 encountered on the way down to a TypeDecl, to allow proper
320 generation from it.
eli.benderskyd5ba3452011-02-18 21:32:47 +0200321 """
322 typ = type(n)
323 #~ print(n, modifiers)
324
325 if typ == c_ast.TypeDecl:
eli.benderskyafcfaac2011-02-25 16:46:01 +0200326 s = ''
327 if n.quals: s += ' '.join(n.quals) + ' '
328 s += self.visit(n.type)
eli.benderskyd5ba3452011-02-18 21:32:47 +0200329
330 nstr = n.declname if n.declname else ''
eli.bendersky3ae9f7a2011-02-27 07:19:41 +0200331 # Resolve modifiers.
eli.benderskyafcfaac2011-02-25 16:46:01 +0200332 # Wrap in parens to distinguish pointer to array and pointer to
333 # function syntax.
eli.benderskyd5ba3452011-02-18 21:32:47 +0200334 #
335 for i, modifier in enumerate(modifiers):
336 if isinstance(modifier, c_ast.ArrayDecl):
337 if (i != 0 and isinstance(modifiers[i - 1], c_ast.PtrDecl)):
338 nstr = '(' + nstr + ')'
eli.benderskyafcfaac2011-02-25 16:46:01 +0200339 nstr += '[' + self.visit(modifier.dim) + ']'
340 elif isinstance(modifier, c_ast.FuncDecl):
341 if (i != 0 and isinstance(modifiers[i - 1], c_ast.PtrDecl)):
342 nstr = '(' + nstr + ')'
343 nstr += '(' + self.visit(modifier.args) + ')'
eli.benderskyd5ba3452011-02-18 21:32:47 +0200344 elif isinstance(modifier, c_ast.PtrDecl):
345 nstr = '*' + nstr
eli.bendersky3ae9f7a2011-02-27 07:19:41 +0200346 s += ' ' + nstr
eli.benderskyafcfaac2011-02-25 16:46:01 +0200347 return s
eli.benderskyd5ba3452011-02-18 21:32:47 +0200348 elif typ in (c_ast.Typename, c_ast.Decl):
eli.benderskyafcfaac2011-02-25 16:46:01 +0200349 return self._generate_decl(n.type)
eli.benderskyd5ba3452011-02-18 21:32:47 +0200350 elif typ == c_ast.IdentifierType:
eli.benderskyafcfaac2011-02-25 16:46:01 +0200351 return ' '.join(n.names) + ' '
352 elif typ in (c_ast.ArrayDecl, c_ast.PtrDecl, c_ast.FuncDecl):
353 return self._generate_type(n.type, modifiers + [n])
eli.benderskyabb96e62011-03-05 16:30:05 +0200354 else:
355 return self.visit(n)
eli.benderskyd5ba3452011-02-18 21:32:47 +0200356
eli.bendersky724b1cc2011-03-05 10:45:08 +0200357 def _parenthesize_if(self, n, condition):
358 """ Visits 'n' and returns its string representation, parenthesized
359 if the condition function applied to the node returns True.
360 """
361 s = self.visit(n)
362 if condition(n):
363 return '(' + s + ')'
364 else:
365 return s
366
eli.benderskyd5ba3452011-02-18 21:32:47 +0200367
368def translate_to_c(filename):
369 ast = parse_file(filename, use_cpp=True)
370 generator = CGenerator()
eli.benderskyafcfaac2011-02-25 16:46:01 +0200371 print(generator.visit(ast))
eli.benderskyd5ba3452011-02-18 21:32:47 +0200372
373
374if __name__ == "__main__":
375 if len(sys.argv) > 1:
376 translate_to_c(sys.argv[1])
377 else:
378 src = r'''
eli.benderskye6ecb1a2011-03-05 10:58:46 +0200379
eli.benderskydcb859c2011-03-05 17:02:43 +0200380void v(void)
eli.benderskyabb96e62011-03-05 16:30:05 +0200381{
eli.benderskydcb859c2011-03-05 17:02:43 +0200382 int poa = {5, 6};
383 int ka = {.ko[4] = 8, [5] = 3};
eli.benderskyae36e962011-02-27 08:25:05 +0200384}
eli.bendersky3ae9f7a2011-02-27 07:19:41 +0200385
eli.benderskyd5ba3452011-02-18 21:32:47 +0200386 '''
387 parser = c_parser.CParser()
388 ast = parser.parse(src)
389 ast.show()
390 generator = CGenerator()
eli.benderskyafcfaac2011-02-25 16:46:01 +0200391 print(generator.visit(ast))
eli.benderskyd5ba3452011-02-18 21:32:47 +0200392
393 print("Please provide a filename as argument")
eli.bendersky3ae9f7a2011-02-27 07:19:41 +0200394
395
eli.benderskydcb859c2011-03-05 17:02:43 +0200396# ZZZ:
397# 1. (*hash)->heads turns to *hash->heads. need to parenthesize left side if it
398# isn't simple
399# 2. sizeof should have parens around argument
400#