summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEli Bendersky <eliben@gmail.com>2021-09-13 11:33:19 -0700
committerEli Bendersky <eliben@gmail.com>2021-09-13 11:33:19 -0700
commita1b5e46cf3015fe83c1f2a9de1a0e6d2fce76c19 (patch)
treed29680a50dab7eeda31d1512f081a5606e6415dd
parentb249fc58e530f3dcbfc9a4c35f62e641a5d34757 (diff)
downloadpycparser-a1b5e46cf3015fe83c1f2a9de1a0e6d2fce76c19.tar.gz
Implement atomic specifiers like _Atomic(int*).
Based on #431 by vit9696 Updates #430
-rw-r--r--pycparser/c_parser.py40
-rwxr-xr-xtests/test_c_parser.py12
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()