This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

String constant concatenation in c-lex.c


As Joseph suggested last week: this patch does C's string constant
concatenation inside lex_string, instead of separately in
combine_strings.  This allows some minor simplifications elsewhere in
the compiler.  For instance, the special 'string' production in
c-parse.in goes away.  There's some C++ front end logic left, that
should be moved into c_build_string.  I haven't done that yet because
I don't understand the requirements.  (See my other message, this afternoon.)

Also, a long-standing bug with wide string conversion is fixed.  Consider

  "abc*def" L"ghijkl"

where the splat is actually a multi-byte character whose wchar_t form
doesn't fit in a single byte.  The C standard says that this is to
wind up as a wide string, and that the multibyte representations are
to be concatenated, then the whole megillah converted to wide
characters at once.

We used to convert each string separately, and we would truncate the
splat to fit in a single byte, because that particular constant
doesn't have the prefix.  Then we'd go back and zero-extend each
single byte to a wide character in combine_strings, but it'd be too
late to get the splat right.

I doubt anyone has noticed this bug, because multibyte support doesn't
work anyway.

There is a silent change to the syntax of Objective C @-strings.
Formerly, if you had a series of string literals to be concatenated,
either they all had to have the @ prefix, or none, or you'd get a
parse error.  Now, all @s except the one on the first string literal
are ignored, so

    @"foo" @"bar" "@baz"	-> string object
    @"foo" "bar" "baz"		-> string object
    "foo" @"bar" @"baz"		-> char array

For consistency with the L prefix, the rule should probably be that if
any string literal in the series has a leading @, it's a string
object.  This requires changes to cpplib, and I would like to get an
opinion from the Objective C maintainers first.

This has passed the C and ObjC test suites.  I'm running a complete
bootstrap on i686-linux, but I think the tree is busted right now.

-- 
zw    This notion of the domain specificity of information is, patently, of
      no use to anybody.  I mention it simply to get it out of the way.
      	-- Jerry Fodor, _The Mind Doesn't Work That Way_

	String constant concatenation moves to lex_string.

	* c-common.c (combine_strings): Delete.
	(c_build_string): New.
	* c-common.h: Update prototypes to match.
	* c-lex.c (_next_mbchar, next_mbchar, reset_conversion_state):
	New abstraction to avoid #ifdefs in the middle of functions.
	(YYDEBUG, ignore_escape_flag): Remove, unused.
	(convert_string, convert_wstring, catenate_strings): New functions.
	(cb_ident, lex_string): Use them.  String constant
	concatenation now happens here.

	* c-parse.in, cp/parse.y: Kill "string" and "objc_string"
	nonterminals.  Replace all uses with the STRING and
	OBJC_STRING terminals.

	* c-parse.in, c-typeck.c, c-common.c. cp/rtti.c,
	cp/semantics.c, objc/objc-act.c: Don't call combine_strings.
	Do call c_build_string where necessary.

	* ch/ch-tree.h: Remove old prototype of combine_strings.

===================================================================
Index: c-common.c
*** c-common.c	2001/06/05 08:03:43	1.237
--- c-common.c	2001/06/21 05:24:19
*************** fname_decl (rid, id)
*** 511,638 ****
    return decl;
  }
  
! /* Given a chain of STRING_CST nodes,
!    concatenate them into one STRING_CST
!    and give it a suitable array-of-chars data type.  */
! 
  tree
! combine_strings (strings)
!      tree strings;
! {
!   register tree value, t;
!   register int length = 1;
!   int wide_length = 0;
!   int wide_flag = 0;
!   int wchar_bytes = TYPE_PRECISION (wchar_type_node) / BITS_PER_UNIT;
!   int nchars;
!   const int nchars_max = flag_isoc99 ? 4095 : 509;
! 
!   if (TREE_CHAIN (strings))
!     {
!       /* More than one in the chain, so concatenate.  */
!       register char *p, *q;
! 
!       /* Don't include the \0 at the end of each substring,
! 	 except for the last one.
! 	 Count wide strings and ordinary strings separately.  */
!       for (t = strings; t; t = TREE_CHAIN (t))
! 	{
! 	  if (TREE_TYPE (t) == wchar_array_type_node)
! 	    {
! 	      wide_length += (TREE_STRING_LENGTH (t) - wchar_bytes);
! 	      wide_flag = 1;
! 	    }
! 	  else
! 	    length += (TREE_STRING_LENGTH (t) - 1);
! 	}
! 
!       /* If anything is wide, the non-wides will be converted,
! 	 which makes them take more space.  */
!       if (wide_flag)
! 	length = length * wchar_bytes + wide_length;
! 
!       p = alloca (length);
  
-       /* Copy the individual strings into the new combined string.
- 	 If the combined string is wide, convert the chars to ints
- 	 for any individual strings that are not wide.  */
- 
-       q = p;
-       for (t = strings; t; t = TREE_CHAIN (t))
- 	{
- 	  int len = (TREE_STRING_LENGTH (t)
- 		     - ((TREE_TYPE (t) == wchar_array_type_node)
- 			? wchar_bytes : 1));
- 	  if ((TREE_TYPE (t) == wchar_array_type_node) == wide_flag)
- 	    {
- 	      memcpy (q, TREE_STRING_POINTER (t), len);
- 	      q += len;
- 	    }
- 	  else
- 	    {
- 	      int i, j;
- 	      for (i = 0; i < len; i++)
- 		{
- 		  if (BYTES_BIG_ENDIAN)
- 		    {
- 		      for (j=0; j<(WCHAR_TYPE_SIZE / BITS_PER_UNIT)-1; j++)
- 			*q++ = 0;
- 		      *q++ = TREE_STRING_POINTER (t)[i];
- 		    }
- 		  else
- 		    {
- 		      *q++ = TREE_STRING_POINTER (t)[i];
- 		      for (j=0; j<(WCHAR_TYPE_SIZE / BITS_PER_UNIT)-1; j++)
- 			*q++ = 0;
- 		    }
- 		}
- 	    }
- 	}
-       if (wide_flag)
- 	{
- 	  int i;
- 	  for (i = 0; i < wchar_bytes; i++)
- 	    *q++ = 0;
- 	}
-       else
- 	*q = 0;
- 
-       value = build_string (length, p);
-     }
-   else
-     {
-       value = strings;
-       length = TREE_STRING_LENGTH (value);
-       if (TREE_TYPE (value) == wchar_array_type_node)
- 	wide_flag = 1;
-     }
- 
-   /* Compute the number of elements, for the array type.  */
-   nchars = wide_flag ? length / wchar_bytes : length;
- 
    if (pedantic && nchars - 1 > nchars_max && c_language == clk_c)
      pedwarn ("string length `%d' is greater than the length `%d' ISO C%d compilers are required to support",
  	     nchars - 1, nchars_max, flag_isoc99 ? 99 : 89);
  
!   /* Create the array type for the string constant.
       -Wwrite-strings says make the string constant an array of const char
       so that copying it to a non-const pointer will get a warning.
       For C++, this is the standard behavior.  */
    if (flag_const_strings
!       && (! flag_traditional  && ! flag_writable_strings))
!     {
!       tree elements
! 	= build_type_variant (wide_flag ? wchar_type_node : char_type_node,
! 			      1, 0);
!       TREE_TYPE (value)
! 	= build_array_type (elements,
! 			    build_index_type (build_int_2 (nchars - 1, 0)));
!     }
!   else
!     TREE_TYPE (value)
!       = build_array_type (wide_flag ? wchar_type_node : char_type_node,
! 			  build_index_type (build_int_2 (nchars - 1, 0)));
  
    TREE_CONSTANT (value) = 1;
    TREE_READONLY (value) = ! flag_writable_strings;
    TREE_STATIC (value) = 1;
--- 511,547 ----
    return decl;
  }
  
! /* Given a string of length LEN bytes, convert it to a string-constant
!    tree and give it a suitable array-of-chars data type based on
!    BASETYPE.  */
  tree
! c_build_string (str, len, basetype)
!      const char *str;
!      size_t len;
!      tree basetype;
! {
!   const size_t nchars_max = flag_isoc99 ? 4095 : 509;
!   const int basewidth = TYPE_PRECISION (basetype) / BITS_PER_UNIT;
!   const unsigned int nchars = len / basewidth;
!   tree index, elements, value;
  
    if (pedantic && nchars - 1 > nchars_max && c_language == clk_c)
      pedwarn ("string length `%d' is greater than the length `%d' ISO C%d compilers are required to support",
  	     nchars - 1, nchars_max, flag_isoc99 ? 99 : 89);
  
!   value = build_string (len, str);
! 
!     /* Create the array type for the string constant.
       -Wwrite-strings says make the string constant an array of const char
       so that copying it to a non-const pointer will get a warning.
       For C++, this is the standard behavior.  */
+   elements = basetype;
    if (flag_const_strings
!       && (! flag_traditional && ! flag_writable_strings))
!     elements = build_type_variant (elements, 1, 0);
  
+   index = build_index_type (build_int_2 (nchars - 1, 0));
+   TREE_TYPE (value) = build_array_type (elements, index);
    TREE_CONSTANT (value) = 1;
    TREE_READONLY (value) = ! flag_writable_strings;
    TREE_STATIC (value) = 1;
*************** c_expand_builtin_printf (arglist, target
*** 4163,4169 ****
  	  memcpy (newstr, TREE_STRING_POINTER (stripped_string), newlen - 1);
  	  newstr[newlen - 1] = 0;
  	  
! 	  arglist = combine_strings (build_string (newlen, newstr));
  	  arglist = build_tree_list (NULL_TREE, arglist);
  	  fn = fn_puts;
  	}
--- 4072,4079 ----
  	  memcpy (newstr, TREE_STRING_POINTER (stripped_string), newlen - 1);
  	  newstr[newlen - 1] = 0;
  	  
! 	  arglist = c_build_string (newstr, newlen, char_type_node);
! 	  TREE_TYPE (arglist) = TREE_TYPE (stripped_string);
  	  arglist = build_tree_list (NULL_TREE, arglist);
  	  fn = fn_puts;
  	}
===================================================================
Index: c-common.h
*** c-common.h	2001/06/18 16:15:01	1.75
--- c-common.h	2001/06/21 05:24:19
*************** extern void c_finish_else               
*** 503,510 ****
  extern void c_expand_end_cond			PARAMS ((void));
  /* Validate the expression after `case' and apply default promotions.  */
  extern tree check_case_value			PARAMS ((tree));
! /* Concatenate a list of STRING_CST nodes into one STRING_CST.  */
! extern tree combine_strings			PARAMS ((tree));
  extern void constant_expression_warning		PARAMS ((tree));
  extern tree convert_and_check			PARAMS ((tree, tree));
  extern void overflow_warning			PARAMS ((tree));
--- 503,511 ----
  extern void c_expand_end_cond			PARAMS ((void));
  /* Validate the expression after `case' and apply default promotions.  */
  extern tree check_case_value			PARAMS ((tree));
! /* Create a string constant with the appropriate C type.  */
! extern tree c_build_string			PARAMS ((const char *,
! 							 size_t, tree));
  extern void constant_expression_warning		PARAMS ((tree));
  extern tree convert_and_check			PARAMS ((tree, tree));
  extern void overflow_warning			PARAMS ((tree));
===================================================================
Index: c-lex.c
*** c-lex.c	2001/05/23 19:05:37	1.141
--- c-lex.c	2001/06/21 05:24:19
*************** Boston, MA 02111-1307, USA.  */
*** 48,54 ****
  #ifdef MULTIBYTE_CHARS
  #include "mbchar.h"
  #include <locale.h>
! #endif /* MULTIBYTE_CHARS */
  #ifndef GET_ENVIRONMENT
  #define GET_ENVIRONMENT(ENV_VALUE,ENV_NAME) ((ENV_VALUE) = getenv (ENV_NAME))
  #endif
--- 48,93 ----
  #ifdef MULTIBYTE_CHARS
  #include "mbchar.h"
  #include <locale.h>
! 
! /* These are used mostly by the string literal parsing routines.  */
! static inline unsigned int _next_mbchar PARAMS ((const char **, const char *));
! 
! static inline unsigned int
! _next_mbchar (pp, limit)
!      const char **pp;
!      const char *limit;
! {
!   wchar_t wc;
!   unsigned int c;
!   int char_len;
!   const char *p = *pp;
! 
!   char_len = local_mbtowc (&wc, p, limit - p);
!   if (char_len == -1)
!     {
!       warning ("Ignoring invalid multibyte character");
!       char_len = 1;
!       c = *p++;
!     }
!   else
!     {
!       p += char_len;
!       c = wc;
!     }
!   *pp = p;
!   return c;
! }
! 
! #define next_mbchar(P, LIMIT) _next_mbchar (&(P), LIMIT)
! #define reset_conversion_state() (void) local_mbtowc (NULL, NULL, 0)
! 
! #else /* not MULTIBYTE_CHARS */
! 
! #define next_mbchar(P, LIMIT) (*P++)
! #define reset_conversion_state() (void) 0
! 
! #endif /* not MULTIBYTE_CHARS */
! 
  #ifndef GET_ENVIRONMENT
  #define GET_ENVIRONMENT(ENV_VALUE,ENV_NAME) ((ENV_VALUE) = getenv (ENV_NAME))
  #endif
*************** static const char *cpp_filename;
*** 60,68 ****
  static int header_time, body_time;
  static splay_tree file_info_tree;
  
- /* Cause the `yydebug' variable to be defined.  */
- #define YYDEBUG 1
- 
  /* File used for outputting assembler code.  */
  extern FILE *asm_out_file;
  
--- 99,104 ----
*************** int indent_level;        /* Number of { 
*** 76,87 ****
  int pending_lang_change; /* If we need to switch languages - C++ only */
  int c_header_level;	 /* depth in C headers - C++ only */
  
! /* Nonzero tells yylex to ignore \ in string constants.  */
! static int ignore_escape_flag;
  
  static void parse_float		PARAMS ((PTR));
  static tree lex_number		PARAMS ((const char *, unsigned int));
! static tree lex_string		PARAMS ((const char *, unsigned int, int));
  static tree lex_charconst	PARAMS ((const cpp_token *));
  static void update_header_times	PARAMS ((const char *));
  static int dump_one_header	PARAMS ((splay_tree_node, void *));
--- 112,127 ----
  int pending_lang_change; /* If we need to switch languages - C++ only */
  int c_header_level;	 /* depth in C headers - C++ only */
  
! static unsigned int convert_string	PARAMS ((char *, const char *,
! 						 unsigned int));
! static unsigned int convert_wstring	PARAMS ((char *, const char *,
! 						 unsigned int));
! static cpp_string catenate_strings	PARAMS ((const cpp_token *, cpp_token *,
! 						 int *));
  
  static void parse_float		PARAMS ((PTR));
  static tree lex_number		PARAMS ((const char *, unsigned int));
! static tree lex_string		PARAMS ((const cpp_token *));
  static tree lex_charconst	PARAMS ((const cpp_token *));
  static void update_header_times	PARAMS ((const char *));
  static int dump_one_header	PARAMS ((splay_tree_node, void *));
*************** cb_ident (pfile, str)
*** 229,236 ****
    if (! flag_no_ident)
      {
        /* Convert escapes in the string.  */
!       tree value = lex_string ((const char *)str->text, str->len, 0);
!       ASM_OUTPUT_IDENT (asm_out_file, TREE_STRING_POINTER (value));
      }
  #endif
  }
--- 269,277 ----
    if (! flag_no_ident)
      {
        /* Convert escapes in the string.  */
!       char *buf = alloca (str->len + 1);
!       convert_string (buf, (const char *)str->text, str->len);
!       ASM_OUTPUT_IDENT (asm_out_file, buf);
      }
  #endif
  }
*************** c_lex (value)
*** 785,792 ****
  
      case CPP_STRING:
      case CPP_WSTRING:
!       *value = lex_string ((const char *)tok.val.str.text,
! 			   tok.val.str.len, tok.type == CPP_WSTRING);
        break;
  
        /* These tokens should not be visible outside cpplib.  */
--- 826,832 ----
  
      case CPP_STRING:
      case CPP_WSTRING:
!       *value = lex_string (&tok);
        break;
  
        /* These tokens should not be visible outside cpplib.  */
*************** lex_number (str, len)
*** 1280,1387 ****
    return integer_zero_node;
  }
  
! static tree
! lex_string (str, len, wide)
       const char *str;
       unsigned int len;
-      int wide;
  {
!   tree value;
!   char *buf = alloca ((len + 1) * (wide ? WCHAR_BYTES : 1));
    char *q = buf;
-   const char *p = str, *limit = str + len;
    unsigned int c;
!   unsigned width = wide ? WCHAR_TYPE_SIZE
! 			: TYPE_PRECISION (char_type_node);
  
! #ifdef MULTIBYTE_CHARS
!   /* Reset multibyte conversion state.  */
!   (void) local_mbtowc (NULL, NULL, 0);
! #endif
  
    while (p < limit)
      {
! #ifdef MULTIBYTE_CHARS
!       wchar_t wc;
!       int char_len;
  
!       char_len = local_mbtowc (&wc, p, limit - p);
!       if (char_len == -1)
! 	{
! 	  warning ("Ignoring invalid multibyte character");
! 	  char_len = 1;
! 	  c = *p++;
! 	}
!       else
! 	{
! 	  p += char_len;
! 	  c = wc;
! 	}
! #else
!       c = *p++;
! #endif
  
!       if (c == '\\' && !ignore_escape_flag)
! 	{
! 	  unsigned int mask;
  
! 	  if (width < HOST_BITS_PER_INT)
! 	    mask = ((unsigned int) 1 << width) - 1;
! 	  else
! 	    mask = ~0;
! 	  c = cpp_parse_escape (parse_in, (const unsigned char **) &p,
! 				(const unsigned char *) limit,
! 				mask, flag_traditional);
! 	}
! 	
!       /* Add this single character into the buffer either as a wchar_t
! 	 or as a single byte.  */
!       if (wide)
! 	{
! 	  unsigned charwidth = TYPE_PRECISION (char_type_node);
! 	  unsigned bytemask = (1 << charwidth) - 1;
! 	  int byte;
  
! 	  for (byte = 0; byte < WCHAR_BYTES; ++byte)
! 	    {
! 	      int n;
! 	      if (byte >= (int) sizeof (c))
! 		n = 0;
! 	      else
! 		n = (c >> (byte * charwidth)) & bytemask;
! 	      if (BYTES_BIG_ENDIAN)
! 		q[WCHAR_BYTES - byte - 1] = n;
! 	      else
! 		q[byte] = n;
! 	    }
! 	  q += WCHAR_BYTES;
! 	}
!       else
  	{
! 	  *q++ = c;
  	}
      }
  
!   /* Terminate the string value, either with a single byte zero
!      or with a wide zero.  */
  
!   if (wide)
!     {
!       memset (q, 0, WCHAR_BYTES);
!       q += WCHAR_BYTES;
!     }
!   else
      {
!       *q++ = '\0';
!     }
  
!   value = build_string (q - buf, buf);
  
    if (wide)
!     TREE_TYPE (value) = wchar_array_type_node;
    else
!     TREE_TYPE (value) = char_array_type_node;
!   return value;
  }
  
  /* Converts a (possibly wide) character constant token into a tree.  */
--- 1320,1504 ----
    return integer_zero_node;
  }
  
! /* Copy STR into BUF, converting escapes, and add a terminating NUL.  */
! static unsigned int
! convert_string (buf, str, len)
!      char *buf;
       const char *str;
       unsigned int len;
  {
!   const char *p = str;
!   const char *limit = str + len;
    char *q = buf;
    unsigned int c;
!   const unsigned int mask
!     = ((unsigned int) 1 << TYPE_PRECISION (char_type_node)) - 1;
  
!   reset_conversion_state ();
  
    while (p < limit)
      {
!       c = next_mbchar (p, limit);
!       if (c == '\\')
! 	c = cpp_parse_escape (parse_in,
! 			      (const unsigned char **) &p,
! 			      (const unsigned char *) limit,
! 			      mask, flag_traditional);
!       *q++ = c;
!     }
  
!   *q++ = '\0';
!   return q - buf;
! }
  
! /* Same, but produces a wide string.  */
! static unsigned int
! convert_wstring (buf, str, len)
!      char *buf;
!      const char *str;
!      unsigned int len;
! {
!   const char *p = str;
!   const char *limit = str + len;
!   char *q = buf;
!   unsigned int c;
!   const unsigned int mask =
!     ((WCHAR_TYPE_SIZE < HOST_BITS_PER_INT)
!      ? ((unsigned int) 1 << WCHAR_TYPE_SIZE) - 1
!      : ~ (unsigned int) 0);
!   const unsigned int charwidth = TYPE_PRECISION (char_type_node);
!   const unsigned int bytemask = (1 << charwidth) - 1;
!   int byte;
  
!   reset_conversion_state ();
  
!   while (p < limit)
!     {
!       c = next_mbchar (p, limit);
!       if (c == '\\')
! 	c = cpp_parse_escape (parse_in,
! 			      (const unsigned char **) &p,
! 			      (const unsigned char *) limit,
! 			      mask, flag_traditional);
! 
!       for (byte = 0; byte < WCHAR_BYTES; ++byte)
  	{
! 	  int n;
! 	  if (byte >= (int) sizeof (c))
! 	    n = 0;
! 	  else
! 	    n = (c >> (byte * charwidth)) & bytemask;
! 	  if (BYTES_BIG_ENDIAN)
! 	    q[WCHAR_BYTES - byte - 1] = n;
! 	  else
! 	    q[byte] = n;
  	}
+       q += WCHAR_BYTES;
      }
  
!   memset (q, 0, WCHAR_BYTES);
!   q += WCHAR_BYTES;
!   return q - buf;
! }
  
! /* Subroutine of lex_string.  Merge TOK, NTOK, and all following
!    CPP_STRING or CPP_WSTRING tokens into one string constant, which
!    is returned.  Caller is responsible for freeing the buffer returned.
!    *WIDEP is set to 1 if any of the tokens is a wide string.  NTOK is
!    clobbered.  */
! static cpp_string
! catenate_strings (tok, ntok, widep)
!      const cpp_token *tok;
!      cpp_token *ntok;
!      int *widep;
! {
!   cpp_string r;
!   unsigned char *text;
!   unsigned int len, offset;
!   int another;
! 
!   if (c_language == clk_c && warn_traditional && !in_system_header)
!     warning ("traditional C rejects string concatenation");
! 
!   /* first copy in TOK */
!   len = tok->val.str.len;
!   text = xmalloc (len);
!   memcpy (text, tok->val.str.text, len);
!   offset = tok->val.str.len;
! 
!   /* now append NTOK, and then loop over any following string constants */
!   do
      {
!       len += ntok->val.str.len;
!       text = xrealloc (text, len);
!       memcpy (text + offset, ntok->val.str.text, ntok->val.str.len);
!       offset += ntok->val.str.len;
! 
!       if (ntok->type == CPP_WSTRING)
! 	*widep = 1;
! 
!       /* Get the next token, but only if it is a plain string.  */
!       timevar_push (TV_CPP);
!       cpp_start_lookahead (parse_in);
!       cpp_get_token (parse_in, ntok);
! 
!       /* Objective C - there might be an at-sign in here.  */
!       if (c_language == clk_objective_c && ntok->type == CPP_ATSIGN)
! 	cpp_get_token (parse_in, ntok);
! 
!       another = (ntok->type == CPP_STRING || ntok->type == CPP_WSTRING);
!       cpp_stop_lookahead (parse_in, another);
!       timevar_pop (TV_CPP);
!     }
!   while (another);
! 
!   r.text = text;
!   r.len = len;
!   return r;
! }
  
! /* Convert a (possibly wide) string literal into a tree.
!    Handles C89 string constant concatenation.  */
! static tree
! lex_string (tok)
!      const cpp_token *tok;
! {
!   cpp_token ntok;
!   cpp_string str = tok->val.str;
!   int wide = (tok->type == CPP_WSTRING);
!   int catenated = 0;
!   char *buf;
!   unsigned int len;
! 
!   /* Look ahead for the next token.  If it is another string, we want to
!      concatenate it and any successive strings with the current one to
!      make one big string constant.  */
!   timevar_push (TV_CPP);
!   cpp_start_lookahead (parse_in);
!   cpp_get_token (parse_in, &ntok);
! 
!   /* Objective C - there might be an at-sign in here.  */
!   if (c_language == clk_objective_c && ntok.type == CPP_ATSIGN)
!     cpp_get_token (parse_in, &ntok);
! 
!   catenated = (ntok.type == CPP_STRING || ntok.type == CPP_WSTRING);
!   cpp_stop_lookahead (parse_in, catenated);
!   timevar_pop (TV_CPP);
  
+   if (catenated)
+     str = catenate_strings (tok, &ntok, &wide);
+ 
+   buf = alloca (str.len * (wide ? WCHAR_BYTES : 1));
    if (wide)
!     len = convert_wstring (buf, (const char *)str.text, str.len);
    else
!     len = convert_string (buf, (const char *)str.text, str.len);
! 
!   if (catenated)
!     free ((PTR) str.text);
! 
!   return c_build_string (buf, len,
! 			 wide ? wchar_type_node : char_type_node);
  }
  
  /* Converts a (possibly wide) character constant token into a tree.  */
===================================================================
Index: c-parse.in
*** c-parse.in	2001/06/10 13:47:54	1.94
--- c-parse.in	2001/06/21 05:24:20
*************** end ifc
*** 110,116 ****
     yylval is the node for the constant.  */
  %token CONSTANT
  
! /* String constants in raw form.
     yylval is a STRING_CST node.  */
  %token STRING
  
--- 110,116 ----
     yylval is the node for the constant.  */
  %token CONSTANT
  
! /* String constants.
     yylval is a STRING_CST node.  */
  %token STRING
  
*************** end ifc
*** 157,173 ****
  %token INTERFACE IMPLEMENTATION END SELECTOR DEFS ENCODE
  %token CLASSNAME PUBLIC PRIVATE PROTECTED PROTOCOL OBJECTNAME CLASS ALIAS
  
! /* Objective-C string constants in raw form.
     yylval is an STRING_CST node.  */
  %token OBJC_STRING
  
- 
  %type <code> unop
  %type <ttype> ENUM STRUCT UNION IF ELSE WHILE DO FOR SWITCH CASE DEFAULT
  %type <ttype> BREAK CONTINUE RETURN GOTO ASM_KEYWORD SIZEOF TYPEOF ALIGNOF
  
  %type <ttype> identifier IDENTIFIER TYPENAME CONSTANT expr nonnull_exprlist exprlist
! %type <ttype> expr_no_commas cast_expr unary_expr primary string STRING
  %type <ttype> declspecs_nosc_nots_nosa_noea declspecs_nosc_nots_nosa_ea
  %type <ttype> declspecs_nosc_nots_sa_noea declspecs_nosc_nots_sa_ea
  %type <ttype> declspecs_nosc_ts_nosa_noea declspecs_nosc_ts_nosa_ea
--- 157,172 ----
  %token INTERFACE IMPLEMENTATION END SELECTOR DEFS ENCODE
  %token CLASSNAME PUBLIC PRIVATE PROTECTED PROTOCOL OBJECTNAME CLASS ALIAS
  
! /* Objective-C string constants.
     yylval is an STRING_CST node.  */
  %token OBJC_STRING
  
  %type <code> unop
  %type <ttype> ENUM STRUCT UNION IF ELSE WHILE DO FOR SWITCH CASE DEFAULT
  %type <ttype> BREAK CONTINUE RETURN GOTO ASM_KEYWORD SIZEOF TYPEOF ALIGNOF
  
  %type <ttype> identifier IDENTIFIER TYPENAME CONSTANT expr nonnull_exprlist exprlist
! %type <ttype> expr_no_commas cast_expr unary_expr primary STRING
  %type <ttype> declspecs_nosc_nots_nosa_noea declspecs_nosc_nots_nosa_ea
  %type <ttype> declspecs_nosc_nots_sa_noea declspecs_nosc_nots_sa_ea
  %type <ttype> declspecs_nosc_ts_nosa_noea declspecs_nosc_ts_nosa_ea
*************** ifobjc
*** 229,235 ****
  %type <ttype> keywordexpr keywordarglist keywordarg
  %type <ttype> myparms myparm optparmlist reservedwords objcselectorexpr
  %type <ttype> selectorarg keywordnamelist keywordname objcencodeexpr
! %type <ttype> objc_string non_empty_protocolrefs protocolrefs identifier_list objcprotocolexpr
  
  %type <ttype> CLASSNAME OBJC_STRING OBJECTNAME
  end ifobjc
--- 228,235 ----
  %type <ttype> keywordexpr keywordarglist keywordarg
  %type <ttype> myparms myparm optparmlist reservedwords objcselectorexpr
  %type <ttype> selectorarg keywordnamelist keywordname objcencodeexpr
! %type <ttype> non_empty_protocolrefs protocolrefs identifier_list
! %type <ttype> objcprotocolexpr
  
  %type <ttype> CLASSNAME OBJC_STRING OBJECTNAME
  end ifobjc
*************** primary:
*** 632,639 ****
  		  $$ = build_external_ref ($1, yychar == '(');
  		}
  	| CONSTANT
! 	| string
! 		{ $$ = combine_strings ($1); }
  	| VAR_FUNC_NAME
  		{ $$ = fname_decl (C_RID_CODE ($$), $$); }
  	| '(' typename ')' '{' 
--- 632,638 ----
  		  $$ = build_external_ref ($1, yychar == '(');
  		}
  	| CONSTANT
! 	| STRING
  	| VAR_FUNC_NAME
  		{ $$ = fname_decl (C_RID_CODE ($$), $$); }
  	| '(' typename ')' '{' 
*************** ifobjc
*** 735,778 ****
  		{ $$ = build_protocol_expr ($1); }
  	| objcencodeexpr
  		{ $$ = build_encode_expr ($1); }
! 	| objc_string
  		{ $$ = build_objc_string_object ($1); }
  end ifobjc
  	;
  
- /* Produces a STRING_CST with perhaps more STRING_CSTs chained onto it.  */
- string:
- 	  STRING
- 	| string STRING
- 		{
- ifc
-                   static int last_lineno = 0;
-                   static const char *last_input_filename = 0;
- end ifc
-                   $$ = chainon ($1, $2);
- ifc
- 		  if (warn_traditional && !in_system_header
- 		      && (lineno != last_lineno || !last_input_filename ||
- 			  strcmp (last_input_filename, input_filename)))
- 		    {
- 		      warning ("traditional C rejects string concatenation");
- 		      last_lineno = lineno;
- 		      last_input_filename = input_filename;
- 		    }
- end ifc
- 		}
- 	;
- 
- ifobjc
- /* Produces an STRING_CST with perhaps more STRING_CSTs chained
-    onto it, which is to be read as an ObjC string object.  */
- objc_string:
- 	  OBJC_STRING
- 	| objc_string OBJC_STRING
- 		{ $$ = chainon ($1, $2); }
- 	;
- end ifobjc
- 
  old_style_parm_decls:
  	/* empty */
  	| datadecls
--- 734,744 ----
  		{ $$ = build_protocol_expr ($1); }
  	| objcencodeexpr
  		{ $$ = build_encode_expr ($1); }
! 	| OBJC_STRING
  		{ $$ = build_objc_string_object ($1); }
  end ifobjc
  	;
  
  old_style_parm_decls:
  	/* empty */
  	| datadecls
*************** notype_initdecls:
*** 1431,1440 ****
  maybeasm:
  	  /* empty */
  		{ $$ = NULL_TREE; }
! 	| ASM_KEYWORD '(' string ')'
! 		{ if (TREE_CHAIN ($3)) $3 = combine_strings ($3);
! 		  $$ = $3;
! 		}
  	;
  
  initdcl:
--- 1397,1404 ----
  maybeasm:
  	  /* empty */
  		{ $$ = NULL_TREE; }
! 	| ASM_KEYWORD '(' STRING ')'
! 		{ $$ = $3; }
  	;
  
  initdcl:
*************** asm_operand:
*** 2497,2506 ****
  	;
  
  asm_clobbers:
! 	  string
! 		{ $$ = tree_cons (NULL_TREE, combine_strings ($1), NULL_TREE); }
! 	| asm_clobbers ',' string
! 		{ $$ = tree_cons (NULL_TREE, combine_strings ($3), $1); }
  	;
  
  /* This is what appears inside the parens in a function declarator.
--- 2461,2470 ----
  	;
  
  asm_clobbers:
! 	  STRING
! 		{ $$ = tree_cons (NULL_TREE, $1, NULL_TREE); }
! 	| asm_clobbers ',' STRING
! 		{ $$ = tree_cons (NULL_TREE, $3, $1); }
  	;
  
  /* This is what appears inside the parens in a function declarator.
*************** end ifobjc
*** 3691,3697 ****
  	       to string constants.  */
  	    const char *name = fname_string (rid_code);
  	  
! 	    yylval.ttype = build_string (strlen (name) + 1, name);
  	    last_token = CPP_STRING;  /* so yyerror won't choke */
  	    return STRING;
  	  }
--- 3655,3662 ----
  	       to string constants.  */
  	    const char *name = fname_string (rid_code);
  	  
! 	    yylval.ttype = c_build_string (name, strlen (name) + 1,
! 					   char_type_node);
  	    last_token = CPP_STRING;  /* so yyerror won't choke */
  	    return STRING;
  	  }
===================================================================
Index: c-typeck.c
*** c-typeck.c	2001/06/12 12:15:43	1.125
--- c-typeck.c	2001/06/21 05:24:21
*************** simple_asm_stmt (expr)
*** 6800,6808 ****
    if (TREE_CODE (expr) == STRING_CST)
      {
        tree stmt;
- 
-       if (TREE_CHAIN (expr))
- 	expr = combine_strings (expr);
        stmt = add_stmt (build_stmt (ASM_STMT, NULL_TREE, expr,
  				   NULL_TREE, NULL_TREE,
  				   NULL_TREE));
--- 6800,6805 ----
*************** build_asm_stmt (cv_qualifier, string, ou
*** 6827,6834 ****
  {
    tree tail;
  
-   if (TREE_CHAIN (string))
-     string = combine_strings (string);
    if (TREE_CODE (string) != STRING_CST)
      {
        error ("asm template is not a string constant");
--- 6824,6829 ----
===================================================================
Index: ch/ch-tree.h
*** ch/ch-tree.h	2001/05/26 01:31:35	1.24
--- ch/ch-tree.h	2001/06/21 05:24:21
*************** extern tree case_else_node;
*** 624,630 ****
  extern void gen_aux_info_record                 PARAMS ((tree, int, int, int));
  
  /* in c-common.c */
- extern tree combine_strings                     PARAMS ((tree));
  extern void constant_expression_warning         PARAMS ((tree));
  extern void decl_attributes                     PARAMS ((tree, tree));
  extern void declare_function_name               PARAMS ((void));
--- 624,629 ----
===================================================================
Index: cp/parse.y
*** cp/parse.y	2001/05/22 17:58:43	1.221
--- cp/parse.y	2001/06/21 05:24:22
*************** cp_parse_init ()
*** 263,269 ****
     yylval contains an IDENTIFIER_NODE which indicates which one.  */
  %token VAR_FUNC_NAME
  
! /* String constants in raw form.
     yylval is a STRING_CST node.  */
  %token STRING
  
--- 263,269 ----
     yylval contains an IDENTIFIER_NODE which indicates which one.  */
  %token VAR_FUNC_NAME
  
! /* String constants.
     yylval is a STRING_CST node.  */
  %token STRING
  
*************** cp_parse_init ()
*** 333,339 ****
  %type <ttype> PFUNCNAME maybe_identifier
  %type <ttype> paren_expr_or_null nontrivial_exprlist SELFNAME
  %type <ttype> expr_no_commas expr_no_comma_rangle
! %type <ttype> cast_expr unary_expr primary string STRING
  %type <ttype> reserved_declspecs boolean.literal
  %type <ttype> reserved_typespecquals
  %type <ttype> SCSPEC TYPESPEC CV_QUALIFIER maybe_cv_qualifier
--- 333,339 ----
  %type <ttype> PFUNCNAME maybe_identifier
  %type <ttype> paren_expr_or_null nontrivial_exprlist SELFNAME
  %type <ttype> expr_no_commas expr_no_comma_rangle
! %type <ttype> cast_expr unary_expr primary STRING
  %type <ttype> reserved_declspecs boolean.literal
  %type <ttype> reserved_typespecquals
  %type <ttype> SCSPEC TYPESPEC CV_QUALIFIER maybe_cv_qualifier
*************** extdef:
*** 501,509 ****
  		{ do_pending_inlines (); }
  	| template_def
  		{ do_pending_inlines (); }
! 	| asm_keyword '(' string ')' ';'
! 		{ if (TREE_CHAIN ($3)) $3 = combine_strings ($3);
! 		  assemble_asm ($3); }
  	| extern_lang_string '{' extdefs_opt '}'
  		{ pop_lang_context (); }
  	| extern_lang_string .hush_warning fndef .warning_ok eat_saved_input
--- 501,508 ----
  		{ do_pending_inlines (); }
  	| template_def
  		{ do_pending_inlines (); }
! 	| asm_keyword '(' STRING ')' ';'
! 		{ assemble_asm ($3); }
  	| extern_lang_string '{' extdefs_opt '}'
  		{ pop_lang_context (); }
  	| extern_lang_string .hush_warning fndef .warning_ok eat_saved_input
*************** primary:
*** 1548,1557 ****
  		}		
  	| CONSTANT
  	| boolean.literal
! 	| string
  		{
! 		  $$ = combine_strings ($$);
! 		  /* combine_strings doesn't set up TYPE_MAIN_VARIANT of
  		     a const array the way we want, so fix it.  */
  		  if (flag_const_strings)
  		    TREE_TYPE ($$) = build_cplus_array_type
--- 1547,1555 ----
  		}		
  	| CONSTANT
  	| boolean.literal
! 	| STRING
  		{
! 		  /* c_build_string doesn't set up TYPE_MAIN_VARIANT of
  		     a const array the way we want, so fix it.  */
  		  if (flag_const_strings)
  		    TREE_TYPE ($$) = build_cplus_array_type
*************** boolean.literal:
*** 1752,1764 ****
  		{ $$ = boolean_false_node; }
  	;
  
- /* Produces a STRING_CST with perhaps more STRING_CSTs chained onto it.  */
- string:
- 	  STRING
- 	| string STRING
- 		{ $$ = chainon ($$, $2); }
- 	;
- 
  nodecls:
  	  /* empty */
  		{
--- 1750,1755 ----
*************** nomods_initdecls:
*** 2042,2049 ****
  maybeasm:
  	  /* empty */
  		{ $$ = NULL_TREE; }
! 	| asm_keyword '(' string ')'
! 		{ if (TREE_CHAIN ($3)) $3 = combine_strings ($3); $$ = $3; }
  	;
  
  initdcl:
--- 2033,2040 ----
  maybeasm:
  	  /* empty */
  		{ $$ = NULL_TREE; }
! 	| asm_keyword '(' STRING ')'
! 		{ $$ = $3; }
  	;
  
  initdcl:
*************** simple_stmt:
*** 3439,3465 ****
                  { $$ = finish_return_stmt (NULL_TREE); }
  	| RETURN_KEYWORD expr ';'
                  { $$ = finish_return_stmt ($2); }
! 	| asm_keyword maybe_cv_qualifier '(' string ')' ';'
  		{ $$ = finish_asm_stmt ($2, $4, NULL_TREE, NULL_TREE,
  					NULL_TREE);
  		  ASM_INPUT_P ($$) = 1; }
  	/* This is the case with just output operands.  */
! 	| asm_keyword maybe_cv_qualifier '(' string ':' asm_operands ')' ';'
  		{ $$ = finish_asm_stmt ($2, $4, $6, NULL_TREE, NULL_TREE); }
  	/* This is the case with input operands as well.  */
! 	| asm_keyword maybe_cv_qualifier '(' string ':' asm_operands ':'
  	  asm_operands ')' ';'
  		{ $$ = finish_asm_stmt ($2, $4, $6, $8, NULL_TREE); }
! 	| asm_keyword maybe_cv_qualifier '(' string SCOPE asm_operands ')' ';'
  		{ $$ = finish_asm_stmt ($2, $4, NULL_TREE, $6, NULL_TREE); }
  	/* This is the case with clobbered registers as well.  */
! 	| asm_keyword maybe_cv_qualifier '(' string ':' asm_operands ':'
  	  asm_operands ':' asm_clobbers ')' ';'
  		{ $$ = finish_asm_stmt ($2, $4, $6, $8, $10); }
! 	| asm_keyword maybe_cv_qualifier '(' string SCOPE asm_operands ':'
  	  asm_clobbers ')' ';'
  		{ $$ = finish_asm_stmt ($2, $4, NULL_TREE, $6, $8); }
! 	| asm_keyword maybe_cv_qualifier '(' string ':' asm_operands SCOPE
  	  asm_clobbers ')' ';'
  		{ $$ = finish_asm_stmt ($2, $4, $6, NULL_TREE, $8); }
  	| GOTO '*' expr ';'
--- 3430,3456 ----
                  { $$ = finish_return_stmt (NULL_TREE); }
  	| RETURN_KEYWORD expr ';'
                  { $$ = finish_return_stmt ($2); }
! 	| asm_keyword maybe_cv_qualifier '(' STRING ')' ';'
  		{ $$ = finish_asm_stmt ($2, $4, NULL_TREE, NULL_TREE,
  					NULL_TREE);
  		  ASM_INPUT_P ($$) = 1; }
  	/* This is the case with just output operands.  */
! 	| asm_keyword maybe_cv_qualifier '(' STRING ':' asm_operands ')' ';'
  		{ $$ = finish_asm_stmt ($2, $4, $6, NULL_TREE, NULL_TREE); }
  	/* This is the case with input operands as well.  */
! 	| asm_keyword maybe_cv_qualifier '(' STRING ':' asm_operands ':'
  	  asm_operands ')' ';'
  		{ $$ = finish_asm_stmt ($2, $4, $6, $8, NULL_TREE); }
! 	| asm_keyword maybe_cv_qualifier '(' STRING SCOPE asm_operands ')' ';'
  		{ $$ = finish_asm_stmt ($2, $4, NULL_TREE, $6, NULL_TREE); }
  	/* This is the case with clobbered registers as well.  */
! 	| asm_keyword maybe_cv_qualifier '(' STRING ':' asm_operands ':'
  	  asm_operands ':' asm_clobbers ')' ';'
  		{ $$ = finish_asm_stmt ($2, $4, $6, $8, $10); }
! 	| asm_keyword maybe_cv_qualifier '(' STRING SCOPE asm_operands ':'
  	  asm_clobbers ')' ';'
  		{ $$ = finish_asm_stmt ($2, $4, NULL_TREE, $6, $8); }
! 	| asm_keyword maybe_cv_qualifier '(' STRING ':' asm_operands SCOPE
  	  asm_clobbers ')' ';'
  		{ $$ = finish_asm_stmt ($2, $4, $6, NULL_TREE, $8); }
  	| GOTO '*' expr ';'
*************** asm_operand:
*** 3612,3621 ****
  	;
  
  asm_clobbers:
! 	  string
! 		{ $$ = tree_cons (NULL_TREE, combine_strings ($1), NULL_TREE);}
! 	| asm_clobbers ',' string
! 		{ $$ = tree_cons (NULL_TREE, combine_strings ($3), $1); }
  	;
  
  /* This is what appears inside the parens in a function declarator.
--- 3603,3612 ----
  	;
  
  asm_clobbers:
! 	  STRING
! 		{ $$ = tree_cons (NULL_TREE, $1, NULL_TREE);}
! 	| asm_clobbers ',' STRING
! 		{ $$ = tree_cons (NULL_TREE, $3, $1); }
  	;
  
  /* This is what appears inside the parens in a function declarator.
===================================================================
Index: cp/rtti.c
*** cp/rtti.c	2001/05/22 19:41:55	1.115
--- cp/rtti.c	2001/06/21 05:24:22
*************** tinfo_name (type)
*** 296,302 ****
    tree name_string;
  
    name = mangle_type_string (type);
!   name_string = combine_strings (build_string (strlen (name) + 1, name));
    return name_string;
  }
  
--- 296,302 ----
    tree name_string;
  
    name = mangle_type_string (type);
!   name_string = c_build_string (name, strlen (name) + 1, char_type_node);
    return name_string;
  }
  
===================================================================
Index: cp/semantics.c
*** cp/semantics.c	2001/06/18 16:15:12	1.214
--- cp/semantics.c	2001/06/21 05:24:22
*************** finish_asm_stmt (cv_qualifier, string, o
*** 882,890 ****
    tree r;
    tree t;
  
-   if (TREE_CHAIN (string))
-     string = combine_strings (string);
- 
    if (cv_qualifier != NULL_TREE
        && cv_qualifier != ridpointers[(int) RID_VOLATILE])
      {
--- 882,887 ----
===================================================================
Index: objc/objc-act.c
*** objc/objc-act.c	2001/06/20 13:51:19	1.86
--- objc/objc-act.c	2001/06/21 05:24:23
*************** my_build_string (len, str)
*** 1430,1447 ****
    return a_string;
  }
  
! /* Given a chain of STRING_CST's, build a static instance of
!    NXConstantString which points at the concatenation of those strings.
!    We place the string object in the __string_objects section of the
!    __OBJC segment.  The Objective-C runtime will initialize the isa
!    pointers of the string objects to point at the NXConstantString
!    class object.  */
  
  tree
! build_objc_string_object (strings)
!      tree strings;
  {
!   tree string, initlist, constructor;
    int length;
  
    if (lookup_interface (constant_string_id) == NULL_TREE)
--- 1430,1446 ----
    return a_string;
  }
  
! /* Given a STRING_CST, build a static instance of NXConstantString
!    which points at it.  We place the string object in the
!    __string_objects section of the __OBJC segment.  The Objective-C
!    runtime will initialize the isa pointers of the string objects to
!    point at the NXConstantString class object.  */
  
  tree
! build_objc_string_object (string)
!      tree string;
  {
!   tree initlist, constructor;
    int length;
  
    if (lookup_interface (constant_string_id) == NULL_TREE)
*************** build_objc_string_object (strings)
*** 1453,1460 ****
  
    add_class_reference (constant_string_id);
  
-   string = combine_strings (strings);
-   TREE_SET_CODE (string, STRING_CST);
    length = TREE_STRING_LENGTH (string) - 1;
  
    /* & ((NXConstantString) {0, string, length})  */
--- 1452,1457 ----


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]