+ else /* Signed _Fract. */
+ {
+ if ((flags & CPP_N_WIDTH) == CPP_N_LARGE)
+ {
+ type = long_long_fract_type_node;
+ copylen -= 3;
+ }
+ else if ((flags & CPP_N_WIDTH) == CPP_N_MEDIUM)
+ {
+ type = long_fract_type_node;
+ copylen -= 2;
+ }
+ else if ((flags & CPP_N_WIDTH) == CPP_N_SMALL)
+ {
+ type = short_fract_type_node;
+ copylen -= 2;
+ }
+ else
+ {
+ type = fract_type_node;
+ copylen --;
+ }
+ }
+ }
+ else /* _Accum. */
+ {
+ if (flags & CPP_N_UNSIGNED) /* Unsigned _Accum. */
+ {
+ if ((flags & CPP_N_WIDTH) == CPP_N_LARGE)
+ {
+ type = unsigned_long_long_accum_type_node;
+ copylen -= 4;
+ }
+ else if ((flags & CPP_N_WIDTH) == CPP_N_MEDIUM)
+ {
+ type = unsigned_long_accum_type_node;
+ copylen -= 3;
+ }
+ else if ((flags & CPP_N_WIDTH) == CPP_N_SMALL)
+ {
+ type = unsigned_short_accum_type_node;
+ copylen -= 3;
+ }
+ else
+ {
+ type = unsigned_accum_type_node;
+ copylen -= 2;
+ }
+ }
+ else /* Signed _Accum. */
+ {
+ if ((flags & CPP_N_WIDTH) == CPP_N_LARGE)
+ {
+ type = long_long_accum_type_node;
+ copylen -= 3;
+ }
+ else if ((flags & CPP_N_WIDTH) == CPP_N_MEDIUM)
+ {
+ type = long_accum_type_node;
+ copylen -= 2;
+ }
+ else if ((flags & CPP_N_WIDTH) == CPP_N_SMALL)
+ {
+ type = short_accum_type_node;
+ copylen -= 2;
+ }
+ else
+ {
+ type = accum_type_node;
+ copylen --;
+ }
+ }
+ }
+
+ copy = (char *) alloca (copylen + 1);
+ memcpy (copy, token->val.str.text, copylen);
+ copy[copylen] = '\0';
+
+ fixed_from_string (&fixed, copy, TYPE_MODE (type));
+
+ /* Create a node with determined type and value. */
+ value = build_fixed (type, fixed);
+
+ return value;
+}
+
+/* Convert a series of STRING and/or WSTRING tokens into a tree,
+ performing string constant concatenation. TOK is the first of
+ these. VALP is the location to write the string into. OBJC_STRING
+ indicates whether an '@' token preceded the incoming token.
+ Returns the CPP token type of the result (CPP_STRING, CPP_WSTRING,
+ or CPP_OBJC_STRING).
+
+ This is unfortunately more work than it should be. If any of the
+ strings in the series has an L prefix, the result is a wide string
+ (6.4.5p4). Whether or not the result is a wide string affects the
+ meaning of octal and hexadecimal escapes (6.4.4.4p6,9). But escape
+ sequences do not continue across the boundary between two strings in
+ a series (6.4.5p7), so we must not lose the boundaries. Therefore
+ cpp_interpret_string takes a vector of cpp_string structures, which
+ we must arrange to provide. */
+
+static enum cpp_ttype
+lex_string (const cpp_token *tok, tree *valp, bool objc_string)
+{
+ tree value;
+ bool wide = false;
+ size_t concats = 0;
+ struct obstack str_ob;
+ cpp_string istr;
+
+ /* Try to avoid the overhead of creating and destroying an obstack
+ for the common case of just one string. */
+ cpp_string str = tok->val.str;
+ cpp_string *strs = &str;
+
+ if (tok->type == CPP_WSTRING)
+ wide = true;
+
+ retry:
+ tok = cpp_get_token (parse_in);
+ switch (tok->type)
+ {
+ case CPP_PADDING:
+ goto retry;
+ case CPP_ATSIGN:
+ if (c_dialect_objc ())
+ {
+ objc_string = true;
+ goto retry;
+ }
+ /* FALLTHROUGH */
+
+ default:
+ break;
+
+ case CPP_WSTRING:
+ wide = true;
+ /* FALLTHROUGH */
+
+ case CPP_STRING:
+ if (!concats)