Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix issues #378, #379, #385 #387

Merged
merged 3 commits into from Jul 18, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
15 changes: 8 additions & 7 deletions pycparser/c_generator.py
Expand Up @@ -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,
Expand Down
12 changes: 7 additions & 5 deletions pycparser/c_parser.py
Expand Up @@ -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
Expand Down Expand Up @@ -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'])
Expand All @@ -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,
Expand Down
7 changes: 7 additions & 0 deletions tests/test_c_generator.py
Expand Up @@ -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):
Expand Down
39 changes: 39 additions & 0 deletions tests/test_c_parser.py
Expand Up @@ -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)

Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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.
Expand Down