-/* Copy the tokens of the expansion. Change the type of macro
- arguments from CPP_NAME to CPP_MACRO_ARG. Remove #'s that
- represent stringification, flagging the CPP_MACRO_ARG it operates
- on STRINGIFY. Remove ##'s, flagging the token on its immediate
- left PASTE_LEFT. Returns non-zero on error. */
-static int
-save_expansion (pfile, list, first, first_param)
- cpp_reader *pfile;
- cpp_toklist *list;
- const cpp_token *first;
- const cpp_token *first_param;
-{
- const cpp_token *token;
- cpp_token *dest;
- unsigned int len, ntokens;
- unsigned char *buf;
-
- /* Count tokens in expansion. We drop paste tokens, and stringize
- tokens, so don't count them. */
- ntokens = len = 0;
- for (token = first; token->type != CPP_EOF; token++)
- {
- const char *msg;
-
- if (token->type == CPP_PASTE)
- {
- /* Token-paste ##, but is a normal token if traditional. */
- if (! CPP_TRADITIONAL (pfile))
- {
- msg = "\"##\" cannot appear at either end of a macro expansion";
- /* Constraint 6.10.3.3.1 */
- if (token == first || token[1].type == CPP_EOF)
- goto error;
- continue;
- }
- }
- else if (token->type == CPP_HASH)
- {
- /* Stringifying #, but is a normal character if traditional,
- or in object-like macros. Constraint 6.10.3.2.1. */
- if (list->paramc >= 0 && ! CPP_TRADITIONAL (pfile))
- {
- if (token[1].type == CPP_NAME
- && find_param (first_param, token + 1))
- continue;
- if (! CPP_OPTION (pfile, lang_asm))
- {
- msg = "'#' is not followed by a macro parameter";
- error:
- cpp_error_with_line (pfile, token->line, token->col, msg);
- return 1;
- }
- }
- }
- else if (token->type == CPP_NAME)
- {
- /* Constraint 6.10.3.5 */
- if (!(list->flags & VAR_ARGS) && is__va_args__ (pfile, token))
- return 1;
- }
- ntokens++;
- if (token_spellings[token->type].type == SPELL_STRING)
- len += token->val.str.len;
- }
-
- /* Allocate space to hold the tokens. Empty expansions are stored
- as a single placemarker token. */
- if (ntokens == 0)
- ntokens++;
- _cpp_expand_token_space (list, ntokens);
- if (len > 0)
- _cpp_expand_name_space (list, len);
-
- dest = list->tokens;
- buf = list->namebuf + list->name_used;
- for (token = first; token->type != CPP_EOF; token++)
- {
- unsigned int param_no;
-
- switch (token->type)
- {
- case CPP_NAME:
- if (list->paramc == -1)
- break;
-
- /* Check if the name is a macro parameter. */
- param_no = find_param (first_param, token);
- if (param_no == 0)
- break;
- dest->val.aux = param_no - 1;
-
- dest->type = CPP_MACRO_ARG;
- if (token[-1].type == CPP_HASH && ! CPP_TRADITIONAL (pfile))
- dest->flags = token[-1].flags | STRINGIFY_ARG;
- else
- dest->flags = token->flags; /* Particularly PREV_WHITE. */
- dest++;
- continue;
-
- case CPP_PASTE:
- if (! CPP_TRADITIONAL (pfile))
- {
- dest[-1].flags |= PASTE_LEFT;
- continue;
- }
- break;
-
- case CPP_HASH:
- /* Stringifying #. Constraint 6.10.3.2.1 */
- if (list->paramc >= 0 && ! CPP_TRADITIONAL (pfile)
- && token[1].type == CPP_NAME
- && find_param (first_param, token + 1))
- continue;
- break;
-
- default:
- break;
- }
-
- /* Copy the token. */
- *dest = *token;
- if (token_spellings[token->type].type == SPELL_STRING)
- {
- memcpy (buf, token->val.str.text, token->val.str.len);
- dest->val.str.text = buf;
- buf += dest->val.str.len;
- }
- dest++;
- }
-
- if (dest == list->tokens)
- {
- dest->type = CPP_PLACEMARKER;
- dest->flags = 0;
- }
-
- list->tokens_used = ntokens;
- list->line = pfile->token_list.line;
- list->file = pfile->token_list.file;
- list->name_used = len;
-
- return 0;
-}