diff --git a/pycparser/c_generator.py b/pycparser/c_generator.py index 973d24a8..53c26fdf 100644 --- a/pycparser/c_generator.py +++ b/pycparser/c_generator.py @@ -59,17 +59,18 @@ def visit_FuncCall(self, n): 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': + if 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) + operand = self._parenthesize_unless_simple(n.expr) + if n.op == 'p++': + return '%s++' % operand + elif n.op == 'p--': + return '%s--' % operand + else: + return '%s%s' % (n.op, operand) def visit_BinaryOp(self, n): lval_str = self._parenthesize_if(n.left, diff --git a/pycparser/c_parser.py b/pycparser/c_parser.py index 744ede8a..c2d82f76 100644 --- a/pycparser/c_parser.py +++ b/pycparser/c_parser.py @@ -413,8 +413,8 @@ def _build_declarations(self, spec, decls, typedef_namespace=False): # A similar problem can occur where the declaration ends up looking # like an abstract declarator. Give it a name if this is the case. # - elif not isinstance(decls[0]['decl'], - (c_ast.Struct, c_ast.Union, c_ast.IdentifierType)): + elif not isinstance(decls[0]['decl'], ( + c_ast.Enum, c_ast.Struct, c_ast.Union, c_ast.IdentifierType)): decls_0_tail = decls[0]['decl'] while not isinstance(decls_0_tail, c_ast.TypeDecl): decls_0_tail = decls_0_tail.type @@ -442,8 +442,9 @@ def _build_declarations(self, spec, decls, typedef_namespace=False): bitsize=decl.get('bitsize'), coord=decl['decl'].coord) - if isinstance(declaration.type, - (c_ast.Struct, c_ast.Union, c_ast.IdentifierType)): + if isinstance(declaration.type, ( + c_ast.Enum, c_ast.Struct, c_ast.Union, + c_ast.IdentifierType)): fixed_decl = declaration else: fixed_decl = self._fix_decl_name_type(declaration, spec['type']) @@ -464,7 +465,8 @@ def _build_declarations(self, spec, decls, typedef_namespace=False): def _build_function_definition(self, spec, decl, param_decls, body): """ Builds a function definition. """ - assert 'typedef' not in spec['storage'] + if 'typedef' in spec['storage']: + self._parse_error("Invalid typedef", decl.coord) declaration = self._build_declarations( spec=spec, diff --git a/tests/test_c_generator.py b/tests/test_c_generator.py index dd19a11a..159c763d 100644 --- a/tests/test_c_generator.py +++ b/tests/test_c_generator.py @@ -354,6 +354,13 @@ def test_ptr_decl(self): self.assertEqual(generator.visit(ast.ext[0].type.type.type), 'const int') + def test_nested_sizeof(self): + src = '1' + for _ in range(30): + src = 'sizeof(' + src + ')' + src = 'int x = ' + src + ';' + self._assert_ctoc_correct(src) + class TestCasttoC(unittest.TestCase): def _find_file(self, name): diff --git a/tests/test_c_parser.py b/tests/test_c_parser.py index b6ecdd5e..d33941cf 100755 --- a/tests/test_c_parser.py +++ b/tests/test_c_parser.py @@ -33,6 +33,13 @@ def expand_decl(decl): elif typ in [Struct, Union]: decls = [expand_decl(d) for d in decl.decls or []] return [typ.__name__, decl.name, decls] + elif typ == Enum: + if decl.values is None: + values = None + else: + assert isinstance(decl.values, EnumeratorList) + values = [enum.name for enum in decl.values.enumerators] + return ['Enum', decl.name, values] else: nested = expand_decl(decl.type) @@ -855,6 +862,31 @@ def test_struct_union(self): ['Decl', 'heads', ['PtrDecl', ['PtrDecl', ['TypeDecl', ['IdentifierType', ['Node']]]]]]]]]]) + def test_struct_enum(self): + s1 = """ + struct Foo { + enum Bar { A = 1 }; + }; + """ + self.assertEqual(expand_decl(self.parse(s1).ext[0]), + ['Decl', None, + ['Struct', 'Foo', + [['Decl', None, + ['Enum', 'Bar', ['A']]]]]]) + s2 = """ + struct Foo { + enum Bar { A = 1, B, C } bar; + enum Baz { D = A } baz; + } foo; + """ + self.assertEqual(expand_decl(self.parse(s2).ext[0]), + ['Decl', 'foo', + ['TypeDecl', ['Struct', 'Foo', + [['Decl', 'bar', + ['TypeDecl', ['Enum', 'Bar', ['A', 'B', 'C']]]], + ['Decl', 'baz', + ['TypeDecl', ['Enum', 'Baz', ['D']]]]]]]]) + def test_struct_with_extra_semis_inside(self): s1 = """ struct { @@ -1190,6 +1222,13 @@ def test_invalid_multiple_types_error(self): for b in bad: self.assertRaises(ParseError, self.parse, b) + def test_invalid_typedef_storage_qual_error(self): + """ Tests that using typedef as a storage qualifier is correctly flagged + as an error. + """ + bad = 'typedef const int foo(int a) { return 0; }' + self.assertRaises(ParseError, self.parse, bad) + def test_duplicate_typedef(self): """ Tests that redeclarations of existing types are parsed correctly. This is non-standard, but allowed by many compilers.