From 38487551c14da143a338dbc0fe1131960a25e6b1 Mon Sep 17 00:00:00 2001 From: Martin Spiessl <33026673+MartinSpiessl@users.noreply.github.com> Date: Mon, 2 Jan 2023 12:27:14 +0100 Subject: [PATCH] Fix GNU statement expression syntax and code gen. The statement expression itself is not allowed just at places where an ordinary statement would stand. As with other expressions, this is only facilitated via the expression_statement rule that adds a semicolon after the expression. The reason why this bug was not discovered is probably because the code generator also drops the parentheses around the statement expression, turning it into a compound statement. This commit fixes that by removing the faulty rule extension, introducing a CoumpoundExpression class, and making sure the parentheses are added when an object of this type is discovered during code generation. --- pycparserext/ext_c_generator.py | 3 +++ pycparserext/ext_c_parser.py | 31 ++++++++++++++++++------------- 2 files changed, 21 insertions(+), 13 deletions(-) diff --git a/pycparserext/ext_c_generator.py b/pycparserext/ext_c_generator.py index a5747fa..0223000 100644 --- a/pycparserext/ext_c_generator.py +++ b/pycparserext/ext_c_generator.py @@ -159,6 +159,9 @@ def visit_TypeList(self, n): def visit_RangeExpression(self, n): return '%s ... %s' % (self.visit(n.first), self.visit(n.last)) + def visit_CompoundExpression(self, n): + return "(%s)" % (self.visit(n.stmt)) + class GNUCGenerator(GnuCGenerator): def __init__(self): diff --git a/pycparserext/ext_c_parser.py b/pycparserext/ext_c_parser.py index 5308ea6..2e36613 100644 --- a/pycparserext/ext_c_parser.py +++ b/pycparserext/ext_c_parser.py @@ -183,6 +183,23 @@ def __iter__(self): attr_names = () +class CompoundExpression(c_ast.Node): + def __init__(self, stmt, coord=None): + self.stmt = stmt + self.coord = coord + + def children(self): + nodelist = [] + if self.stmt is not None: nodelist.append(("stmt", self.stmt)) + return tuple(nodelist) + + def __iter__(self): + if self.stmt is not None: + yield self.stmt + + attr_names = () + + # These are the same as pycparser's, but it does *not* declare __slots__-- # so we can poke in attributes at our leisure. class TypeDeclExt(c_ast.TypeDecl): @@ -528,24 +545,12 @@ def p_postfix_expression_gnu_tcp(self, p): def p_gnu_statement_expression(self, p): """ gnu_statement_expression : LPAREN compound_statement RPAREN """ - p[0] = p[2] + p[0] = CompoundExpression(p[2], coord=self._coord(p.lineno(1))) def p_gnu_primary_expression_6(self, p): """ primary_expression : gnu_statement_expression """ p[0] = p[1] - def p_statement(self, p): - """ statement : labeled_statement - | expression_statement - | compound_statement - | selection_statement - | iteration_statement - | jump_statement - | pppragma_directive - | gnu_statement_expression - """ - p[0] = p[1] - def p_attribute_const(self, p): """ attribute : __CONST """