diff options
author | obrien <obrien@FreeBSD.org> | 2002-02-01 18:16:02 +0000 |
---|---|---|
committer | obrien <obrien@FreeBSD.org> | 2002-02-01 18:16:02 +0000 |
commit | c9ab9ae440a8066b2c2b85b157b1fdadcf09916a (patch) | |
tree | 086d9d6c8fbd4fc8fe4495059332f66bc0f8d12b /contrib/gcc/cppmacro.c | |
parent | 2ecfd8bd04b63f335c1ec6295740a4bfd97a4fa6 (diff) | |
download | FreeBSD-src-c9ab9ae440a8066b2c2b85b157b1fdadcf09916a.zip FreeBSD-src-c9ab9ae440a8066b2c2b85b157b1fdadcf09916a.tar.gz |
Enlist the FreeBSD-CURRENT users as testers of what is to become Gcc 3.1.0.
These bits are taken from the FSF anoncvs repo on 1-Feb-2002 08:20 PST.
Diffstat (limited to 'contrib/gcc/cppmacro.c')
-rw-r--r-- | contrib/gcc/cppmacro.c | 1620 |
1 files changed, 1620 insertions, 0 deletions
diff --git a/contrib/gcc/cppmacro.c b/contrib/gcc/cppmacro.c new file mode 100644 index 0000000..538c689 --- /dev/null +++ b/contrib/gcc/cppmacro.c @@ -0,0 +1,1620 @@ +/* Part of CPP library. (Macro and #define handling.) + Copyright (C) 1986, 1987, 1989, 1992, 1993, 1994, 1995, 1996, 1998, + 1999, 2000, 2001, 2002 Free Software Foundation, Inc. + Written by Per Bothner, 1994. + Based on CCCP program by Paul Rubin, June 1986 + Adapted to ANSI C, Richard Stallman, Jan 1987 + +This program is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + In other words, you are welcome to use, share and improve this program. + You are forbidden to forbid anyone else to use, share and improve + what you give them. Help stamp out software-hoarding! */ + +#include "config.h" +#include "system.h" +#include "cpplib.h" +#include "cpphash.h" + +struct cpp_macro +{ + cpp_hashnode **params; /* Parameters, if any. */ + cpp_token *expansion; /* First token of replacement list. */ + unsigned int line; /* Starting line number. */ + unsigned int count; /* Number of tokens in expansion. */ + unsigned short paramc; /* Number of parameters. */ + unsigned int fun_like : 1; /* If a function-like macro. */ + unsigned int variadic : 1; /* If a variadic macro. */ + unsigned int syshdr : 1; /* If macro defined in system header. */ +}; + +typedef struct macro_arg macro_arg; +struct macro_arg +{ + 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. */ +}; + +/* Macro expansion. */ + +static int enter_macro_context PARAMS ((cpp_reader *, cpp_hashnode *)); +static int builtin_macro PARAMS ((cpp_reader *, cpp_hashnode *)); +static void push_token_context + PARAMS ((cpp_reader *, cpp_hashnode *, const cpp_token *, unsigned int)); +static void push_ptoken_context + PARAMS ((cpp_reader *, cpp_hashnode *, _cpp_buff *, + const cpp_token **, unsigned int)); +static _cpp_buff *collect_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 const cpp_token *new_string_token PARAMS ((cpp_reader *, U_CHAR *, + unsigned int)); +static const cpp_token *new_number_token PARAMS ((cpp_reader *, unsigned int)); +static const cpp_token *stringify_arg PARAMS ((cpp_reader *, macro_arg *)); +static void paste_all_tokens PARAMS ((cpp_reader *, const cpp_token *)); +static bool paste_tokens PARAMS ((cpp_reader *, const cpp_token **, + const cpp_token *)); +static void replace_args PARAMS ((cpp_reader *, cpp_hashnode *, macro_arg *)); +static _cpp_buff *funlike_invocation_p PARAMS ((cpp_reader *, cpp_hashnode *)); + +/* #define directive parsing and handling. */ + +static cpp_token *alloc_expansion_token PARAMS ((cpp_reader *, cpp_macro *)); +static cpp_token *lex_expansion_token PARAMS ((cpp_reader *, cpp_macro *)); +static int warn_of_redefinition PARAMS ((const cpp_hashnode *, + const cpp_macro *)); +static int save_parameter PARAMS ((cpp_reader *, cpp_macro *, cpp_hashnode *)); +static int parse_params PARAMS ((cpp_reader *, cpp_macro *)); +static void check_trad_stringification PARAMS ((cpp_reader *, + const cpp_macro *, + const cpp_string *)); + +/* 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; +{ + cpp_token *token = _cpp_temp_token (pfile); + + text[len] = '\0'; + token->type = CPP_STRING; + token->val.str.len = len; + token->val.str.text = text; + token->flags = 0; + return token; +} + +/* Allocates and returns a CPP_NUMBER token evaluating to NUMBER. */ +static const cpp_token * +new_number_token (pfile, number) + cpp_reader *pfile; + unsigned int number; +{ + cpp_token *token = _cpp_temp_token (pfile); + /* 21 bytes holds all NUL-terminated unsigned 64-bit numbers. */ + unsigned char *buf = _cpp_unaligned_alloc (pfile, 21); + + sprintf ((char *) buf, "%u", number); + token->type = CPP_NUMBER; + token->val.str.text = buf; + token->val.str.len = ustrlen (buf); + token->flags = 0; + return token; +} + +static const char * const monthnames[] = +{ + "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" +}; + +/* Handle builtin macros like __FILE__, and push the resulting token + on the context stack. Also handles _Pragma, for which no new token + is created. Returns 1 if it generates a new token context, 0 to + return the token to the caller. */ +static int +builtin_macro (pfile, node) + cpp_reader *pfile; + cpp_hashnode *node; +{ + const cpp_token *result; + + switch (node->value.builtin) + { + default: + cpp_ice (pfile, "invalid built-in macro \"%s\"", NODE_NAME (node)); + return 0; + + 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) + while (! MAIN_FILE_P (map)) + map = INCLUDED_FROM (&pfile->line_maps, map); + + name = map->to_file; + len = strlen (name); + buf = _cpp_unaligned_alloc (pfile, len * 4 + 1); + len = quote_string (buf, (const unsigned char *) name, len) - buf; + + result = 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. */ + result = new_number_token (pfile, pfile->line_maps.depth - 1); + break; + + 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. */ + result = new_number_token (pfile, + SOURCE_LINE (pfile->map, + pfile->cur_token[-1].line)); + break; + + case BT_STDC: + { + int stdc = (!CPP_IN_SYSTEM_HEADER (pfile) + || pfile->spec_nodes.n__STRICT_ANSI__->type != NT_VOID); + result = new_number_token (pfile, stdc); + } + break; + + case BT_DATE: + case BT_TIME: + if (pfile->date.type == CPP_EOF) + { + /* 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); + + pfile->date.val.str.text = + _cpp_unaligned_alloc (pfile, 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_unaligned_alloc (pfile, 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); + } + + if (node->value.builtin == BT_DATE) + result = &pfile->date; + else + result = &pfile->time; + break; + + case BT_PRAGMA: + /* Don't interpret _Pragma within directives. The standard is + not clear on this, but to me this makes most sense. */ + if (pfile->state.in_directive) + return 0; + + _cpp_do__Pragma (pfile); + return 1; + } + + push_token_context (pfile, NULL, result, 1); + return 1; +} + +/* Copies SRC, of length LEN, to DEST, adding backslashes before all + backslashes and double quotes. Non-printable characters are + converted to octal. DEST must be of sufficient size. */ +static U_CHAR * +quote_string (dest, src, len) + U_CHAR *dest; + const U_CHAR *src; + unsigned int len; +{ + while (len--) + { + U_CHAR c = *src++; + + if (c == '\\' || c == '"') + { + *dest++ = '\\'; + *dest++ = c; + } + else + { + if (ISPRINT (c)) + *dest++ = c; + else + { + sprintf ((char *) dest, "\\%03o", c); + dest += 4; + } + } + } + + return dest; +} + +/* Convert a token sequence ARG to a single string token according to + the rules of the ISO C #-operator. */ +static const cpp_token * +stringify_arg (pfile, arg) + cpp_reader *pfile; + macro_arg *arg; +{ + unsigned char *dest = BUFF_FRONT (pfile->u_buff); + unsigned int i, escape_it, backslash_count = 0; + const cpp_token *source = NULL; + size_t len; + + /* Loop, reading in the argument's tokens. */ + for (i = 0; i < arg->count; i++) + { + const cpp_token *token = arg->first[i]; + + 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); + + /* Room for each char being written in octal, initial space and + final NUL. */ + len = cpp_token_len (token); + if (escape_it) + len *= 4; + len += 2; + + if ((size_t) (BUFF_LIMIT (pfile->u_buff) - dest) < len) + { + size_t len_so_far = dest - BUFF_FRONT (pfile->u_buff); + _cpp_extend_buff (pfile, &pfile->u_buff, len); + dest = BUFF_FRONT (pfile->u_buff) + len_so_far; + } + + /* Leading white space? */ + if (dest != BUFF_FRONT (pfile->u_buff)) + { + if (source == NULL) + source = token; + if (source->flags & PREV_WHITE) + *dest++ = ' '; + } + source = NULL; + + if (escape_it) + { + _cpp_buff *buff = _cpp_get_buff (pfile, len); + unsigned char *buf = BUFF_FRONT (buff); + len = cpp_spell_token (pfile, token, buf) - buf; + dest = quote_string (dest, buf, len); + _cpp_release_buff (pfile, buff); + } + else + dest = cpp_spell_token (pfile, token, dest); + + if (token->type == CPP_OTHER && token->val.c == '\\') + backslash_count++; + else + backslash_count = 0; + } + + /* Ignore the final \ of invalid string literals. */ + if (backslash_count & 1) + { + cpp_warning (pfile, "invalid string literal, ignoring final '\\'"); + dest--; + } + + /* Commit the memory, including NUL, and return the token. */ + len = dest - BUFF_FRONT (pfile->u_buff); + BUFF_FRONT (pfile->u_buff) = dest + 1; + return new_string_token (pfile, dest - len, len); +} + +/* Try to paste two tokens. On success, return non-zero. In any + case, PLHS is updated to point to the pasted token, which is + guaranteed to not have the PASTE_LEFT flag set. */ +static bool +paste_tokens (pfile, plhs, rhs) + cpp_reader *pfile; + const cpp_token **plhs, *rhs; +{ + unsigned char *buf, *end; + const cpp_token *lhs; + unsigned int len; + bool valid; + + lhs = *plhs; + len = cpp_token_len (lhs) + cpp_token_len (rhs) + 1; + buf = (unsigned char *) alloca (len); + end = cpp_spell_token (pfile, lhs, buf); + + /* Avoid comment headers, since they are still processed in stage 3. + It is simpler to insert a space here, rather than modifying the + lexer to ignore comments in some circumstances. Simply returning + false doesn't work, since we want to clear the PASTE_LEFT flag. */ + if (lhs->type == CPP_DIV + && (rhs->type == CPP_MULT || rhs->type == CPP_DIV)) + *end++ = ' '; + end = cpp_spell_token (pfile, rhs, end); + *end = '\0'; + + cpp_push_buffer (pfile, buf, end - buf, /* from_stage3 */ true, 1); + + /* Tweak the column number the lexer will report. */ + pfile->buffer->col_adjust = pfile->cur_token[-1].col - 1; + + /* We don't want a leading # to be interpreted as a directive. */ + pfile->buffer->saved_flags = 0; + + /* Set pfile->cur_token as required by _cpp_lex_direct. */ + pfile->cur_token = _cpp_temp_token (pfile); + *plhs = _cpp_lex_direct (pfile); + valid = pfile->buffer->cur == pfile->buffer->rlimit; + _cpp_pop_buffer (pfile); + + return valid; +} + +/* Handles an arbitrarily long sequence of ## operators, with initial + operand LHS. This implementation is left-associative, + non-recursive, and finishes a paste before handling succeeding + ones. If a paste fails, we back up to the RHS of the failing ## + operator before pushing the context containing the result of prior + successful pastes, with the effect that the RHS appears in the + output stream after the pasted LHS normally. */ +static void +paste_all_tokens (pfile, lhs) + cpp_reader *pfile; + const cpp_token *lhs; +{ + const cpp_token *rhs; + cpp_context *context = pfile->context; + + do + { + /* Take the token directly from the current context. We can do + this, because we are in the replacement list of either an + 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. */ + if (context->direct_p) + rhs = context->first.token++; + else + rhs = *context->first.ptoken++; + + if (rhs->type == CPP_PADDING) + abort (); + + if (!paste_tokens (pfile, &lhs, rhs)) + { + _cpp_backup_tokens (pfile, 1); + + /* Mandatory warning for all apart from assembler. */ + if (CPP_OPTION (pfile, lang) != CLK_ASM) + cpp_warning (pfile, + "pasting \"%s\" and \"%s\" does not give a valid preprocessing token", + cpp_token_as_text (pfile, lhs), + cpp_token_as_text (pfile, rhs)); + break; + } + } + while (rhs->flags & PASTE_LEFT); + + /* Put the resulting token in its own context. */ + push_token_context (pfile, NULL, lhs, 1); +} + +/* Reads and returns the arguments to a function-like macro + invocation. Assumes the opening parenthesis has been processed. + If there is an error, emits an appropriate diagnostic and returns + NULL. Each argument is terminated by a CPP_EOF token, for the + future benefit of expand_arg(). */ +static _cpp_buff * +collect_args (pfile, node) + cpp_reader *pfile; + const cpp_hashnode *node; +{ + _cpp_buff *buff, *base_buff; + cpp_macro *macro; + macro_arg *args, *arg; + const cpp_token *token; + unsigned int argc; + bool error = false; + + macro = node->value.macro; + if (macro->paramc) + argc = macro->paramc; + else + argc = 1; + buff = _cpp_get_buff (pfile, argc * (50 * sizeof (cpp_token *) + + sizeof (macro_arg))); + base_buff = buff; + args = (macro_arg *) buff->base; + memset (args, 0, argc * sizeof (macro_arg)); + buff->cur = (unsigned char *) &args[argc]; + arg = args, argc = 0; + + /* Collect the tokens making up each argument. We don't yet know + how many arguments have been supplied, whether too many or too + few. Hence the slightly bizarre usage of "argc" and "arg". */ + do + { + unsigned int paren_depth = 0; + unsigned int ntokens = 0; + + argc++; + arg->first = (const cpp_token **) buff->cur; + + for (;;) + { + /* Require space for 2 new tokens (including a CPP_EOF). */ + if ((unsigned char *) &arg->first[ntokens + 2] > buff->limit) + { + buff = _cpp_append_extend_buff (pfile, buff, + 1000 * sizeof (cpp_token *)); + arg->first = (const cpp_token **) buff->cur; + } + + token = cpp_get_token (pfile); + + if (token->type == CPP_PADDING) + { + /* Drop leading padding. */ + if (ntokens == 0) + continue; + } + else if (token->type == CPP_OPEN_PAREN) + paren_depth++; + else if (token->type == CPP_CLOSE_PAREN) + { + if (paren_depth-- == 0) + break; + } + else if (token->type == CPP_COMMA) + { + /* A comma does not terminate an argument within + parentheses or as part of a variable argument. */ + if (paren_depth == 0 + && ! (macro->variadic && argc == macro->paramc)) + break; + } + else if (token->type == CPP_EOF + || (token->type == CPP_HASH && token->flags & BOL)) + break; + + arg->first[ntokens++] = token; + } + + /* Drop trailing padding. */ + while (ntokens > 0 && arg->first[ntokens - 1]->type == CPP_PADDING) + ntokens--; + + arg->count = ntokens; + arg->first[ntokens] = &pfile->eof; + + /* Terminate the argument. Excess arguments loop back and + overwrite the final legitimate argument, before failing. */ + if (argc <= macro->paramc) + { + buff->cur = (unsigned char *) &arg->first[ntokens + 1]; + if (argc != macro->paramc) + arg++; + } + } + while (token->type != CPP_CLOSE_PAREN + && token->type != CPP_EOF + && token->type != CPP_HASH); + + if (token->type == CPP_EOF || token->type == CPP_HASH) + { + bool step_back = false; + + /* 6.10.3 paragraph 11: If there are sequences of preprocessing + tokens within the list of arguments that would otherwise act + as preprocessing directives, the behavior is undefined. + + This implementation will report a hard error, terminate the + macro invocation, and proceed to process the directive. */ + if (token->type == CPP_HASH) + { + cpp_error (pfile, + "directives may not be used inside a macro argument"); + step_back = true; + } + else + step_back = (pfile->context->prev || pfile->state.in_directive); + + /* We still need the CPP_EOF to end directives, and to end + pre-expansion of a macro argument. Step back is not + unconditional, since we don't want to return a CPP_EOF to our + callers at the end of an -include-d file. */ + if (step_back) + _cpp_backup_tokens (pfile, 1); + cpp_error (pfile, "unterminated argument list invoking macro \"%s\"", + NODE_NAME (node)); + error = true; + } + else if (argc < macro->paramc) + { + /* As an extension, a rest argument is allowed to not appear in + the invocation at all. + e.g. #define debug(format, args...) something + debug("string"); + + This is exactly the same as if there had been an empty rest + argument - debug("string", ). */ + + if (argc + 1 == macro->paramc && macro->variadic) + { + if (CPP_PEDANTIC (pfile) && ! macro->syshdr) + cpp_pedwarn (pfile, "ISO C99 requires rest arguments to be used"); + } + else + { + cpp_error (pfile, + "macro \"%s\" requires %u arguments, but only %u given", + NODE_NAME (node), macro->paramc, argc); + error = true; + } + } + else if (argc > macro->paramc) + { + /* Empty argument to a macro taking no arguments is OK. */ + if (argc != 1 || arg->count) + { + cpp_error (pfile, + "macro \"%s\" passed %u arguments, but takes just %u", + NODE_NAME (node), argc, macro->paramc); + error = true; + } + } + + if (!error) + return base_buff; + + _cpp_release_buff (pfile, base_buff); + return NULL; +} + +/* Search for an opening parenthesis to the macro of NODE, in such a + way that, if none is found, we don't lose the information in any + intervening padding tokens. If we find the parenthesis, collect + the arguments and return the buffer containing them. */ +static _cpp_buff * +funlike_invocation_p (pfile, node) + cpp_reader *pfile; + cpp_hashnode *node; +{ + const cpp_token *token, *padding = NULL; + + for (;;) + { + token = cpp_get_token (pfile); + if (token->type != CPP_PADDING) + break; + if (padding == NULL + || (!(padding->flags & PREV_WHITE) && token->val.source == NULL)) + padding = token; + } + + if (token->type == CPP_OPEN_PAREN) + { + pfile->state.parsing_args = 2; + return collect_args (pfile, node); + } + + /* Back up. We may have skipped padding, in which case backing up + more than one token when expanding macros is in general too + difficult. We re-insert it in its own context. */ + _cpp_backup_tokens (pfile, 1); + if (padding) + push_token_context (pfile, NULL, padding, 1); + + return NULL; +} + +/* Push the context of a macro with hash entry NODE onto the context + stack. If we can successfully expand the macro, we push a context + containing its yet-to-be-rescanned replacement list and return one. + Otherwise, we don't push a context and return zero. */ +static int +enter_macro_context (pfile, node) + cpp_reader *pfile; + cpp_hashnode *node; +{ + /* The presence of a macro invalidates a file's controlling macro. */ + pfile->mi_valid = false; + + /* Handle standard macros. */ + if (! (node->flags & NODE_BUILTIN)) + { + cpp_macro *macro = node->value.macro; + + if (macro->fun_like) + { + _cpp_buff *buff; + + pfile->state.prevent_expansion++; + pfile->keep_tokens++; + pfile->state.parsing_args = 1; + buff = funlike_invocation_p (pfile, node); + pfile->state.parsing_args = 0; + pfile->keep_tokens--; + pfile->state.prevent_expansion--; + + if (buff == NULL) + { + if (CPP_WTRADITIONAL (pfile) && ! node->value.macro->syshdr) + cpp_warning (pfile, + "function-like macro \"%s\" must be used with arguments in traditional C", + NODE_NAME (node)); + + return 0; + } + + if (node->value.macro->paramc > 0) + replace_args (pfile, node, (macro_arg *) buff->base); + _cpp_release_buff (pfile, buff); + } + + /* Disable the macro within its expansion. */ + node->flags |= NODE_DISABLED; + + if (macro->paramc == 0) + push_token_context (pfile, node, macro->expansion, macro->count); + + return 1; + } + + /* Handle built-in macros and the _Pragma operator. */ + return builtin_macro (pfile, node); +} + +/* Replace the parameters in a function-like macro of NODE with the + actual ARGS, and place the result in a newly pushed token context. + Expand each argument before replacing, unless it is operated upon + by the # or ## operators. */ +static void +replace_args (pfile, node, args) + cpp_reader *pfile; + cpp_hashnode *node; + macro_arg *args; +{ + unsigned int i, total; + const cpp_token *src, *limit; + const cpp_token **dest, **first; + macro_arg *arg; + _cpp_buff *buff; + cpp_macro *macro; + + /* First, fully macro-expand arguments, calculating the number of + tokens in the final expansion as we go. The ordering of the if + statements below is subtle; we must handle stringification before + pasting. */ + macro = node->value.macro; + 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]; + + if (src->flags & STRINGIFY_ARG) + { + if (!arg->stringified) + arg->stringified = stringify_arg (pfile, arg); + } + else if ((src->flags & PASTE_LEFT) + || (src > macro->expansion && (src[-1].flags & PASTE_LEFT))) + total += arg->count - 1; + else + { + if (!arg->expanded) + expand_arg (pfile, arg); + total += arg->expanded_count - 1; + } + } + + /* Now allocate space for the expansion, copy the tokens and replace + the arguments. */ + buff = _cpp_get_buff (pfile, total * sizeof (cpp_token *)); + first = (const cpp_token **) buff->base; + dest = first; + + for (src = macro->expansion; src < limit; src++) + { + unsigned int count; + const cpp_token **from, **paste_flag; + + if (src->type != CPP_MACRO_ARG) + { + *dest++ = src; + continue; + } + + 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; + + /* 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); + + if (count) + { + memcpy (dest, from, count * sizeof (cpp_token *)); + 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; + } + + /* Avoid paste on RHS (even case count == 0). */ + if (!pfile->state.in_directive && !(src->flags & PASTE_LEFT)) + *dest++ = &pfile->avoid_paste; + + /* 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, node, buff, 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; +} + +/* Get a new uninitialized context. Create a new one if we cannot + re-use an old one. */ +static cpp_context * +next_context (pfile) + cpp_reader *pfile; +{ + cpp_context *result = pfile->context->next; + + if (result == 0) + { + result = xnew (cpp_context); + result->prev = pfile->context; + result->next = 0; + pfile->context->next = result; + } + + pfile->context = result; + return result; +} + +/* Push a list of pointers to tokens. */ +static void +push_ptoken_context (pfile, macro, buff, first, count) + cpp_reader *pfile; + cpp_hashnode *macro; + _cpp_buff *buff; + const cpp_token **first; + unsigned int count; +{ + cpp_context *context = next_context (pfile); + + context->direct_p = false; + context->macro = macro; + context->buff = buff; + 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_hashnode *macro; + const cpp_token *first; + unsigned int count; +{ + cpp_context *context = next_context (pfile); + + context->direct_p = true; + context->macro = macro; + context->buff = NULL; + context->first.token = first; + context->last.token = first + count; +} + +/* Expand an argument ARG before replacing parameters in a + function-like macro. This works by pushing a context with the + argument's tokens, and then expanding that into a temporary buffer + as if it were a normal part of the token stream. collect_args() + has terminated the argument's tokens with a CPP_EOF so that we know + when we have fully expanded the argument. */ +static void +expand_arg (pfile, arg) + cpp_reader *pfile; + macro_arg *arg; +{ + unsigned int capacity; + + if (arg->count == 0) + return; + + /* Loop, reading in the arguments. */ + capacity = 256; + arg->expanded = (const cpp_token **) + xmalloc (capacity * sizeof (cpp_token *)); + + push_ptoken_context (pfile, NULL, NULL, arg->first, arg->count + 1); + for (;;) + { + const cpp_token *token; + + if (arg->expanded_count + 1 >= capacity) + { + capacity *= 2; + arg->expanded = (const cpp_token **) + xrealloc (arg->expanded, capacity * sizeof (cpp_token *)); + } + + token = cpp_get_token (pfile); + + if (token->type == CPP_EOF) + break; + + arg->expanded[arg->expanded_count++] = token; + } + + _cpp_pop_context (pfile); +} + +/* Pop the current context off the stack, re-enabling the macro if the + context represented a macro's replacement list. The context + structure is not freed so that we can re-use it later. */ +void +_cpp_pop_context (pfile) + cpp_reader *pfile; +{ + cpp_context *context = pfile->context; + + if (context->macro) + context->macro->flags &= ~NODE_DISABLED; + + if (context->buff) + _cpp_release_buff (pfile, context->buff); + + pfile->context = context->prev; +} + +/* Eternal routine to get a token. Also used nearly everywhere + internally, except for places where we know we can safely call + the lexer directly, such as lexing a directive name. + + Macro expansions and directives are transparently handled, + including entering included files. Thus tokens are post-macro + expansion, and after any intervening directives. External callers + see CPP_EOF only at EOF. Internal callers also see it when meeting + 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. */ +const cpp_token * +cpp_get_token (pfile) + cpp_reader *pfile; +{ + const cpp_token *result; + + for (;;) + { + cpp_hashnode *node; + cpp_context *context = pfile->context; + + /* Context->prev == 0 <=> base context. */ + if (!context->prev) + result = _cpp_lex_token (pfile); + else if (context->first.token != context->last.token) + { + if (context->direct_p) + result = context->first.token++; + else + result = *context->first.ptoken++; + + if (result->flags & PASTE_LEFT) + { + paste_all_tokens (pfile, result); + if (pfile->state.in_directive) + continue; + return padding_token (pfile, result); + } + } + else + { + _cpp_pop_context (pfile); + if (pfile->state.in_directive) + continue; + return &pfile->avoid_paste; + } + + if (result->type != CPP_NAME) + break; + + node = result->val.node; + + if (node->type != NT_MACRO || (result->flags & NO_EXPAND)) + break; + + if (!(node->flags & NODE_DISABLED)) + { + if (!pfile->state.prevent_expansion + && enter_macro_context (pfile, node)) + { + if (pfile->state.in_directive) + continue; + return padding_token (pfile, result); + } + } + else + { + /* Flag this token as always unexpandable. FIXME: move this + to collect_args()?. */ + 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; + } + + break; + } + + return result; +} + +/* Returns true if we're expanding an object-like macro that was + defined in a system header. Just checks the macro at the top of + the stack. Used for diagnostic suppression. */ +int +cpp_sys_macro_p (pfile) + cpp_reader *pfile; +{ + cpp_hashnode *node = pfile->context->macro; + + return node && node->value.macro && node->value.macro->syshdr; +} + +/* Read each token in, until EOF. Directives are transparently + processed. */ +void +cpp_scan_nooutput (pfile) + cpp_reader *pfile; +{ + while (cpp_get_token (pfile)->type != CPP_EOF) + ; +} + +/* Step back one (or more) tokens. Can only step mack more than 1 if + they are from the lexer, and not from macro expansion. */ +void +_cpp_backup_tokens (pfile, count) + cpp_reader *pfile; + unsigned int count; +{ + if (pfile->context->prev == NULL) + { + pfile->lookaheads += count; + while (count--) + { + pfile->cur_token--; + if (pfile->cur_token == pfile->cur_run->base + /* Possible with -fpreprocessed and no leading #line. */ + && pfile->cur_run->prev != NULL) + { + pfile->cur_run = pfile->cur_run->prev; + pfile->cur_token = pfile->cur_run->limit; + } + } + } + else + { + if (count != 1) + abort (); + if (pfile->context->direct_p) + pfile->context->first.token--; + else + pfile->context->first.ptoken--; + } +} + +/* #define directive parsing and handling. */ + +/* Returns non-zero if a macro redefinition warning is required. */ +static int +warn_of_redefinition (node, macro2) + const cpp_hashnode *node; + const cpp_macro *macro2; +{ + const cpp_macro *macro1; + unsigned int i; + + /* Some redefinitions need to be warned about regardless. */ + if (node->flags & NODE_WARN) + return 1; + + /* Redefinition of a macro is allowed if and only if the old and new + definitions are the same. (6.10.3 paragraph 2). */ + macro1 = node->value.macro; + + /* The quick failures. */ + if (macro1->count != macro2->count + || macro1->paramc != macro2->paramc + || macro1->fun_like != macro2->fun_like + || macro1->variadic != macro2->variadic) + return 1; + + /* Check each token. */ + for (i = 0; i < macro1->count; i++) + if (! _cpp_equiv_tokens (¯o1->expansion[i], ¯o2->expansion[i])) + return 1; + + /* Check parameter spellings. */ + for (i = 0; i < macro1->paramc; i++) + if (macro1->params[i] != macro2->params[i]) + return 1; + + return 0; +} + +/* Free the definition of hashnode H. */ +void +_cpp_free_definition (h) + cpp_hashnode *h; +{ + /* Macros and assertions no longer have anything to free. */ + h->type = NT_VOID; + /* Clear builtin flag in case of redefinition. */ + h->flags &= ~(NODE_BUILTIN | NODE_DISABLED); +} + +/* Save parameter NODE to the parameter list of macro MACRO. Returns + zero on success, non-zero if the parameter is a duplicate. */ +static int +save_parameter (pfile, macro, node) + cpp_reader *pfile; + cpp_macro *macro; + cpp_hashnode *node; +{ + /* Constraint 6.10.3.6 - duplicate parameter names. */ + if (node->arg_index) + { + cpp_error (pfile, "duplicate macro parameter \"%s\"", NODE_NAME (node)); + return 1; + } + + if (BUFF_ROOM (pfile->a_buff) + < (macro->paramc + 1) * sizeof (cpp_hashnode *)) + _cpp_extend_buff (pfile, &pfile->a_buff, sizeof (cpp_hashnode *)); + + ((cpp_hashnode **) BUFF_FRONT (pfile->a_buff))[macro->paramc++] = node; + node->arg_index = macro->paramc; + return 0; +} + +/* Check the syntax of the parameters in a MACRO definition. */ +static int +parse_params (pfile, macro) + cpp_reader *pfile; + cpp_macro *macro; +{ + unsigned int prev_ident = 0; + + for (;;) + { + const cpp_token *token = _cpp_lex_token (pfile); + + switch (token->type) + { + default: + cpp_error (pfile, "\"%s\" may not appear in macro parameter list", + cpp_token_as_text (pfile, token)); + return 0; + + case CPP_NAME: + if (prev_ident) + { + cpp_error (pfile, "macro parameters must be comma-separated"); + return 0; + } + prev_ident = 1; + + if (save_parameter (pfile, macro, token->val.node)) + return 0; + continue; + + case CPP_CLOSE_PAREN: + if (prev_ident || macro->paramc == 0) + return 1; + + /* Fall through to pick up the error. */ + case CPP_COMMA: + if (!prev_ident) + { + cpp_error (pfile, "parameter name missing"); + return 0; + } + prev_ident = 0; + continue; + + case CPP_ELLIPSIS: + macro->variadic = 1; + if (!prev_ident) + { + save_parameter (pfile, macro, pfile->spec_nodes.n__VA_ARGS__); + pfile->state.va_args_ok = 1; + if (! CPP_OPTION (pfile, c99) && CPP_OPTION (pfile, pedantic)) + cpp_pedwarn (pfile, + "anonymous variadic macros were introduced in C99"); + } + else if (CPP_OPTION (pfile, pedantic)) + cpp_pedwarn (pfile, "ISO C does not permit named variadic macros"); + + /* We're at the end, and just expect a closing parenthesis. */ + token = _cpp_lex_token (pfile); + if (token->type == CPP_CLOSE_PAREN) + return 1; + /* Fall through. */ + + case CPP_EOF: + cpp_error (pfile, "missing ')' in macro parameter list"); + return 0; + } + } +} + +/* Allocate room for a token from a macro's replacement list. */ +static cpp_token * +alloc_expansion_token (pfile, macro) + cpp_reader *pfile; + cpp_macro *macro; +{ + if (BUFF_ROOM (pfile->a_buff) < (macro->count + 1) * sizeof (cpp_token)) + _cpp_extend_buff (pfile, &pfile->a_buff, sizeof (cpp_token)); + + return &((cpp_token *) BUFF_FRONT (pfile->a_buff))[macro->count++]; +} + +/* Lex a token from the expansion of MACRO, but mark parameters as we + find them and warn of traditional stringification. */ +static cpp_token * +lex_expansion_token (pfile, macro) + cpp_reader *pfile; + cpp_macro *macro; +{ + cpp_token *token; + + pfile->cur_token = alloc_expansion_token (pfile, macro); + token = _cpp_lex_direct (pfile); + + /* Is this a parameter? */ + if (token->type == CPP_NAME && token->val.node->arg_index) + { + token->type = CPP_MACRO_ARG; + token->val.arg_no = token->val.node->arg_index; + } + else if (CPP_WTRADITIONAL (pfile) && macro->paramc > 0 + && (token->type == CPP_STRING || token->type == CPP_CHAR)) + check_trad_stringification (pfile, macro, &token->val.str); + + return token; +} + +/* Parse a macro and save its expansion. Returns non-zero on success. */ +int +_cpp_create_definition (pfile, node) + cpp_reader *pfile; + cpp_hashnode *node; +{ + cpp_macro *macro; + cpp_token *token, *saved_cur_token; + const cpp_token *ctoken; + unsigned int i, ok = 1; + + macro = (cpp_macro *) _cpp_aligned_alloc (pfile, sizeof (cpp_macro)); + macro->line = pfile->directive_line; + macro->params = 0; + macro->paramc = 0; + macro->variadic = 0; + macro->count = 0; + macro->fun_like = 0; + + /* Get the first token of the expansion (or the '(' of a + function-like macro). */ + ctoken = _cpp_lex_token (pfile); + + if (ctoken->type == CPP_OPEN_PAREN && !(ctoken->flags & PREV_WHITE)) + { + ok = parse_params (pfile, macro); + macro->params = (cpp_hashnode **) BUFF_FRONT (pfile->a_buff); + if (!ok) + goto cleanup2; + + /* Success. Commit the parameter array. */ + BUFF_FRONT (pfile->a_buff) = (U_CHAR *) ¯o->params[macro->paramc]; + macro->fun_like = 1; + } + else if (ctoken->type != CPP_EOF && !(ctoken->flags & PREV_WHITE)) + cpp_pedwarn (pfile, "ISO C requires whitespace after the macro name"); + + saved_cur_token = pfile->cur_token; + + if (macro->fun_like) + token = lex_expansion_token (pfile, macro); + else + { + token = alloc_expansion_token (pfile, macro); + *token = *ctoken; + } + + for (;;) + { + /* Check the stringifying # constraint 6.10.3.2.1 of + function-like macros when lexing the subsequent token. */ + if (macro->count > 1 && token[-1].type == CPP_HASH && macro->fun_like) + { + if (token->type == CPP_MACRO_ARG) + { + token->flags &= ~PREV_WHITE; + token->flags |= STRINGIFY_ARG; + token->flags |= token[-1].flags & PREV_WHITE; + token[-1] = token[0]; + macro->count--; + } + /* Let assembler get away with murder. */ + else if (CPP_OPTION (pfile, lang) != CLK_ASM) + { + ok = 0; + cpp_error (pfile, "'#' is not followed by a macro parameter"); + goto cleanup1; + } + } + + if (token->type == CPP_EOF) + break; + + /* Paste operator constraint 6.10.3.3.1. */ + if (token->type == CPP_PASTE) + { + /* Token-paste ##, can appear in both object-like and + function-like macros, but not at the ends. */ + if (--macro->count > 0) + token = lex_expansion_token (pfile, macro); + + if (macro->count == 0 || token->type == CPP_EOF) + { + ok = 0; + cpp_error (pfile, + "'##' cannot appear at either end of a macro expansion"); + goto cleanup1; + } + + token[-1].flags |= PASTE_LEFT; + } + + token = lex_expansion_token (pfile, macro); + } + + macro->expansion = (cpp_token *) BUFF_FRONT (pfile->a_buff); + + /* Don't count the CPP_EOF. */ + macro->count--; + + /* Clear whitespace on first token for warn_of_redefinition(). */ + if (macro->count) + macro->expansion[0].flags &= ~PREV_WHITE; + + /* Commit the memory. */ + BUFF_FRONT (pfile->a_buff) = (U_CHAR *) ¯o->expansion[macro->count]; + + /* Implement the macro-defined-to-itself optimisation. */ + if (macro->count == 1 && !macro->fun_like + && macro->expansion[0].type == CPP_NAME + && macro->expansion[0].val.node == node) + node->flags |= NODE_DISABLED; + + /* To suppress some diagnostics. */ + macro->syshdr = pfile->map->sysp != 0; + + if (node->type != NT_VOID) + { + if (warn_of_redefinition (node, macro)) + { + cpp_pedwarn_with_line (pfile, pfile->directive_line, 0, + "\"%s\" redefined", NODE_NAME (node)); + + if (node->type == NT_MACRO && !(node->flags & NODE_BUILTIN)) + cpp_pedwarn_with_line (pfile, node->value.macro->line, 0, + "this is the location of the previous definition"); + } + _cpp_free_definition (node); + } + + /* Enter definition in hash table. */ + node->type = NT_MACRO; + node->value.macro = macro; + if (! ustrncmp (NODE_NAME (node), DSC ("__STDC_"))) + node->flags |= NODE_WARN; + + cleanup1: + + /* Set type for SEEN_EOL() in cpplib.c, restore the lexer position. */ + saved_cur_token[-1].type = pfile->cur_token[-1].type; + pfile->cur_token = saved_cur_token; + + cleanup2: + + /* Stop the lexer accepting __VA_ARGS__. */ + pfile->state.va_args_ok = 0; + + /* Clear the fast argument lookup indices. */ + for (i = macro->paramc; i-- > 0; ) + macro->params[i]->arg_index = 0; + + return ok; +} + +/* Warn if a token in STRING matches one of a function-like MACRO's + parameters. */ +static void +check_trad_stringification (pfile, macro, string) + cpp_reader *pfile; + const cpp_macro *macro; + const cpp_string *string; +{ + unsigned int i, len; + const U_CHAR *p, *q, *limit = string->text + string->len; + + /* Loop over the string. */ + for (p = string->text; p < limit; p = q) + { + /* Find the start of an identifier. */ + while (p < limit && !is_idstart (*p)) + p++; + + /* Find the end of the identifier. */ + q = p; + while (q < limit && is_idchar (*q)) + q++; + + len = q - p; + + /* Loop over the function macro arguments to see if the + identifier inside the string matches one of them. */ + for (i = 0; i < macro->paramc; i++) + { + const cpp_hashnode *node = macro->params[i]; + + if (NODE_LEN (node) == len + && !memcmp (p, NODE_NAME (node), len)) + { + cpp_warning (pfile, + "macro argument \"%s\" would be stringified with -traditional", + NODE_NAME (node)); + break; + } + } + } +} + +/* Returns the name, arguments and expansion of a macro, in a format + suitable to be read back in again, and therefore also for DWARF 2 + debugging info. e.g. "PASTE(X, Y) X ## Y", or "MACNAME EXPANSION". + Caller is expected to generate the "#define" bit if needed. The + returned text is temporary, and automatically freed later. */ +const unsigned char * +cpp_macro_definition (pfile, node) + cpp_reader *pfile; + const cpp_hashnode *node; +{ + unsigned int i, len; + const cpp_macro *macro = node->value.macro; + unsigned char *buffer; + + if (node->type != NT_MACRO || (node->flags & NODE_BUILTIN)) + { + cpp_ice (pfile, "invalid hash type %d in cpp_macro_definition", node->type); + return 0; + } + + /* Calculate length. */ + len = NODE_LEN (node) + 1; /* ' ' */ + if (macro->fun_like) + { + len += 3; /* "()" plus possible final "." of named + varargs (we have + 2 below). */ + for (i = 0; i < macro->paramc; i++) + len += NODE_LEN (macro->params[i]) + 2; /* ", " */ + } + + for (i = 0; i < macro->count; i++) + { + cpp_token *token = ¯o->expansion[i]; + + if (token->type == CPP_MACRO_ARG) + len += NODE_LEN (macro->params[token->val.arg_no - 1]); + else + len += cpp_token_len (token); /* Includes room for ' '. */ + if (token->flags & STRINGIFY_ARG) + len++; /* "#" */ + if (token->flags & PASTE_LEFT) + len += 3; /* " ##" */ + } + + if (len > pfile->macro_buffer_len) + { + pfile->macro_buffer = (U_CHAR *) xrealloc (pfile->macro_buffer, len); + pfile->macro_buffer_len = len; + } + + /* Fill in the buffer. Start with the macro name. */ + buffer = pfile->macro_buffer; + memcpy (buffer, NODE_NAME (node), NODE_LEN (node)); + buffer += NODE_LEN (node); + + /* Parameter names. */ + if (macro->fun_like) + { + *buffer++ = '('; + for (i = 0; i < macro->paramc; i++) + { + cpp_hashnode *param = macro->params[i]; + + if (param != pfile->spec_nodes.n__VA_ARGS__) + { + memcpy (buffer, NODE_NAME (param), NODE_LEN (param)); + buffer += NODE_LEN (param); + } + + if (i + 1 < macro->paramc) + *buffer++ = ',', *buffer++ = ' '; + else if (macro->variadic) + *buffer++ = '.', *buffer++ = '.', *buffer++ = '.'; + } + *buffer++ = ')'; + } + + /* Expansion tokens. */ + if (macro->count) + { + *buffer++ = ' '; + for (i = 0; i < macro->count; i++) + { + cpp_token *token = ¯o->expansion[i]; + + if (token->flags & PREV_WHITE) + *buffer++ = ' '; + if (token->flags & STRINGIFY_ARG) + *buffer++ = '#'; + + if (token->type == CPP_MACRO_ARG) + { + len = NODE_LEN (macro->params[token->val.arg_no - 1]); + memcpy (buffer, + NODE_NAME (macro->params[token->val.arg_no - 1]), len); + buffer += len; + } + else + buffer = cpp_spell_token (pfile, token, buffer); + + if (token->flags & PASTE_LEFT) + { + *buffer++ = ' '; + *buffer++ = '#'; + *buffer++ = '#'; + /* Next has PREV_WHITE; see _cpp_create_definition. */ + } + } + } + + *buffer = '\0'; + return pfile->macro_buffer; +} |