diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 6fe6d37877c..6351846ed5f 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,37 @@ +2000-04-23 Zack Weinberg + + * cpphash.h (struct definition): Move file, line, col members... + (struct hashnode): ... here. Also add 'disabled' flag. + (enum node_type): Add T_VOID, T_XCONST, T_FMACRO, and + T_IDENTITY. Remove T_DISABLED. + Update prototypes. + + * cpphash.c (_cpp_dump_definition): Split out dump_DEFINITION. + (collect_expansion): Split into collect_objlike_expansion and + collect_funlike_expansion. + (_cpp_macroexpand): Split out scan_arguments, stringify, and + funlike_macroexpand. + (_cpp_compare_defs): Rename compare_defs, make static. + (_cpp_make_hashnode): Initialize hp->disabled. + (macro_cleanup): Adjust for new token types. Clear + m->disabled. + (_cpp_create_definition): Move code here to determine what + sort of macro it is, and code to check for redefinitions, from + do_define. Implement a few simple cases without creating a + full DEFINITION. + (_cpp_macroexpand, special_symbol, _cpp_dump_definition): + Handle the simple cases. + (push_macro_expansion): Set buf->has_escapes and hp->disabled + here. + + * cppinit.c (builtin_array): Change MCONST to XCONST + everywhere. + * cpplex.c (maybe_macroexpand): Handle IDENTITY macros here; + fix check for disabled and function-like macros. + * cpplib.c (do_define): Move most logic to + _cpp_create_definition. + (do_undef): Handle new special token types. + Sun Apr 23 14:27:44 MET DST 2000 Jan Hubicka * loop.c (maybe_eliminate_biv_1): Use GET_CODE (x) == CONST_INT instead @@ -53,31 +87,31 @@ Sat Apr 22 22:35:38 MET DST 2000 Jan Hubicka * Makefile.in (diagnostic.o): Depends on diagnostic.h - * diagnostic.c: Tweak. Rationalize the output logic. Adjust + * diagnostic.c: Tweak. Rationalize the output logic. Adjust various function prototypes. - (diagnostic.h): #include. - (struct output_buffer): Move into diagnostic.h. - (get_output_prefix): Rename to output_get_prefix. Export. - (init_output_buffer): Export. Break out. Ajust intialization. - (output_space_left, output_append): Export. - (output_newline): Rename to output_add_newline. Export. + (diagnostic.h): #include. + (struct output_buffer): Move into diagnostic.h. + (get_output_prefix): Rename to output_get_prefix. Export. + (init_output_buffer): Export. Break out. Ajust intialization. + (output_space_left, output_append): Export. + (output_newline): Rename to output_add_newline. Export. (output_clear): Nullify additional output_buffer fields. - (output_puts): Rename to output_add_string. Export. - (dump_output): Rename to output_flush_on. Export. - (build_location_prefix): Constify return-type. - (emit_output_prefix): Rename to output_emit_prefix. Export. - (set_real_maximum_length): New function. - (output_set_maximum_length): Ditto - (output_clear): Ditto. - (output_add_character): Ditto. - (output_add_integer): Ditto. - (output_add_space): Ditto. - (output_format): Ditto. - (output_printf): Adjust buffer initialization. - (vline_wrapper_message_with_location): Ditto. - (v_message_with_decl): Ditto. Adjust call to output_puts + (output_puts): Rename to output_add_string. Export. + (dump_output): Rename to output_flush_on. Export. + (build_location_prefix): Constify return-type. + (emit_output_prefix): Rename to output_emit_prefix. Export. + (set_real_maximum_length): New function. + (output_set_maximum_length): Ditto + (output_clear): Ditto. + (output_add_character): Ditto. + (output_add_integer): Ditto. + (output_add_space): Ditto. + (output_format): Ditto. + (output_printf): Adjust buffer initialization. + (vline_wrapper_message_with_location): Ditto. + (v_message_with_decl): Ditto. Adjust call to output_puts and get_output_prefix. - (default_print_error_function): Adjust buffer intialization. + (default_print_error_function): Adjust buffer intialization. Sat Apr 22 06:45:04 2000 Richard Kenner diff --git a/gcc/cpphash.c b/gcc/cpphash.c index 26d03fec055..cc704657abe 100644 --- a/gcc/cpphash.c +++ b/gcc/cpphash.c @@ -34,14 +34,17 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. static unsigned int hash_HASHNODE PARAMS ((const void *)); static int eq_HASHNODE PARAMS ((const void *, const void *)); static void del_HASHNODE PARAMS ((void *)); +static void dump_DEFINITION PARAMS ((cpp_reader *, DEFINITION *)); static int dump_hash_helper PARAMS ((void **, void *)); -static void push_macro_expansion PARAMS ((cpp_reader *, - U_CHAR *, int, HASHNODE *)); +static void push_macro_expansion PARAMS ((cpp_reader *, const U_CHAR *, + int, HASHNODE *)); static int unsafe_chars PARAMS ((cpp_reader *, int, int)); static int macro_cleanup PARAMS ((cpp_buffer *, cpp_reader *)); static enum cpp_ttype macarg PARAMS ((cpp_reader *, int)); -static void special_symbol PARAMS ((HASHNODE *, cpp_reader *)); +static void special_symbol PARAMS ((cpp_reader *, HASHNODE *)); +static int compare_defs PARAMS ((cpp_reader *, DEFINITION *, + DEFINITION *)); /* Initial hash table size. (It can grow if necessary - see hashtab.c.) */ #define HASHSIZE 500 @@ -72,8 +75,11 @@ struct arglist }; -static DEFINITION *collect_expansion PARAMS ((cpp_reader *, cpp_toklist *, - struct arglist *, unsigned int)); +static DEFINITION * +collect_objlike_expansion PARAMS ((cpp_reader *, cpp_toklist *)); +static DEFINITION * +collect_funlike_expansion PARAMS ((cpp_reader *, cpp_toklist *, + struct arglist *, unsigned int)); static unsigned int collect_params PARAMS ((cpp_reader *, cpp_toklist *, struct arglist *)); @@ -105,6 +111,12 @@ struct argdata int stringified_length; }; +static void scan_arguments PARAMS ((cpp_reader *, DEFINITION *, + struct argdata *, const U_CHAR *)); +static void stringify PARAMS ((cpp_reader *, struct argdata *)); +static void funlike_macroexpand PARAMS ((cpp_reader *, HASHNODE *, + struct argdata *)); + /* Calculate hash of a string of length LEN. */ unsigned int _cpp_calc_hash (str, len) @@ -174,6 +186,7 @@ _cpp_make_hashnode (name, len, type, hash) hp->length = len; hp->name = p; hp->hash = hash; + hp->disabled = 0; memcpy (p, name, len); p[len] = 0; @@ -277,10 +290,13 @@ macro_cleanup (pbuf, pfile) cpp_buffer *pbuf; cpp_reader *pfile ATTRIBUTE_UNUSED; { - HASHNODE *macro = pbuf->macro; - if (macro->type == T_DISABLED) - macro->type = T_MACRO; - if (macro->type != T_MACRO || pbuf->buf != macro->value.defn->expansion) + HASHNODE *m = pbuf->macro; + + m->disabled = 0; + if (m->type == T_FMACRO && pbuf->buf != m->value.defn->expansion) + free ((PTR) pbuf->buf); + else if (m->type != T_MACRO && m->type != T_FMACRO && m->type != T_CONST + && m->type != T_MCONST && m->type != T_XCONST) free ((PTR) pbuf->buf); return 0; } @@ -398,16 +414,90 @@ trad_stringify (pfile, base, len, argc, argv, pat, endpat, last) return last; } +/* Read a replacement list for an object-like macro, and build the + DEFINITION structure. LIST contains the replacement list, + beginning at 1. */ +static DEFINITION * +collect_objlike_expansion (pfile, list) + cpp_reader *pfile; + cpp_toklist *list; +{ + DEFINITION *defn; + unsigned int i; + unsigned int start; + int last_was_paste = 0; + U_CHAR *exp; + size_t len; -/* Read a replacement list for a macro, and build the DEFINITION - structure. LIST contains the replacement list, beginning at - REPLACEMENT. ARGLIST specifies the formal parameters to look for - in the text of the definition. If ARGLIST is null, this is an - object-like macro; if it points to an empty arglist, this is a - function-like macro with no arguments. */ + /* We copy the expansion text into the token_buffer, then out to + its proper home. */ + start = CPP_WRITTEN (pfile); + CPP_PUTS (pfile, "\r ", 2); + + for (i = 1; i < list->tokens_used; i++) + { + switch (list->tokens[i].type) + { + case CPP_POP: + case CPP_EOF: + cpp_ice (pfile, "EOF in collect_expansion"); + /* fall through */ + case CPP_VSPACE: + goto done; + + case CPP_PASTE: + /* ## is not special if it appears right after another ##; + nor is it special if -traditional. */ + if (last_was_paste || CPP_TRADITIONAL (pfile)) + break; + if (i == 1) + cpp_error (pfile, "`##' at start of macro definition"); + + last_was_paste = 1; + continue; + + default:; + } + + if (i > 1 && !last_was_paste && (list->tokens[i].flags & HSPACE_BEFORE)) + CPP_PUTC (pfile, ' '); + + CPP_PUTS (pfile, + list->tokens[i].val.name.offset + list->namebuf, + list->tokens[i].val.name.len); + last_was_paste = 0; + } + done: + + if (last_was_paste) + cpp_error (pfile, "`##' at end of macro definition"); + + CPP_PUTS (pfile, "\r ", 2); + len = CPP_WRITTEN (pfile) - start; + CPP_SET_WRITTEN (pfile, start); + + exp = (U_CHAR *) xmalloc (len + 1); + memcpy (exp, pfile->token_buffer + start, len); + exp[len] = '\0'; + + defn = (DEFINITION *) xmalloc (sizeof (DEFINITION)); + defn->length = len; + defn->expansion = exp; + defn->pattern = 0; + defn->rest_args = 0; + defn->argnames = 0; + defn->nargs = -1; + + return defn; +} + +/* Read a replacement list for a function-like macro, and build the + DEFINITION structure. LIST contains the replacement list, + beginning at REPLACEMENT. ARGLIST specifies the formal parameters + to look for in the text of the definition. */ static DEFINITION * -collect_expansion (pfile, list, arglist, replacement) +collect_funlike_expansion (pfile, list, arglist, replacement) cpp_reader *pfile; cpp_toklist *list; struct arglist *arglist; @@ -424,16 +514,8 @@ collect_expansion (pfile, list, arglist, replacement) U_CHAR *tok, *exp; enum { START = 0, NORM, ARG, STRIZE, PASTE } last_token = START; - if (arglist) - { - argv = arglist->argv; - argc = arglist->argc; - } - else - { - argv = 0; - argc = 0; - } + argv = arglist->argv; + argc = arglist->argc; /* We copy the expansion text into the token_buffer, then out to its proper home. */ @@ -455,12 +537,11 @@ collect_expansion (pfile, list, arglist, replacement) goto done; case CPP_HASH: - /* # is not special in object-like macros. It is special in - function-like macros with no args. (6.10.3.2 para 1.) - However, it is not special after PASTE. (Implied by - 6.10.3.3 para 4.) Nor is it special if -traditional. */ - if (arglist == NULL || last_token == PASTE - || CPP_TRADITIONAL (pfile)) + /* # is special in function-like macros with no args. + (6.10.3.2 para 1.) However, it is not special after + PASTE. (Implied by 6.10.3.3 para 4.) Nor is it special + if -traditional. */ + if (last_token == PASTE || CPP_TRADITIONAL (pfile)) break; last_token = STRIZE; continue; @@ -497,18 +578,20 @@ collect_expansion (pfile, list, arglist, replacement) { case CPP_STRING: case CPP_CHAR: - if (argc) + if (argc == 0) + goto norm; + if (CPP_TRADITIONAL (pfile)) + { + last = trad_stringify (pfile, tok, len, argc, argv, + &pat, &endpat, last); + break; + } + else { - if (CPP_TRADITIONAL (pfile)) - { - last = trad_stringify (pfile, tok, len, argc, argv, - &pat, &endpat, last); - break; - } if (CPP_WTRADITIONAL (pfile)) warn_trad_stringify (pfile, tok, len, argc, argv); + goto norm; } - goto norm; case CPP_NAME: for (j = 0; j < argc; j++) @@ -521,9 +604,6 @@ collect_expansion (pfile, list, arglist, replacement) norm: if (last_token == STRIZE) cpp_error (pfile, "# is not followed by a macro argument name"); - if (last_token != PASTE && last_token != START - && (list->tokens[i].flags & HSPACE_BEFORE)) - CPP_PUTC (pfile, ' '); CPP_PUTS (pfile, tok, len); last_token = NORM; } @@ -563,19 +643,11 @@ collect_expansion (pfile, list, arglist, replacement) defn->length = len; defn->expansion = exp; defn->pattern = pat; - defn->rest_args = argv && argv[argc - 1].rest_arg; - if (arglist) - { - defn->nargs = argc; - defn->argnames = arglist->namebuf; - if (argv) - free ((PTR) argv); - } - else - { - defn->nargs = -1; - defn->argnames = 0; - } + defn->rest_args = argc && argv[argc - 1].rest_arg; + defn->nargs = argc; + defn->argnames = arglist->namebuf; + if (argv) + free ((PTR) argv); return defn; } @@ -745,31 +817,134 @@ collect_params (pfile, list, arglist) (including formal parameters if present) is in LIST. If FUNLIKE is true, this is a function-like macro. */ -DEFINITION * -_cpp_create_definition (pfile, list, funlike) +int +_cpp_create_definition (pfile, list, hp) cpp_reader *pfile; cpp_toklist *list; - int funlike; + HASHNODE *hp; { - struct arglist args; - DEFINITION *defn; - int replacement = 1; /* replacement begins at this token */ + DEFINITION *defn = 0; + U_CHAR *cpval = 0; + enum node_type ntype; + int ok; - if (funlike) + /* Special-case a few simple and common idioms: + #define TOKEN // nothing + #define TOKEN TOKEN + #define TOKEN OTHERTOKEN + + Might also be good to special-case these: + + #define FUNC() // nothing + #define FUNC(a, b, ...) // nothing + #define FUNC(a, b, c) FUNC(a, b, c) + #define FUNC(a, b, c) foobar(a, b, c) */ + + if (list->tokens_used == 2) + ntype = T_EMPTY; /* Empty definition of object-like macro. */ + else if (list->tokens_used == 3 && list->tokens[1].type == CPP_NAME) { + if (list->tokens[0].val.name.len == list->tokens[1].val.name.len + && !strncmp (list->tokens[0].val.name.offset + list->namebuf, + list->tokens[1].val.name.offset + list->namebuf, + list->tokens[0].val.name.len)) + ntype = T_IDENTITY; + else + { + ntype = T_MCONST; + cpval = xmalloc (list->tokens[1].val.name.len + 1); + memcpy (cpval, list->tokens[1].val.name.offset + list->namebuf, + list->tokens[1].val.name.len); + cpval[list->tokens[1].val.name.len] = '\0'; + } + } + + /* The macro is function-like only if the next character, + with no intervening whitespace, is '('. */ + else if (list->tokens[1].type == CPP_OPEN_PAREN + && ! (list->tokens[1].flags & HSPACE_BEFORE)) + { + struct arglist args; + int replacement; + replacement = collect_params (pfile, list, &args); if (replacement == 0) return 0; + defn = collect_funlike_expansion (pfile, list, &args, replacement); + if (defn == 0) + return 0; + + ntype = T_FMACRO; } - defn = collect_expansion (pfile, list, funlike ? &args : 0, replacement); - if (defn == 0) - return 0; + /* Otherwise it is an object-like macro, and C99 requires + whitespace after the name (6.10.3 para 3). */ + else + { + if (! (list->tokens[1].flags & CPP_OPEN_PAREN)) + cpp_pedwarn (pfile, + "The C standard requires whitespace after #define %s", + hp->name); - defn->file = CPP_BUFFER (pfile)->nominal_fname; - defn->line = list->line; - defn->col = list->tokens[0].col; - return defn; + defn = collect_objlike_expansion (pfile, list); + if (defn == 0) + return 0; + + ntype = T_MACRO; + } + + /* Check for a redefinition, and its legality. Redefining a macro + of whatever stripe is ok if the definitions are the same. + Redefining a built-in _constant_ (T_CONST or T_XCONST) is ok only + with -D. Otherwise a redefinition is not ok. */ + + switch (hp->type) + { + case T_VOID: ok = 1; break; + default: ok = 0; break; + + case T_MACRO: case T_FMACRO: + ok = (ntype == hp->type && !compare_defs (pfile, defn, hp->value.defn)); + break; + case T_IDENTITY: + case T_EMPTY: + ok = (ntype == hp->type); + break; + case T_MCONST: + ok = (ntype == hp->type && !strcmp (cpval, hp->value.cpval)); + break; + case T_CONST: + case T_XCONST: + ok = ! pfile->done_initializing; + break; + } + + /* Print the warning or error if it's not ok. */ + if (! ok) + { + cpp_pedwarn (pfile, "\"%s\" redefined", hp->name); + if (pfile->done_initializing) + cpp_pedwarn_with_file_and_line (pfile, hp->file, hp->line, hp->col, + "this is the location of the previous definition"); + } + + /* And replace the old definition (if any). */ + + if (hp->type == T_MACRO || hp->type == T_FMACRO) + _cpp_free_definition (hp->value.defn); + else if (hp->type == T_MCONST || hp->type == T_XCONST) + free ((PTR) hp->value.cpval); + + if (ntype == T_MACRO || ntype == T_FMACRO) + hp->value.defn = defn; + else + hp->value.cpval = cpval; + + hp->type = ntype; + hp->file = CPP_BUFFER (pfile)->nominal_fname; + hp->line = list->line; + hp->col = list->tokens[0].col; + return 1; } /* @@ -874,9 +1049,9 @@ _cpp_quote_string (pfile, src) #define DSC(str) (const U_CHAR *)str, sizeof str - 1 static void -special_symbol (hp, pfile) - HASHNODE *hp; +special_symbol (pfile, hp) cpp_reader *pfile; + HASHNODE *hp; { const char *buf; cpp_buffer *ip; @@ -929,6 +1104,7 @@ special_symbol (hp, pfile) /* else fall through */ case T_CONST: case T_MCONST: + case T_XCONST: constant: buf = hp->value.cpval; if (!buf) @@ -1005,18 +1181,87 @@ _cpp_macroexpand (pfile, hp) cpp_reader *pfile; HASHNODE *hp; { - int nargs; DEFINITION *defn; - register U_CHAR *xbuf; - unsigned int start_line, start_column; - cpp_buffer *ip; - int xbuf_len; - struct argdata *args = 0; - long old_written = CPP_WRITTEN (pfile); - int rest_args, rest_zero = 0; - register int i; + struct argdata *args; + unsigned int old_written; + int i; - ip = cpp_file_buffer (pfile); + /* Object like macro - most common case. */ + if (hp->type == T_MACRO) + { + push_macro_expansion (pfile, hp->value.defn->expansion, + hp->value.defn->length, hp); + return; + } + + /* Or might it be a constant string? */ + if (hp->type == T_MCONST || hp->type == T_CONST || hp->type == T_XCONST) + { + const U_CHAR *cpval = hp->value.cpval; + if (!cpval || *cpval == '\0') + cpval = (const U_CHAR *) "\r \r "; + push_macro_expansion (pfile, cpval, strlen (cpval), hp); + return; + } + + /* Or a special symbol? */ + if (hp->type != T_FMACRO) + { + U_CHAR *xbuf; + unsigned int len, old_written = CPP_WRITTEN (pfile); + + special_symbol (pfile, hp); + len = CPP_WRITTEN (pfile) - old_written; + CPP_SET_WRITTEN (pfile, old_written); + xbuf = (U_CHAR *) xmalloc (len + 1); + memcpy (xbuf, CPP_PWRITTEN (pfile), len); + xbuf[len] = '\0'; + push_macro_expansion (pfile, xbuf, len, hp); + return; + } + + /* Okay, it's a full-on function-like macro... */ + old_written = CPP_WRITTEN (pfile); + defn = hp->value.defn; + + args = alloca (MAX (defn->nargs, 1) * sizeof (struct argdata)); + for (i = 0; i < MAX (defn->nargs, 1); i++) + { + args[i].raw = args[i].expanded = 0; + args[i].raw_length = 0; + args[i].expand_length = args[i].stringified_length = -1; + } + + pfile->output_escapes++; + scan_arguments (pfile, defn, args, hp->name); + + /* If macro wants zero args, we parsed the arglist for checking only. + Read directly from the macro definition. */ + if (defn->nargs == 0 || defn->pattern == 0) + { + CPP_SET_WRITTEN (pfile, old_written); + pfile->output_escapes--; + push_macro_expansion (pfile, defn->expansion, defn->length, hp); + return; + } + + funlike_macroexpand (pfile, hp, args); + pfile->output_escapes--; +} + +static void +scan_arguments (pfile, defn, args, name) + cpp_reader *pfile; + DEFINITION *defn; + struct argdata *args; + const U_CHAR *name; +{ + enum cpp_ttype token; + unsigned int start_line, start_column; + unsigned int nargs = defn->nargs; + unsigned int i; + + cpp_buffer *ip = cpp_file_buffer (pfile); if (ip) { start_line = CPP_BUF_LINE (ip); @@ -1025,410 +1270,340 @@ _cpp_macroexpand (pfile, hp) else start_line = start_column = 0; - /* Check for and handle special symbols. */ - if (hp->type != T_MACRO) + /* Parse all the macro args that are supplied. I counts them. The + first NARGS args are stored in ARGS. The rest are discarded. If + rest_args is set then we assume macarg absorbed the rest of the + args. */ + i = 0; + + /* Skip over the opening parenthesis. */ + CPP_OPTION (pfile, discard_comments)++; + pfile->no_macro_expand++; + pfile->no_directives++; + + token = cpp_get_non_space_token (pfile); + if (token != CPP_OPEN_PAREN) + cpp_ice (pfile, "macroexpand: unexpected token %d (wanted LPAREN)", + token); + CPP_ADJUST_WRITTEN (pfile, -1); + + token = CPP_EOF; + do { - special_symbol (hp, pfile); - xbuf_len = CPP_WRITTEN (pfile) - old_written; - xbuf = (U_CHAR *) xmalloc (xbuf_len + 1); - CPP_SET_WRITTEN (pfile, old_written); - memcpy (xbuf, CPP_PWRITTEN (pfile), xbuf_len + 1); - push_macro_expansion (pfile, xbuf, xbuf_len, hp); - CPP_BUFFER (pfile)->has_escapes = 1; - return; + if (i < MAX (nargs, 1)) + { + args[i].raw = CPP_WRITTEN (pfile); + token = macarg (pfile, (i == nargs - 1 && defn->rest_args)); + args[i].raw_length = CPP_WRITTEN (pfile) - args[i].raw; + } + else + token = macarg (pfile, 0); + if (token == CPP_EOF || token == CPP_POP) + cpp_error_with_line (pfile, start_line, start_column, + "unterminated macro call"); + i++; + } + while (token == CPP_COMMA); + CPP_OPTION (pfile, discard_comments)--; + pfile->no_macro_expand--; + pfile->no_directives--; + if (token != CPP_CLOSE_PAREN) + return; + + /* foo ( ) is equivalent to foo () unless foo takes exactly one + argument, in which case the former is allowed and the latter + is not. XXX C99 is silent on this rule, but it seems + inconsistent to me. */ + if (i == 1 && nargs == 0) + { + register U_CHAR *bp = ARG_BASE + args[0].raw; + register U_CHAR *lim = bp + args[0].raw_length; + while (bp != lim && is_space(*bp)) + bp++; + if (bp == lim) + i = 0; } - defn = hp->value.defn; - nargs = defn->nargs; - pfile->output_escapes++; - - if (nargs >= 0) + /* Don't output an error message if we have already output one for + a parse error above. */ + if (nargs == 0 && i > 0) { - enum cpp_ttype token; + cpp_error (pfile, "arguments given to macro `%s'", name); + } + else if (i < nargs) + { + /* traditional C allows foo() if foo wants one argument. */ + if (nargs == 1 && i == 0 && CPP_TRADITIONAL (pfile)) + ; + /* the rest args token is allowed to absorb 0 tokens */ + else if (i == nargs - 1 && defn->rest_args) + ; + else if (i == 0) + cpp_error (pfile, "macro `%s' used without args", name); + else if (i == 1) + cpp_error (pfile, "macro `%s' used with just one arg", name); + else + cpp_error (pfile, "macro `%s' used with only %d args", name, i); + } + else if (i > nargs) + { + cpp_error (pfile, "macro `%s' used with too many (%d) args", name, i); + } +} - args = (struct argdata *) alloca ((nargs + 1) * sizeof (struct argdata)); +static void +stringify (pfile, arg) + cpp_reader *pfile; + struct argdata *arg; +{ + int arglen = arg->raw_length; + int escaped = 0; + int in_string = 0; + int c; + int i; + /* Initially need_space is -1. Otherwise, 1 means the previous + character was a space, but we suppressed it; 0 means the previous + character was a non-space. */ + int need_space = -1; + i = 0; + arg->stringified = CPP_WRITTEN (pfile); + CPP_PUTC (pfile, '\"'); /* insert beginning quote */ + for (; i < arglen; i++) + { + c = (ARG_BASE + arg->raw)[i]; - for (i = 0; i < nargs; i++) + if (!in_string) { - args[i].raw = args[i].expanded = 0; - args[i].raw_length = 0; - args[i].expand_length = args[i].stringified_length = -1; - } - - /* Parse all the macro args that are supplied. I counts them. - The first NARGS args are stored in ARGS. - The rest are discarded. If rest_args is set then we assume - macarg absorbed the rest of the args. */ - i = 0; - rest_args = 0; - - /* Skip over the opening parenthesis. */ - CPP_OPTION (pfile, discard_comments)++; - pfile->no_macro_expand++; - pfile->no_directives++; - - token = cpp_get_non_space_token (pfile); - if (token != CPP_OPEN_PAREN) - cpp_ice (pfile, "macroexpand: unexpected token %d (wanted LPAREN)", - token); - CPP_ADJUST_WRITTEN (pfile, -1); - - token = CPP_EOF; - do - { - if (rest_args) - continue; - if (i < nargs || (nargs == 0 && i == 0)) + /* Delete "\r " and "\r-" escapes. */ + if (c == '\r') { - /* if we are working on last arg which absorbs rest of args... */ - if (i == nargs - 1 && defn->rest_args) - rest_args = 1; - args[i].raw = CPP_WRITTEN (pfile); - token = macarg (pfile, rest_args); - args[i].raw_length = CPP_WRITTEN (pfile) - args[i].raw; + i++; + continue; } - else - token = macarg (pfile, 0); - if (token == CPP_EOF || token == CPP_POP) - cpp_error_with_line (pfile, start_line, start_column, - "unterminated macro call"); - i++; - } - while (token == CPP_COMMA); - CPP_OPTION (pfile, discard_comments)--; - pfile->no_macro_expand--; - pfile->no_directives--; - if (token != CPP_CLOSE_PAREN) - return; - - /* foo ( ) is equivalent to foo () unless foo takes exactly one - argument, in which case the former is allowed and the latter - is not. XXX C99 is silent on this rule, but it seems - inconsistent to me. */ - if (i == 1 && nargs != 1) - { - register U_CHAR *bp = ARG_BASE + args[0].raw; - register U_CHAR *lim = bp + args[0].raw_length; - while (bp != lim && is_space(*bp)) - bp++; - if (bp == lim) - i = 0; - } - - /* Don't output an error message if we have already output one for - a parse error above. */ - rest_zero = 0; - if (nargs == 0 && i > 0) - { - cpp_error (pfile, "arguments given to macro `%s'", hp->name); - } - else if (i < nargs) - { - /* traditional C allows foo() if foo wants one argument. */ - if (nargs == 1 && i == 0 && CPP_TRADITIONAL (pfile)) - ; - /* the rest args token is allowed to absorb 0 tokens */ - else if (i == nargs - 1 && defn->rest_args) - rest_zero = 1; - else if (i == 0) - cpp_error (pfile, "macro `%s' used without args", hp->name); - else if (i == 1) - cpp_error (pfile, "macro `%s' used with just one arg", hp->name); - else - cpp_error (pfile, "macro `%s' used with only %d args", - hp->name, i); - } - else if (i > nargs) - { - cpp_error (pfile, - "macro `%s' used with too many (%d) args", hp->name, i); - } - } - - /* If macro wants zero args, we parsed the arglist for checking only. - Read directly from the macro definition. */ - if (nargs <= 0) - { - xbuf = defn->expansion; - xbuf_len = defn->length; - } - else - { - register U_CHAR *exp = defn->expansion; - register int offset; /* offset in expansion, - copied a piece at a time */ - register int totlen; /* total amount of exp buffer filled so far */ - - register struct reflist *ap, *last_ap; - - /* Macro really takes args. Compute the expansion of this call. */ - - /* Compute length in characters of the macro's expansion. - Also count number of times each arg is used. */ - xbuf_len = defn->length; - for (ap = defn->pattern; ap != NULL; ap = ap->next) - { - if (ap->stringify) + /* Internal sequences of whitespace are replaced by one + space except within a string or char token. */ + else if (is_space(c)) { - register struct argdata *arg = &args[ap->argno]; - /* Stringify if it hasn't already been */ - if (arg->stringified_length < 0) + if (need_space == 0) + need_space = 1; + continue; + } + else if (need_space > 0) + CPP_PUTC (pfile, ' '); + need_space = 0; + } + + if (escaped) + escaped = 0; + else + { + if (c == '\\') + escaped = 1; + if (in_string) + { + if (c == in_string) + in_string = 0; + } + else if (c == '\"' || c == '\'') + in_string = c; + } + + /* Escape these chars */ + if (c == '\"' || (in_string && c == '\\')) + CPP_PUTC (pfile, '\\'); + if (ISPRINT (c)) + CPP_PUTC (pfile, c); + else + { + CPP_RESERVE (pfile, 4); + sprintf ((char *) CPP_PWRITTEN (pfile), "\\%03o", (unsigned int) c); + CPP_ADJUST_WRITTEN (pfile, 4); + } + } + CPP_PUTC (pfile, '\"'); /* insert ending quote */ + arg->stringified_length = CPP_WRITTEN (pfile) - arg->stringified; +} + +static void +funlike_macroexpand (pfile, hp, args) + cpp_reader *pfile; + HASHNODE *hp; + struct argdata *args; +{ + DEFINITION *defn = hp->value.defn; + register U_CHAR *xbuf; + int xbuf_len; + long old_written = CPP_WRITTEN (pfile); + U_CHAR *exp = defn->expansion; + int offset; /* offset in expansion, copied a piece at a time */ + int totlen; /* total amount of exp buffer filled so far */ + struct reflist *ap, *last_ap; + int i; + + /* Compute length in characters of the macro's expansion. + Also count number of times each arg is used. */ + xbuf_len = defn->length; + for (ap = defn->pattern; ap != NULL; ap = ap->next) + { + if (ap->stringify) + { + /* Stringify if it hasn't already been */ + if (args[ap->argno].stringified_length < 0) + stringify (pfile, &args[ap->argno]); + xbuf_len += args[ap->argno].stringified_length; + } + else if (ap->raw_before || ap->raw_after) + /* Add 4 for two \r-space markers to prevent + token concatenation. */ + xbuf_len += args[ap->argno].raw_length + 4; + else + { + /* We have an ordinary (expanded) occurrence of the arg. + So compute its expansion, if we have not already. */ + if (args[ap->argno].expand_length < 0) + { + args[ap->argno].expanded = CPP_WRITTEN (pfile); + _cpp_expand_to_buffer (pfile, ARG_BASE + args[ap->argno].raw, + args[ap->argno].raw_length); + + args[ap->argno].expand_length + = CPP_WRITTEN (pfile) - args[ap->argno].expanded; + } + + /* Add 4 for two \r-space markers to prevent + token concatenation. */ + xbuf_len += args[ap->argno].expand_length + 4; + } + } + + xbuf = (U_CHAR *) xmalloc (xbuf_len + 1); + + /* Generate in XBUF the complete expansion with arguments + substituted in. TOTLEN is the total size generated so far. + OFFSET is the index in the definition of where we are copying + from. */ + offset = totlen = 0; + for (last_ap = NULL, ap = defn->pattern; ap != NULL; + last_ap = ap, ap = ap->next) + { + register struct argdata *arg = &args[ap->argno]; + int count_before = totlen; + + /* Add chars to XBUF. */ + i = ap->nchars; + memcpy (&xbuf[totlen], &exp[offset], i); + totlen += i; + offset += i; + + /* If followed by an empty rest arg with concatenation, + delete the last run of nonwhite chars. */ + if (arg->raw_length == 0 && totlen > count_before + && ((ap->rest_args && ap->raw_before) + || (last_ap != NULL && last_ap->rest_args + && last_ap->raw_after))) + { + /* Delete final whitespace. */ + while (totlen > count_before && is_space(xbuf[totlen - 1])) + totlen--; + + /* Delete the nonwhites before them. */ + while (totlen > count_before && !is_space(xbuf[totlen - 1])) + totlen--; + } + + if (ap->stringify != 0) + { + memcpy (xbuf + totlen, ARG_BASE + arg->stringified, + arg->stringified_length); + totlen += arg->stringified_length; + } + else if (ap->raw_before || ap->raw_after) + { + U_CHAR *p1 = ARG_BASE + arg->raw; + U_CHAR *l1 = p1 + arg->raw_length; + if (ap->raw_before) + { + /* Arg is concatenated before: delete leading whitespace, + whitespace markers, and no-reexpansion markers. */ + while (p1 != l1) { - int arglen = arg->raw_length; - int escaped = 0; - int in_string = 0; - int c; - /* Initially need_space is -1. Otherwise, 1 means the - previous character was a space, but we suppressed it; - 0 means the previous character was a non-space. */ - int need_space = -1; - i = 0; - arg->stringified = CPP_WRITTEN (pfile); - CPP_PUTC (pfile, '\"'); /* insert beginning quote */ - for (; i < arglen; i++) - { - c = (ARG_BASE + arg->raw)[i]; - - if (!in_string) - { - /* Delete "\r " and "\r-" escapes. */ - if (c == '\r') - { - i++; - continue; - } - /* Internal sequences of whitespace are - replaced by one space except within - a string or char token. */ - else if (is_space(c)) - { - if (need_space == 0) - need_space = 1; - continue; - } - else if (need_space > 0) - CPP_PUTC (pfile, ' '); - need_space = 0; - } - - if (escaped) - escaped = 0; - else - { - if (c == '\\') - escaped = 1; - if (in_string) - { - if (c == in_string) - in_string = 0; - } - else if (c == '\"' || c == '\'') - in_string = c; - } - - /* Escape these chars */ - if (c == '\"' || (in_string && c == '\\')) - CPP_PUTC (pfile, '\\'); - if (ISPRINT (c)) - CPP_PUTC (pfile, c); - else - { - CPP_RESERVE (pfile, 4); - sprintf ((char *) CPP_PWRITTEN (pfile), "\\%03o", - (unsigned int) c); - CPP_ADJUST_WRITTEN (pfile, 4); - } - } - CPP_PUTC (pfile, '\"'); /* insert ending quote */ - arg->stringified_length - = CPP_WRITTEN (pfile) - arg->stringified; + if (is_space(p1[0])) + p1++; + else if (p1[0] == '\r') + p1 += 2; + else + break; } - xbuf_len += args[ap->argno].stringified_length; } - else if (ap->raw_before || ap->raw_after) - /* Add 4 for two \r-space markers to prevent - token concatenation. */ - xbuf_len += args[ap->argno].raw_length + 4; - else + if (ap->raw_after) { - /* We have an ordinary (expanded) occurrence of the arg. - So compute its expansion, if we have not already. */ - if (args[ap->argno].expand_length < 0) + /* Arg is concatenated after: delete trailing whitespace, + whitespace markers, and no-reexpansion markers. */ + while (p1 != l1) { - args[ap->argno].expanded = CPP_WRITTEN (pfile); - _cpp_expand_to_buffer (pfile, - ARG_BASE + args[ap->argno].raw, - args[ap->argno].raw_length); - - args[ap->argno].expand_length - = CPP_WRITTEN (pfile) - args[ap->argno].expanded; - } - - /* Add 4 for two \r-space markers to prevent - token concatenation. */ - xbuf_len += args[ap->argno].expand_length + 4; - } - } - - xbuf = (U_CHAR *) xmalloc (xbuf_len + 1); - - /* Generate in XBUF the complete expansion - with arguments substituted in. - TOTLEN is the total size generated so far. - OFFSET is the index in the definition - of where we are copying from. */ - offset = totlen = 0; - for (last_ap = NULL, ap = defn->pattern; ap != NULL; - last_ap = ap, ap = ap->next) - { - register struct argdata *arg = &args[ap->argno]; - int count_before = totlen; - - /* Add chars to XBUF. */ - i = ap->nchars; - memcpy (&xbuf[totlen], &exp[offset], i); - totlen += i; - offset += i; - - /* If followed by an empty rest arg with concatenation, - delete the last run of nonwhite chars. */ - if (rest_zero && totlen > count_before - && ((ap->rest_args && ap->raw_before) - || (last_ap != NULL && last_ap->rest_args - && last_ap->raw_after))) - { - /* Delete final whitespace. */ - while (totlen > count_before && is_space(xbuf[totlen - 1])) - totlen--; - - /* Delete the nonwhites before them. */ - while (totlen > count_before && !is_space(xbuf[totlen - 1])) - totlen--; - } - - if (ap->stringify != 0) - { - memcpy (xbuf + totlen, ARG_BASE + arg->stringified, - arg->stringified_length); - totlen += arg->stringified_length; - } - else if (ap->raw_before || ap->raw_after) - { - U_CHAR *p1 = ARG_BASE + arg->raw; - U_CHAR *l1 = p1 + arg->raw_length; - if (ap->raw_before) - { - /* Arg is concatenated before: delete leading whitespace, - whitespace markers, and no-reexpansion markers. */ - while (p1 != l1) + if (is_space(l1[-1])) + l1--; + else if (l1[-1] == '\r') + l1--; + else if (l1[-1] == '-') { - if (is_space(p1[0])) - p1++; - else if (p1[0] == '\r') - p1 += 2; + if (l1 != p1 + 1 && l1[-2] == '\r') + l1 -= 2; else break; } - } - if (ap->raw_after) - { - /* Arg is concatenated after: delete trailing whitespace, - whitespace markers, and no-reexpansion markers. */ - while (p1 != l1) - { - if (is_space(l1[-1])) - l1--; - else if (l1[-1] == '\r') - l1--; - else if (l1[-1] == '-') - { - if (l1 != p1 + 1 && l1[-2] == '\r') - l1 -= 2; - else - break; - } - else - break; - } - } - - /* Delete any no-reexpansion marker that precedes - an identifier at the beginning of the argument. */ - if (p1[0] == '\r' && p1[1] == '-') - p1 += 2; - - memcpy (xbuf + totlen, p1, l1 - p1); - totlen += l1 - p1; - } - else - { - U_CHAR *expanded = ARG_BASE + arg->expanded; - if (!ap->raw_before && totlen > 0 && arg->expand_length - && unsafe_chars (pfile, xbuf[totlen - 1], expanded[0])) - { - xbuf[totlen++] = '\r'; - xbuf[totlen++] = ' '; - } - - memcpy (xbuf + totlen, expanded, arg->expand_length); - totlen += arg->expand_length; - - if (!ap->raw_after && totlen > 0 && offset < defn->length - && unsafe_chars (pfile, xbuf[totlen - 1], exp[offset])) - { - xbuf[totlen++] = '\r'; - xbuf[totlen++] = ' '; + else + break; } } - if (totlen > xbuf_len) - { - cpp_ice (pfile, "buffer overrun in macroexpand"); - return; - } + /* Delete any no-reexpansion marker that precedes + an identifier at the beginning of the argument. */ + if (p1[0] == '\r' && p1[1] == '-') + p1 += 2; + + memcpy (xbuf + totlen, p1, l1 - p1); + totlen += l1 - p1; } - - /* if there is anything left of the definition - after handling the arg list, copy that in too. */ - - for (i = offset; i < defn->length; i++) + else { - /* if we've reached the end of the macro */ - if (exp[i] == ')') - rest_zero = 0; - if (!(rest_zero && last_ap != NULL && last_ap->rest_args - && last_ap->raw_after)) - xbuf[totlen++] = exp[i]; + U_CHAR *expanded = ARG_BASE + arg->expanded; + if (!ap->raw_before && totlen > 0 && arg->expand_length + && unsafe_chars (pfile, xbuf[totlen - 1], expanded[0])) + { + xbuf[totlen++] = '\r'; + xbuf[totlen++] = ' '; + } + + memcpy (xbuf + totlen, expanded, arg->expand_length); + totlen += arg->expand_length; + + if (!ap->raw_after && totlen > 0 && offset < defn->length + && unsafe_chars (pfile, xbuf[totlen - 1], exp[offset])) + { + xbuf[totlen++] = '\r'; + xbuf[totlen++] = ' '; + } } - - xbuf[totlen] = 0; - xbuf_len = totlen; - } - pfile->output_escapes--; + /* if there is anything left of the definition + after handling the arg list, copy that in too. */ + for (i = offset; i < defn->length; i++) + xbuf[totlen++] = exp[i]; + xbuf[totlen] = 0; + + if (totlen > xbuf_len) + /* Just die - we've trashed the heap at this point. */ + abort (); + /* Now put the expansion on the input stack so our caller will commence reading from it. */ - push_macro_expansion (pfile, xbuf, xbuf_len, hp); - CPP_BUFFER (pfile)->has_escapes = 1; + push_macro_expansion (pfile, xbuf, totlen, hp); /* Pop the space we've used in the token_buffer for argument expansion. */ CPP_SET_WRITTEN (pfile, old_written); - - /* In C89, a macro cannot be expanded recursively. Traditional C - permits it, but any use in an object-like macro must lead to - infinite recursion, so always follow C89 in object-like macros. - - The only example known where this doesn't cause infinite recursion - in function-like macros is: - #define foo(x,y) bar(x(y, 0)) - foo(foo, baz) - which expands to bar(foo(baz, 0)) in C89 and - bar(bar(baz(0, 0)) in K+R. This looks pathological to me. - If someone has a real-world example I would love to see it. */ - if (nargs <= 0 || !CPP_TRADITIONAL (pfile)) - hp->type = T_DISABLED; } /* Return 1 iff a token ending in C1 followed directly by a token C2 @@ -1501,7 +1676,7 @@ unsafe_chars (pfile, c1, c2) static void push_macro_expansion (pfile, xbuf, len, hp) cpp_reader *pfile; - register U_CHAR *xbuf; + const U_CHAR *xbuf; int len; HASHNODE *hp; { @@ -1539,12 +1714,33 @@ push_macro_expansion (pfile, xbuf, len, hp) mbuf->cur += 2; mbuf->cleanup = macro_cleanup; mbuf->macro = hp; + mbuf->has_escapes = 1; + + /* In C89, a macro cannot be expanded recursively. Traditional C + permits it, but any use in an object-like macro must lead to + infinite recursion, so always follow C89 in object-like macros. + Likewise, in a function-like macro it must cause infinite + recursion unless we are actually doing something with the + arguments. + + Even that criterion is too weak. The only example known where + macro recursion isn't infinite is: + #define bar(x,y) foo(x(y, 0)) + bar(bar, baz) + which expands to foo(bar(baz, 0)) in C89 and + foo(foo(baz(0, 0)) in K+R. This looks pathological to me. + If someone has a real-world example I would love to see it. */ + if (hp->type != T_FMACRO + || hp->value.defn->nargs == 0 + || hp->value.defn->pattern == 0 + || !CPP_TRADITIONAL (pfile)) + hp->disabled = 1; } /* Return zero if two DEFINITIONs are isomorphic. */ -int -_cpp_compare_defs (pfile, d1, d2) +static int +compare_defs (pfile, d1, d2) cpp_reader *pfile; DEFINITION *d1, *d2; { @@ -1590,93 +1786,109 @@ _cpp_compare_defs (pfile, d1, d2) to be read back in again. */ void -_cpp_dump_definition (pfile, sym, len, defn) +_cpp_dump_definition (pfile, hp) cpp_reader *pfile; - const U_CHAR *sym; - long len; - DEFINITION *defn; + HASHNODE *hp; { - CPP_RESERVE (pfile, len + sizeof "#define "); - CPP_PUTS_Q (pfile, "#define ", sizeof "#define " -1); - CPP_PUTS_Q (pfile, sym, len); + CPP_RESERVE (pfile, hp->length + sizeof "#define "); + CPP_PUTS_Q (pfile, "#define ", sizeof "#define " - 1); + CPP_PUTS_Q (pfile, hp->name, hp->length); - if (defn->nargs == -1) + if (hp->type == T_EMPTY) + /* do nothing */; + else if (hp->type == T_FMACRO) + dump_DEFINITION (pfile, hp->value.defn); + else { CPP_PUTC_Q (pfile, ' '); - /* The first and last two characters of a macro expansion are - always "\r "; this needs to be trimmed out. - So we need length-4 chars of space, plus one for the NUL. */ - CPP_RESERVE (pfile, defn->length - 4 + 1); - CPP_PUTS_Q (pfile, defn->expansion + 2, defn->length - 4); - } - else - { - struct reflist *r; - unsigned char **argv = (unsigned char **) alloca (defn->nargs * - sizeof(char *)); - int *argl = (int *) alloca (defn->nargs * sizeof(int)); - unsigned char *x; - int i; - - /* First extract the argument list. */ - x = defn->argnames; - for (i = 0; i < defn->nargs; i++) + if (hp->type == T_IDENTITY) + CPP_PUTS (pfile, hp->name, hp->length); + else if (hp->type == T_MCONST) + CPP_PUTS (pfile, hp->value.cpval, strlen (hp->value.cpval)); + else if (hp->type == T_MACRO) { - argv[i] = x; - argl[i] = strlen (x); - x += argl[i] + 1; + /* The first and last two characters of a macro expansion are + always "\r "; this needs to be trimmed out. + So we need length-4 chars of space, plus one for the NUL. */ + CPP_RESERVE (pfile, hp->value.defn->length - 4 + 1); + CPP_PUTS_Q (pfile, hp->value.defn->expansion + 2, + hp->value.defn->length - 4); } - - /* Now print out the argument list. */ - CPP_PUTC_Q (pfile, '('); - for (i = 0; i < defn->nargs; i++) - { - CPP_RESERVE (pfile, argl[i] + 2); - if (!(i == defn->nargs-1 && defn->rest_args - && !strcmp (argv[i], "__VA_ARGS__"))) - CPP_PUTS_Q (pfile, argv[i], argl[i]); - if (i < defn->nargs-1) - CPP_PUTS_Q (pfile, ", ", 2); - } - if (defn->rest_args) - CPP_PUTS (pfile, "...", 3); - CPP_PUTS (pfile, ") ", 2); - - /* Now the definition. */ - x = defn->expansion; - for (r = defn->pattern; r; r = r->next) - { - i = r->nchars; - if (*x == '\r') x += 2, i -= 2; - /* i chars for macro text, plus the length of the macro - argument name, plus one for a stringify marker, plus two for - each concatenation marker. */ - CPP_RESERVE (pfile, - i + argl[r->argno] + r->stringify - + (r->raw_before + r->raw_after) * 2); - - if (i > 0) CPP_PUTS_Q (pfile, x, i); - if (r->raw_before) - CPP_PUTS_Q (pfile, "##", 2); - if (r->stringify) - CPP_PUTC_Q (pfile, '#'); - CPP_PUTS_Q (pfile, argv[r->argno], argl[r->argno]); - if (r->raw_after && !(r->next && r->next->nchars == 0 - && r->next->raw_before)) - CPP_PUTS_Q (pfile, "##", 2); - - x += i; - } - - i = defn->length - (x - defn->expansion) - 2; - if (*x == '\r') x += 2, i -= 2; - if (i > 0) CPP_PUTS (pfile, x, i); + else + cpp_ice (pfile, "invalid hash type %d in dump_definition", hp->type); } if (CPP_BUFFER (pfile) == 0 || ! pfile->done_initializing) CPP_PUTC (pfile, '\n'); } +static void +dump_DEFINITION (pfile, defn) + cpp_reader *pfile; + DEFINITION *defn; +{ + struct reflist *r; + unsigned char **argv = (unsigned char **) alloca (defn->nargs * + sizeof(char *)); + int *argl = (int *) alloca (defn->nargs * sizeof(int)); + unsigned char *x; + int i; + + /* First extract the argument list. */ + x = defn->argnames; + for (i = 0; i < defn->nargs; i++) + { + argv[i] = x; + argl[i] = strlen (x); + x += argl[i] + 1; + } + + /* Now print out the argument list. */ + CPP_PUTC_Q (pfile, '('); + for (i = 0; i < defn->nargs; i++) + { + CPP_RESERVE (pfile, argl[i] + 2); + if (!(i == defn->nargs-1 && defn->rest_args + && !strcmp (argv[i], "__VA_ARGS__"))) + CPP_PUTS_Q (pfile, argv[i], argl[i]); + if (i < defn->nargs-1) + CPP_PUTS_Q (pfile, ", ", 2); + } + if (defn->rest_args) + CPP_PUTS (pfile, "...", 3); + CPP_PUTS (pfile, ") ", 2); + + /* Now the definition. */ + x = defn->expansion; + for (r = defn->pattern; r; r = r->next) + { + i = r->nchars; + if (*x == '\r') x += 2, i -= 2; + /* i chars for macro text, plus the length of the macro + argument name, plus one for a stringify marker, plus two for + each concatenation marker. */ + CPP_RESERVE (pfile, + i + argl[r->argno] + r->stringify + + (r->raw_before + r->raw_after) * 2); + + if (i > 0) CPP_PUTS_Q (pfile, x, i); + if (r->raw_before) + CPP_PUTS_Q (pfile, "##", 2); + if (r->stringify) + CPP_PUTC_Q (pfile, '#'); + CPP_PUTS_Q (pfile, argv[r->argno], argl[r->argno]); + if (r->raw_after && !(r->next && r->next->nchars == 0 + && r->next->raw_before)) + CPP_PUTS_Q (pfile, "##", 2); + + x += i; + } + + i = defn->length - (x - defn->expansion) - 2; + if (*x == '\r') x += 2, i -= 2; + if (i > 0) CPP_PUTS (pfile, x, i); +} + /* Dump out the hash table. */ static int dump_hash_helper (h, p) @@ -1687,7 +1899,7 @@ dump_hash_helper (h, p) cpp_reader *pfile = (cpp_reader *)p; if (hp->type == T_MACRO) - _cpp_dump_definition (pfile, hp->name, hp->length, hp->value.defn); + _cpp_dump_definition (pfile, hp); return 1; } diff --git a/gcc/cpphash.h b/gcc/cpphash.h index 2b8a5d1fa1a..78185f2001d 100644 --- a/gcc/cpphash.h +++ b/gcc/cpphash.h @@ -64,9 +64,6 @@ struct definition int nargs; int length; /* length of expansion string */ U_CHAR *expansion; - int line; /* Line number of definition */ - int col; - const char *file; /* File of definition */ char rest_args; /* Nonzero if last arg. absorbs the rest */ struct reflist *pattern; @@ -86,6 +83,7 @@ struct definition /* different flavors of hash nodes */ enum node_type { + T_VOID = 0, /* no definition yet */ T_SPECLINE, /* `__LINE__' */ T_DATE, /* `__DATE__' */ T_FILE, /* `__FILE__' */ @@ -94,10 +92,12 @@ enum node_type T_TIME, /* `__TIME__' */ T_STDC, /* `__STDC__' */ T_CONST, /* Constant string, used by `__SIZE_TYPE__' etc */ - T_MCONST, /* Ditto, but the string is malloced memory */ - T_MACRO, /* macro defined by `#define' */ - T_DISABLED, /* macro temporarily turned off for rescan */ - T_POISON, /* macro defined with `#pragma poison' */ + T_XCONST, /* Ditto, but the string is malloced memory */ + T_POISON, /* poisoned identifier */ + T_MCONST, /* object-like macro defined to a single identifier */ + T_MACRO, /* general object-like macro */ + T_FMACRO, /* general function-like macro */ + T_IDENTITY, /* macro defined to itself */ T_EMPTY /* macro defined to nothing */ }; @@ -118,6 +118,11 @@ struct hashnode unsigned long hash; /* cached hash value */ union hashval value; /* pointer to expansion, or whatever */ enum node_type type; /* type of special token */ + int disabled; /* macro turned off for rescan? */ + + const char *file; /* File, line, column of definition; */ + int line; + int col; }; /* List of directories to look for include files in. */ @@ -272,12 +277,9 @@ extern HASHNODE **_cpp_lookup_slot PARAMS ((cpp_reader *, enum insert_option, unsigned long *)); extern void _cpp_free_definition PARAMS ((DEFINITION *)); -extern DEFINITION *_cpp_create_definition PARAMS ((cpp_reader *, - cpp_toklist *, int)); -extern void _cpp_dump_definition PARAMS ((cpp_reader *, const U_CHAR *, - long, DEFINITION *)); -extern int _cpp_compare_defs PARAMS ((cpp_reader *, DEFINITION *, - DEFINITION *)); +extern int _cpp_create_definition PARAMS ((cpp_reader *, + cpp_toklist *, HASHNODE *)); +extern void _cpp_dump_definition PARAMS ((cpp_reader *, HASHNODE *)); extern void _cpp_quote_string PARAMS ((cpp_reader *, const char *)); extern void _cpp_macroexpand PARAMS ((cpp_reader *, HASHNODE *)); extern void _cpp_init_macro_hash PARAMS ((cpp_reader *)); diff --git a/gcc/cppinit.c b/gcc/cppinit.c index d1e7c117b26..957e6112fef 100644 --- a/gcc/cppinit.c +++ b/gcc/cppinit.c @@ -635,7 +635,7 @@ static const struct builtin builtin_array[] = { "__LINE__", 0, T_SPECLINE, 0 }, { "__INCLUDE_LEVEL__", 0, T_INCLUDE_LEVEL, 0 }, - { "__VERSION__", 0, T_MCONST, DUMP|VERS }, + { "__VERSION__", 0, T_XCONST, DUMP|VERS }, { "__USER_LABEL_PREFIX__", 0, T_CONST, DUMP|ULP }, { "__STDC__", "1", T_STDC, DUMP }, { "__REGISTER_PREFIX__", REGISTER_PREFIX, T_CONST, DUMP }, diff --git a/gcc/cpplex.c b/gcc/cpplex.c index 3e6a89feac5..f46b63892bb 100644 --- a/gcc/cpplex.c +++ b/gcc/cpplex.c @@ -1455,7 +1455,7 @@ maybe_macroexpand (pfile, written) if (!hp) return 0; - if (hp->type == T_DISABLED) + if (hp->disabled || hp->type == T_IDENTITY) { if (pfile->output_escapes) { @@ -1479,7 +1479,7 @@ maybe_macroexpand (pfile, written) } /* If macro wants an arglist, verify that a '(' follows. */ - if (hp->type == T_MACRO && hp->value.defn->nargs >= 0) + if (hp->type == T_FMACRO) { int macbuf_whitespace = 0; int c; diff --git a/gcc/cpplib.c b/gcc/cpplib.c index 7f2554bfc06..5bb51623d3b 100644 --- a/gcc/cpplib.c +++ b/gcc/cpplib.c @@ -316,10 +316,8 @@ do_define (pfile) cpp_reader *pfile; { HASHNODE **slot; - DEFINITION *def = 0; unsigned long hash; int len; - int funlike = 0, empty = 0; U_CHAR *sym; cpp_toklist *list = &pfile->directbuf; @@ -350,90 +348,26 @@ do_define (pfile) goto out; } - - if (list->tokens_used == 2 && list->tokens[1].type == CPP_VSPACE) - empty = 1; /* Empty definition of object-like macro. */ - - /* If the next character, with no intervening whitespace, is '(', - then this is a function-like macro. Otherwise it is an object- - like macro, and C99 requires whitespace after the name - (6.10.3 para 3). */ - else if (!(list->tokens[1].flags & HSPACE_BEFORE)) - { - if (list->tokens[1].type == CPP_OPEN_PAREN) - funlike = 1; - else - cpp_pedwarn (pfile, - "The C standard requires whitespace after #define %.*s", - len, sym); - } - - if (! empty) - { - def = _cpp_create_definition (pfile, list, funlike); - if (def == 0) - goto out; - } - slot = _cpp_lookup_slot (pfile, sym, len, INSERT, &hash); if (*slot) { - int ok; - HASHNODE *hp = *slot; - - /* Redefining a macro is ok if the definitions are the same. */ - if (hp->type == T_MACRO) - ok = ! empty && ! _cpp_compare_defs (pfile, def, hp->value.defn); - else if (hp->type == T_EMPTY) - ok = empty; - /* Redefining a constant is ok with -D. */ - else if (hp->type == T_CONST || hp->type == T_STDC) - ok = ! pfile->done_initializing; - /* Otherwise it's not ok. */ - else - ok = 0; - /* Print the warning or error if it's not ok. */ - if (! ok) + /* Check for poisoned identifiers now. All other checks + are done in cpphash.c. */ + if ((*slot)->type == T_POISON) { - if (hp->type == T_POISON) - cpp_error (pfile, "redefining poisoned `%.*s'", len, sym); - else - cpp_pedwarn (pfile, "`%.*s' redefined", len, sym); - if (hp->type == T_MACRO && pfile->done_initializing) - { - DEFINITION *d = hp->value.defn; - cpp_pedwarn_with_file_and_line (pfile, d->file, d->line, d->col, - "this is the location of the previous definition"); - } - } - if (hp->type != T_POISON) - { - /* Replace the old definition. */ - if (hp->type == T_MACRO) - _cpp_free_definition (hp->value.defn); - if (empty) - { - hp->type = T_EMPTY; - hp->value.defn = 0; - } - else - { - hp->type = T_MACRO; - hp->value.defn = def; - } + cpp_error (pfile, "redefining poisoned `%.*s'", len, sym); + goto out; } } else - { - HASHNODE *hp = _cpp_make_hashnode (sym, len, empty ? T_EMPTY : T_MACRO, - hash); - hp->value.defn = def; - *slot = hp; - } + *slot = _cpp_make_hashnode (sym, len, T_VOID, hash); + + if (_cpp_create_definition (pfile, list, *slot) == 0) + goto out; if (CPP_OPTION (pfile, debug_output) || CPP_OPTION (pfile, dump_macros) == dump_definitions) - _cpp_dump_definition (pfile, sym, len, def); + _cpp_dump_definition (pfile, *slot); else if (CPP_OPTION (pfile, dump_macros) == dump_names) pass_thru_directive (sym, len, pfile, T_DEFINE); @@ -769,7 +703,9 @@ do_undef (pfile) if (CPP_OPTION (pfile, debug_output)) pass_thru_directive (hp->name, len, pfile, T_UNDEF); - if (hp->type != T_MACRO && hp->type != T_EMPTY) + if (hp->type != T_MACRO && hp->type != T_FMACRO + && hp->type != T_MCONST + && hp->type != T_EMPTY && hp->type != T_IDENTITY) cpp_warning (pfile, "undefining `%s'", hp->name); htab_clear_slot (pfile->hashtab, (void **)slot);