Skip to content

Commit

Permalink
c_parser: support parenthesized compounds (#423)
Browse files Browse the repository at this point in the history
* c_parser: support parenthesized compounds

Support parenthesized compound statements as described here:
    https://gcc.gnu.org/onlinedocs/gcc/Statement-Exprs.html

Signed-off-by: Jordan Yates <jordan.yates@data61.csiro.au>

* test_c_parser: support additional initializers

Add support to `expand_init` for additional `c_ast` types. If a type
is not explicitly handled, return the type name instead of `None`.

Signed-off-by: Jordan Yates <jordan.yates@data61.csiro.au>

* test_c_parser: test parenthesized compounds

Add parsing tests for various situations of parenthesized compound
statements. The complete tree generated by the test string is:

```
FileAST:
  FuncDef:
    Decl: foo, [], [], []
      FuncDecl:
        TypeDecl: foo, []
          IdentifierType: ['void']
    Compound:
      Decl: a, [], [], []
        TypeDecl: a, []
          IdentifierType: ['int']
      Compound:
      Compound:
        Constant: int, 1
      Compound:
        Constant: int, 1
        Constant: int, 2
      Decl: b, [], [], []
        TypeDecl: b, []
          IdentifierType: ['int']
        Compound:
          Constant: int, 1
      Decl: c, [], [], []
        TypeDecl: c, []
          IdentifierType: ['int']
      Decl: d, [], [], []
        TypeDecl: d, []
          IdentifierType: ['int']
        Compound:
          Decl: x, [], [], []
            TypeDecl: x, []
              IdentifierType: ['int']
            Constant: int, 1
          BinaryOp: +
            ID: x
            Constant: int, 2
      Assignment: =
        ID: a
        Compound:
          Decl: x, [], [], []
            TypeDecl: x, []
              IdentifierType: ['int']
            Constant: int, 1
          BinaryOp: *
            Constant: int, 2
            ID: x
```

Signed-off-by: Jordan Yates <jordan.yates@data61.csiro.au>
  • Loading branch information
JordanYates committed Jul 7, 2021
1 parent c819d53 commit 56b1467
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 0 deletions.
4 changes: 4 additions & 0 deletions pycparser/c_parser.py
Expand Up @@ -1564,6 +1564,10 @@ def p_expression(self, p):
p[1].exprs.append(p[3])
p[0] = p[1]

def p_parenthesized_compound_expression(self, p):
""" assignment_expression : LPAREN compound_statement RPAREN """
p[0] = p[2]

def p_typedef_name(self, p):
""" typedef_name : TYPEID """
p[0] = c_ast.IdentifierType([p[1]], coord=self._token_coord(p, 1))
Expand Down
53 changes: 53 additions & 0 deletions tests/test_c_parser.py
Expand Up @@ -85,8 +85,20 @@ def expand_init(init):
return ['Constant', init.type, init.value]
elif typ == ID:
return ['ID', init.name]
elif typ == Decl:
return ['Decl', init.name]
elif typ == UnaryOp:
return ['UnaryOp', init.op, expand_decl(init.expr)]
elif typ == BinaryOp:
return ['BinaryOp', expand_init(init.left), init.op, expand_init(init.right)]
elif typ == Compound:
blocks = []
if init.block_items:
blocks = [expand_init(i) for i in init.block_items]
return ['Compound', blocks]
else:
# Fallback to type name
return [typ.__name__]


class TestCParser_base(unittest.TestCase):
Expand Down Expand Up @@ -612,6 +624,47 @@ def test_compound_literals(self):
([['ID', 'a']], [['Constant', 'int', '1'], ['Constant', 'int', '2']]),
([['ID', 'b'], ['Constant', 'int', '0']], ['ID', 't'])])

def test_parenthesized_compounds(self):
e = self.parse(r'''
void foo() {
int a;
({});
({ 1; });
({ 1; 2; });
int b = ({ 1; });
int c, d = ({ int x = 1; x + 2; });
a = ({ int x = 1; 2 * x; });
}''')
body = e.ext[0].body.block_items

self.assertIsInstance(body[1], Compound)
self.assertEqual(body[1].block_items, None)

self.assertIsInstance(body[2], Compound)
self.assertEqual(len(body[2].block_items), 1)
self.assertIsInstance(body[2].block_items[0], Constant)

self.assertIsInstance(body[3], Compound)
self.assertEqual(len(body[3].block_items), 2)
self.assertIsInstance(body[3].block_items[0], Constant)
self.assertIsInstance(body[3].block_items[1], Constant)

self.assertIsInstance(body[4], Decl)
self.assertEqual(expand_init(body[4].init),
['Compound', [['Constant', 'int', '1']]])

self.assertIsInstance(body[5], Decl)
self.assertEqual(body[5].init, None)

self.assertIsInstance(body[6], Decl)
self.assertEqual(expand_init(body[6].init),
['Compound', [['Decl', 'x'], ['BinaryOp', ['ID', 'x'], '+', ['Constant', 'int', '2']]]])

self.assertIsInstance(body[7], Assignment)
self.assertIsInstance(body[7].rvalue, Compound)
self.assertEqual(expand_init(body[7].rvalue),
['Compound', [['Decl', 'x'], ['BinaryOp', ['Constant', 'int', '2'], '*', ['ID', 'x']]]])

def test_enums(self):
e1 = "enum mycolor op;"
e1_type = self.parse(e1).ext[0].type.type
Expand Down

0 comments on commit 56b1467

Please sign in to comment.