Commits

Anonymous committed 5ea6ceb

initial implementation of C99 named initializers and compound literals. The latter still doesn't work because of a shift/reduce conflict

  • Participants
  • Parent commits e03e7c7

Comments (0)

Files changed (7)

 
 Implement:
 
-- long long: including literal endings LL in lexer
+V- long long: including literal endings LL in lexer
 V- new keywords restrict, inline
 V- mix declarations and statements inside a block
 V- VLAs (non-constants in arr[n]), including [*] for parameter lists
 V- declarations in the first expression of "for" loops
 - named initializers for structs and arrays
+  - including unnamed objects 
 
 * Make the changelog in the readme a normal bullet list
 

File pycparser/_build_tables.py

 # compiling them into .pyc for faster execution in optimized mode.
 # Also generates AST code from the _c_ast.yaml configuration file.
 #
-# Copyright (C) 2008, Eli Bendersky
+# Copyright (C) 2008-2010, Eli Bendersky
 # License: LGPL
 #-----------------------------------------------------------------
 

File pycparser/_c_ast.yaml

 #   <name>**    - a sequence of child nodes
 #   <name>      - an attribute
 #
-# Copyright (C) 2008-2009, Eli Bendersky
+# Copyright (C) 2008-2010, Eli Bendersky
 # License: LGPL
 #-----------------------------------------------------------------
 
 #
 Compound: [block_items**]
 
+# Compound literal (anonymous aggregate) for C99.
+# (type-name) {initializer_list}
+# type: the type decl
+# init: ExprList for the initializer list
+#
+CompoundLiteral: [type*, init*]
+
 # type: int, char, float, etc. see CLexer for constant token types
 #
 Constant: [type, value]
 
 Label: [name, stmt*]
 
+# A named initializer for C99
+#
+NamedInitializer: [name, expr*]
+
 # a list of comma separated function parameter declarations
 #
 ParamList: [params**]

File pycparser/c_ast.py

             c.show(buf, offset + 2, attrnames, showcoord)
 
 
-class FuncCall(Node):
-    def __init__(self, name, args, coord=None):
-        self.name = name
-        self.args = args
+class For(Node):
+    def __init__(self, init, cond, next, stmt, coord=None):
+        self.init = init
+        self.cond = cond
+        self.next = next
+        self.stmt = stmt
         self.coord = coord
 
     def children(self):
         nodelist = []
-        if self.name is not None: nodelist.append(self.name)
-        if self.args is not None: nodelist.append(self.args)
+        if self.init is not None: nodelist.append(self.init)
+        if self.cond is not None: nodelist.append(self.cond)
+        if self.next is not None: nodelist.append(self.next)
+        if self.stmt is not None: nodelist.append(self.stmt)
         return tuple(nodelist)
 
     def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False):
         lead = ' ' * offset
-        buf.write(lead + 'FuncCall: ')
+        buf.write(lead + 'For: ')
 
         if showcoord:
             buf.write(' (at %s)' % self.coord)
             c.show(buf, offset + 2, attrnames, showcoord)
 
 
+class CompoundLiteral(Node):
+    def __init__(self, type, init, coord=None):
+        self.type = type
+        self.init = init
+        self.coord = coord
+
+    def children(self):
+        nodelist = []
+        if self.type is not None: nodelist.append(self.type)
+        if self.init is not None: nodelist.append(self.init)
+        return tuple(nodelist)
+
+    def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False):
+        lead = ' ' * offset
+        buf.write(lead + 'CompoundLiteral: ')
+
+        if showcoord:
+            buf.write(' (at %s)' % self.coord)
+        buf.write('\n')
+
+        for c in self.children():
+            c.show(buf, offset + 2, attrnames, showcoord)
+
+
 class TernaryOp(Node):
     def __init__(self, cond, iftrue, iffalse, coord=None):
         self.cond = cond
             c.show(buf, offset + 2, attrnames, showcoord)
 
 
-class For(Node):
-    def __init__(self, init, cond, next, stmt, coord=None):
-        self.init = init
-        self.cond = cond
-        self.next = next
-        self.stmt = stmt
+class FuncCall(Node):
+    def __init__(self, name, args, coord=None):
+        self.name = name
+        self.args = args
         self.coord = coord
 
     def children(self):
         nodelist = []
-        if self.init is not None: nodelist.append(self.init)
-        if self.cond is not None: nodelist.append(self.cond)
-        if self.next is not None: nodelist.append(self.next)
-        if self.stmt is not None: nodelist.append(self.stmt)
+        if self.name is not None: nodelist.append(self.name)
+        if self.args is not None: nodelist.append(self.args)
         return tuple(nodelist)
 
     def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False):
         lead = ' ' * offset
-        buf.write(lead + 'For: ')
+        buf.write(lead + 'FuncCall: ')
 
         if showcoord:
             buf.write(' (at %s)' % self.coord)
             c.show(buf, offset + 2, attrnames, showcoord)
 
 
+class NamedInitializer(Node):
+    def __init__(self, name, expr, coord=None):
+        self.name = name
+        self.expr = expr
+        self.coord = coord
+
+    def children(self):
+        nodelist = []
+        if self.expr is not None: nodelist.append(self.expr)
+        return tuple(nodelist)
+
+    def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False):
+        lead = ' ' * offset
+        buf.write(lead + 'NamedInitializer: ')
+
+        if attrnames:
+            attrstr = ', '.join('%s=%s' % nv for nv in [("name", repr(self.name))])
+        else:
+            attrstr = ', '.join('%s' % v for v in [self.name])
+        buf.write(attrstr)
+
+        if showcoord:
+            buf.write(' (at %s)' % self.coord)
+        buf.write('\n')
+
+        for c in self.children():
+            c.show(buf, offset + 2, attrnames, showcoord)
+
+
 class EnumeratorList(Node):
     def __init__(self, enumerators, coord=None):
         self.enumerators = enumerators

File pycparser/c_parser.py

             'assignment_expression',
             'declaration_list',
             'declaration_specifiers',
+            'designation',
             'expression',
             'identifier_list',
             'init_declarator_list',
                             | CHAR
                             | SHORT
                             | INT
-                            | LONG LONG
                             | LONG
                             | FLOAT
                             | DOUBLE
                             | enum_specifier
                             | struct_or_union_specifier
         """
-        # The join is currently aimed only at the 'long long' type
-        #
-        p[0] = ' '.join(p[1:]) if len(p) > 2 else p[1]
+        p[0] = p[1]
     
     def p_type_qualifier(self, p):
         """ type_qualifier  : CONST
         """
         p[0] = p[1] + [p[3]] if len(p) == 4 else [p[1]]
 
-    # Returns a (declarator, intializer) pair
+    # Returns a (declarator, initializer) pair
     # If there's no initializer, returns (declarator, None)
     #
     def p_init_declarator(self, p):
             type=p[2] or c_ast.TypeDecl(None, None, None))
             
         typename = spec['type'] or ['int']
-        
         p[0] = self._fix_decl_name_type(decl, typename)        
     
     def p_identifier_list(self, p):
         p[0] = p[2]
 
     def p_initializer_list(self, p):
-        """ initializer_list    : initializer
-                                | initializer_list COMMA initializer
+        """ initializer_list    : designation_opt initializer
+                                | initializer_list COMMA designation_opt initializer
         """
-        if len(p) == 2: # single initializer
-            p[0] = c_ast.ExprList([p[1]], p[1].coord)
+        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)
         else:
-            p[1].exprs.append(p[3])
+            init = p[4] if p[3] is None else c_ast.NamedInitializer(p[3], p[4])
+            p[1].exprs.append(init)
             p[0] = p[1]
-        
+    
+    def p_designation(self, p):
+        """ designation : designator_list EQUALS
+        """
+        p[0] = p[1]
+    
+    # Designators are represented as a list of nodes, in the order in which
+    # they're written in the code.
+    #
+    def p_designator_list(self, p):
+        """ designator_list : designator
+                            | designator_list designator
+        """
+        p[0] = [p[1]] if len(p) == 2 else p[1] + [p[2]]
+    
+    def p_designator(self, p):
+        """ designator  : LBRACKET constant_expression RBRACKET
+                        | PERIOD identifier
+        """
+        p[0] = p[2]
+    
     def p_type_name(self, p):
         """ type_name   : specifier_qualifier_list abstract_declarator_opt 
         """
         """
         p[0] = c_ast.UnaryOp('p' + p[2], p[1], p[1].coord)
 
+    def p_postfix_expression_6(self, p):
+        """ postfix_expression  : LPAREN type_name RPAREN LBRACE initializer_list LBRACE
+        """
+        p[0] = c_ast.CompoundLiteral(p[2], p[5])
+
     def p_primary_expression_1(self, p):
         """ primary_expression  : identifier """
         p[0] = p[1]

File pycparser/plyparser.py

 # PLYParser class and other utilites for simplifying programming
 # parsers with PLY
 #
-# Copyright (C) 2008-2009, Eli Bendersky
+# Copyright (C) 2008-2010, Eli Bendersky
 # License: LGPL
 #-----------------------------------------------------------------
 

File tests/test_c_parser.py

     """
     typ = type(init)
     
-    if typ == Constant:
+    if typ == NamedInitializer:
+        des = [expand_init(dp) for dp in init.name]
+        return (des, expand_init(init.expr))
+    elif typ == ExprList:
+        return [expand_init(expr) for expr in init.exprs]
+    elif typ == Constant:
         return ['Constant', init.type, init.value]
     elif typ == ID:
         return ['ID', init.name]
-    elif typ == ExprList:
-        return [expand_init(expr) for expr in init.exprs]
 
 
 class TestCParser_fundamentals(unittest.TestCase):
         self.assertEqual(self.get_decl('long long ar[15];'), 
             ['Decl', 'ar', 
                 ['ArrayDecl', '15', 
-                    ['TypeDecl', ['IdentifierType', ['long long']]]]])
+                    ['TypeDecl', ['IdentifierType', ['long', 'long']]]]])
         
         self.assertEqual(self.get_decl('unsigned ar[];'), 
             ['Decl', 'ar', 
                         ['TypeDecl', 
                             ['IdentifierType', ['int']]]]]])
     
+    def test_compound_literals(self):
+        s1 = r'''
+            void foo() {
+                int p = (int []){.kwa = 4};
+            }'''
+        
+        self.parse(s1).show()
+
+        
     def test_enums(self):
         e1 = "enum mycolor op;"
         e1_type = self.parse(e1).ext[0].type.type
     
     def test_decl_inits(self):
         d1 = 'int a = 16;'
+        #~ self.parse(d1).show()
         self.assertEqual(self.get_decl(d1),
             ['Decl', 'a', ['TypeDecl', ['IdentifierType', ['int']]]])
         self.assertEqual(self.get_decl_init(d1),
             ['Constant', 'int', '16'])
         
         d2 = 'long ar[] = {7, 8, 9};'
+        #~ self.parse(d2).show()
         self.assertEqual(self.get_decl(d2),
             ['Decl', 'ar', 
                 ['ArrayDecl', '',
         self.assertEqual(self.get_decl_init(d2),
             [   ['Constant', 'int', '7'],
                 ['Constant', 'int', '8'],
-                ['Constant', 'int', '9'],])
+                ['Constant', 'int', '9']])
         
         d3 = 'char p = j;'
         self.assertEqual(self.get_decl(d3),
             ['Decl', 'p', 
                 ['PtrDecl',
                     ['TypeDecl', ['IdentifierType', ['char']]]]])
+        
         self.assertEqual(self.get_decl_init(d4, 1),
             [   ['Constant', 'int', '0'], 
                 ['Constant', 'int', '1'], 
                 ['Constant', 'int', '2'], 
-                [   ['Constant', 'int', '4'], 
-                    ['Constant', 'int', '5']], 
+                [['Constant', 'int', '4'], 
+                 ['Constant', 'int', '5']], 
                 ['Constant', 'int', '6']])
+        
+    def test_decl_named_inits(self):
+        d1 = 'int a = {.k = 16};'
+        self.assertEqual(self.get_decl_init(d1),
+            [(   [['ID', 'k']],
+                 ['Constant', 'int', '16'])])
+
+        d2 = 'int a = { [0].a = {1}, [1].a[0] = 2 };'
+        self.assertEqual(self.get_decl_init(d2),
+            [
+                ([['Constant', 'int', '0'], ['ID', 'a']], 
+                    [['Constant', 'int', '1']]), 
+                ([['Constant', 'int', '1'], ['ID', 'a'], ['Constant', 'int', '0']], 
+                    ['Constant', 'int', '2'])])
+
+        d3 = 'int a = { .a = 1, .c = 3, 4, .b = 5};'
+        self.assertEqual(self.get_decl_init(d3),
+            [
+                ([['ID', 'a']], ['Constant', 'int', '1']), 
+                ([['ID', 'c']], ['Constant', 'int', '3']), 
+                ['Constant', 'int', '4'], 
+                ([['ID', 'b']], ['Constant', 'int', '5'])])
 
     def test_function_definitions(self):
         def parse_fdef(str):