summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEli Bendersky <eliben@gmail.com>2012-12-25 14:52:48 -0800
committerEli Bendersky <eliben@gmail.com>2012-12-25 14:52:48 -0800
commit293ea91f99a57a3f1fde187d99554ae59c492285 (patch)
treeecb5559d002166aab8378c54a1adc4dd991852aa
parent4476d099d78c0288c8aaf907f236ab94e418bd44 (diff)
downloadpycparser-293ea91f99a57a3f1fde187d99554ae59c492285.tar.gz
Issue #83: Distinguish initializer lists from expression lists
-rw-r--r--CHANGES3
-rw-r--r--pycparser/_c_ast.cfg8
-rw-r--r--pycparser/c_ast.py13
-rw-r--r--pycparser/c_generator.py47
-rw-r--r--pycparser/c_parser.py2
-rw-r--r--tests/test_c_generator.py7
-rw-r--r--tests/test_c_parser.py2
-rw-r--r--z_test.py26
8 files changed, 63 insertions, 45 deletions
diff --git a/CHANGES b/CHANGES
index 6cad334..5fe9baf 100644
--- a/CHANGES
+++ b/CHANGES
@@ -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]
diff --git a/z_test.py b/z_test.py
index 962c72c..cfaf17c 100644
--- a/z_test.py
+++ b/z_test.py
@@ -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)