blob: f237839a36d08742b3cba2bc9a3a330548f3599a [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.benderskyabb96e62011-03-05 16:30:05 +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)
96 if n.init: s += ' = ' + self.visit(n.init)
97 return s
eli.benderskyd5ba3452011-02-18 21:32:47 +020098
eli.benderskyabb96e62011-03-05 16:30:05 +020099 def visit_DeclList(self, n):
100 s = self.visit(n.decls[0])
101 if len(n.decls) > 1:
102 s += ', ' + ', '.join(self.visit_Decl(decl, no_type=True)
103 for decl in n.decls[1:])
104 return s
105
eli.bendersky3ae9f7a2011-02-27 07:19:41 +0200106 def visit_Typedef(self, n):
107 s = ''
108 if n.storage: s += ' '.join(n.storage) + ' '
109 s += self._generate_type(n.type)
110 return s
111
112 def visit_Cast(self, n):
113 s = '(' + self.visit(n.to_type) + ')'
114 return s + ' ' + self.visit(n.expr)
115
eli.bendersky724b1cc2011-03-05 10:45:08 +0200116 def visit_ExprList(self, n):
117 return ', '.join(self.visit(expr) for expr in n.exprs)
118
eli.bendersky3ae9f7a2011-02-27 07:19:41 +0200119 def visit_Enum(self, n):
120 s = 'enum'
121 if n.name: s += ' ' + n.name
122 if n.values:
123 s += ' {'
124 for i, enumerator in enumerate(n.values.enumerators):
125 s += enumerator.name
126 if enumerator.value:
127 s += ' = ' + self.visit(enumerator.value)
128 if i != len(n.values.enumerators) - 1:
129 s += ', '
130 s += '}'
131 return s
132
133 def visit_Struct(self, n):
134 s = 'struct'
135 if n.name: s += ' ' + n.name
136 if n.decls:
137 s += ' { \n'
138 for decl in n.decls:
139 s += ' ' + self.visit(decl) + ';\n'
140 s += '}'
141 return s
142
eli.benderskyafcfaac2011-02-25 16:46:01 +0200143 def visit_FuncDef(self, n):
144 decl = self.visit(n.decl)
145 self.indent_level = 0
eli.bendersky3ae9f7a2011-02-27 07:19:41 +0200146 # The body is a Compound node
eli.benderskyafcfaac2011-02-25 16:46:01 +0200147 body = self.visit(n.body)
eli.bendersky3ae9f7a2011-02-27 07:19:41 +0200148 return decl + '\n' + body + '\n'
149
150 def visit_FileAST(self, n):
151 s = ''
152 for ext in n.ext:
153 if isinstance(ext, c_ast.FuncDef):
154 s += self.visit(ext)
155 else:
156 s += self.visit(ext) + ';\n'
157 return s
158
159 def visit_Compound(self, n):
160 s = self._make_indent() + '{\n'
161 self.indent_level += 2
162 s += ''.join(self._generate_stmt(stmt) for stmt in n.block_items)
163 self.indent_level -= 2
164 s += self._make_indent() + '}\n'
165 return s
166
167 def visit_ParamList(self, n):
168 return ', '.join(self.visit(param) for param in n.params)
169
170 def visit_Return(self, n):
171 s = 'return'
172 if n.expr: s += ' ' + self.visit(n.expr)
173 return s + ';'
174
eli.benderskyfc96e5e2011-03-04 09:51:23 +0200175 def visit_Break(self, n):
176 return 'break;'
177
178 def visit_Continue(self, n):
179 return 'continue;'
eli.bendersky724b1cc2011-03-05 10:45:08 +0200180
181 def visit_TernaryOp(self, n):
182 s = self.visit(n.cond) + ' ? '
183 s += self.visit(n.iftrue) + ' : '
184 s += self.visit(n.iffalse)
185 return s
186
eli.benderskye6ecb1a2011-03-05 10:58:46 +0200187 def visit_If(self, n):
188 s = 'if ('
189 if n.cond: s += self.visit(n.cond)
190 s += ')\n'
191 s += self._generate_stmt(n.iftrue, add_indent=True)
192 if n.iffalse:
193 s += self._make_indent() + 'else\n'
194 s += self._generate_stmt(n.iffalse, add_indent=True)
195 return s
196
eli.benderskyae36e962011-02-27 08:25:05 +0200197 def visit_For(self, n):
198 s = 'for ('
199 if n.init: s += self.visit(n.init)
200 s += ';'
201 if n.cond: s += ' ' + self.visit(n.cond)
202 s += ';'
203 if n.next: s += ' ' + self.visit(n.next)
204 s += ')\n'
205 s += self._generate_stmt(n.stmt, add_indent=True)
206 return s
207
eli.benderskyfc96e5e2011-03-04 09:51:23 +0200208 def visit_While(self, n):
209 s = 'while ('
210 if n.cond: s += self.visit(n.cond)
211 s += ')\n'
212 s += self._generate_stmt(n.stmt, add_indent=True)
213 return s
214
eli.benderskye6ecb1a2011-03-05 10:58:46 +0200215 def visit_DoWhile(self, n):
216 s = 'do\n'
217 s += self._generate_stmt(n.stmt, add_indent=True)
218 s += self._make_indent() + 'while ('
219 if n.cond: s += self.visit(n.cond)
220 s += ');'
221 return s
222
eli.benderskyabb96e62011-03-05 16:30:05 +0200223 def visit_Switch(self, n):
224 s = 'switch (' + self.visit(n.cond) + ')\n'
225 s += self._generate_stmt(n.stmt, add_indent=True)
226 return s
227
228 def visit_Case(self, n):
229 s = 'case ' + self.visit(n.expr) + ':\n'
230 s += self._generate_stmt(n.stmt, add_indent=True)
231 return s
232
233 def visit_Default(self, n):
234 return 'default:\n' + self._generate_stmt(n.stmt, add_indent=True)
235
236 def visit_Label(self, n):
237 return n.name + ':\n' + self._generate_stmt(n.stmt)
238
239 def visit_Goto(self, n):
240 return 'goto ' + n.name + ';'
241
eli.benderskye6ecb1a2011-03-05 10:58:46 +0200242 def visit_EllipsisParam(self, n):
243 return '...'
244
eli.benderskyabb96e62011-03-05 16:30:05 +0200245 def visit_Struct(self, n):
246 return self._generate_struct_union(n, 'struct')
247
248 def visit_Union(self, n):
249 return self._generate_struct_union(n, 'union')
250
251 def _generate_struct_union(self, n, name):
252 """ Generates code for structs and unions. name should be either
253 'struct' or union.
254 """
255 s = name + ' ' + (n.name or '') + '\n'
256 s += self._make_indent() + '{\n'
257 self.indent_level += 2
258 for decl in n.decls:
259 s += self._generate_stmt(decl)
260 self.indent_level -= 2
261 s += self._make_indent() + '}'
262 return s
263
eli.benderskyae36e962011-02-27 08:25:05 +0200264 def _generate_stmt(self, n, add_indent=False):
eli.bendersky3ae9f7a2011-02-27 07:19:41 +0200265 """ Generation from a statement node. This method exists as a wrapper
266 for individual visit_* methods to handle different treatment of
267 some statements in this context.
268 """
269 typ = type(n)
eli.benderskyae36e962011-02-27 08:25:05 +0200270 if add_indent: self.indent_level += 2
eli.benderskyfc96e5e2011-03-04 09:51:23 +0200271 indent = self._make_indent()
eli.benderskyae36e962011-02-27 08:25:05 +0200272 if add_indent: self.indent_level -= 2
eli.bendersky3ae9f7a2011-02-27 07:19:41 +0200273
eli.bendersky724b1cc2011-03-05 10:45:08 +0200274 if typ in (
275 c_ast.Decl, c_ast.Assignment, c_ast.Cast, c_ast.UnaryOp,
276 c_ast.BinaryOp, c_ast.TernaryOp, c_ast.FuncCall):
eli.bendersky3ae9f7a2011-02-27 07:19:41 +0200277 # These can also appear in an expression context so no semicolon
278 # is added to them automatically
279 #
eli.benderskyfc96e5e2011-03-04 09:51:23 +0200280 return indent + self.visit(n) + ';\n'
eli.bendersky3ae9f7a2011-02-27 07:19:41 +0200281 elif typ in (c_ast.Compound,):
282 # No extra indentation required before the opening brace of a
283 # compound - because it consists of multiple lines it has to
284 # compute its own indentation.
285 #
eli.benderskyae36e962011-02-27 08:25:05 +0200286 return self.visit(n)
eli.bendersky3ae9f7a2011-02-27 07:19:41 +0200287 else:
eli.benderskyfc96e5e2011-03-04 09:51:23 +0200288 return indent + self.visit(n) + '\n'
eli.benderskyafcfaac2011-02-25 16:46:01 +0200289
eli.benderskyd5ba3452011-02-18 21:32:47 +0200290 def _generate_decl(self, n):
291 """ Generation from a Decl node.
292 """
eli.benderskyafcfaac2011-02-25 16:46:01 +0200293 s = ''
294 if n.funcspec: s = ' '.join(n.funcspec) + ' '
295 if n.storage: s += ' '.join(n.storage) + ' '
296 s += self._generate_type(n.type)
297 return s
eli.benderskyd5ba3452011-02-18 21:32:47 +0200298
299 def _generate_type(self, n, modifiers=[]):
300 """ Recursive generation from a type node. n is the type node.
eli.benderskyafcfaac2011-02-25 16:46:01 +0200301 modifiers collects the PtrDecl, ArrayDecl and FuncDecl modifiers
302 encountered on the way down to a TypeDecl, to allow proper
303 generation from it.
eli.benderskyd5ba3452011-02-18 21:32:47 +0200304 """
305 typ = type(n)
306 #~ print(n, modifiers)
307
308 if typ == c_ast.TypeDecl:
eli.benderskyafcfaac2011-02-25 16:46:01 +0200309 s = ''
310 if n.quals: s += ' '.join(n.quals) + ' '
311 s += self.visit(n.type)
eli.benderskyd5ba3452011-02-18 21:32:47 +0200312
313 nstr = n.declname if n.declname else ''
eli.bendersky3ae9f7a2011-02-27 07:19:41 +0200314 # Resolve modifiers.
eli.benderskyafcfaac2011-02-25 16:46:01 +0200315 # Wrap in parens to distinguish pointer to array and pointer to
316 # function syntax.
eli.benderskyd5ba3452011-02-18 21:32:47 +0200317 #
318 for i, modifier in enumerate(modifiers):
319 if isinstance(modifier, c_ast.ArrayDecl):
320 if (i != 0 and isinstance(modifiers[i - 1], c_ast.PtrDecl)):
321 nstr = '(' + nstr + ')'
eli.benderskyafcfaac2011-02-25 16:46:01 +0200322 nstr += '[' + self.visit(modifier.dim) + ']'
323 elif isinstance(modifier, c_ast.FuncDecl):
324 if (i != 0 and isinstance(modifiers[i - 1], c_ast.PtrDecl)):
325 nstr = '(' + nstr + ')'
326 nstr += '(' + self.visit(modifier.args) + ')'
eli.benderskyd5ba3452011-02-18 21:32:47 +0200327 elif isinstance(modifier, c_ast.PtrDecl):
328 nstr = '*' + nstr
eli.bendersky3ae9f7a2011-02-27 07:19:41 +0200329 s += ' ' + nstr
eli.benderskyafcfaac2011-02-25 16:46:01 +0200330 return s
eli.benderskyd5ba3452011-02-18 21:32:47 +0200331 elif typ in (c_ast.Typename, c_ast.Decl):
eli.benderskyafcfaac2011-02-25 16:46:01 +0200332 return self._generate_decl(n.type)
eli.benderskyd5ba3452011-02-18 21:32:47 +0200333 elif typ == c_ast.IdentifierType:
eli.benderskyafcfaac2011-02-25 16:46:01 +0200334 return ' '.join(n.names) + ' '
335 elif typ in (c_ast.ArrayDecl, c_ast.PtrDecl, c_ast.FuncDecl):
336 return self._generate_type(n.type, modifiers + [n])
eli.benderskyabb96e62011-03-05 16:30:05 +0200337 else:
338 return self.visit(n)
eli.benderskyd5ba3452011-02-18 21:32:47 +0200339
eli.bendersky724b1cc2011-03-05 10:45:08 +0200340 def _parenthesize_if(self, n, condition):
341 """ Visits 'n' and returns its string representation, parenthesized
342 if the condition function applied to the node returns True.
343 """
344 s = self.visit(n)
345 if condition(n):
346 return '(' + s + ')'
347 else:
348 return s
349
eli.benderskyd5ba3452011-02-18 21:32:47 +0200350
351def translate_to_c(filename):
352 ast = parse_file(filename, use_cpp=True)
353 generator = CGenerator()
eli.benderskyafcfaac2011-02-25 16:46:01 +0200354 print(generator.visit(ast))
eli.benderskyd5ba3452011-02-18 21:32:47 +0200355
356
357if __name__ == "__main__":
358 if len(sys.argv) > 1:
359 translate_to_c(sys.argv[1])
360 else:
361 src = r'''
eli.benderskye6ecb1a2011-03-05 10:58:46 +0200362
363int mydecl(float joe, ...);
364
eli.benderskyabb96e62011-03-05 16:30:05 +0200365struct blah_t
366{
367 int k;
368 float b;
369
370 union {
371 int bla : 5;
372 int asd : 3;
373 int : 4;
374 } uu;
375};
376
eli.bendersky724b1cc2011-03-05 10:45:08 +0200377typedef int koe;
eli.benderskyae36e962011-02-27 08:25:05 +0200378static unsigned int hash_func(const char* str, unsigned int table_size)
eli.bendersky3ae9f7a2011-02-27 07:19:41 +0200379{
eli.benderskyabb96e62011-03-05 16:30:05 +0200380 for (int j = 8; k < n; ++k)
381 printf(k);
eli.benderskyae36e962011-02-27 08:25:05 +0200382 return hash_value;
383}
eli.bendersky3ae9f7a2011-02-27 07:19:41 +0200384
eli.benderskyd5ba3452011-02-18 21:32:47 +0200385 '''
386 parser = c_parser.CParser()
387 ast = parser.parse(src)
388 ast.show()
389 generator = CGenerator()
eli.benderskyafcfaac2011-02-25 16:46:01 +0200390 print(generator.visit(ast))
eli.benderskyd5ba3452011-02-18 21:32:47 +0200391
392 print("Please provide a filename as argument")
eli.bendersky3ae9f7a2011-02-27 07:19:41 +0200393
394
eli.benderskyfc96e5e2011-03-04 09:51:23 +0200395# ZZZ: turn self.indent_level += 2 ... -= 2 into a context manager!
396