Skip to content

Commit

Permalink
Merge pull request #1 from eliben/master
Browse files Browse the repository at this point in the history
  • Loading branch information
tomoguara committed Jul 30, 2020
2 parents 61eac63 + 6da5009 commit 7c7fe7b
Show file tree
Hide file tree
Showing 4 changed files with 61 additions and 12 deletions.
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

0 comments on commit 7c7fe7b

Please sign in to comment.