eli.bendersky | d5ba345 | 2011-02-18 21:32:47 +0200 | [diff] [blame] | 1 | #----------------------------------------------------------------- |
| 2 | # pycparser: c-to-c.py |
| 3 | # |
eli.bendersky | afcfaac | 2011-02-25 16:46:01 +0200 | [diff] [blame^] | 4 | # 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.bendersky | d5ba345 | 2011-02-18 21:32:47 +0200 | [diff] [blame] | 6 | # |
| 7 | # Copyright (C) 2008-2011, Eli Bendersky |
| 8 | # License: LGPL |
| 9 | #----------------------------------------------------------------- |
| 10 | from __future__ import print_function |
| 11 | import sys |
| 12 | |
| 13 | # This is not required if you've installed pycparser into |
| 14 | # your site-packages/ with setup.py |
| 15 | # |
| 16 | sys.path.insert(0, '..') |
| 17 | |
| 18 | from pycparser import c_parser, c_ast, parse_file |
| 19 | |
| 20 | |
eli.bendersky | afcfaac | 2011-02-25 16:46:01 +0200 | [diff] [blame^] | 21 | class 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.bendersky | d5ba345 | 2011-02-18 21:32:47 +0200 | [diff] [blame] | 26 | def __init__(self): |
| 27 | self.output = '' |
| 28 | |
eli.bendersky | afcfaac | 2011-02-25 16:46:01 +0200 | [diff] [blame^] | 29 | # Statements start with indentation of self.indent_level spaces |
| 30 | # |
| 31 | self.indent_level = 0 |
| 32 | |
| 33 | def visit(self, node): |
| 34 | method = 'visit_' + node.__class__.__name__ |
| 35 | return getattr(self, method, self.generic_visit)(node) |
| 36 | |
| 37 | def generic_visit(self, node): |
| 38 | #~ print('generic:', type(node)) |
| 39 | if node is None: |
| 40 | return '' |
| 41 | else: |
| 42 | return ''.join(self.visit(c) for c in node.children()) |
eli.bendersky | d5ba345 | 2011-02-18 21:32:47 +0200 | [diff] [blame] | 43 | |
| 44 | def visit_Constant(self, n): |
eli.bendersky | afcfaac | 2011-02-25 16:46:01 +0200 | [diff] [blame^] | 45 | return n.value |
| 46 | |
eli.bendersky | d5ba345 | 2011-02-18 21:32:47 +0200 | [diff] [blame] | 47 | def visit_ID(self, n): |
eli.bendersky | afcfaac | 2011-02-25 16:46:01 +0200 | [diff] [blame^] | 48 | return n.name |
eli.bendersky | d5ba345 | 2011-02-18 21:32:47 +0200 | [diff] [blame] | 49 | |
| 50 | def visit_IdentifierType(self, n): |
eli.bendersky | afcfaac | 2011-02-25 16:46:01 +0200 | [diff] [blame^] | 51 | return ' '.join(n.names) + ' ' |
eli.bendersky | d5ba345 | 2011-02-18 21:32:47 +0200 | [diff] [blame] | 52 | |
eli.bendersky | afcfaac | 2011-02-25 16:46:01 +0200 | [diff] [blame^] | 53 | def visit_Decl(self, n): |
| 54 | s = self._generate_decl(n) |
| 55 | if n.bitsize: s += ' : ' + self.visit(n.bitsize) |
| 56 | if n.init: s += ' = ' + self.visit(n.init) |
| 57 | return s |
eli.bendersky | d5ba345 | 2011-02-18 21:32:47 +0200 | [diff] [blame] | 58 | |
eli.bendersky | afcfaac | 2011-02-25 16:46:01 +0200 | [diff] [blame^] | 59 | def visit_FuncDef(self, n): |
| 60 | decl = self.visit(n.decl) |
| 61 | self.indent_level = 0 |
| 62 | body = self.visit(n.body) |
| 63 | return decl + '\n' + body |
| 64 | |
eli.bendersky | d5ba345 | 2011-02-18 21:32:47 +0200 | [diff] [blame] | 65 | def _generate_decl(self, n): |
| 66 | """ Generation from a Decl node. |
| 67 | """ |
eli.bendersky | afcfaac | 2011-02-25 16:46:01 +0200 | [diff] [blame^] | 68 | s = '' |
| 69 | if n.funcspec: s = ' '.join(n.funcspec) + ' ' |
| 70 | if n.storage: s += ' '.join(n.storage) + ' ' |
| 71 | s += self._generate_type(n.type) |
| 72 | return s |
eli.bendersky | d5ba345 | 2011-02-18 21:32:47 +0200 | [diff] [blame] | 73 | |
| 74 | def _generate_type(self, n, modifiers=[]): |
| 75 | """ Recursive generation from a type node. n is the type node. |
eli.bendersky | afcfaac | 2011-02-25 16:46:01 +0200 | [diff] [blame^] | 76 | modifiers collects the PtrDecl, ArrayDecl and FuncDecl modifiers |
| 77 | encountered on the way down to a TypeDecl, to allow proper |
| 78 | generation from it. |
eli.bendersky | d5ba345 | 2011-02-18 21:32:47 +0200 | [diff] [blame] | 79 | """ |
| 80 | typ = type(n) |
| 81 | #~ print(n, modifiers) |
| 82 | |
| 83 | if typ == c_ast.TypeDecl: |
eli.bendersky | afcfaac | 2011-02-25 16:46:01 +0200 | [diff] [blame^] | 84 | s = '' |
| 85 | if n.quals: s += ' '.join(n.quals) + ' ' |
| 86 | s += self.visit(n.type) |
eli.bendersky | d5ba345 | 2011-02-18 21:32:47 +0200 | [diff] [blame] | 87 | |
| 88 | nstr = n.declname if n.declname else '' |
eli.bendersky | afcfaac | 2011-02-25 16:46:01 +0200 | [diff] [blame^] | 89 | # Resolve odifiers. |
| 90 | # Wrap in parens to distinguish pointer to array and pointer to |
| 91 | # function syntax. |
eli.bendersky | d5ba345 | 2011-02-18 21:32:47 +0200 | [diff] [blame] | 92 | # |
| 93 | for i, modifier in enumerate(modifiers): |
| 94 | if isinstance(modifier, c_ast.ArrayDecl): |
| 95 | if (i != 0 and isinstance(modifiers[i - 1], c_ast.PtrDecl)): |
| 96 | nstr = '(' + nstr + ')' |
eli.bendersky | afcfaac | 2011-02-25 16:46:01 +0200 | [diff] [blame^] | 97 | nstr += '[' + self.visit(modifier.dim) + ']' |
| 98 | elif isinstance(modifier, c_ast.FuncDecl): |
| 99 | if (i != 0 and isinstance(modifiers[i - 1], c_ast.PtrDecl)): |
| 100 | nstr = '(' + nstr + ')' |
| 101 | nstr += '(' + self.visit(modifier.args) + ')' |
eli.bendersky | d5ba345 | 2011-02-18 21:32:47 +0200 | [diff] [blame] | 102 | elif isinstance(modifier, c_ast.PtrDecl): |
| 103 | nstr = '*' + nstr |
eli.bendersky | afcfaac | 2011-02-25 16:46:01 +0200 | [diff] [blame^] | 104 | s += nstr |
| 105 | return s |
eli.bendersky | d5ba345 | 2011-02-18 21:32:47 +0200 | [diff] [blame] | 106 | elif typ in (c_ast.Typename, c_ast.Decl): |
eli.bendersky | afcfaac | 2011-02-25 16:46:01 +0200 | [diff] [blame^] | 107 | return self._generate_decl(n.type) |
eli.bendersky | d5ba345 | 2011-02-18 21:32:47 +0200 | [diff] [blame] | 108 | elif typ == c_ast.IdentifierType: |
eli.bendersky | afcfaac | 2011-02-25 16:46:01 +0200 | [diff] [blame^] | 109 | return ' '.join(n.names) + ' ' |
| 110 | elif typ in (c_ast.ArrayDecl, c_ast.PtrDecl, c_ast.FuncDecl): |
| 111 | return self._generate_type(n.type, modifiers + [n]) |
eli.bendersky | d5ba345 | 2011-02-18 21:32:47 +0200 | [diff] [blame] | 112 | |
| 113 | |
| 114 | def translate_to_c(filename): |
| 115 | ast = parse_file(filename, use_cpp=True) |
| 116 | generator = CGenerator() |
eli.bendersky | afcfaac | 2011-02-25 16:46:01 +0200 | [diff] [blame^] | 117 | print(generator.visit(ast)) |
eli.bendersky | d5ba345 | 2011-02-18 21:32:47 +0200 | [diff] [blame] | 118 | |
| 119 | |
| 120 | if __name__ == "__main__": |
| 121 | if len(sys.argv) > 1: |
| 122 | translate_to_c(sys.argv[1]) |
| 123 | else: |
| 124 | src = r''' |
eli.bendersky | afcfaac | 2011-02-25 16:46:01 +0200 | [diff] [blame^] | 125 | static const int (**c[chevo])[2] = t; |
| 126 | int (*joe)(); |
| 127 | |
| 128 | int main() { |
| 129 | int kk; |
| 130 | } |
eli.bendersky | d5ba345 | 2011-02-18 21:32:47 +0200 | [diff] [blame] | 131 | ''' |
| 132 | parser = c_parser.CParser() |
| 133 | ast = parser.parse(src) |
| 134 | ast.show() |
| 135 | generator = CGenerator() |
eli.bendersky | afcfaac | 2011-02-25 16:46:01 +0200 | [diff] [blame^] | 136 | print(generator.visit(ast)) |
eli.bendersky | d5ba345 | 2011-02-18 21:32:47 +0200 | [diff] [blame] | 137 | |
| 138 | print("Please provide a filename as argument") |