Commits

Anonymous committed 095457c

Fix for issue 6: support concatenation of string literals

  • Participants
  • Parent commits b1a265c

Comments (0)

Files changed (4)

 ===============
-pycparser v1.06
+pycparser v1.07
 ===============
 
 :Author: `Eli Bendersky <http://eli.thegreenplace.net>`_
 Fixes since last:
 ------------------
 
+* bugfix: correct handling of do{} while statements in some cases
 
 
 Version Update

File pycparser/c_parser.py

         p[0] = p[1]
         
     def p_primary_expression_3(self, p):
-        """ primary_expression  : STRING_LITERAL 
-                                | WSTRING_LITERAL
+        """ primary_expression  : unified_string_literal 
+                                | unified_wstring_literal
         """
-        p[0] = c_ast.Constant(
-            'string', p[1], self._coord(p.lineno(1)))
+        p[0] = p[1]
             
     def p_primary_expression_4(self, p):
         """ primary_expression  : LPAREN expression RPAREN """
         """
         p[0] = c_ast.Constant(
             'char', p[1], self._coord(p.lineno(1)))
-        
+    
+    # The "unified" string and wstring literal rules are for supporting 
+    # concatenation of adjacent string literals.
+    # I.e. "hello " "world" is seen by the C compiler as a single string literal
+    # with the value "hello world"
+    #
+    def p_unified_string_literal(self, p):
+        """ unified_string_literal  : STRING_LITERAL
+                                    | unified_string_literal STRING_LITERAL  
+        """
+        if len(p) == 2: # single literal
+            p[0] = c_ast.Constant(
+                'string', p[1], self._coord(p.lineno(1)))
+        else:
+            p[1].value = p[1].value.rstrip('"') + p[2].lstrip('"')
+            p[0] = p[1]
+            
+    def p_unified_wstring_literal(self, p):
+        """ unified_wstring_literal : WSTRING_LITERAL
+                                    | unified_wstring_literal WSTRING_LITERAL  
+        """
+        if len(p) == 2: # single literal
+            p[0] = c_ast.Constant(
+                'string', p[1], self._coord(p.lineno(1)))
+        else:
+            p[1].value = p[1].value.rstrip('"') + p[2].lstrip('"')
+            p[0] = p[1]
+            
     def p_empty(self, p):
         'empty : '
         p[0] = None

File tests/test_c_parser.py

         self.assertEqual(expand_decl(f3.param_decls[1]),
             ['Decl', 'c', ['PtrDecl', ['TypeDecl', ['IdentifierType', ['long']]]]])
 
+    def test_unified_string_literals(self):
+        # simple string, for reference
+        d1 = self.get_decl_init('char* s = "hello";')
+        self.assertEqual(d1, ['Constant', 'string', '"hello"'])
+        
+        d2 = self.get_decl_init('char* s = "hello" " world";')
+        self.assertEqual(d2, ['Constant', 'string', '"hello world"'])
+        
+        # the test case from issue 6
+        d3 = self.parse(r'''
+            int main() {
+                fprintf(stderr,
+                "Wrong Params?\n"
+                "Usage:\n"
+                "%s <binary_file_path>\n",
+                argv[0]
+                );
+            }
+        ''')
+        
+        self.assertEqual(
+            d3.ext[0].body.stmts[0].args.exprs[1].value,
+            r'"Wrong Params?\nUsage:\n%s <binary_file_path>\n"')
+
 
 class TestCParser_whole_code(unittest.TestCase):
     """ Testing of parsing whole chunks of code.