blob: a3fe14886abf7127d1bce1477d3c56ddca2aaabd [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):
42 #~ print('generic:', type(node))
43 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.benderskyafcfaac2011-02-25 16:46:01 +020090 def visit_Decl(self, n):
91 s = self._generate_decl(n)
92 if n.bitsize: s += ' : ' + self.visit(n.bitsize)
93 if n.init: s += ' = ' + self.visit(n.init)
94 return s
eli.benderskyd5ba3452011-02-18 21:32:47 +020095
eli.bendersky3ae9f7a2011-02-27 07:19:41 +020096 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
102 def visit_Cast(self, n):
103 s = '(' + self.visit(n.to_type) + ')'
104 return s + ' ' + self.visit(n.expr)
105
eli.bendersky724b1cc2011-03-05 10:45:08 +0200106 def visit_ExprList(self, n):
107 return ', '.join(self.visit(expr) for expr in n.exprs)
108
eli.bendersky3ae9f7a2011-02-27 07:19:41 +0200109 def visit_Enum(self, n):
110 s = 'enum'
111 if n.name: s += ' ' + n.name
112 if n.values:
113 s += ' {'
114 for i, enumerator in enumerate(n.values.enumerators):
115 s += enumerator.name
116 if enumerator.value:
117 s += ' = ' + self.visit(enumerator.value)
118 if i != len(n.values.enumerators) - 1:
119 s += ', '
120 s += '}'
121 return s
122
123 def visit_Struct(self, n):
124 s = 'struct'
125 if n.name: s += ' ' + n.name
126 if n.decls:
127 s += ' { \n'
128 for decl in n.decls:
129 s += ' ' + self.visit(decl) + ';\n'
130 s += '}'
131 return s
132
eli.benderskyafcfaac2011-02-25 16:46:01 +0200133 def visit_FuncDef(self, n):
134 decl = self.visit(n.decl)
135 self.indent_level = 0
eli.bendersky3ae9f7a2011-02-27 07:19:41 +0200136 # The body is a Compound node
eli.benderskyafcfaac2011-02-25 16:46:01 +0200137 body = self.visit(n.body)
eli.bendersky3ae9f7a2011-02-27 07:19:41 +0200138 return decl + '\n' + body + '\n'
139
140 def visit_FileAST(self, n):
141 s = ''
142 for ext in n.ext:
143 if isinstance(ext, c_ast.FuncDef):
144 s += self.visit(ext)
145 else:
146 s += self.visit(ext) + ';\n'
147 return s
148
149 def visit_Compound(self, n):
150 s = self._make_indent() + '{\n'
151 self.indent_level += 2
152 s += ''.join(self._generate_stmt(stmt) for stmt in n.block_items)
153 self.indent_level -= 2
154 s += self._make_indent() + '}\n'
155 return s
156
157 def visit_ParamList(self, n):
158 return ', '.join(self.visit(param) for param in n.params)
159
160 def visit_Return(self, n):
161 s = 'return'
162 if n.expr: s += ' ' + self.visit(n.expr)
163 return s + ';'
164
eli.benderskyfc96e5e2011-03-04 09:51:23 +0200165 def visit_Break(self, n):
166 return 'break;'
167
168 def visit_Continue(self, n):
169 return 'continue;'
eli.bendersky724b1cc2011-03-05 10:45:08 +0200170
171 def visit_TernaryOp(self, n):
172 s = self.visit(n.cond) + ' ? '
173 s += self.visit(n.iftrue) + ' : '
174 s += self.visit(n.iffalse)
175 return s
176
eli.benderskye6ecb1a2011-03-05 10:58:46 +0200177 def visit_If(self, n):
178 s = 'if ('
179 if n.cond: s += self.visit(n.cond)
180 s += ')\n'
181 s += self._generate_stmt(n.iftrue, add_indent=True)
182 if n.iffalse:
183 s += self._make_indent() + 'else\n'
184 s += self._generate_stmt(n.iffalse, add_indent=True)
185 return s
186
eli.benderskyae36e962011-02-27 08:25:05 +0200187 def visit_For(self, n):
188 s = 'for ('
189 if n.init: s += self.visit(n.init)
190 s += ';'
191 if n.cond: s += ' ' + self.visit(n.cond)
192 s += ';'
193 if n.next: s += ' ' + self.visit(n.next)
194 s += ')\n'
195 s += self._generate_stmt(n.stmt, add_indent=True)
196 return s
197
eli.benderskyfc96e5e2011-03-04 09:51:23 +0200198 def visit_While(self, n):
199 s = 'while ('
200 if n.cond: s += self.visit(n.cond)
201 s += ')\n'
202 s += self._generate_stmt(n.stmt, add_indent=True)
203 return s
204
eli.benderskye6ecb1a2011-03-05 10:58:46 +0200205 def visit_DoWhile(self, n):
206 s = 'do\n'
207 s += self._generate_stmt(n.stmt, add_indent=True)
208 s += self._make_indent() + 'while ('
209 if n.cond: s += self.visit(n.cond)
210 s += ');'
211 return s
212
213 def visit_EllipsisParam(self, n):
214 return '...'
215
eli.benderskyae36e962011-02-27 08:25:05 +0200216 def _generate_stmt(self, n, add_indent=False):
eli.bendersky3ae9f7a2011-02-27 07:19:41 +0200217 """ Generation from a statement node. This method exists as a wrapper
218 for individual visit_* methods to handle different treatment of
219 some statements in this context.
220 """
221 typ = type(n)
eli.benderskyae36e962011-02-27 08:25:05 +0200222 if add_indent: self.indent_level += 2
eli.benderskyfc96e5e2011-03-04 09:51:23 +0200223 indent = self._make_indent()
eli.benderskyae36e962011-02-27 08:25:05 +0200224 if add_indent: self.indent_level -= 2
eli.bendersky3ae9f7a2011-02-27 07:19:41 +0200225
eli.bendersky724b1cc2011-03-05 10:45:08 +0200226 if typ in (
227 c_ast.Decl, c_ast.Assignment, c_ast.Cast, c_ast.UnaryOp,
228 c_ast.BinaryOp, c_ast.TernaryOp, c_ast.FuncCall):
eli.bendersky3ae9f7a2011-02-27 07:19:41 +0200229 # These can also appear in an expression context so no semicolon
230 # is added to them automatically
231 #
eli.benderskyfc96e5e2011-03-04 09:51:23 +0200232 return indent + self.visit(n) + ';\n'
eli.bendersky3ae9f7a2011-02-27 07:19:41 +0200233 elif typ in (c_ast.Compound,):
234 # No extra indentation required before the opening brace of a
235 # compound - because it consists of multiple lines it has to
236 # compute its own indentation.
237 #
eli.benderskyae36e962011-02-27 08:25:05 +0200238 return self.visit(n)
eli.bendersky3ae9f7a2011-02-27 07:19:41 +0200239 else:
eli.benderskyfc96e5e2011-03-04 09:51:23 +0200240 return indent + self.visit(n) + '\n'
eli.benderskyafcfaac2011-02-25 16:46:01 +0200241
eli.benderskyd5ba3452011-02-18 21:32:47 +0200242 def _generate_decl(self, n):
243 """ Generation from a Decl node.
244 """
eli.benderskyafcfaac2011-02-25 16:46:01 +0200245 s = ''
246 if n.funcspec: s = ' '.join(n.funcspec) + ' '
247 if n.storage: s += ' '.join(n.storage) + ' '
248 s += self._generate_type(n.type)
249 return s
eli.benderskyd5ba3452011-02-18 21:32:47 +0200250
251 def _generate_type(self, n, modifiers=[]):
252 """ Recursive generation from a type node. n is the type node.
eli.benderskyafcfaac2011-02-25 16:46:01 +0200253 modifiers collects the PtrDecl, ArrayDecl and FuncDecl modifiers
254 encountered on the way down to a TypeDecl, to allow proper
255 generation from it.
eli.benderskyd5ba3452011-02-18 21:32:47 +0200256 """
257 typ = type(n)
258 #~ print(n, modifiers)
259
260 if typ == c_ast.TypeDecl:
eli.benderskyafcfaac2011-02-25 16:46:01 +0200261 s = ''
262 if n.quals: s += ' '.join(n.quals) + ' '
263 s += self.visit(n.type)
eli.benderskyd5ba3452011-02-18 21:32:47 +0200264
265 nstr = n.declname if n.declname else ''
eli.bendersky3ae9f7a2011-02-27 07:19:41 +0200266 # Resolve modifiers.
eli.benderskyafcfaac2011-02-25 16:46:01 +0200267 # Wrap in parens to distinguish pointer to array and pointer to
268 # function syntax.
eli.benderskyd5ba3452011-02-18 21:32:47 +0200269 #
270 for i, modifier in enumerate(modifiers):
271 if isinstance(modifier, c_ast.ArrayDecl):
272 if (i != 0 and isinstance(modifiers[i - 1], c_ast.PtrDecl)):
273 nstr = '(' + nstr + ')'
eli.benderskyafcfaac2011-02-25 16:46:01 +0200274 nstr += '[' + self.visit(modifier.dim) + ']'
275 elif isinstance(modifier, c_ast.FuncDecl):
276 if (i != 0 and isinstance(modifiers[i - 1], c_ast.PtrDecl)):
277 nstr = '(' + nstr + ')'
278 nstr += '(' + self.visit(modifier.args) + ')'
eli.benderskyd5ba3452011-02-18 21:32:47 +0200279 elif isinstance(modifier, c_ast.PtrDecl):
280 nstr = '*' + nstr
eli.bendersky3ae9f7a2011-02-27 07:19:41 +0200281 s += ' ' + nstr
eli.benderskyafcfaac2011-02-25 16:46:01 +0200282 return s
eli.benderskyd5ba3452011-02-18 21:32:47 +0200283 elif typ in (c_ast.Typename, c_ast.Decl):
eli.benderskyafcfaac2011-02-25 16:46:01 +0200284 return self._generate_decl(n.type)
eli.benderskyd5ba3452011-02-18 21:32:47 +0200285 elif typ == c_ast.IdentifierType:
eli.benderskyafcfaac2011-02-25 16:46:01 +0200286 return ' '.join(n.names) + ' '
287 elif typ in (c_ast.ArrayDecl, c_ast.PtrDecl, c_ast.FuncDecl):
288 return self._generate_type(n.type, modifiers + [n])
eli.benderskyd5ba3452011-02-18 21:32:47 +0200289
eli.bendersky724b1cc2011-03-05 10:45:08 +0200290 def _parenthesize_if(self, n, condition):
291 """ Visits 'n' and returns its string representation, parenthesized
292 if the condition function applied to the node returns True.
293 """
294 s = self.visit(n)
295 if condition(n):
296 return '(' + s + ')'
297 else:
298 return s
299
eli.benderskyd5ba3452011-02-18 21:32:47 +0200300
301def translate_to_c(filename):
302 ast = parse_file(filename, use_cpp=True)
303 generator = CGenerator()
eli.benderskyafcfaac2011-02-25 16:46:01 +0200304 print(generator.visit(ast))
eli.benderskyd5ba3452011-02-18 21:32:47 +0200305
306
307if __name__ == "__main__":
308 if len(sys.argv) > 1:
309 translate_to_c(sys.argv[1])
310 else:
311 src = r'''
eli.benderskye6ecb1a2011-03-05 10:58:46 +0200312
313int mydecl(float joe, ...);
314
eli.bendersky724b1cc2011-03-05 10:45:08 +0200315typedef int koe;
eli.benderskyae36e962011-02-27 08:25:05 +0200316static unsigned int hash_func(const char* str, unsigned int table_size)
eli.bendersky3ae9f7a2011-02-27 07:19:41 +0200317{
eli.benderskye6ecb1a2011-03-05 10:58:46 +0200318 foo(bar, bas, moe, callme(func));
eli.bendersky724b1cc2011-03-05 10:45:08 +0200319 print(joe ? moe : baba[4]);
eli.benderskyae36e962011-02-27 08:25:05 +0200320 a++;
321 ++a;
eli.bendersky724b1cc2011-03-05 10:45:08 +0200322
eli.benderskye6ecb1a2011-03-05 10:58:46 +0200323 if (k > 2) {
324 print(5);
325 } else
326 print(888888);
eli.bendersky3ae9f7a2011-02-27 07:19:41 +0200327
eli.benderskyae36e962011-02-27 08:25:05 +0200328 return hash_value;
329}
eli.bendersky3ae9f7a2011-02-27 07:19:41 +0200330
eli.benderskyd5ba3452011-02-18 21:32:47 +0200331 '''
332 parser = c_parser.CParser()
333 ast = parser.parse(src)
334 ast.show()
335 generator = CGenerator()
eli.benderskyafcfaac2011-02-25 16:46:01 +0200336 print(generator.visit(ast))
eli.benderskyd5ba3452011-02-18 21:32:47 +0200337
338 print("Please provide a filename as argument")
eli.bendersky3ae9f7a2011-02-27 07:19:41 +0200339
340
eli.benderskyfc96e5e2011-03-04 09:51:23 +0200341# ZZZ: turn self.indent_level += 2 ... -= 2 into a context manager!
342