summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authornecase <necase@users.sf.net>2014-12-19 16:38:37 -0600
committernecase <necase@users.sf.net>2015-01-11 14:16:34 -0600
commit4a6afa0587bfb340dad5838f847e71704ea48ea7 (patch)
tree06a1b1f455e7a88a7833ed9b1bb8a908a3195846
parent497880550069b2a887c70c18cf45cfcd3eaf934d (diff)
downloadpycparser-4a6afa0587bfb340dad5838f847e71704ea48ea7.tar.gz
Align array dimension grammar with the C standard.
The pycparser grammar for direct-declarators diverged with the C standard, which permits const, volatile, restrict, and static to be modifiers in the array dimension. The relevant grammar can be found in section 6.7.5. The old p_direct_declarator_3 was split into two rules, and the remaining p_direct_declarator rules were renumbered, preserving precedence. So p_direct_declarator_3 now matches array declarations with optional type qualifiers or assignment expressions; p_direct_declarator_4 matches declarations with the static keyword; p_direct_declarator_5 matches the variable-length array declarations; and p_direct_declarator_6 matches declarations with parentheses.
-rw-r--r--pycparser/c_parser.py56
-rw-r--r--tests/test_c_parser.py16
2 files changed, 49 insertions, 23 deletions
diff --git a/pycparser/c_parser.py b/pycparser/c_parser.py
index 8e17f03..643b88c 100644
--- a/pycparser/c_parser.py
+++ b/pycparser/c_parser.py
@@ -983,41 +983,51 @@ class CParser(PLYParser):
p[0] = p[2]
def p_direct_declarator_3(self, p):
- """ direct_declarator : direct_declarator LBRACKET assignment_expression_opt RBRACKET
- | direct_declarator LBRACKET STATIC assignment_expression_opt RBRACKET
- | direct_declarator LBRACKET CONST assignment_expression_opt RBRACKET
- """
- if len(p) > 5:
- # Have dimension qualifiers
- # Per C99 6.7.5.3 p7
- arr = c_ast.ArrayDecl(
- type=None,
- dim=p[4],
- dim_quals=[p[3]],
- coord=p[1].coord)
- else:
- arr = c_ast.ArrayDecl(
- type=None,
- dim=p[3],
- dim_quals=[],
- coord=p[1].coord)
+ """ direct_declarator : direct_declarator LBRACKET type_qualifier_list_opt assignment_expression_opt RBRACKET
+ """
+ # Accept dimension qualifiers
+ # Per C99 6.7.5.3 p7
+ arr = c_ast.ArrayDecl(
+ type=None,
+ dim=p[4],
+ dim_quals=p[3] if p[3] != None else [],
+ coord=p[1].coord)
+
+ p[0] = self._type_modify_decl(decl=p[1], modifier=arr)
+
+ def p_direct_declarator_4(self, p):
+ """ direct_declarator : direct_declarator LBRACKET STATIC type_qualifier_list_opt assignment_expression RBRACKET
+ | direct_declarator LBRACKET type_qualifier_list STATIC assignment_expression RBRACKET
+ """
+ # Using slice notation for PLY objects doesn't work in Python 3 for the
+ # version of PLY embedded with pycparser; see PLY Google Code issue 30.
+ # Work around that here by listing the two elements separately.
+ listed_quals = [item if isinstance(item, list) else [item]
+ for item in [p[3],p[4]]]
+ dim_quals = [qual for sublist in listed_quals for qual in sublist
+ if qual is not None]
+ arr = c_ast.ArrayDecl(
+ type=None,
+ dim=p[5],
+ dim_quals=dim_quals,
+ coord=p[1].coord)
p[0] = self._type_modify_decl(decl=p[1], modifier=arr)
# Special for VLAs
#
- def p_direct_declarator_4(self, p):
- """ direct_declarator : direct_declarator LBRACKET TIMES RBRACKET
+ def p_direct_declarator_5(self, p):
+ """ direct_declarator : direct_declarator LBRACKET type_qualifier_list_opt TIMES RBRACKET
"""
arr = c_ast.ArrayDecl(
type=None,
- dim=c_ast.ID(p[3], self._coord(p.lineno(3))),
- dim_quals=[],
+ dim=c_ast.ID(p[4], self._coord(p.lineno(4))),
+ dim_quals=p[3] if p[3] != None else [],
coord=p[1].coord)
p[0] = self._type_modify_decl(decl=p[1], modifier=arr)
- def p_direct_declarator_5(self, p):
+ def p_direct_declarator_6(self, p):
""" direct_declarator : direct_declarator LPAREN parameter_type_list RPAREN
| direct_declarator LPAREN identifier_list_opt RPAREN
"""
diff --git a/tests/test_c_parser.py b/tests/test_c_parser.py
index d0ef741..5c7d723 100644
--- a/tests/test_c_parser.py
+++ b/tests/test_c_parser.py
@@ -396,6 +396,22 @@ class TestCParser_fundamentals(TestCParser_base):
['TypeDecl', ['IdentifierType', ['int']]]]]],
['TypeDecl', ['IdentifierType', ['int']]]]])
+ self.assertEqual(self.get_decl('int zz(int p[restrict][5]);'),
+ ['Decl', 'zz',
+ ['FuncDecl',
+ [['Decl', 'p', ['ArrayDecl', '', ['restrict'],
+ ['ArrayDecl', '5', [],
+ ['TypeDecl', ['IdentifierType', ['int']]]]]]],
+ ['TypeDecl', ['IdentifierType', ['int']]]]])
+
+ self.assertEqual(self.get_decl('int zz(int p[const restrict static 10][5]);'),
+ ['Decl', 'zz',
+ ['FuncDecl',
+ [['Decl', 'p', ['ArrayDecl', '10', ['const', 'restrict', 'static'],
+ ['ArrayDecl', '5', [],
+ ['TypeDecl', ['IdentifierType', ['int']]]]]]],
+ ['TypeDecl', ['IdentifierType', ['int']]]]])
+
def test_qualifiers_storage_specifiers(self):
def assert_qs(txt, index, quals, storage):
d = self.parse(txt).ext[index]