diff options
author | Eli Bendersky <eliben@gmail.com> | 2012-01-24 05:53:41 +0200 |
---|---|---|
committer | Eli Bendersky <eliben@gmail.com> | 2012-01-24 05:53:41 +0200 |
commit | 0e8e1b7676c3db660c7ee39439f5387b85682a09 (patch) | |
tree | 02dc0cbc8f9af7246a072872a5a30713228c6705 /examples | |
parent | 665a0bd5c7ce7c9b7be87aed962bb33a541c0850 (diff) | |
download | pycparser-0e8e1b7676c3db660c7ee39439f5387b85682a09.tar.gz |
moving CGenerator from examples/c-to-c.py into its own class in pycparser/. c-to-c remains as a shell example over it
Diffstat (limited to 'examples')
-rw-r--r-- | examples/c-to-c.py | 391 |
1 files changed, 9 insertions, 382 deletions
diff --git a/examples/c-to-c.py b/examples/c-to-c.py index e1277ab..ca76cc5 100644 --- a/examples/c-to-c.py +++ b/examples/c-to-c.py @@ -1,15 +1,12 @@ -#----------------------------------------------------------------- +#------------------------------------------------------------------------------ # pycparser: c-to-c.py # -# Example of a C code generator from pycparser AST nodes, serving -# as a simplistic translator from C to AST and back to C. -# Note: at this stage, the example is "alpha release" and considered -# experimental. Please file any bugs you find in the Issues page on pycparser's -# website. +# Example of using pycparser.c_generator, serving as a simplistic translator +# from C to AST and back to C. # -# Copyright (C) 2008-2011, Eli Bendersky +# Copyright (C) 2008-2012, Eli Bendersky # License: BSD -#----------------------------------------------------------------- +#------------------------------------------------------------------------------ from __future__ import print_function import sys @@ -18,382 +15,12 @@ import sys # sys.path.insert(0, '..') -from pycparser import c_parser, c_ast, parse_file - - -class CGenerator(object): - """ Uses the same visitor pattern as c_ast.NodeVisitor, but modified to - return a value from each visit method, using string accumulation in - generic_visit. - """ - def __init__(self): - self.output = '' - - # Statements start with indentation of self.indent_level spaces, using - # the _make_indent method - # - self.indent_level = 0 - - def _make_indent(self): - return ' ' * self.indent_level - - def visit(self, node): - method = 'visit_' + node.__class__.__name__ - return getattr(self, method, self.generic_visit)(node) - - def generic_visit(self, node): - #~ print('generic:', type(node)) - if node is None: - return '' - else: - return ''.join(self.visit(c) for c in node.children()) - - def visit_Constant(self, n): - return n.value - - def visit_ID(self, n): - return n.name - - def visit_ArrayRef(self, n): - arrref = self._parenthesize_unless_simple(n.name) - return arrref + '[' + self.visit(n.subscript) + ']' - - def visit_StructRef(self, n): - sref = self._parenthesize_unless_simple(n.name) - return sref + n.type + self.visit(n.field) - - def visit_FuncCall(self, n): - fref = self._parenthesize_unless_simple(n.name) - return fref + '(' + self.visit(n.args) + ')' - - def visit_UnaryOp(self, n): - operand = self._parenthesize_unless_simple(n.expr) - if n.op == 'p++': - return '%s++' % operand - elif n.op == 'p--': - return '%s--' % operand - elif n.op == 'sizeof': - # Always parenthesize the argument of sizeof since it can be - # a name. - return 'sizeof(%s)' % self.visit(n.expr) - else: - return '%s%s' % (n.op, operand) - - def visit_BinaryOp(self, n): - lval_str = self._parenthesize_if(n.left, - lambda d: not self._is_simple_node(d)) - rval_str = self._parenthesize_if(n.right, - lambda d: not self._is_simple_node(d)) - return '%s %s %s' % (lval_str, n.op, rval_str) - - def visit_Assignment(self, n): - rval_str = self._parenthesize_if( - n.rvalue, - lambda n: isinstance(n, c_ast.Assignment)) - return '%s %s %s' % (self.visit(n.lvalue), n.op, rval_str) - - def visit_IdentifierType(self, n): - return ' '.join(n.names) - - def visit_Decl(self, n, no_type=False): - # no_type is used when a Decl is part of a DeclList, where the type is - # explicitly only for the first delaration in a list. - # - s = n.name if no_type else self._generate_decl(n) - if n.bitsize: s += ' : ' + self.visit(n.bitsize) - if n.init: - if isinstance(n.init, c_ast.ExprList): - s += ' = {' + self.visit(n.init) + '}' - else: - s += ' = ' + self.visit(n.init) - return s - - def visit_DeclList(self, n): - s = self.visit(n.decls[0]) - if len(n.decls) > 1: - s += ', ' + ', '.join(self.visit_Decl(decl, no_type=True) - for decl in n.decls[1:]) - return s - - def visit_Typedef(self, n): - s = '' - if n.storage: s += ' '.join(n.storage) + ' ' - s += self._generate_type(n.type) - return s - - def visit_Cast(self, n): - s = '(' + self._generate_type(n.to_type) + ')' - return s + ' ' + self._parenthesize_unless_simple(n.expr) - - def visit_ExprList(self, n): - visited_subexprs = [] - for expr in n.exprs: - if isinstance(expr, c_ast.ExprList): - visited_subexprs.append('{' + self.visit(expr) + '}') - else: - visited_subexprs.append(self.visit(expr)) - return ', '.join(visited_subexprs) - - def visit_Enum(self, n): - s = 'enum' - if n.name: s += ' ' + n.name - if n.values: - s += ' {' - for i, enumerator in enumerate(n.values.enumerators): - s += enumerator.name - if enumerator.value: - s += ' = ' + self.visit(enumerator.value) - if i != len(n.values.enumerators) - 1: - s += ', ' - s += '}' - return s - - def visit_FuncDef(self, n): - decl = self.visit(n.decl) - self.indent_level = 0 - # The body is a Compound node - body = self.visit(n.body) - return decl + '\n' + body + '\n' - - def visit_FileAST(self, n): - s = '' - for ext in n.ext: - if isinstance(ext, c_ast.FuncDef): - s += self.visit(ext) - else: - s += self.visit(ext) + ';\n' - return s - - def visit_Compound(self, n): - s = self._make_indent() + '{\n' - self.indent_level += 2 - if n.block_items: - s += ''.join(self._generate_stmt(stmt) for stmt in n.block_items) - self.indent_level -= 2 - s += self._make_indent() + '}\n' - return s - - def visit_EmptyStatement(self, n): - return ';' - - def visit_ParamList(self, n): - return ', '.join(self.visit(param) for param in n.params) - - def visit_Return(self, n): - s = 'return' - if n.expr: s += ' ' + self.visit(n.expr) - return s + ';' - - def visit_Break(self, n): - return 'break;' - - def visit_Continue(self, n): - return 'continue;' - - def visit_TernaryOp(self, n): - s = self.visit(n.cond) + ' ? ' - s += self.visit(n.iftrue) + ' : ' - s += self.visit(n.iffalse) - return s - - def visit_If(self, n): - s = 'if (' - if n.cond: s += self.visit(n.cond) - s += ')\n' - s += self._generate_stmt(n.iftrue, add_indent=True) - if n.iffalse: - s += self._make_indent() + 'else\n' - s += self._generate_stmt(n.iffalse, add_indent=True) - return s - - def visit_For(self, n): - s = 'for (' - if n.init: s += self.visit(n.init) - s += ';' - if n.cond: s += ' ' + self.visit(n.cond) - s += ';' - if n.next: s += ' ' + self.visit(n.next) - s += ')\n' - s += self._generate_stmt(n.stmt, add_indent=True) - return s - - def visit_While(self, n): - s = 'while (' - if n.cond: s += self.visit(n.cond) - s += ')\n' - s += self._generate_stmt(n.stmt, add_indent=True) - return s - - def visit_DoWhile(self, n): - s = 'do\n' - s += self._generate_stmt(n.stmt, add_indent=True) - s += self._make_indent() + 'while (' - if n.cond: s += self.visit(n.cond) - s += ');' - return s - - def visit_Switch(self, n): - s = 'switch (' + self.visit(n.cond) + ')\n' - s += self._generate_stmt(n.stmt, add_indent=True) - return s - - def visit_Case(self, n): - s = 'case ' + self.visit(n.expr) + ':\n' - s += self._generate_stmt(n.stmt, add_indent=True) - return s - - def visit_Default(self, n): - return 'default:\n' + self._generate_stmt(n.stmt, add_indent=True) - - def visit_Label(self, n): - return n.name + ':\n' + self._generate_stmt(n.stmt) - - def visit_Goto(self, n): - return 'goto ' + n.name + ';' - - def visit_EllipsisParam(self, n): - return '...' - - def visit_Struct(self, n): - return self._generate_struct_union(n, 'struct') - - def visit_Typename(self, n): - return self._generate_type(n.type) - - def visit_Union(self, n): - return self._generate_struct_union(n, 'union') - - def visit_NamedInitializer(self, n): - s = '' - for name in n.name: - if isinstance(name, c_ast.ID): - s += '.' + name.name - elif isinstance(name, c_ast.Constant): - s += '[' + name.value + ']' - s += ' = ' + self.visit(n.expr) - return s - - def _generate_struct_union(self, n, name): - """ Generates code for structs and unions. name should be either - 'struct' or union. - """ - s = name + ' ' + (n.name or '') - if n.decls: - s += '\n' - s += self._make_indent() - self.indent_level += 2 - s += '{\n' - for decl in n.decls: - s += self._generate_stmt(decl) - self.indent_level -= 2 - s += self._make_indent() + '}' - return s - - def _generate_stmt(self, n, add_indent=False): - """ Generation from a statement node. This method exists as a wrapper - for individual visit_* methods to handle different treatment of - some statements in this context. - """ - typ = type(n) - if add_indent: self.indent_level += 2 - indent = self._make_indent() - if add_indent: self.indent_level -= 2 - - if typ in ( - c_ast.Decl, c_ast.Assignment, c_ast.Cast, c_ast.UnaryOp, - c_ast.BinaryOp, c_ast.TernaryOp, c_ast.FuncCall, c_ast.ArrayRef, - c_ast.StructRef): - # These can also appear in an expression context so no semicolon - # is added to them automatically - # - return indent + self.visit(n) + ';\n' - elif typ in (c_ast.Compound,): - # No extra indentation required before the opening brace of a - # compound - because it consists of multiple lines it has to - # compute its own indentation. - # - return self.visit(n) - else: - return indent + self.visit(n) + '\n' - - def _generate_decl(self, n): - """ Generation from a Decl node. - """ - s = '' - if n.funcspec: s = ' '.join(n.funcspec) + ' ' - if n.storage: s += ' '.join(n.storage) + ' ' - s += self._generate_type(n.type) - return s - - def _generate_type(self, n, modifiers=[]): - """ Recursive generation from a type node. n is the type node. - modifiers collects the PtrDecl, ArrayDecl and FuncDecl modifiers - encountered on the way down to a TypeDecl, to allow proper - generation from it. - """ - typ = type(n) - #~ print(n, modifiers) - - if typ == c_ast.TypeDecl: - s = '' - if n.quals: s += ' '.join(n.quals) + ' ' - s += self.visit(n.type) - - nstr = n.declname if n.declname else '' - # Resolve modifiers. - # Wrap in parens to distinguish pointer to array and pointer to - # function syntax. - # - for i, modifier in enumerate(modifiers): - if isinstance(modifier, c_ast.ArrayDecl): - if (i != 0 and isinstance(modifiers[i - 1], c_ast.PtrDecl)): - nstr = '(' + nstr + ')' - nstr += '[' + self.visit(modifier.dim) + ']' - elif isinstance(modifier, c_ast.FuncDecl): - if (i != 0 and isinstance(modifiers[i - 1], c_ast.PtrDecl)): - nstr = '(' + nstr + ')' - nstr += '(' + self.visit(modifier.args) + ')' - elif isinstance(modifier, c_ast.PtrDecl): - nstr = '*' + nstr - if nstr: s += ' ' + nstr - return s - elif typ == c_ast.Decl: - return self._generate_decl(n.type) - elif typ == c_ast.Typename: - return self._generate_type(n.type) - elif typ == c_ast.IdentifierType: - return ' '.join(n.names) + ' ' - elif typ in (c_ast.ArrayDecl, c_ast.PtrDecl, c_ast.FuncDecl): - return self._generate_type(n.type, modifiers + [n]) - else: - return self.visit(n) - - def _parenthesize_if(self, n, condition): - """ Visits 'n' and returns its string representation, parenthesized - if the condition function applied to the node returns True. - """ - s = self.visit(n) - if condition(n): - return '(' + s + ')' - else: - return s - - def _parenthesize_unless_simple(self, n): - """ Common use case for _parenthesize_if - """ - return self._parenthesize_if(n, lambda d: not self._is_simple_node(d)) - - def _is_simple_node(self, n): - """ Returns True for nodes that are "simple" - i.e. nodes that always - have higher precedence than operators. - """ - return isinstance(n,( c_ast.Constant, c_ast.ID, c_ast.ArrayRef, - c_ast.StructRef, c_ast.FuncCall)) +from pycparser import parse_file, c_parser, c_generator def translate_to_c(filename): ast = parse_file(filename, use_cpp=True) - generator = CGenerator() + generator = c_generator.CGenerator() print(generator.visit(ast)) @@ -412,7 +39,7 @@ int main(void) parser = c_parser.CParser() ast = parser.parse(src) ast.show() - generator = CGenerator() + generator = c_generator.CGenerator() print(generator.visit(ast)) @@ -425,7 +52,7 @@ int main(void) #------------------------------------------------------------------------------ if __name__ == "__main__": - zz_test_translate() + #zz_test_translate() if len(sys.argv) > 1: translate_to_c(sys.argv[1]) else: |