diff options
author | Eli Bendersky <eliben@gmail.com> | 2012-12-25 14:52:48 -0800 |
---|---|---|
committer | Eli Bendersky <eliben@gmail.com> | 2012-12-25 14:52:48 -0800 |
commit | 293ea91f99a57a3f1fde187d99554ae59c492285 (patch) | |
tree | ecb5559d002166aab8378c54a1adc4dd991852aa | |
parent | 4476d099d78c0288c8aaf907f236ab94e418bd44 (diff) | |
download | pycparser-293ea91f99a57a3f1fde187d99554ae59c492285.tar.gz |
Issue #83: Distinguish initializer lists from expression lists
-rw-r--r-- | CHANGES | 3 | ||||
-rw-r--r-- | pycparser/_c_ast.cfg | 8 | ||||
-rw-r--r-- | pycparser/c_ast.py | 13 | ||||
-rw-r--r-- | pycparser/c_generator.py | 47 | ||||
-rw-r--r-- | pycparser/c_parser.py | 2 | ||||
-rw-r--r-- | tests/test_c_generator.py | 7 | ||||
-rw-r--r-- | tests/test_c_parser.py | 2 | ||||
-rw-r--r-- | z_test.py | 26 |
8 files changed, 63 insertions, 45 deletions
@@ -7,6 +7,9 @@ - pycparser now carries its PLY dependency along. The pycparser/ply directory contains the source of PLY for the currently supported version. This makes distribution and testing easier. + - Issue #83: fix parsing and C generation to distinguish between initializer + lists in declarations and initializing variables with parenthesized + comma-separated expressions. - Issue #84: fix C generation for some statements. - Issues #86 and #87: improve location reporting for parse errors. - Issue #89: fix C generation for K&R-style function definitions. diff --git a/pycparser/_c_ast.cfg b/pycparser/_c_ast.cfg index ca2379b..ee9d51a 100644 --- a/pycparser/_c_ast.cfg +++ b/pycparser/_c_ast.cfg @@ -37,7 +37,7 @@ Compound: [block_items**] # Compound literal (anonymous aggregate) for C99.
# (type-name) {initializer_list}
# type: the typename
-# init: ExprList for the initializer list
+# init: InitExprList for the initializer list
#
CompoundLiteral: [type*, init*]
@@ -86,7 +86,7 @@ Enumerator: [name, value*] #
EnumeratorList: [enumerators**]
-# a list of comma separated expressions
+# A list of expressions separated by the comma operator.
#
ExprList: [exprs**]
@@ -128,6 +128,10 @@ IdentifierType: [names] If: [cond*, iftrue*, iffalse*]
+# An initialization list used for compound literals.
+#
+InitList: [exprs**]
+
Label: [name, stmt*]
# A named initializer for C99.
diff --git a/pycparser/c_ast.py b/pycparser/c_ast.py index a1c92fb..2b9b00a 100644 --- a/pycparser/c_ast.py +++ b/pycparser/c_ast.py @@ -525,6 +525,19 @@ class If(Node): attr_names = () +class InitList(Node): + def __init__(self, exprs, coord=None): + self.exprs = exprs + self.coord = coord + + def children(self): + nodelist = [] + for i, child in enumerate(self.exprs or []): + nodelist.append(("exprs[%d]" % i, child)) + return tuple(nodelist) + + attr_names = () + class Label(Node): def __init__(self, name, stmt, coord=None): self.name = name diff --git a/pycparser/c_generator.py b/pycparser/c_generator.py index be709a8..3b5d8e8 100644 --- a/pycparser/c_generator.py +++ b/pycparser/c_generator.py @@ -73,16 +73,16 @@ class CGenerator(object): rval_str = self._parenthesize_if(n.right, lambda d: not self._is_simple_node(d)) return '%s %s %s' % (lval_str, n.op, rval_str) - + def visit_Assignment(self, n): rval_str = self._parenthesize_if( n.rvalue, lambda n: isinstance(n, c_ast.Assignment)) return '%s %s %s' % (self.visit(n.lvalue), n.op, rval_str) - + def visit_IdentifierType(self, n): return ' '.join(n.names) - + def visit_Decl(self, n, no_type=False): # no_type is used when a Decl is part of a DeclList, where the type is # explicitly only for the first delaration in a list. @@ -90,29 +90,31 @@ class CGenerator(object): s = n.name if no_type else self._generate_decl(n) if n.bitsize: s += ' : ' + self.visit(n.bitsize) if n.init: - if isinstance(n.init, c_ast.ExprList): + if isinstance(n.init, c_ast.InitList): s += ' = {' + self.visit(n.init) + '}' + elif isinstance(n.init, c_ast.ExprList): + s += ' = (' + self.visit(n.init) + ')' else: s += ' = ' + self.visit(n.init) return s - + def visit_DeclList(self, n): s = self.visit(n.decls[0]) if len(n.decls) > 1: s += ', ' + ', '.join(self.visit_Decl(decl, no_type=True) for decl in n.decls[1:]) return s - + def visit_Typedef(self, n): s = '' if n.storage: s += ' '.join(n.storage) + ' ' s += self._generate_type(n.type) return s - + def visit_Cast(self, n): s = '(' + self._generate_type(n.to_type) + ')' return s + ' ' + self._parenthesize_unless_simple(n.expr) - + def visit_ExprList(self, n): visited_subexprs = [] for expr in n.exprs: @@ -121,7 +123,16 @@ class CGenerator(object): else: visited_subexprs.append(self.visit(expr)) return ', '.join(visited_subexprs) - + + def visit_InitList(self, n): + visited_subexprs = [] + for expr in n.exprs: + if isinstance(expr, c_ast.InitList): + visited_subexprs.append('(' + self.visit(expr) + ')') + else: + visited_subexprs.append(self.visit(expr)) + return ', '.join(visited_subexprs) + def visit_Enum(self, n): s = 'enum' if n.name: s += ' ' + n.name @@ -135,7 +146,7 @@ class CGenerator(object): s += ', ' s += '}' return s - + def visit_FuncDef(self, n): decl = self.visit(n.decl) self.indent_level = 0 @@ -163,10 +174,10 @@ class CGenerator(object): self.indent_level -= 2 s += self._make_indent() + '}\n' return s - + def visit_EmptyStatement(self, n): return ';' - + def visit_ParamList(self, n): return ', '.join(self.visit(param) for param in n.params) @@ -177,16 +188,16 @@ class CGenerator(object): def visit_Break(self, n): return 'break;' - + def visit_Continue(self, n): return 'continue;' - + def visit_TernaryOp(self, n): s = self.visit(n.cond) + ' ? ' s += self.visit(n.iftrue) + ' : ' s += self.visit(n.iffalse) return s - + def visit_If(self, n): s = 'if (' if n.cond: s += self.visit(n.cond) @@ -196,7 +207,7 @@ class CGenerator(object): s += self._make_indent() + 'else\n' s += self._generate_stmt(n.iffalse, add_indent=True) return s - + def visit_For(self, n): s = 'for (' if n.init: s += self.visit(n.init) @@ -227,12 +238,12 @@ class CGenerator(object): s = 'switch (' + self.visit(n.cond) + ')\n' s += self._generate_stmt(n.stmt, add_indent=True) return s - + def visit_Case(self, n): s = 'case ' + self.visit(n.expr) + ':\n' s += self._generate_stmt(n.stmt, add_indent=True) return s - + def visit_Default(self, n): return 'default:\n' + self._generate_stmt(n.stmt, add_indent=True) diff --git a/pycparser/c_parser.py b/pycparser/c_parser.py index 6c17971..04959c3 100644 --- a/pycparser/c_parser.py +++ b/pycparser/c_parser.py @@ -950,7 +950,7 @@ class CParser(PLYParser): """ if len(p) == 3: # single initializer init = p[2] if p[1] is None else c_ast.NamedInitializer(p[1], p[2]) - p[0] = c_ast.ExprList([init], p[2].coord) + p[0] = c_ast.InitList([init], p[2].coord) else: init = p[4] if p[3] is None else c_ast.NamedInitializer(p[3], p[4]) p[1].exprs.append(init) diff --git a/tests/test_c_generator.py b/tests/test_c_generator.py index 5392603..4251535 100644 --- a/tests/test_c_generator.py +++ b/tests/test_c_generator.py @@ -130,6 +130,13 @@ class TestCtoC(unittest.TestCase): return 0; }''') + def test_issue83(self): + self._assert_ctoc_correct(r''' + void x(void) { + int i = (9, k); + } + ''') + def test_issue84(self): self._assert_ctoc_correct(r''' void x(void) { diff --git a/tests/test_c_parser.py b/tests/test_c_parser.py index 946cee5..c0bfe1e 100644 --- a/tests/test_c_parser.py +++ b/tests/test_c_parser.py @@ -68,7 +68,7 @@ def expand_init(init): if typ == NamedInitializer: des = [expand_init(dp) for dp in init.name] return (des, expand_init(init.expr)) - elif typ == ExprList: + elif typ in (InitList, ExprList): return [expand_init(expr) for expr in init.exprs] elif typ == Constant: return ['Constant', init.type, init.value] @@ -75,30 +75,10 @@ class NodeVisitor(object): if __name__ == "__main__": - source_code = ''' -''' - - - #--------------- Lexing - #~ def errfoo(msg, a, b): - #~ printme(msg) - #~ sys.exit() - #~ clex = CLexer(errfoo, lambda t: False) - #~ clex.build() - #~ clex.input(source_code) - - #~ while 1: - #~ tok = clex.token() - #~ if not tok: break - - #~ printme([tok.value, tok.type, tok.lineno, clex.filename, tok.lexpos]) - - #--------------- Parsing source_code = r''' - typedef int int8_t; - int boo, 8sd; - - + void main(void) { + i = (a, b); + } ''' parser = CParser(lex_optimize=False, yacc_optimize=False, yacc_debug=True) |