diff options
author | Neil Booth <neil@daikokuya.demon.co.uk> | 2001-09-24 22:53:12 +0000 |
---|---|---|
committer | Neil Booth <neil@gcc.gnu.org> | 2001-09-24 22:53:12 +0000 |
commit | 4ed5bcfb1ed415c32bdd8735b2cd0ea0ed37e8b6 (patch) | |
tree | f2b5dd04bb961bbe8dac8d988d52d574f0cb2b47 /gcc/cppmacro.c | |
parent | ad43d46f3abe6f4d9b41f5b1d7b46a0c320efda8 (diff) | |
download | gcc-4ed5bcfb1ed415c32bdd8735b2cd0ea0ed37e8b6.zip gcc-4ed5bcfb1ed415c32bdd8735b2cd0ea0ed37e8b6.tar.gz gcc-4ed5bcfb1ed415c32bdd8735b2cd0ea0ed37e8b6.tar.bz2 |
c-lex.c (cb_def_pragma): Update.
* c-lex.c (cb_def_pragma): Update.
(c_lex): Update, and skip padding.
* cppexp.c (lex, parse_defined): Update, remove unused variable.
* cpphash.h (struct toklist): Delete.
(union utoken): New.
(struct cpp_context): Update.
(struct cpp_reader): New members eof, avoid_paste.
(_cpp_temp_token): New.
* cppinit.c (cpp_create_reader): Update.
* cpplex.c (_cpp_temp_token): New.
(_cpp_lex_direct): Add PREV_WHITE when parsing args.
(cpp_output_token): Don't print leading whitespace.
(cpp_output_line): Update.
* cpplib.c (glue_header_name, parse_include, get__Pragma_string,
do_include_common, do_line, do_ident, do_pragma,
do_pragma_dependency, _cpp_do__Pragma, parse_answer,
parse_assertion): Update.
(get_token_no_padding): New.
* cpplib.h (CPP_PADDING): New.
(AVOID_LPASTE): Delete.
(struct cpp_token): New union member source.
(cpp_get_token): Update.
* cppmacro.c (macro_arg): Convert to use pointers to const tokens.
(builtin_macro, paste_all_tokens, paste_tokens, funlike_invocation_p,
replace_args, quote_string, stringify_arg, parse_arg, next_context,
enter_macro_context, expand_arg, _cpp_pop_context, cpp_scan_nooutput,
_cpp_backup_tokens, _cpp_create_definition): Update.
(push_arg_context): Delete.
(padding_token, push_token_context, push_ptoken_context): New.
(make_string_token, make_number_token): Update, rename.
(cpp_get_token): Update to handle tokens as pointers to const,
and insert padding appropriately.
* cppmain.c (struct printer): New member prev.
(check_multiline_token): Constify.
(do_preprocessing, cb_line_change): Update.
(scan_translation_unit): Update to handle spacing.
* scan-decls.c (get_a_token): New.
(skip_to_closing_brace, scan_decls): Update.
* fix-header.c (read_scan_file): Update.
* doc/cpp.texi: Update.
* gcc.dg/cpp/macro10.c: New test.
* gcc.dg/cpp/strify3.c: New test.
* gcc.dg/cpp/spacing1.c: Add tests.
* gcc.dg/cpp/19990703-1.c: Remove bogus test.
* gcc.dg/cpp/20000625-2.c: Fudge to pass.
From-SVN: r45793
Diffstat (limited to 'gcc/cppmacro.c')
-rw-r--r-- | gcc/cppmacro.c | 723 |
1 files changed, 387 insertions, 336 deletions
diff --git a/gcc/cppmacro.c b/gcc/cppmacro.c index e526069..6cc4502 100644 --- a/gcc/cppmacro.c +++ b/gcc/cppmacro.c @@ -45,9 +45,9 @@ struct cpp_macro typedef struct macro_arg macro_arg; struct macro_arg { - cpp_token *first; /* First token in unexpanded argument. */ - cpp_token *expanded; /* Macro-expanded argument. */ - cpp_token *stringified; /* Stringified argument. */ + const cpp_token **first; /* First token in unexpanded argument. */ + const cpp_token **expanded; /* Macro-expanded argument. */ + const cpp_token *stringified; /* Stringified argument. */ unsigned int count; /* # of tokens in argument. */ unsigned int expanded_count; /* # of tokens in expanded argument. */ }; @@ -57,25 +57,29 @@ struct macro_arg static void lock_pools PARAMS ((cpp_reader *)); static void unlock_pools PARAMS ((cpp_reader *)); static int enter_macro_context PARAMS ((cpp_reader *, cpp_hashnode *)); -static void builtin_macro PARAMS ((cpp_reader *, cpp_token *)); -static cpp_context *push_arg_context PARAMS ((cpp_reader *, macro_arg *)); +static const cpp_token *builtin_macro PARAMS ((cpp_reader *, cpp_hashnode *)); +static void push_token_context + PARAMS ((cpp_reader *, cpp_macro *, const cpp_token *, unsigned int)); +static void push_ptoken_context + PARAMS ((cpp_reader *, cpp_macro *, const cpp_token **, unsigned int)); static enum cpp_ttype parse_arg PARAMS ((cpp_reader *, macro_arg *, int)); static macro_arg *parse_args PARAMS ((cpp_reader *, const cpp_hashnode *)); static cpp_context *next_context PARAMS ((cpp_reader *)); +static const cpp_token *padding_token + PARAMS ((cpp_reader *, const cpp_token *)); static void expand_arg PARAMS ((cpp_reader *, macro_arg *)); static unsigned char *quote_string PARAMS ((unsigned char *, const unsigned char *, unsigned int)); -static void make_string_token PARAMS ((cpp_pool *, cpp_token *, - const U_CHAR *, unsigned int)); -static void make_number_token PARAMS ((cpp_reader *, cpp_token *, int)); -static void stringify_arg PARAMS ((cpp_reader *, macro_arg *)); -static void paste_all_tokens PARAMS ((cpp_reader *, cpp_token *)); -static int paste_tokens PARAMS ((cpp_reader *, cpp_token *, cpp_token *)); -static int funlike_invocation_p PARAMS ((cpp_reader *, const cpp_hashnode *, - struct toklist *)); -static void replace_args PARAMS ((cpp_reader *, cpp_macro *, macro_arg *, - struct toklist *)); +static const cpp_token *new_string_token PARAMS ((cpp_reader *, U_CHAR *, + unsigned int)); +static const cpp_token *new_number_token PARAMS ((cpp_reader *, int)); +static const cpp_token *stringify_arg PARAMS ((cpp_reader *, macro_arg *)); +static void paste_all_tokens PARAMS ((cpp_reader *, const cpp_token *)); +static int paste_tokens PARAMS ((cpp_reader *, cpp_token *, + const cpp_token *)); +static int funlike_invocation_p PARAMS ((cpp_reader *, const cpp_hashnode *)); +static void replace_args PARAMS ((cpp_reader *, cpp_macro *, macro_arg *)); /* #define directive parsing and handling. */ @@ -89,32 +93,31 @@ static void check_trad_stringification PARAMS ((cpp_reader *, const cpp_macro *, const cpp_string *)); -/* Allocates a buffer to hold a token's TEXT, and converts TOKEN to a - CPP_STRING token containing TEXT in quoted form. */ -static void -make_string_token (pool, token, text, len) - cpp_pool *pool; - cpp_token *token; - const U_CHAR *text; +/* Allocates and returns a CPP_STRING token, containing TEXT of length + LEN, after null-terminating it. TEXT must be in permanent storage. */ +static const cpp_token * +new_string_token (pfile, text, len) + cpp_reader *pfile; + unsigned char *text; unsigned int len; { - U_CHAR *buf = _cpp_pool_alloc (pool, len * 4 + 1); + cpp_token *token = _cpp_temp_token (pfile); + text[len] = '\0'; token->type = CPP_STRING; - token->val.str.text = buf; - token->val.str.len = quote_string (buf, text, len) - buf; - buf[token->val.str.len] = '\0'; + token->val.str.len = len; + token->val.str.text = text; token->flags = 0; + return token; } -/* Allocates and converts a temporary token to a CPP_NUMBER token, - evaluating to NUMBER. */ -static void -make_number_token (pfile, token, number) +/* Allocates and returns a CPP_NUMBER token evaluating to NUMBER. */ +static const cpp_token * +new_number_token (pfile, number) cpp_reader *pfile; - cpp_token *token; int number; { + cpp_token *token = _cpp_temp_token (pfile); unsigned char *buf = _cpp_pool_alloc (&pfile->ident_pool, 20); sprintf ((char *) buf, "%d", number); @@ -122,6 +125,7 @@ make_number_token (pfile, token, number) token->val.str.text = buf; token->val.str.len = ustrlen (buf); token->flags = 0; + return token; } static const char * const monthnames[] = @@ -131,20 +135,23 @@ static const char * const monthnames[] = }; /* Handle builtin macros like __FILE__. */ -static void -builtin_macro (pfile, token) +static const cpp_token * +builtin_macro (pfile, node) cpp_reader *pfile; - cpp_token *token; + cpp_hashnode *node; { - unsigned char flags = ((token->flags & (PREV_WHITE | BOL)) | AVOID_LPASTE); - cpp_hashnode *node = token->val.node; - switch (node->value.builtin) { + default: + cpp_ice (pfile, "invalid builtin macro \"%s\"", NODE_NAME (node)); + return new_number_token (pfile, 1); + case BT_FILE: case BT_BASE_FILE: { + unsigned int len; const char *name; + U_CHAR *buf; const struct line_map *map = pfile->map; if (node->value.builtin == BT_BASE_FILE) @@ -152,64 +159,63 @@ builtin_macro (pfile, token) map = INCLUDED_FROM (&pfile->line_maps, map); name = map->to_file; - make_string_token (&pfile->ident_pool, token, - (const unsigned char *) name, strlen (name)); + len = strlen (name); + buf = _cpp_pool_alloc (&pfile->ident_pool, len * 4 + 1); + len = quote_string (buf, (const unsigned char *) name, len) - buf; + + return new_string_token (pfile, buf, len); } - break; case BT_INCLUDE_LEVEL: /* The line map depth counts the primary source as level 1, but historically __INCLUDE_DEPTH__ has called the primary source level 0. */ - make_number_token (pfile, token, pfile->line_maps.depth - 1); - break; + return new_number_token (pfile, pfile->line_maps.depth - 1); case BT_SPECLINE: /* If __LINE__ is embedded in a macro, it must expand to the line of the macro's invocation, not its definition. Otherwise things like assert() will not work properly. */ - make_number_token (pfile, token, - SOURCE_LINE (pfile->map, pfile->cur_token[-1].line)); - break; + return new_number_token (pfile, SOURCE_LINE (pfile->map, + pfile->cur_token[-1].line)); case BT_STDC: { int stdc = (!CPP_IN_SYSTEM_HEADER (pfile) || pfile->spec_nodes.n__STRICT_ANSI__->type != NT_VOID); - make_number_token (pfile, token, stdc); + return new_number_token (pfile, stdc); } - break; case BT_DATE: case BT_TIME: if (pfile->date.type == CPP_EOF) { - /* Allocate __DATE__ and __TIME__ from permanent storage, - and save them in pfile so we don't have to do this again. - We don't generate these strings at init time because - time() and localtime() are very slow on some systems. */ + /* Allocate __DATE__ and __TIME__ strings from permanent + storage. We only do this once, and don't generate them + at init time, because time() and localtime() are very + slow on some systems. */ time_t tt = time (NULL); struct tm *tb = localtime (&tt); - make_string_token (&pfile->ident_pool, &pfile->date, - DSC("Oct 11 1347")); - make_string_token (&pfile->ident_pool, &pfile->time, - DSC("12:34:56")); - + pfile->date.val.str.text = + _cpp_pool_alloc (&pfile->ident_pool, sizeof ("Oct 11 1347")); + pfile->date.val.str.len = sizeof ("Oct 11 1347") - 1; + pfile->date.type = CPP_STRING; + pfile->date.flags = 0; sprintf ((char *) pfile->date.val.str.text, "%s %2d %4d", monthnames[tb->tm_mon], tb->tm_mday, tb->tm_year + 1900); + + pfile->time.val.str.text = + _cpp_pool_alloc (&pfile->ident_pool, sizeof ("12:34:56")); + pfile->time.val.str.len = sizeof ("12:34:56") - 1; + pfile->time.type = CPP_STRING; + pfile->time.flags = 0; sprintf ((char *) pfile->time.val.str.text, "%02d:%02d:%02d", tb->tm_hour, tb->tm_min, tb->tm_sec); } - *token = node->value.builtin == BT_DATE ? pfile->date: pfile->time; - break; - default: - cpp_ice (pfile, "invalid builtin macro \"%s\"", NODE_NAME (node)); - break; + return node->value.builtin == BT_DATE ? &pfile->date: &pfile->time; } - - token->flags = flags; } static void @@ -260,7 +266,7 @@ quote_string (dest, src, len) /* Convert a token sequence to a single string token according to the rules of the ISO C #-operator. */ -static void +static const cpp_token * stringify_arg (pfile, arg) cpp_reader *pfile; macro_arg *arg; @@ -268,17 +274,26 @@ stringify_arg (pfile, arg) cpp_pool *pool = &pfile->ident_pool; unsigned char *start = POOL_FRONT (pool); unsigned int i, escape_it, total_len = 0, backslash_count = 0; + const cpp_token *source = NULL; /* Loop, reading in the argument's tokens. */ for (i = 0; i < arg->count; i++) { unsigned char *dest; - const cpp_token *token = &arg->first[i]; - unsigned int len = cpp_token_len (token); + const cpp_token *token = arg->first[i]; + unsigned int len; + + if (token->type == CPP_PADDING) + { + if (source == NULL) + source = token->val.source; + continue; + } escape_it = (token->type == CPP_STRING || token->type == CPP_WSTRING || token->type == CPP_CHAR || token->type == CPP_WCHAR); + len = cpp_token_len (token); if (escape_it) /* Worst case is each char is octal. */ len *= 4; @@ -291,9 +306,15 @@ stringify_arg (pfile, arg) dest = &start[total_len]; } - /* No leading white space. */ - if (token->flags & PREV_WHITE && total_len > 0) - *dest++ = ' '; + /* Leading white space? */ + if (total_len) + { + if (source == NULL) + source = token; + if (source->flags & PREV_WHITE) + *dest++ = ' '; + } + source = NULL; if (escape_it) { @@ -320,15 +341,9 @@ stringify_arg (pfile, arg) total_len--; } - /* Null terminate, and commit the memory. */ - start[total_len] = '\0'; + /* Commit the memory, including NUL, and return the token. */ POOL_COMMIT (pool, total_len + 1); - - arg->stringified = xnew (cpp_token); - arg->stringified->flags = 0; - arg->stringified->type = CPP_STRING; - arg->stringified->val.str.text = start; - arg->stringified->val.str.len = total_len; + return new_string_token (pfile, start, total_len); } /* Try to paste two tokens. On success, the LHS becomes the pasted @@ -337,9 +352,10 @@ stringify_arg (pfile, arg) static int paste_tokens (pfile, lhs, rhs) cpp_reader *pfile; - cpp_token *lhs, *rhs; + cpp_token *lhs; + const cpp_token *rhs; { - unsigned char flags; + unsigned char flags = 0; int digraph = 0; enum cpp_ttype type; @@ -353,20 +369,9 @@ paste_tokens (pfile, lhs, rhs) "pasting \"%s\" and \"%s\" does not give a valid preprocessing token", cpp_token_as_text (pfile, lhs), cpp_token_as_text (pfile, rhs)); - - /* The standard states that behaviour is undefined. By the - principle of least surpise, we step back before the RHS, and - mark it to prevent macro expansion. Tests in the testsuite - rely on clearing PREV_WHITE here, though you could argue we - should actually set it. Assembler can have '.' in labels and - so requires that we don't insert spaces there. Maybe we should - change this to put out a space unless it's assembler. */ - rhs->flags &= ~PREV_WHITE; - rhs->flags |= NO_EXPAND; return 1; } - flags = lhs->flags & ~DIGRAPH; if (digraph) flags |= DIGRAPH; @@ -416,10 +421,17 @@ paste_tokens (pfile, lhs, rhs) static void paste_all_tokens (pfile, lhs) cpp_reader *pfile; - cpp_token *lhs; + const cpp_token *lhs; { - cpp_token *rhs; - unsigned char orig_flags = lhs->flags; + cpp_token *pasted; + const cpp_token *rhs; + cpp_context *context = pfile->context; + + /* Copy lhs to pasted, but preserve original line and column. */ + pasted = _cpp_temp_token (pfile); + pasted->type = lhs->type; + pasted->flags = lhs->flags; + pasted->val.str = lhs->val.str; do { @@ -428,20 +440,25 @@ paste_all_tokens (pfile, lhs) object-like macro, or a function-like macro with arguments inserted. In either case, the constraints to #define guarantee we have at least one more token. */ - rhs = pfile->context->list.first++; - if (paste_tokens (pfile, lhs, rhs)) + if (context->direct_p) + rhs = context->first.token++; + else + rhs = *context->first.ptoken++; + + if (rhs->type == CPP_PADDING) + abort (); + + if (paste_tokens (pfile, pasted, rhs)) { - /* We failed. Step back so we read the RHS in next. */ - pfile->context->list.first--; + _cpp_backup_tokens (pfile, 1); break; } } while (rhs->flags & PASTE_LEFT); - /* The pasted token has the PREV_WHITE flag of the LHS, is no longer - PASTE_LEFT, and is subject to macro expansion. */ - lhs->flags &= ~(PREV_WHITE | BOL | PASTE_LEFT | NO_EXPAND); - lhs->flags |= orig_flags & (PREV_WHITE | BOL | AVOID_LPASTE); + /* Clear PASTE_LEFT flag, put the token in its own context. */ + pasted->flags &= ~PASTE_LEFT; + push_token_context (pfile, NULL, pasted, 1); } /* Reads the unexpanded tokens of a macro argument into ARG. VAR_ARGS @@ -455,26 +472,24 @@ parse_arg (pfile, arg, variadic) { enum cpp_ttype result; unsigned int paren = 0; - unsigned int line; - arg->first = (cpp_token *) POOL_FRONT (&pfile->argument_pool); + arg->first = (const cpp_token **) POOL_FRONT (&pfile->argument_pool); for (;; arg->count++) { - cpp_token *token = &arg->first[arg->count]; - if ((unsigned char *) (token + 1) >= POOL_LIMIT (&pfile->argument_pool)) + const cpp_token *token; + const cpp_token **ptoken = &arg->first[arg->count]; + if ((unsigned char *) (ptoken + 2) >= POOL_LIMIT (&pfile->argument_pool)) { - _cpp_next_chunk (&pfile->argument_pool, sizeof (cpp_token), + _cpp_next_chunk (&pfile->argument_pool, 2 * sizeof (cpp_token *), (unsigned char **) &arg->first); - token = &arg->first[arg->count]; + ptoken = &arg->first[arg->count]; } - /* Newlines in arguments are white space (6.10.3.10). */ - line = pfile->line; - cpp_get_token (pfile, token); - - if (line != pfile->line) - token->flags |= PREV_WHITE; - + /* Drop leading padding. */ + do + token = cpp_get_token (pfile); + while (arg->count == 0 && token->type == CPP_PADDING); + *ptoken++ = token; result = token->type; if (result == CPP_OPEN_PAREN) @@ -511,12 +526,15 @@ parse_arg (pfile, arg, variadic) } } + /* Drop trailing padding. */ + while (arg->count > 0 && arg->first[arg->count - 1]->type == CPP_PADDING) + arg->count--; + /* Commit the memory used to store the arguments. We make the last argument a CPP_EOF, so that it terminates macro pre-expansion, but it is not included in arg->count. */ - arg->first[arg->count].type = CPP_EOF; - POOL_COMMIT (&pfile->argument_pool, (arg->count + 1) * sizeof (cpp_token)); - + arg->first[arg->count] = &pfile->eof; + POOL_COMMIT (&pfile->argument_pool, (arg->count + 1) * sizeof (cpp_token *)); return result; } @@ -599,22 +617,23 @@ parse_args (pfile, node) } static int -funlike_invocation_p (pfile, node, list) +funlike_invocation_p (pfile, node) cpp_reader *pfile; const cpp_hashnode *node; - struct toklist *list; { - cpp_token maybe_paren; + const cpp_token *maybe_paren; macro_arg *args = 0; - pfile->state.parsing_args = 1; pfile->state.prevent_expansion++; - pfile->keep_tokens++; - cpp_get_token (pfile, &maybe_paren); + + pfile->state.parsing_args = 1; + do + maybe_paren = cpp_get_token (pfile); + while (maybe_paren->type == CPP_PADDING); pfile->state.parsing_args = 2; - if (maybe_paren.type == CPP_OPEN_PAREN) + if (maybe_paren->type == CPP_OPEN_PAREN) args = parse_args (pfile, node); else { @@ -625,14 +644,14 @@ funlike_invocation_p (pfile, node, list) NODE_NAME (node)); } - pfile->state.prevent_expansion--; pfile->state.parsing_args = 0; pfile->keep_tokens--; + pfile->state.prevent_expansion--; if (args) { if (node->value.macro->paramc > 0) - replace_args (pfile, node->value.macro, args, list); + replace_args (pfile, node->value.macro, args); free (args); } @@ -648,80 +667,60 @@ enter_macro_context (pfile, node) cpp_reader *pfile; cpp_hashnode *node; { - cpp_context *context; - cpp_macro *macro = node->value.macro; - struct toklist list; - - /* Save the position of the outermost macro invocation. */ - if (!pfile->context->prev) - lock_pools (pfile); - - if (macro->fun_like && !funlike_invocation_p (pfile, node, &list)) - { - if (!pfile->context->prev) - unlock_pools (pfile); - return 0; - } - - if (macro->paramc == 0) + if (node->flags & NODE_BUILTIN) + push_token_context (pfile, NULL, builtin_macro (pfile, node), 1); + else { - list.first = macro->expansion; - list.limit = macro->expansion + macro->count; - } + cpp_macro *macro = node->value.macro; - context = next_context (pfile); - context->list = list; - context->macro = macro; - - /* Disable the macro within its expansion. */ - macro->disabled = 1; + if (!pfile->context->prev) + lock_pools (pfile); - return 1; -} + if (macro->fun_like && !funlike_invocation_p (pfile, node)) + { + if (!pfile->context->prev) + unlock_pools (pfile); + return 0; + } -/* Move to the next context. Create one if there is none. */ -static cpp_context * -next_context (pfile) - cpp_reader *pfile; -{ - cpp_context *prev = pfile->context; - cpp_context *result = prev->next; + /* Disable the macro within its expansion. */ + macro->disabled = 1; - if (result == 0) - { - result = xnew (cpp_context); - prev->next = result; - result->prev = prev; - result->next = 0; + if (macro->paramc == 0) + push_token_context (pfile, macro, macro->expansion, macro->count); } - - pfile->context = result; - return result; + + return 1; } +/* Take the expansion of a function-like MACRO, replacing parameters + with the actual arguments. Each instance is first macro-expanded, + unless that paramter is operated upon by the # or ## operators. */ static void -replace_args (pfile, macro, args, list) +replace_args (pfile, macro, args) cpp_reader *pfile; cpp_macro *macro; macro_arg *args; - struct toklist *list; { - unsigned char flags = 0; unsigned int i, total; const cpp_token *src, *limit; - cpp_token *dest; + const cpp_token **dest, **first; macro_arg *arg; - src = macro->expansion; - limit = src + macro->count; - /* First, fully macro-expand arguments, calculating the number of tokens in the final expansion as we go. This ensures that the - possible recursive use of argument_pool is fine. */ - total = limit - src; - for (; src < limit; src++) + possible recursive use of argument_pool is fine. The ordering of + the if statements below is subtle; we must handle stringification + before pasting. */ + total = macro->count; + limit = macro->expansion + macro->count; + + for (src = macro->expansion; src < limit; src++) if (src->type == CPP_MACRO_ARG) { + /* Leading and trailing padding tokens. */ + total += 2; + /* We have an argument. If it is not being stringified or pasted it is macro-replaced before insertion. */ arg = &args[src->val.arg_no - 1]; @@ -729,7 +728,7 @@ replace_args (pfile, macro, args, list) if (src->flags & STRINGIFY_ARG) { if (!arg->stringified) - stringify_arg (pfile, arg); + arg->stringified = stringify_arg (pfile, arg); } else if ((src->flags & PASTE_LEFT) || (src > macro->expansion && (src[-1].flags & PASTE_LEFT))) @@ -737,113 +736,165 @@ replace_args (pfile, macro, args, list) else { if (!arg->expanded) - { - arg->expanded_count = 0; - if (arg->count) - expand_arg (pfile, arg); - } + expand_arg (pfile, arg); total += arg->expanded_count - 1; } } - dest = (cpp_token *) _cpp_pool_alloc (&pfile->argument_pool, - total * sizeof (cpp_token)); - list->first = dest; + /* Now allocate space for the expansion, copy the tokens and replace + the arguments. */ + first = (const cpp_token **) _cpp_pool_alloc (&pfile->argument_pool, + total * sizeof (cpp_token *)); + dest = first; for (src = macro->expansion; src < limit; src++) - if (src->type == CPP_MACRO_ARG) - { - unsigned int count; - const cpp_token *from; + { + unsigned int count; + const cpp_token **from, **paste_flag; - arg = &args[src->val.arg_no - 1]; - if (src->flags & STRINGIFY_ARG) - { - from = arg->stringified, count = 1; - /* Ugh. Maintain position of original argument. */ - arg->stringified->line = src->line; - arg->stringified->col = src->col; - } - else if (src->flags & PASTE_LEFT) - count = arg->count, from = arg->first; - else if (src > macro->expansion && (src[-1].flags & PASTE_LEFT)) - { - count = arg->count, from = arg->first; - if (dest != list->first) - { - /* GCC has special semantics for , ## b where b is a - varargs parameter: the comma disappears if b was - given no actual arguments (not merely if b is an - empty argument); otherwise pasting is turned off. */ - if (dest[-1].type == CPP_COMMA - && macro->variadic - && src->val.arg_no == macro->paramc) - { - if (count == 0) - dest--; - else - dest[-1].flags &= ~PASTE_LEFT; - } - /* Count == 0 is the RHS a placemarker case. */ - else if (count == 0) - dest[-1].flags &= ~PASTE_LEFT; - } - } - else - count = arg->expanded_count, from = arg->expanded; + if (src->type != CPP_MACRO_ARG) + { + *dest++ = src; + continue; + } - /* Count == 0 is the LHS a placemarker case. */ - if (count) - { - memcpy (dest, from, count * sizeof (cpp_token)); + paste_flag = 0; + arg = &args[src->val.arg_no - 1]; + if (src->flags & STRINGIFY_ARG) + count = 1, from = &arg->stringified; + else if (src->flags & PASTE_LEFT) + count = arg->count, from = arg->first; + else if (src != macro->expansion && (src[-1].flags & PASTE_LEFT)) + { + count = arg->count, from = arg->first; + if (dest != first) + { + /* GCC has special semantics for , ## b where b is a + varargs parameter: the comma disappears if b was + given no actual arguments (not merely if b is an + empty argument); otherwise the paste flag is removed. */ + if (dest[-1]->type == CPP_COMMA + && macro->variadic + && src->val.arg_no == macro->paramc) + { + if (count == 0) + dest--; + else + paste_flag = dest - 1; + } + /* Remove the paste flag if the RHS is a placemarker. */ + else if (count == 0) + paste_flag = dest - 1; + } + } + else + count = arg->expanded_count, from = arg->expanded; - /* The first token gets PREV_WHITE of the CPP_MACRO_ARG. */ - dest->flags &= ~(PREV_WHITE | BOL); - dest->flags |= src->flags & (PREV_WHITE | BOL); - dest->flags |= AVOID_LPASTE; + /* Padding on the left of an argument (unless RHS of ##). */ + if (!pfile->state.in_directive + && src != macro->expansion && !(src[-1].flags & PASTE_LEFT)) + *dest++ = padding_token (pfile, src); - /* The last token gets the PASTE_LEFT of the CPP_MACRO_ARG. */ - dest[count - 1].flags |= src->flags & PASTE_LEFT; + if (count) + { + memcpy (dest, from, count * sizeof (cpp_token *)); + dest += count; - dest += count; - } + /* With a non-empty argument on the LHS of ##, the last + token should be flagged PASTE_LEFT. */ + if (src->flags & PASTE_LEFT) + paste_flag = dest - 1; + } - /* The token after the argument must avoid an accidental paste. */ - flags = AVOID_LPASTE; - } - else - { - *dest = *src; - dest->flags |= flags; - dest++; - flags = 0; - } + /* Avoid paste on RHS (even case count == 0). */ + if (!pfile->state.in_directive && !(src->flags & PASTE_LEFT)) + *dest++ = &pfile->avoid_paste; - list->limit = dest; + /* Add a new paste flag, or remove an unwanted one. */ + if (paste_flag) + { + cpp_token *token = _cpp_temp_token (pfile); + token->type = (*paste_flag)->type; + token->val.str = (*paste_flag)->val.str; + if (src->flags & PASTE_LEFT) + token->flags = (*paste_flag)->flags | PASTE_LEFT; + else + token->flags = (*paste_flag)->flags & ~PASTE_LEFT; + *paste_flag = token; + } + } /* Free the expanded arguments. */ for (i = 0; i < macro->paramc; i++) + if (args[i].expanded) + free (args[i].expanded); + + push_ptoken_context (pfile, macro, first, dest - first); +} + +/* Return a special padding token, with padding inherited from SOURCE. */ +static const cpp_token * +padding_token (pfile, source) + cpp_reader *pfile; + const cpp_token *source; +{ + cpp_token *result = _cpp_temp_token (pfile); + + result->type = CPP_PADDING; + result->val.source = source; + result->flags = 0; + return result; +} + +/* Move to the next context. Create one if there is none. */ +static cpp_context * +next_context (pfile) + cpp_reader *pfile; +{ + cpp_context *result = pfile->context->next; + + if (result == 0) { - if (args[i].expanded) - free (args[i].expanded); - if (args[i].stringified) - free (args[i].stringified); + result = xnew (cpp_context); + result->prev = pfile->context; + result->next = 0; + pfile->context->next = result; } + + pfile->context = result; + return result; } -/* Subroutine of expand_arg to put the unexpanded tokens on the - context stack. */ -static cpp_context * -push_arg_context (pfile, arg) +/* Push a list of pointers to tokens. */ +static void +push_ptoken_context (pfile, macro, first, count) cpp_reader *pfile; - macro_arg *arg; + cpp_macro *macro; + const cpp_token **first; + unsigned int count; +{ + cpp_context *context = next_context (pfile); + + context->direct_p = false; + context->macro = macro; + context->first.ptoken = first; + context->last.ptoken = first + count; +} + +/* Push a list of tokens. */ +static void +push_token_context (pfile, macro, first, count) + cpp_reader *pfile; + cpp_macro *macro; + const cpp_token *first; + unsigned int count; { cpp_context *context = next_context (pfile); - context->macro = 0; - context->list.first = arg->first; - context->list.limit = arg->first + arg->count + 1; - return context; + context->direct_p = true; + context->macro = macro; + context->first.token = first; + context->last.token = first + count; } static void @@ -851,29 +902,39 @@ expand_arg (pfile, arg) cpp_reader *pfile; macro_arg *arg; { - cpp_token *token; - unsigned int capacity = 256; + unsigned int capacity; + + arg->expanded_count = 0; + if (arg->count == 0) + return; /* Loop, reading in the arguments. */ - arg->expanded = (cpp_token *) xmalloc (capacity * sizeof (cpp_token)); + capacity = 256; + arg->expanded = (const cpp_token **) + xmalloc (capacity * sizeof (cpp_token *)); - push_arg_context (pfile, arg); - do + push_ptoken_context (pfile, NULL, arg->first, arg->count + 1); + for (;;) { - if (arg->expanded_count >= capacity) + const cpp_token *token; + + if (arg->expanded_count + 1 >= capacity) { capacity *= 2; - arg->expanded = (cpp_token *) - xrealloc (arg->expanded, capacity * sizeof (cpp_token)); + arg->expanded = (const cpp_token **) + xrealloc (arg->expanded, capacity * sizeof (cpp_token *)); } - token = &arg->expanded[arg->expanded_count++]; - cpp_get_token (pfile, token); - } - while (token->type != CPP_EOF); - arg->expanded_count--; + token = cpp_get_token (pfile); + + if (token->type == CPP_EOF) + break; + + arg->expanded[arg->expanded_count++] = token; + } - /* Pop the context we pushed. */ + /* Avoid the unlock_pools test of _cpp_pop_context. Change this to + call _cpp_pop_context once we remove pool locking. */ pfile->context = pfile->context->prev; } @@ -881,14 +942,13 @@ void _cpp_pop_context (pfile) cpp_reader *pfile; { - cpp_context *context = pfile->context; + /* Re-enable a macro when leaving its expansion. */ + if (pfile->context->macro) + pfile->context->macro->disabled = 0; - pfile->context = context->prev; + pfile->context = pfile->context->prev; if (!pfile->context->prev && !pfile->state.parsing_args) unlock_pools (pfile); - - /* Re-enable a macro when leaving its expansion. */ - context->macro->disabled = 0; } /* Eternal routine to get a token. Also used nearly everywhere @@ -902,77 +962,75 @@ _cpp_pop_context (pfile) a directive inside a macro call, when at the end of a directive and state.in_directive is still 1, and at the end of argument pre-expansion. */ -void -cpp_get_token (pfile, token) +const cpp_token * +cpp_get_token (pfile) cpp_reader *pfile; - cpp_token *token; { + const cpp_token *result; + for (;;) { + cpp_hashnode *node; cpp_context *context = pfile->context; /* Context->prev == 0 <=> base context. */ if (!context->prev) - *token = *_cpp_lex_token (pfile); - else if (context->list.first != context->list.limit) + result = _cpp_lex_token (pfile); + else if (context->first.token != context->last.token) { - *token = *context->list.first++; - token->flags |= pfile->buffer->saved_flags; - pfile->buffer->saved_flags = 0; - /* PASTE_LEFT tokens can only appear in macro expansions. */ - if (token->flags & PASTE_LEFT) + if (context->direct_p) + result = context->first.token++; + else + result = *context->first.ptoken++; + + if (result->flags & PASTE_LEFT) { - /* Maintains position of original token. */ - paste_all_tokens (pfile, token); - pfile->buffer->saved_flags = AVOID_LPASTE; + paste_all_tokens (pfile, result); + if (pfile->state.in_directive) + continue; + return padding_token (pfile, result); } } else { - if (!context->macro) - cpp_ice (pfile, "context->macro == 0"); - - /* Avoid accidental paste at the end of a macro. */ - pfile->buffer->saved_flags |= AVOID_LPASTE; _cpp_pop_context (pfile); - continue; + if (pfile->state.in_directive) + continue; + return &pfile->avoid_paste; } - if (token->type != CPP_NAME) + if (result->type != CPP_NAME) break; + node = result->val.node; + /* Handle macros and the _Pragma operator. */ - if (token->val.node->type == NT_MACRO - && !pfile->state.prevent_expansion - && !(token->flags & NO_EXPAND)) + if (node->type == NT_MACRO && !(result->flags & NO_EXPAND)) { - cpp_hashnode *node = token->val.node; - /* Macros invalidate controlling macros. */ pfile->mi_valid = false; - if (node->flags & NODE_BUILTIN) + if (!(node->flags & NODE_BUILTIN) && node->value.macro->disabled) { - /* Maintains position of original token. */ - builtin_macro (pfile, token); - pfile->buffer->saved_flags = AVOID_LPASTE; - break; + /* Flag this token as always unexpandable. */ + cpp_token *t = _cpp_temp_token (pfile); + t->type = result->type; + t->flags = result->flags | NO_EXPAND; + t->val.str = result->val.str; + result = t; } - - if (node->value.macro->disabled) - token->flags |= NO_EXPAND; - else if (enter_macro_context (pfile, node)) + else if (!pfile->state.prevent_expansion + && enter_macro_context (pfile, node)) { - /* Pass AVOID_LPASTE and our PREV_WHITE to next token. */ - pfile->buffer->saved_flags = ((token->flags & (PREV_WHITE | BOL)) - | AVOID_LPASTE); - continue; + if (pfile->state.in_directive) + continue; + return padding_token (pfile, result); } } /* Don't interpret _Pragma within directives. The standard is not clear on this, but to me this makes most sense. */ - if (token->val.node != pfile->spec_nodes.n__Pragma + if (node != pfile->spec_nodes.n__Pragma || pfile->state.in_directive) break; @@ -980,6 +1038,8 @@ cpp_get_token (pfile, token) since this token came from either the lexer or a macro. */ _cpp_do__Pragma (pfile); } + + return result; } /* Returns true if we're expanding an object-like macro that was @@ -1000,11 +1060,8 @@ void cpp_scan_nooutput (pfile) cpp_reader *pfile; { - cpp_token token; - - do - cpp_get_token (pfile, &token); - while (token.type != CPP_EOF); + while (cpp_get_token (pfile)->type != CPP_EOF) + ; } /* Step back one (or more) tokens. Can only step mack more than 1 if @@ -1031,7 +1088,10 @@ _cpp_backup_tokens (pfile, count) { if (count != 1) abort (); - pfile->context->list.first--; + if (pfile->context->direct_p) + pfile->context->first.token--; + else + pfile->context->first.ptoken--; } } @@ -1330,8 +1390,6 @@ _cpp_create_definition (pfile, node) } token[-1].flags |= PASTE_LEFT; - /* Give it a PREV_WHITE for -dM etc. */ - token->flags |= PREV_WHITE; } token = lex_expansion_token (pfile, macro); @@ -1340,13 +1398,6 @@ _cpp_create_definition (pfile, node) /* Don't count the CPP_EOF. */ macro->count--; - /* Clear the whitespace flag from the leading token, but put a space - in front of a leading # which might be used to fake a directive. */ - if (macro->expansion[0].type == CPP_HASH) - macro->expansion[0].flags |= PREV_WHITE; - else - macro->expansion[0].flags &= ~PREV_WHITE; - /* Implement the macro-defined-to-itself optimisation. */ macro->disabled = (macro->count == 1 && !macro->fun_like && macro->expansion[0].type == CPP_NAME |