diff options
author | ldore <laurent.dore@gmail.com> | 2018-04-28 05:09:24 +0200 |
---|---|---|
committer | Eli Bendersky <eliben@users.noreply.github.com> | 2018-04-27 20:09:24 -0700 |
commit | 81a12ca210a75969ca0d2a606369e65968cf14a6 (patch) | |
tree | bb1c67a850731751ecbc64c80b21c802de84f1d8 | |
parent | a2a8f4a384bd86efc9faff9030fbb8d905a8ecee (diff) | |
download | platform_external_python_pycparser-81a12ca210a75969ca0d2a606369e65968cf14a6.tar.gz platform_external_python_pycparser-81a12ca210a75969ca0d2a606369e65968cf14a6.tar.bz2 platform_external_python_pycparser-81a12ca210a75969ca0d2a606369e65968cf14a6.zip |
Add support for empty struct (#66) (#254)
-rw-r--r-- | pycparser/c_generator.py | 6 | ||||
-rw-r--r-- | pycparser/c_parser.py | 35 | ||||
-rw-r--r-- | tests/test_c_generator.py | 12 | ||||
-rwxr-xr-x | tests/test_c_parser.py | 20 |
4 files changed, 63 insertions, 10 deletions
diff --git a/pycparser/c_generator.py b/pycparser/c_generator.py index 4c86f84..8f2e69a 100644 --- a/pycparser/c_generator.py +++ b/pycparser/c_generator.py @@ -300,10 +300,12 @@ class CGenerator(object): body_function = self._generate_struct_union_body else: assert name == 'enum' - members = () if n.values is None else n.values.enumerators + members = None if n.values is None else n.values.enumerators body_function = self._generate_enum_body s = name + ' ' + (n.name or '') - if members: + if members is not None: + # None means no members + # Empty sequence means an empty list of members s += '\n' s += self._make_indent() self.indent_level += 2 diff --git a/pycparser/c_parser.py b/pycparser/c_parser.py index 47d958f..0ce41bd 100644 --- a/pycparser/c_parser.py +++ b/pycparser/c_parser.py @@ -908,6 +908,7 @@ class CParser(PLYParser): | struct_or_union TYPEID """ klass = self._select_struct_union_class(p[1]) + # None means no list of members p[0] = klass( name=p[2], decls=None, @@ -915,22 +916,40 @@ class CParser(PLYParser): def p_struct_or_union_specifier_2(self, p): """ struct_or_union_specifier : struct_or_union brace_open struct_declaration_list brace_close + | struct_or_union brace_open brace_close """ klass = self._select_struct_union_class(p[1]) - p[0] = klass( - name=None, - decls=p[3], - coord=self._token_coord(p, 2)) + if len(p) == 4: + # Empty sequence means an empty list of members + p[0] = klass( + name=None, + decls=[], + coord=self._token_coord(p, 2)) + else: + p[0] = klass( + name=None, + decls=p[3], + coord=self._token_coord(p, 2)) + def p_struct_or_union_specifier_3(self, p): """ struct_or_union_specifier : struct_or_union ID brace_open struct_declaration_list brace_close + | struct_or_union ID brace_open brace_close | struct_or_union TYPEID brace_open struct_declaration_list brace_close + | struct_or_union TYPEID brace_open brace_close """ klass = self._select_struct_union_class(p[1]) - p[0] = klass( - name=p[2], - decls=p[4], - coord=self._token_coord(p, 2)) + if len(p) == 5: + # Empty sequence means an empty list of members + p[0] = klass( + name=p[2], + decls=[], + coord=self._token_coord(p, 2)) + else: + p[0] = klass( + name=p[2], + decls=p[4], + coord=self._token_coord(p, 2)) def p_struct_or_union(self, p): """ struct_or_union : STRUCT diff --git a/tests/test_c_generator.py b/tests/test_c_generator.py index 4e38f28..3727f91 100644 --- a/tests/test_c_generator.py +++ b/tests/test_c_generator.py @@ -213,6 +213,18 @@ class TestCtoC(unittest.TestCase): return 0; }''') + def test_issue66(self): + # A non-existing body must not be generated + # (previous valid behavior, still working) + self._assert_ctoc_correct(r''' + struct foo; + ''') + # An empty body must be generated + # (added behavior) + self._assert_ctoc_correct(r''' + struct foo {}; + ''') + def test_issue83(self): self._assert_ctoc_correct(r''' void x(void) { diff --git a/tests/test_c_parser.py b/tests/test_c_parser.py index 3b336bf..9dfb132 100755 --- a/tests/test_c_parser.py +++ b/tests/test_c_parser.py @@ -998,6 +998,26 @@ class TestCParser_fundamentals(TestCParser_base): self.assertEqual(parsed_struct.type.type.decls[0].bitsize.value, '6') self.assertEqual(parsed_struct.type.type.decls[1].bitsize.value, '2') + def test_struct_empty(self): + """ + Tests that parsing an empty struct works. + + Empty structs do NOT follow C99 (See 6.2.5-20 of the C99 standard). + This is nevertheless supported by some compilers (clang, gcc), + especially when using FORTIFY code. + Some compilers (visual) will fail to compile with an error. + """ + # an empty struct. This is NOT C99 compliant + s1 = """ + struct foo { }; + """ + + parsed_struct = self.parse(s1).ext[0] + + self.assertEqual(expand_decl(parsed_struct), + ['Decl', None, ['Struct', 'foo', []]] + ) + def test_tags_namespace(self): """ Tests that the tags of structs/unions/enums reside in a separate namespace and can be named after existing types. |