From a1b5e46cf3015fe83c1f2a9de1a0e6d2fce76c19 Mon Sep 17 00:00:00 2001 From: Eli Bendersky Date: Mon, 13 Sep 2021 11:33:19 -0700 Subject: Implement atomic specifiers like _Atomic(int*). Based on #431 by vit9696 Updates #430 --- pycparser/c_parser.py | 40 ++++++++++++++++++++++++++++++++++------ tests/test_c_parser.py | 12 ++++++++++++ 2 files changed, 46 insertions(+), 6 deletions(-) diff --git a/pycparser/c_parser.py b/pycparser/c_parser.py index 5f2818d..e6d1f3e 100644 --- a/pycparser/c_parser.py +++ b/pycparser/c_parser.py @@ -315,15 +315,20 @@ class CParser(PLYParser): # type in the list (it's illegal to declare "int enum ..") # If all the types are basic, they're collected in the # IdentifierType holder. - # for tn in typename: if not isinstance(tn, c_ast.IdentifierType): if len(typename) > 1: self._parse_error( "Invalid multiple types specified", tn.coord) else: - type.type = tn - return decl + # This is a nested TypeDecl which we don't need. + if isinstance(tn, c_ast.TypeDecl): + type.type = tn.type + type.quals.extend(tn.quals) + return decl + else: + type.type = tn + return decl if not typename: # Functions default to returning int @@ -783,7 +788,6 @@ class CParser(PLYParser): """ p[0] = self._add_declaration_specifier(p[2], p[1], 'function') - def p_declaration_specifiers_1(self, p): """ declaration_specifiers : declaration_specifiers type_qualifier """ @@ -814,7 +818,6 @@ class CParser(PLYParser): """ p[0] = self._add_declaration_specifier(p[1], p[2], 'type', append=True) - def p_storage_class_specifier(self, p): """ storage_class_specifier : AUTO | REGISTER @@ -847,7 +850,7 @@ class CParser(PLYParser): """ p[0] = c_ast.IdentifierType([p[1]], coord=self._token_coord(p, 1)) - def p_type_specifier(self, p): + def p_type_specifier_1(self, p): """ type_specifier : typedef_name | enum_specifier | struct_or_union_specifier @@ -855,6 +858,31 @@ class CParser(PLYParser): """ p[0] = p[1] + # See section 6.7.2.4 of the C11 standard. + # Note: according to the standard, "The type name in an atomic type + # specifier shall not refer to an array type, a function type, an atomic + # type, or a qualified type." + def p_type_specifier_2(self, p): + """ type_specifier : _ATOMIC LPAREN type_name RPAREN + """ + assert isinstance(p[3], c_ast.Typename) + typ = p[3].type + + # Since type_name may already include a TypeDecl, and this + # type_specifier node itself creates a TypeDecl, do some de-duplication. + # This will leave some cases unchanged, because we need to propagate the + # atomic qualifier somewhere. These leftover cases will be de=duplicated + # in _fix_decl_name_type. + searchNode = typ + while hasattr(searchNode, 'type') and searchNode.type is not None: + if isinstance(searchNode.type, c_ast.TypeDecl): + searchNode.type = searchNode.type.type + break + searchNode = searchNode.type + + typ.quals.append('_Atomic') + p[0] = typ + def p_type_qualifier(self, p): """ type_qualifier : CONST | RESTRICT diff --git a/tests/test_c_parser.py b/tests/test_c_parser.py index 8c1ccc5..492cbd1 100755 --- a/tests/test_c_parser.py +++ b/tests/test_c_parser.py @@ -545,6 +545,18 @@ class TestCParser_fundamentals(TestCParser_base): self.assertIsInstance(pdecl, PtrDecl) self.assertEqual(pdecl.quals, ['const']) + def test_atomic_specifier(self): + self.assertEqual(self.get_decl('_Atomic(int) ai;'), + ['Decl', + ['_Atomic'], + 'ai', + ['TypeDecl', ['IdentifierType', ['int']]]]) + + self.assertEqual(self.get_decl('_Atomic(int*) ai;'), + ['Decl', + 'ai', + ['TypeDecl', ['PtrDecl', ['_Atomic'], ['IdentifierType', ['int']]]]]) + def test_sizeof(self): e = """ void foo() -- cgit v1.2.1