Commits

eli.bendersky  committed 4255659

Issue 19: Anonymous unions within struct cause parser error

  • Participants
  • Parent commits d5fb44d

Comments (0)

Files changed (2)

File pycparser/c_parser.py

             'specifier_qualifier_list',
             'block_item_list',
             'type_qualifier_list',
+            'struct_declarator_list'
         ]
         
         for rule in rules_with_opt:
         p[0] = p[1] if len(p) == 2 else p[1] + p[2]
 
     def p_struct_declaration_1(self, p):
-        """ struct_declaration : specifier_qualifier_list struct_declarator_list SEMI
+        """ struct_declaration : specifier_qualifier_list struct_declarator_list_opt SEMI
         """
         spec = p[1]
         decls = []
         
-        for struct_decl in p[2]:
-            if struct_decl['decl'] is not None:
-                decl_coord = struct_decl['decl'].coord
-            else:
-                decl_coord = struct_decl['bitsize'].coord
+        if p[2] is not None:
+            for struct_decl in p[2]:
+                if struct_decl['decl'] is not None:
+                    decl_coord = struct_decl['decl'].coord
+                else:
+                    decl_coord = struct_decl['bitsize'].coord
             
-            decl = c_ast.Decl(
-                name=None,
-                quals=spec['qual'],
-                funcspec=spec['function'],
-                storage=spec['storage'],
-                type=struct_decl['decl'],
-                init=None,
-                bitsize=struct_decl['bitsize'],
-                coord=decl_coord)
+                decl = c_ast.Decl(
+                    name=None,
+                    quals=spec['qual'],
+                    funcspec=spec['function'],
+                    storage=spec['storage'],
+                    type=struct_decl['decl'],
+                    init=None,
+                    bitsize=struct_decl['bitsize'],
+                    coord=decl_coord)
             
-            typename = spec['type']
-            decls.append(self._fix_decl_name_type(decl, typename))
+                typename = spec['type']
+                decls.append(self._fix_decl_name_type(decl, typename))
+
+        else:  # anonymous struct/union, gcc extension, C1x feature
+            node = spec['type'][0]
+            if isinstance(node, c_ast.Union) or isinstance(node, c_ast.Struct):
+                decl = c_ast.Decl(
+                    name=None,
+                    quals=spec['qual'],
+                    funcspec=spec['function'],
+                    storage=spec['storage'],
+                    type=node,
+                    init=None,
+                    bitsize=None,
+                    coord=self._coord(p.lineno(2)))
+                decls.append(decl)
         
         p[0] = decls
     

File tests/test_c_parser.py

 from pycparser.c_ast import *
 from pycparser.c_parser import CParser, Coord, ParseError
 
-
 _c_parser = c_parser.CParser(
                 lex_optimize=False,
                 yacc_debug=True, 
                     ['Decl', 'heads', 
                         ['PtrDecl', ['PtrDecl', ['TypeDecl', ['IdentifierType', ['Node']]]]]]]]]])
     
+    def test_anonymous_struct_union(self):
+        s1 = """
+            union
+            {
+                union
+                {
+                    int i;
+                    long l;
+                };
+
+                struct
+                {
+                    int type;
+                    int intnode;
+                };
+            } u;
+        """
+
+        self.assertEqual(expand_decl(self.parse(s1).ext[0]),
+            ['Decl', 'u',
+                ['TypeDecl',
+                    ['Union', None,
+                        [['Decl', None,
+                            ['Union', None,
+                                [['Decl', 'i',
+                                    ['TypeDecl',
+                                        ['IdentifierType', ['int']]]],
+                                ['Decl', 'l',
+                                    ['TypeDecl',
+                                        ['IdentifierType', ['long']]]]]]],
+                        ['Decl', None,
+                            ['Struct', None,
+                                [['Decl', 'type',
+                                    ['TypeDecl',
+                                        ['IdentifierType', ['int']]]],
+                                ['Decl', 'intnode',
+                                    ['TypeDecl',
+                                        ['IdentifierType', ['int']]]]]]]]]]])
+
+        s2 = """
+            struct
+            {
+                int i;
+                union
+                {
+                    int id;
+                    char* name;
+                };
+                float f;
+            } joe;
+            """
+
+        self.assertEqual(expand_decl(self.parse(s2).ext[0]),
+            ['Decl', 'joe',
+                ['TypeDecl',
+                    ['Struct', None,
+                       [['Decl', 'i',
+                            ['TypeDecl',
+                                ['IdentifierType', ['int']]]],
+                        ['Decl', None,
+                            ['Union', None,
+                                [['Decl', 'id',
+                                    ['TypeDecl',
+                                        ['IdentifierType', ['int']]]],
+                                ['Decl', 'name',
+                                    ['PtrDecl',
+                                        ['TypeDecl',
+                                            ['IdentifierType', ['char']]]]]]]],
+                        ['Decl', 'f',
+                            ['TypeDecl',
+                                ['IdentifierType', ['float']]]]]]]])
+
+        # ISO/IEC 9899:201x Commitee Draft 2010-11-16, N1539
+        # section 6.7.2.1, par. 19, example 1
+        s3 = """
+            struct v {
+                union {
+                    struct { int i, j; };
+                    struct { long k, l; } w;
+                };
+                int m;
+            } v1;
+            """
+
+        self.assertEqual(expand_decl(self.parse(s3).ext[0]),
+            ['Decl', 'v1',
+                ['TypeDecl',
+                    ['Struct', 'v',
+                       [['Decl', None,
+                            ['Union', None,
+                                [['Decl', None,
+                                    ['Struct', None,
+                                        [['Decl', 'i',
+                                            ['TypeDecl',
+                                                ['IdentifierType', ['int']]]],
+                                        ['Decl', 'j',
+                                            ['TypeDecl',
+                                                ['IdentifierType', ['int']]]]]]],
+                                ['Decl', 'w',
+                                    ['TypeDecl',
+                                        ['Struct', None,
+                                            [['Decl', 'k',
+                                                ['TypeDecl',
+                                                    ['IdentifierType', ['long']]]],
+                                            ['Decl', 'l',
+                                                ['TypeDecl',
+                                                    ['IdentifierType', ['long']]]]]]]]]]],
+                        ['Decl', 'm',
+                            ['TypeDecl',
+                                ['IdentifierType', ['int']]]]]]]])
+
     def test_struct_bitfields(self):
         # a struct with two bitfields, one unnamed
         s1 = """