From ba412f14ad13a1e71af1aebe1ee97c6591e1f12e Mon Sep 17 00:00:00 2001 From: Zack Weinberg Date: Wed, 1 Mar 2000 00:57:09 +0000 Subject: [PATCH] cpplib.h (CPP_ASSERTION, [...]): New token types. * cpplib.h (CPP_ASSERTION, CPP_STRINGIZE, CPP_TOKPASTE): New token types. (struct cpp_reader): Add parsing_if_directive and parsing_define_directive flags. (struct cpp_options): Remove output_conditionals flag. (check_macro_name): Delete prototype. * cpphash.h (struct macrodef): Delete. (struct reflist): Separate from struct definition. (struct definition): Remove unused fields. Add column number. (create_definition): Returns a DEFINITION *. Takes a cpp_reader * and an int. * cpphash.c (SKIP_WHITE_SPACE): Delete. (PEEKC): Copy defn from cpplib.c. (rest_extension, REST_EXTENSION_LENGTH): Delete. (struct arg): New. (struct arglist): Simplify. (collect_expansion): Rewrite. Get tokens by calling cpp_get_token. Add more error checking. (collect_formal_parameters): New function, broken out of create_definition and reworked to use get_directive_token. (create_definition): All real work is now in collect_expansion and collect_formal_parameters. do_define handles finding the macro name. Return a DEFINITION, not a MACRODEF. (macroexpand): Replace bcopy with memcpy throughout. Replace character-at-a-time copy loop with memcpy and pointer increments. (compare-defs): d1->argnames / d2->argnames might be null. * cpplib.c (copy_rest_of_line): Delete function. (skip_rest_of_line): Do all the work ourselves. (skip_string): New function. (parse_string): Use skip_string. (get_macro_name): New function. (check_macro_name): Delete. (copy_comment): Use CPP_RESERVE and CPP_PUTC_Q. (cpp_skip_hspace): Use CPP_BUMP_LINE. (handle_directive): ICE if we're called on a macro buffer. (do_define): Determine macro name and type (funlike/objlike) here. Expunge all uses of MACRODEF. (cpp_push_buffer): Set line_base to NULL. (do_undef, read_line_number): Don't worry about getting a POP token. (eval_if_expression): Set/reset parsing_if_directive around cpp_parse_expr. Don't clear only_seen_white. (skip_if_group): Remove output_conditionals logic. Use skip_rest_of_line. (cpp_get_token): Return ASSERTION, STRINGIZE, and TOKPASTE tokens under appropriate conditions. (cpp_unassert): Call do_unassert not do_assert. Oops. * cppexp.c (parse_defined): New function, break out of cpp_lex. (cpp_lex): We now get CPP_ASSERTION tokens and can check them ourselves, with cpp_defined. * cppinit.c (cpp_handle_option, print_help): Delete -ifoutput. * gcc.dg/20000209-2.c: Turn off -pedantic-errors. * gcc.dg/strpaste-2.c: New. From-SVN: r32274 --- gcc/ChangeLog | 61 ++ gcc/cppexp.c | 106 ++-- gcc/cpphash.c | 966 +++++++++++++++--------------- gcc/cpphash.h | 53 +- gcc/cppinit.c | 4 - gcc/cpplib.c | 344 +++++------ gcc/cpplib.h | 35 +- gcc/testsuite/gcc.dg/20000209-2.c | 4 +- gcc/testsuite/gcc.dg/strpaste-2.c | 23 + 9 files changed, 818 insertions(+), 778 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/strpaste-2.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index c65598e2214..c2638d3235e 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,64 @@ +2000-02-29 Zack Weinberg + + * cpplib.h (CPP_ASSERTION, CPP_STRINGIZE, CPP_TOKPASTE): New + token types. + (struct cpp_reader): Add parsing_if_directive and + parsing_define_directive flags. + (struct cpp_options): Remove output_conditionals flag. + (check_macro_name): Delete prototype. + + * cpphash.h (struct macrodef): Delete. + (struct reflist): Separate from struct definition. + (struct definition): Remove unused fields. Add column number. + (create_definition): Returns a DEFINITION *. Takes a + cpp_reader * and an int. + + * cpphash.c (SKIP_WHITE_SPACE): Delete. + (PEEKC): Copy defn from cpplib.c. + (rest_extension, REST_EXTENSION_LENGTH): Delete. + (struct arg): New. + (struct arglist): Simplify. + (collect_expansion): Rewrite. Get tokens by calling + cpp_get_token. Add more error checking. + (collect_formal_parameters): New function, broken out of + create_definition and reworked to use get_directive_token. + (create_definition): All real work is now in collect_expansion + and collect_formal_parameters. do_define handles finding the + macro name. Return a DEFINITION, not a MACRODEF. + (macroexpand): Replace bcopy with memcpy throughout. Replace + character-at-a-time copy loop with memcpy and pointer increments. + (compare-defs): d1->argnames / d2->argnames might be null. + + * cpplib.c (copy_rest_of_line): Delete function. + (skip_rest_of_line): Do all the work ourselves. + (skip_string): New function. + (parse_string): Use skip_string. + (get_macro_name): New function. + (check_macro_name): Delete. + (copy_comment): Use CPP_RESERVE and CPP_PUTC_Q. + (cpp_skip_hspace): Use CPP_BUMP_LINE. + (handle_directive): ICE if we're called on a macro buffer. + (do_define): Determine macro name and type (funlike/objlike) + here. Expunge all uses of MACRODEF. + (cpp_push_buffer): Set line_base to NULL. + (do_undef, read_line_number): Don't worry about getting a POP token. + (eval_if_expression): Set/reset parsing_if_directive around + cpp_parse_expr. Don't clear only_seen_white. + (skip_if_group): Remove output_conditionals logic. Use + skip_rest_of_line. + (cpp_get_token): Return ASSERTION, STRINGIZE, and TOKPASTE + tokens under appropriate conditions. + (cpp_unassert): Call do_unassert not do_assert. Oops. + + * cppexp.c (parse_defined): New function, break out of + cpp_lex. + (cpp_lex): We now get CPP_ASSERTION tokens and can check them + ourselves, with cpp_defined. + * cppinit.c (cpp_handle_option, print_help): Delete -ifoutput. + + * gcc.dg/20000209-2.c: Turn off -pedantic-errors. + * gcc.dg/strpaste-2.c: New. + 2000-02-29 Mark Mitchell * fold-const.c (size_binop): Don't asert inputs are the same and diff --git a/gcc/cppexp.c b/gcc/cppexp.c index f6595596c01..ec9fecf5134 100644 --- a/gcc/cppexp.c +++ b/gcc/cppexp.c @@ -81,6 +81,7 @@ static HOST_WIDEST_INT left_shift PARAMS ((cpp_reader *, HOST_WIDEST_INT, int, u static HOST_WIDEST_INT right_shift PARAMS ((cpp_reader *, HOST_WIDEST_INT, int, unsigned HOST_WIDEST_INT)); static struct operation parse_number PARAMS ((cpp_reader *, U_CHAR *, U_CHAR *)); static struct operation parse_charconst PARAMS ((cpp_reader *, U_CHAR *, U_CHAR *)); +static struct operation parse_defined PARAMS ((cpp_reader *)); static struct operation cpp_lex PARAMS ((cpp_reader *, int)); extern HOST_WIDEST_INT cpp_parse_expr PARAMS ((cpp_reader *)); static HOST_WIDEST_INT cpp_parse_escape PARAMS ((cpp_reader *, U_CHAR **, HOST_WIDEST_INT)); @@ -349,6 +350,53 @@ parse_charconst (pfile, start, end) return op; } +static struct operation +parse_defined (pfile) + cpp_reader *pfile; +{ + int paren = 0, len; + U_CHAR *tok; + enum cpp_token token; + struct operation op; + long old_written = CPP_WRITTEN (pfile); + + op.unsignedp = 0; + op.op = INT; + + pfile->no_macro_expand++; + token = get_directive_token (pfile); + if (token == CPP_LPAREN) + { + paren++; + CPP_SET_WRITTEN (pfile, old_written); + token = get_directive_token (pfile); + } + + if (token != CPP_NAME) + goto oops; + + tok = pfile->token_buffer + old_written; + len = CPP_PWRITTEN (pfile) - tok; + op.value = cpp_defined (pfile, tok, len); + + if (paren) + { + if (get_directive_token (pfile) != CPP_RPAREN) + goto oops; + } + CPP_SET_WRITTEN (pfile, old_written); + pfile->no_macro_expand--; + return op; + + oops: + CPP_SET_WRITTEN (pfile, old_written); + pfile->no_macro_expand--; + cpp_error (pfile, "`defined' without an identifier"); + + op.op = ERROR; + return op; +} + struct token { const char *operator; @@ -389,7 +437,7 @@ cpp_lex (pfile, skip_evaluation) tok_end = CPP_PWRITTEN (pfile); CPP_SET_WRITTEN (pfile, old_written); switch (token) - { + { case CPP_EOF: /* Should not happen ... */ case CPP_VSPACE: op.op = 0; @@ -407,51 +455,22 @@ cpp_lex (pfile, skip_evaluation) return parse_charconst (pfile, tok_start, tok_end); case CPP_NAME: + if (!strcmp (tok_start, "defined")) + return parse_defined (pfile); + op.op = INT; op.unsignedp = 0; op.value = 0; - if (strcmp (tok_start, "defined")) - { - if (CPP_WARN_UNDEF (pfile) && !skip_evaluation) - cpp_warning (pfile, "`%.*s' is not defined", - (int) (tok_end - tok_start), tok_start); - } - else - { - int paren = 0, len; - U_CHAR *tok; - pfile->no_macro_expand++; - token = get_directive_token (pfile); - if (token == CPP_LPAREN) - { - paren++; - CPP_SET_WRITTEN (pfile, old_written); - token = get_directive_token (pfile); - } - - if (token != CPP_NAME) - goto oops; - - tok = pfile->token_buffer + old_written; - len = CPP_PWRITTEN (pfile) - tok; - if (cpp_defined (pfile, tok, len)) - op.value = 1; - - if (paren) - { - if (get_directive_token (pfile) != CPP_RPAREN) - goto oops; - } - CPP_SET_WRITTEN (pfile, old_written); - pfile->no_macro_expand--; - } + if (CPP_WARN_UNDEF (pfile) && !skip_evaluation) + cpp_warning (pfile, "`%.*s' is not defined", + (int) (tok_end - tok_start), tok_start); return op; - oops: - CPP_SET_WRITTEN (pfile, old_written); - pfile->no_macro_expand--; - cpp_error (pfile, "`defined' without an identifier"); + case CPP_ASSERTION: + op.op = INT; + op.unsignedp = 0; + op.value = cpp_defined (pfile, tok_start, tok_end - tok_start); return op; case CPP_OTHER: @@ -468,13 +487,6 @@ cpp_lex (pfile, skip_evaluation) op.op = toktab->token; return op; } - else if (tok_start + 1 == tok_end && *tok_start == '#') - { - CPP_FORWARD (CPP_BUFFER (pfile), -1); - op.op = INT; - op.value = cpp_read_check_assertion (pfile); - return op; - } /* fall through */ default: op.op = *tok_start; diff --git a/gcc/cpphash.c b/gcc/cpphash.c index 9d79979a876..c5c20ac9bf8 100644 --- a/gcc/cpphash.c +++ b/gcc/cpphash.c @@ -41,10 +41,9 @@ static enum cpp_token macarg PARAMS ((cpp_reader *, int)); static struct tm *timestamp PARAMS ((cpp_reader *)); static void special_symbol PARAMS ((HASHNODE *, cpp_reader *)); - -#define SKIP_WHITE_SPACE(p) do { while (is_hspace(*p)) p++; } while (0) #define CPP_IS_MACRO_BUFFER(PBUF) ((PBUF)->data != NULL) #define FORWARD(N) CPP_FORWARD (CPP_BUFFER (pfile), (N)) +#define PEEKC() CPP_BUF_PEEK (CPP_BUFFER (pfile)) /* The arglist structure is built by create_definition to tell collect_expansion where the argument names begin. That @@ -57,17 +56,23 @@ static void special_symbol PARAMS ((HASHNODE *, cpp_reader *)); the current #define has been processed and entered into the hash table. */ -struct arglist +struct arg { - struct arglist *next; U_CHAR *name; - int length; - int argno; - char rest_args; + int len; + char rest_arg; }; -static DEFINITION *collect_expansion PARAMS ((cpp_reader *, U_CHAR *, U_CHAR *, - int, struct arglist *)); +struct arglist +{ + U_CHAR *namebuf; + struct arg *argv; + int argc; +}; + + +static DEFINITION *collect_expansion PARAMS ((cpp_reader *, struct arglist *)); +static struct arglist *collect_formal_parameters PARAMS ((cpp_reader *)); /* This structure represents one parsed argument in a macro call. `raw' points to the argument text as written (`raw_length' is its length). @@ -251,502 +256,470 @@ macro_cleanup (pbuf, pfile) } -/* Read a replacement list for a macro with parameters. - Build the DEFINITION structure. - Reads characters of text starting at BUF until END. - ARGLIST specifies the formal parameters to look for - in the text of the definition; NARGS is the number of args - in that list, or -1 for a macro name that wants no argument list. - MACRONAME is the macro name itself (so we can avoid recursive expansion) - and NAMELEN is its length in characters. - - Note that comments, backslash-newlines, and leading white space - have already been deleted from the argument. */ +/* Read a replacement list for a macro, and build the DEFINITION + structure. 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. + + A good half of this is devoted to supporting -traditional. + Kill me now. */ static DEFINITION * -collect_expansion (pfile, buf, limit, nargs, arglist) +collect_expansion (pfile, arglist) cpp_reader *pfile; - U_CHAR *buf, *limit; - int nargs; struct arglist *arglist; { DEFINITION *defn; - register U_CHAR *p, *lastp, *exp_p; - struct reflist *endpat = NULL; - /* Pointer to first nonspace after last ## seen. */ - U_CHAR *concat = 0; - /* Pointer to first nonspace after last single-# seen. */ - U_CHAR *stringify = 0; - int maxsize; - int expected_delimiter = '\0'; + struct reflist *pat = 0, *endpat = 0; + enum cpp_token token; + long start, here, last; + int i; + int argc; + size_t len; + struct arg *argv; + U_CHAR *tok, *exp; + enum { START = 0, NORM, ARG, STRIZE, PASTE } last_token = START; - /* Scan thru the replacement list, ignoring comments and quoted - strings, picking up on the macro calls. It does a linear search - thru the arg list on every potential symbol. Profiling might say - that something smarter should happen. */ - - if (limit < buf) + if (arglist) { - cpp_ice (pfile, "limit < buf in collect_expansion"); - limit = buf; /* treat it like a null defn */ - } - - /* Find the beginning of the trailing whitespace. */ - p = buf; - while (p < limit && is_space(limit[-1])) - limit--; - - /* Allocate space for the text in the macro definition. - Leading and trailing whitespace chars need 2 bytes each. - Each other input char may or may not need 1 byte, - so this is an upper bound. The extra 5 are for invented - leading and trailing escape-marker and final null. */ - maxsize = (sizeof (DEFINITION) - + (limit - p) + 5); - defn = (DEFINITION *) xcalloc (1, maxsize); - - defn->nargs = nargs; - exp_p = defn->expansion = (U_CHAR *) defn + sizeof (DEFINITION); - lastp = exp_p; - - p = buf; - - /* Add one initial space escape-marker to prevent accidental - token-pasting (often removed by macroexpand). */ - *exp_p++ = '\r'; - *exp_p++ = ' '; - - if (limit - p >= 2 && p[0] == '#' && p[1] == '#') - { - cpp_error (pfile, "`##' at start of macro definition"); - p += 2; - } - - /* Process the main body of the definition. */ - while (p < limit) - { - int skipped_arg = 0; - register U_CHAR c = *p++; - - *exp_p++ = c; - - if (!CPP_TRADITIONAL (pfile)) - { - switch (c) - { - case '\'': - case '\"': - if (expected_delimiter != '\0') - { - if (c == expected_delimiter) - expected_delimiter = '\0'; - } - else - expected_delimiter = c; - break; - - case '\\': - if (p < limit && expected_delimiter) - { - /* In a string, backslash goes through - and makes next char ordinary. */ - *exp_p++ = *p++; - } - break; - - case '#': - /* # is ordinary inside a string. */ - if (expected_delimiter) - break; - if (p < limit && *p == '#') - { - /* ##: concatenate preceding and following tokens. */ - /* Take out the first #, discard preceding whitespace. */ - exp_p--; - while (exp_p > lastp && is_hspace(exp_p[-1])) - --exp_p; - /* Skip the second #. */ - p++; - /* Discard following whitespace. */ - SKIP_WHITE_SPACE (p); - concat = p; - if (p == limit) - cpp_error (pfile, "`##' at end of macro definition"); - } - else if (nargs >= 0) - { - /* Single #: stringify following argument ref. - Don't leave the # in the expansion. */ - exp_p--; - SKIP_WHITE_SPACE (p); - if (p == limit || !is_idstart(*p) - || (*p == 'L' && p + 1 < limit && (p[1] == '\'' || - p[1] == '"'))) - cpp_error (pfile, - "`#' operator is not followed by a macro argument name"); - else - stringify = p; - } - break; - } - } - else - { - /* In -traditional mode, recognize arguments inside strings and - character constants, and ignore special properties of #. - Arguments inside strings are considered "stringified", but no - extra quote marks are supplied. */ - switch (c) - { - case '\'': - case '\"': - if (expected_delimiter != '\0') - { - if (c == expected_delimiter) - expected_delimiter = '\0'; - } - else - expected_delimiter = c; - break; - - case '\\': - /* Backslash quotes delimiters and itself, - but not macro args. */ - if (expected_delimiter != 0 && p < limit - && (*p == expected_delimiter || *p == '\\')) - { - *exp_p++ = *p++; - continue; - } - break; - - case '/': - if (expected_delimiter != '\0') - /* No comments inside strings. */ - break; - if (*p == '*') - { - /* If we find a comment that wasn't removed by - handle_directive, this must be -traditional. - So replace the comment with nothing at all. */ - exp_p--; - p += 1; - while (p < limit && !(p[-2] == '*' && p[-1] == '/')) - p++; - } - break; - } - } - - /* Handle the start of a symbol. */ - if (is_idchar(c) && nargs > 0) - { - U_CHAR *id_beg = p - 1; - int id_len; - - --exp_p; - while (p != limit && is_idchar(*p)) - p++; - id_len = p - id_beg; - - if (is_idstart(c) - && !(id_len == 1 && c == 'L' && (*p == '\'' || *p == '"'))) - { - register struct arglist *arg; - - for (arg = arglist; arg != NULL; arg = arg->next) - { - struct reflist *tpat; - - if (arg->name[0] == c - && arg->length == id_len - && strncmp (arg->name, id_beg, id_len) == 0) - { - if (expected_delimiter && CPP_OPTIONS - (pfile)->warn_stringify) - { - if (CPP_TRADITIONAL (pfile)) - { - cpp_warning (pfile, - "macro argument `%.*s' is stringified.", - id_len, arg->name); - } - else - { - cpp_warning (pfile, - "macro arg `%.*s' would be stringified with -traditional.", - id_len, arg->name); - } - } - /* If ANSI, don't actually substitute - inside a string. */ - if (!CPP_TRADITIONAL (pfile) && expected_delimiter) - break; - /* make a pat node for this arg and append it - to the end of the pat list */ - tpat = (struct reflist *) - xmalloc (sizeof (struct reflist)); - tpat->next = NULL; - tpat->raw_before = concat == id_beg; - tpat->raw_after = 0; - tpat->rest_args = arg->rest_args; - tpat->stringify = (CPP_TRADITIONAL (pfile) - ? expected_delimiter != '\0' - : stringify == id_beg); - - if (endpat == NULL) - defn->pattern = tpat; - else - endpat->next = tpat; - endpat = tpat; - - tpat->argno = arg->argno; - tpat->nchars = exp_p - lastp; - { - register U_CHAR *p1 = p; - SKIP_WHITE_SPACE (p1); - if (p1 + 2 <= limit && p1[0] == '#' && p1[1] == '#') - tpat->raw_after = 1; - } - lastp = exp_p; - skipped_arg = 1; - break; - } - } - } - - /* If this was not a macro arg, copy it into the expansion. */ - if (!skipped_arg) - { - register U_CHAR *lim1 = p; - p = id_beg; - while (p != lim1) - *exp_p++ = *p++; - if (stringify == id_beg) - cpp_error (pfile, - "`#' operator should be followed by a macro argument name"); - } - } - } - - if (!CPP_TRADITIONAL (pfile) && expected_delimiter == 0) - { - /* If ANSI, put in a "\r " marker to prevent token pasting. - But not if "inside a string" (which in ANSI mode - happens only for -D option). */ - *exp_p++ = '\r'; - *exp_p++ = ' '; - } - - *exp_p = '\0'; - - defn->length = exp_p - defn->expansion; - - /* Crash now if we overrun the allocated size. */ - if (defn->length + 1 > maxsize) - abort (); - -#if 0 -/* This isn't worth the time it takes. */ - /* give back excess storage */ - defn->expansion = (U_CHAR *) xrealloc (defn->expansion, defn->length + 1); -#endif - - return defn; -} - -/* - * special extension string that can be added to the last macro argument to - * allow it to absorb the "rest" of the arguments when expanded. Ex: - * #define wow(a, b...) process (b, a, b) - * { wow (1, 2, 3); } -> { process (2, 3, 1, 2, 3); } - * { wow (one, two); } -> { process (two, one, two); } - * if this "rest_arg" is used with the concat token '##' and if it is not - * supplied then the token attached to with ## will not be outputted. Ex: - * #define wow (a, b...) process (b ## , a, ## b) - * { wow (1, 2); } -> { process (2, 1, 2); } - * { wow (one); } -> { process (one); { - */ -static char rest_extension[] = "..."; -#define REST_EXTENSION_LENGTH (sizeof (rest_extension) - 1) - -/* Create a DEFINITION node from a #define directive. Arguments are - as for do_define. */ - -MACRODEF -create_definition (buf, limit, pfile) - U_CHAR *buf, *limit; - cpp_reader *pfile; -{ - U_CHAR *bp; /* temp ptr into input buffer */ - U_CHAR *symname; /* remember where symbol name starts */ - int sym_length; /* and how long it is */ - int rest_args = 0; - long line, col; - const char *file = - CPP_BUFFER (pfile) ? CPP_BUFFER (pfile)->nominal_fname : ""; - DEFINITION *defn; - int arglengths = 0; /* Accumulate lengths of arg names - plus number of args. */ - MACRODEF mdef; - cpp_buf_line_and_col (CPP_BUFFER (pfile), &line, &col); - - bp = buf; - - while (is_hspace(*bp)) - bp++; - - symname = bp; /* remember where it starts */ - - sym_length = check_macro_name (pfile, bp); - bp += sym_length; - - /* Lossage will occur if identifiers or control keywords are broken - across lines using backslash. This is not the right place to take - care of that. */ - - if (*bp == '(') - { - struct arglist *arg_ptrs = NULL; - int argno = 0; - - bp++; /* skip '(' */ - SKIP_WHITE_SPACE (bp); - - /* Loop over macro argument names. */ - while (*bp != ')') - { - struct arglist *temp; - - temp = (struct arglist *) alloca (sizeof (struct arglist)); - temp->name = bp; - temp->next = arg_ptrs; - temp->argno = argno++; - temp->rest_args = 0; - arg_ptrs = temp; - - if (rest_args) - cpp_pedwarn (pfile, "another parameter follows `%s'", - rest_extension); - - if (!is_idstart(*bp)) - cpp_pedwarn (pfile, "invalid character in macro parameter name"); - - /* Find the end of the arg name. */ - while (is_idchar(*bp)) - { - bp++; - /* do we have a "special" rest-args extension here? */ - if ((size_t) (limit - bp) > REST_EXTENSION_LENGTH - && !strncmp (rest_extension, bp, REST_EXTENSION_LENGTH)) - { - rest_args = 1; - temp->rest_args = 1; - break; - } - } - temp->length = bp - temp->name; - if (rest_args == 1) - bp += REST_EXTENSION_LENGTH; - arglengths += temp->length + 2; - SKIP_WHITE_SPACE (bp); - if (temp->length == 0 || (*bp != ',' && *bp != ')')) - { - cpp_error (pfile, - "badly punctuated parameter list in `#define'"); - goto nope; - } - if (*bp == ',') - { - bp++; - SKIP_WHITE_SPACE (bp); - } - if (bp >= limit) - { - cpp_error (pfile, "unterminated parameter list in `#define'"); - goto nope; - } - { - struct arglist *otemp; - - for (otemp = temp->next; otemp != NULL; otemp = otemp->next) - if (temp->length == otemp->length - && strncmp (temp->name, otemp->name, temp->length) == 0) - { - U_CHAR *name; - - name = (U_CHAR *) alloca (temp->length + 1); - (void) strncpy (name, temp->name, temp->length); - name[temp->length] = '\0'; - cpp_error (pfile, - "duplicate argument name `%s' in `#define'", - name); - goto nope; - } - } - } - - ++bp; /* skip paren */ - SKIP_WHITE_SPACE (bp); - /* now everything from bp before limit is the definition. */ - defn = collect_expansion (pfile, bp, limit, argno, arg_ptrs); - defn->rest_args = rest_args; - - /* Now set defn->argnames to the result of concatenating - the argument names in reverse order - with comma-space between them. */ - defn->argnames = (U_CHAR *) xmalloc (arglengths + 1); - { - struct arglist *temp; - int i = 0; - for (temp = arg_ptrs; temp; temp = temp->next) - { - bcopy (temp->name, &defn->argnames[i], temp->length); - i += temp->length; - if (temp->next != 0) - { - defn->argnames[i++] = ','; - defn->argnames[i++] = ' '; - } - } - defn->argnames[i] = 0; - } + argv = arglist->argv; + argc = arglist->argc; } else { - /* Simple expansion or empty definition. */ - - if (bp < limit) - { - if (is_hspace(*bp)) - { - bp++; - SKIP_WHITE_SPACE (bp); - } - else - /* Per C9x, missing white space after the name in a #define - of an object-like macro is always a constraint violation. */ - cpp_pedwarn (pfile, - "missing white space after `#define %.*s'", - sym_length, symname); - } - /* now everything from bp before limit is the definition. */ - defn = collect_expansion (pfile, bp, limit, -1, NULL_PTR); - defn->argnames = (U_CHAR *) ""; + argv = 0; + argc = 0; } + last = start = CPP_WRITTEN (pfile); + last -= 2; /* two extra chars for the leading escape */ + for (;;) + { + /* We use cpp_get_token because get_directive_token would + discard whitespace and we can't cope with that yet. Macro + expansion is off, so we are guaranteed not to see POP or EOF. */ + + while (PEEKC () == '\r') + { + FORWARD (1); + CPP_BUMP_LINE (pfile); + } + if (PEEKC () == '\n') + goto done; + here = CPP_WRITTEN (pfile); + token = cpp_get_token (pfile); + tok = pfile->token_buffer + here; + switch (token) + { + case CPP_POP: + case CPP_EOF: + case CPP_VSPACE: + cpp_ice (pfile, "EOF or VSPACE in collect_expansion"); + goto done; + + case CPP_HSPACE: + if (last_token == STRIZE || last_token == PASTE + || last_token == START) + CPP_SET_WRITTEN (pfile, here); + break; + + case CPP_STRINGIZE: + if (last_token == PASTE) + /* Not really a stringifier. */ + goto norm; + last_token = STRIZE; + CPP_SET_WRITTEN (pfile, here); /* delete from replacement text */ + break; + + case CPP_TOKPASTE: + /* If the last token was an argument, discard this token and + any hspace between it and the argument's position. Then + mark the arg raw_after. */ + if (last_token == ARG) + { + endpat->raw_after = 1; + last_token = PASTE; + CPP_SET_WRITTEN (pfile, last); + break; + } + else if (last_token == PASTE) + /* ## ## - the second ## is ordinary. */ + goto norm; + + /* Discard the token and any hspace before it. */ + while (is_hspace (pfile->token_buffer[here-1])) + here--; + CPP_SET_WRITTEN (pfile, here); + + if (last_token == STRIZE) + /* Oops - that wasn't a stringify operator. */ + CPP_PUTC (pfile, '#'); + last_token = PASTE; + break; + + case CPP_COMMENT: + /* We must be in -traditional mode. Pretend this was a + token paste, but only if there was no leading or + trailing space. */ + CPP_SET_WRITTEN (pfile, here); + if (is_hspace (pfile->token_buffer[here-1])) + break; + if (is_hspace (PEEKC ())) + break; + if (last_token == ARG) + endpat->raw_after = 1; + last_token = PASTE; + break; + + case CPP_STRING: + case CPP_CHAR: + if (last_token == STRIZE) + cpp_error (pfile, "`#' is not followed by a macro argument name"); + + if (CPP_TRADITIONAL (pfile) || CPP_OPTIONS (pfile)->warn_stringify) + goto maybe_trad_stringify; + else + goto norm; + + case CPP_NAME: + for (i = 0; i < argc; i++) + if (!strncmp (tok, argv[i].name, argv[i].len) + && ! is_idchar (tok[argv[i].len])) + goto addref; + + /* fall through */ + default: + norm: + if (last_token == STRIZE) + cpp_error (pfile, "`#' is not followed by a macro argument name"); + last_token = NORM; + break; + } + continue; + + addref: + { + struct reflist *tpat; + + /* Make a pat node for this arg and add it to the pat list */ + tpat = (struct reflist *) xmalloc (sizeof (struct reflist)); + tpat->next = NULL; + tpat->raw_before = (last_token == PASTE); + tpat->raw_after = 0; + tpat->stringify = (last_token == STRIZE); + tpat->rest_args = argv[i].rest_arg; + tpat->argno = i; + tpat->nchars = here - last; + + if (endpat == NULL) + pat = tpat; + else + endpat->next = tpat; + endpat = tpat; + last = here; + } + CPP_SET_WRITTEN (pfile, here); /* discard arg name */ + last_token = ARG; + continue; + + maybe_trad_stringify: + { + U_CHAR *base, *p, *limit; + struct reflist *tpat; + + base = p = pfile->token_buffer + here; + limit = CPP_PWRITTEN (pfile); + + while (++p < limit) + { + if (is_idstart (*p)) + continue; + for (i = 0; i < argc; i++) + if (!strncmp (tok, argv[i].name, argv[i].len) + && ! is_idchar (tok[argv[i].len])) + goto mts_addref; + continue; + + mts_addref: + if (!CPP_TRADITIONAL (pfile)) + { + /* Must have got here because of -Wtraditional. */ + cpp_warning (pfile, + "macro argument `%.*s' would be stringified with -traditional", + (int) argv[i].len, argv[i].name); + continue; + } + if (CPP_OPTIONS (pfile)->warn_stringify) + cpp_warning (pfile, "macro argument `%.*s' is stringified", + (int) argv[i].len, argv[i].name); + + /* Remove the argument from the string. */ + memmove (p, p + argv[i].len, limit - (p + argv[i].len)); + limit -= argv[i].len; + + /* Make a pat node for this arg and add it to the pat list */ + tpat = (struct reflist *) xmalloc (sizeof (struct reflist)); + tpat->next = NULL; + + /* Don't attempt to paste this with anything. */ + tpat->raw_before = 0; + tpat->raw_after = 0; + tpat->stringify = 1; + tpat->rest_args = argv[i].rest_arg; + tpat->argno = i; + tpat->nchars = (p - base) + here - last; + + if (endpat == NULL) + pat = tpat; + else + endpat->next = tpat; + endpat = tpat; + last = (p - base) + here; + } + CPP_ADJUST_WRITTEN (pfile, CPP_PWRITTEN (pfile) - limit); + } + } + done: + + if (last_token == STRIZE) + cpp_error (pfile, "`#' is not followed by a macro argument name"); + else if (last_token == PASTE) + cpp_error (pfile, "`##' at end of macro definition"); + + CPP_NUL_TERMINATE (pfile); + len = CPP_WRITTEN (pfile) - start + 1; + exp = xmalloc (len + 4); /* space for no-concat markers at either end */ + exp[0] = '\r'; + exp[1] = ' '; + exp[len + 1] = '\r'; + exp[len + 2] = ' '; + exp[len + 3] = '\0'; + memcpy (&exp[2], pfile->token_buffer + start, len - 1); + CPP_SET_WRITTEN (pfile, start); + + defn = (DEFINITION *) xmalloc (sizeof (DEFINITION)); + defn->length = len + 3; + defn->expansion = exp; + defn->pattern = pat; + defn->rest_args = 0; + if (arglist) + { + defn->nargs = argc; + defn->argnames = arglist->namebuf; + if (argv) + { + defn->rest_args = argv[argc - 1].rest_arg; + free (argv); + } + free (arglist); + } + else + { + defn->nargs = -1; + defn->argnames = 0; + defn->rest_args = 0; + } + return defn; +} + +static struct arglist * +collect_formal_parameters (pfile) + cpp_reader *pfile; +{ + struct arglist *result = 0; + struct arg *argv = 0; + U_CHAR *namebuf = xstrdup (""); + + U_CHAR *name, *tok; + size_t argslen = 1; + int len; + int argc = 0; + int i; + enum cpp_token token; + long old_written; + + old_written = CPP_WRITTEN (pfile); + token = get_directive_token (pfile); + if (token != CPP_LPAREN) + { + cpp_ice (pfile, "first token = %d not %d in collect_formal_parameters", + token, CPP_LPAREN); + goto invalid; + } + + argv = (struct arg *) xmalloc (sizeof (struct arg)); + argv[argc].len = 0; + argv[argc].rest_arg = 0; + for (;;) + { + CPP_SET_WRITTEN (pfile, old_written); + token = get_directive_token (pfile); + switch (token) + { + case CPP_NAME: + tok = pfile->token_buffer + old_written; + len = CPP_PWRITTEN (pfile) - tok; + if (namebuf + && (name = strstr (namebuf, tok)) + && name[len] == ',' + && (name == namebuf || name[-1] == ',')) + { + cpp_error (pfile, "duplicate macro argument name `%s'", tok); + continue; + } + namebuf = xrealloc (namebuf, argslen + len + 1); + name = &namebuf[argslen - 1]; + argslen += len + 1; + + memcpy (name, tok, len); + name[len] = ','; + name[len+1] = '\0'; + argv[argc].len = len; + argv[argc].rest_arg = 0; + break; + + case CPP_COMMA: + argc++; + argv = xrealloc (argv, (argc + 1)*sizeof(struct arg)); + argv[argc].len = 0; + break; + + case CPP_RPAREN: + goto done; + + case CPP_3DOTS: + goto rest_arg; + + case CPP_VSPACE: + cpp_error (pfile, "missing right paren in macro argument list"); + goto invalid; + + default: + cpp_error (pfile, "syntax error in #define"); + goto invalid; + } + } + + rest_arg: + /* There are two possible styles for a vararg macro: + the C99 way: #define foo(a, ...) a, __VA_ARGS__ + the gnu way: #define foo(a, b...) a, b + The C99 way can be considered a special case of the gnu way. + There are also some constraints to worry about, but we'll handle + those elsewhere. */ + if (argv[argc].len == 0) + { + if (CPP_PEDANTIC (pfile) && ! CPP_OPTIONS (pfile)->c99) + cpp_pedwarn (pfile, "C89 does not permit varargs macros"); + + len = sizeof "__VA_ARGS__" - 1; + namebuf = xrealloc (namebuf, argslen + len + 1); + name = &namebuf[argslen - 1]; + argslen += len; + memcpy (name, "__VA_ARGS__", len); + + argslen += len + 1; + argv[argc].len = len; + } + else + if (CPP_PEDANTIC (pfile)) + cpp_pedwarn (pfile, "ISO C does not permit named varargs macros"); + + argv[argc].rest_arg = 1; + namebuf = xrealloc (namebuf, argslen + 3); + memcpy (&namebuf[argslen - 1], "...", 4); + argslen += 3; + + token = get_directive_token (pfile); + if (token != CPP_RPAREN) + { + cpp_error (pfile, "another parameter follows `...'"); + goto invalid; + } + + done: + /* Go through argv and fix up the pointers. */ + len = 0; + for (i = 0; i <= argc; i++) + { + argv[i].name = namebuf + len; + len += argv[i].len + 1; + } + + CPP_SET_WRITTEN (pfile, old_written); + + result = (struct arglist *) xmalloc (sizeof (struct arglist)); + if (namebuf[0] != '\0') + { + result->namebuf = namebuf; + result->argc = argc + 1; + result->argv = argv; + } + else + { + free (namebuf); + result->namebuf = 0; + result->argc = 0; + result->argv = 0; + } + + return result; + + invalid: + if (argv) + free (argv); + if (namebuf) + free (namebuf); + return 0; +} + +/* Create a DEFINITION node for a macro. The reader's point is just + after the macro name. If FUNLIKE is true, this is a function-like + macro. */ + +DEFINITION * +create_definition (pfile, funlike) + cpp_reader *pfile; + int funlike; +{ + struct arglist *args = 0; + long line, col; + const char *file; + DEFINITION *defn; + + cpp_buf_line_and_col (CPP_BUFFER (pfile), &line, &col); + file = CPP_BUFFER (pfile)->nominal_fname; + + pfile->no_macro_expand++; + pfile->parsing_define_directive++; + CPP_OPTIONS (pfile)->discard_comments++; + + if (funlike) + { + args = collect_formal_parameters (pfile); + if (args == 0) + goto err; + } + + defn = collect_expansion (pfile, args); + if (defn == 0) + goto err; + defn->line = line; defn->file = file; + defn->col = col; - mdef.defn = defn; - mdef.symnam = symname; - mdef.symlen = sym_length; + pfile->no_macro_expand--; + pfile->parsing_define_directive--; + CPP_OPTIONS (pfile)->discard_comments--; + return defn; - return mdef; - -nope: - mdef.defn = 0; - return mdef; + err: + pfile->no_macro_expand--; + pfile->parsing_define_directive--; + CPP_OPTIONS (pfile)->discard_comments--; + return 0; } /* @@ -987,7 +960,7 @@ macroexpand (pfile, hp) xbuf_len = CPP_WRITTEN (pfile) - old_written; xbuf = (U_CHAR *) xmalloc (xbuf_len + 1); CPP_SET_WRITTEN (pfile, old_written); - bcopy (CPP_PWRITTEN (pfile), xbuf, xbuf_len + 1); + memcpy (xbuf, CPP_PWRITTEN (pfile), xbuf_len + 1); push_macro_expansion (pfile, xbuf, xbuf_len, hp); CPP_BUFFER (pfile)->has_escapes = 1; return; @@ -1244,8 +1217,10 @@ macroexpand (pfile, hp) int count_before = totlen; /* Add chars to XBUF. */ - for (i = 0; i < ap->nchars; i++, offset++) - xbuf[totlen++] = exp[offset]; + 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. */ @@ -1265,8 +1240,8 @@ macroexpand (pfile, hp) if (ap->stringify != 0) { - bcopy (ARG_BASE + arg->stringified, - xbuf + totlen, arg->stringified_length); + memcpy (xbuf + totlen, ARG_BASE + arg->stringified, + arg->stringified_length); totlen += arg->stringified_length; } else if (ap->raw_before || ap->raw_after || CPP_TRADITIONAL (pfile)) @@ -1314,7 +1289,7 @@ macroexpand (pfile, hp) if (p1[0] == '\r' && p1[1] == '-') p1 += 2; - bcopy (p1, xbuf + totlen, l1 - p1); + memcpy (xbuf + totlen, p1, l1 - p1); totlen += l1 - p1; } else @@ -1328,7 +1303,7 @@ macroexpand (pfile, hp) xbuf[totlen++] = ' '; } - bcopy (expanded, xbuf + totlen, arg->expand_length); + memcpy (xbuf + totlen, expanded, arg->expand_length); totlen += arg->expand_length; if (!ap->raw_after && totlen > 0 && offset < defn->length @@ -1493,6 +1468,7 @@ compare_defs (pfile, d1, d2) if (d1->nargs != d2->nargs) return 1; if (CPP_PEDANTIC (pfile) + && d1->argnames && d2->argnames && strcmp ((char *) d1->argnames, (char *) d2->argnames)) return 1; for (a1 = d1->pattern, a2 = d2->pattern; a1 && a2; diff --git a/gcc/cpphash.h b/gcc/cpphash.h index c9273d56db9..278ad24de64 100644 --- a/gcc/cpphash.h +++ b/gcc/cpphash.h @@ -18,15 +18,6 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef __GCC_CPPHASH__ #define __GCC_CPPHASH__ -/* Structure returned by create_definition */ -typedef struct macrodef MACRODEF; -struct macrodef -{ - struct definition *defn; - const U_CHAR *symnam; - int symlen; -}; - /* Structure allocated for every #define. For a simple replacement such as #define foo bar , @@ -48,30 +39,35 @@ struct macrodef { (0, 1), (1, 1), (1, 1), ..., (1, 1), NULL } where (x, y) means (nchars, argno). */ +struct reflist +{ + struct reflist *next; + char stringify; /* nonzero if this arg was preceded by a + # operator. */ + char raw_before; /* Nonzero if a ## operator before arg. */ + char raw_after; /* Nonzero if a ## operator after arg. */ + char rest_args; /* Nonzero if this arg. absorbs the rest */ + int nchars; /* Number of literal chars to copy before + this arg occurrence. */ + int argno; /* Number of arg to substitute (origin-0) */ +}; + typedef struct definition DEFINITION; -struct definition { +struct definition +{ int nargs; int length; /* length of expansion string */ - unsigned char *expansion; + 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 { - struct reflist *next; - char stringify; /* nonzero if this arg was preceded by a - # operator. */ - char raw_before; /* Nonzero if a ## operator before arg. */ - char raw_after; /* Nonzero if a ## operator after arg. */ - char rest_args; /* Nonzero if this arg. absorbs the rest */ - int nchars; /* Number of literal chars to copy before - this arg occurrence. */ - int argno; /* Number of arg to substitute (origin-0) */ - } *pattern; - /* Names of macro args, concatenated in reverse order - with comma-space between them. - The only use of this is that we warn on redefinition - if this differs between the old and new definitions. */ - unsigned char *argnames; + struct reflist *pattern; + + /* Names of macro args, concatenated in order with commas between + them. The only use of this is that we warn on redefinition if + this differs between the old and new definitions. */ + U_CHAR *argnames; }; /* different kinds of things that can appear in the value field @@ -102,8 +98,7 @@ extern HASHNODE *cpp_lookup PARAMS ((cpp_reader *, const U_CHAR *, int)); extern void free_definition PARAMS ((DEFINITION *)); extern void delete_macro PARAMS ((HASHNODE *)); -extern MACRODEF create_definition PARAMS ((U_CHAR *, U_CHAR *, - cpp_reader *)); +extern DEFINITION *create_definition PARAMS ((cpp_reader *, int)); extern int compare_defs PARAMS ((cpp_reader *, DEFINITION *, DEFINITION *)); extern void macroexpand PARAMS ((cpp_reader *, HASHNODE *)); diff --git a/gcc/cppinit.c b/gcc/cppinit.c index eb2124ed1d2..d6fbad2247e 100644 --- a/gcc/cppinit.c +++ b/gcc/cppinit.c @@ -1256,9 +1256,6 @@ cpp_handle_option (pfile, argc, argv) opts->include_prefix_len = strlen (argv[i]); } } - else if (!strcmp (argv[i], "-ifoutput")) - opts->output_conditionals = 1; - break; case 'o': @@ -1736,7 +1733,6 @@ Switches:\n\ -dD Preserve macro definitions in output\n\ -dN As -dD except that only the names are preserved\n\ -dI Include #include directives in the output\n\ - -ifoutput Describe skipped code blocks in output \n\ -P Do not generate #line directives\n\ -$ Do not allow '$' in identifiers\n\ -remap Remap file names when including files.\n\ diff --git a/gcc/cpplib.c b/gcc/cpplib.c index 9f96297940e..8cdc241573e 100644 --- a/gcc/cpplib.c +++ b/gcc/cpplib.c @@ -46,7 +46,8 @@ extern HOST_WIDEST_INT cpp_parse_expr PARAMS ((cpp_reader *)); /* `struct directive' defines one #-directive, including how to handle it. */ -struct directive { +struct directive +{ int length; /* Length of name */ int (*func) /* Function to handle directive */ PARAMS ((cpp_reader *, const struct directive *)); @@ -93,7 +94,7 @@ static enum cpp_token null_underflow PARAMS ((cpp_reader *)); static int null_cleanup PARAMS ((cpp_buffer *, cpp_reader *)); static int skip_comment PARAMS ((cpp_reader *, int)); static int copy_comment PARAMS ((cpp_reader *, int)); -static void copy_rest_of_line PARAMS ((cpp_reader *)); +static void skip_string PARAMS ((cpp_reader *, int)); static void skip_rest_of_line PARAMS ((cpp_reader *)); static void cpp_skip_hspace PARAMS ((cpp_reader *)); static int handle_directive PARAMS ((cpp_reader *)); @@ -108,6 +109,7 @@ static void skip_block_comment PARAMS ((cpp_reader *)); static void skip_line_comment PARAMS ((cpp_reader *)); static void parse_set_mark PARAMS ((cpp_reader *)); static void parse_goto_mark PARAMS ((cpp_reader *)); +static int get_macro_name PARAMS ((cpp_reader *)); /* Here is the actual list of #-directives. This table is ordered by frequency of occurrence; the numbers @@ -410,10 +412,13 @@ copy_comment (pfile, m) if (skip_comment (pfile, m) == m) return m; - CPP_PUTC (pfile, m); - for (limit = CPP_BUFFER (pfile)->cur; start <= limit; start++) + limit = CPP_BUFFER (pfile)->cur; + CPP_RESERVE (pfile, limit - start + 2); + CPP_PUTC_Q (pfile, m); + for (; start <= limit; start++) if (*start != '\r') - CPP_PUTC (pfile, *start); + CPP_PUTC_Q (pfile, *start); + return ' '; } @@ -447,7 +452,7 @@ cpp_skip_hspace (pfile) break; } else - CPP_BUFFER (pfile)->lineno++; + CPP_BUMP_LINE (pfile); } else if (c == '/' || c == '-') { @@ -461,11 +466,10 @@ cpp_skip_hspace (pfile) FORWARD(-1); } -/* Read the rest of the current line. - The line is appended to PFILE's output buffer. */ +/* Read and discard the rest of the current line. */ static void -copy_rest_of_line (pfile) +skip_rest_of_line (pfile) cpp_reader *pfile; { for (;;) @@ -476,32 +480,21 @@ copy_rest_of_line (pfile) case '\n': FORWARD(-1); case EOF: - CPP_NUL_TERMINATE (pfile); return; case '\r': - if (CPP_BUFFER (pfile)->has_escapes) - break; - else - { - CPP_BUFFER (pfile)->lineno++; - continue; - } + if (! CPP_BUFFER (pfile)->has_escapes) + CPP_BUMP_LINE (pfile); + break; + case '\'': case '\"': - parse_string (pfile, c); - continue; + skip_string (pfile, c); + break; + case '/': - if (PEEKC() == '*') - { - if (CPP_TRADITIONAL (pfile)) - CPP_PUTS (pfile, "/**/", 4); - skip_block_comment (pfile); - continue; - } - /* else fall through */ case '-': - c = skip_comment (pfile, c); + skip_comment (pfile, c); break; case '\f': @@ -512,23 +505,9 @@ copy_rest_of_line (pfile) break; } - CPP_PUTC (pfile, c); } } -/* FIXME: It is almost definitely a performance win to make this do - the scan itself. >75% of calls to copy_r_o_l are from here or - skip_if_group, which means the common case is to copy stuff into the - token_buffer only to discard it. */ -static void -skip_rest_of_line (pfile) - cpp_reader *pfile; -{ - long old = CPP_WRITTEN (pfile); - copy_rest_of_line (pfile); - CPP_SET_WRITTEN (pfile, old); -} - /* Handle a possible # directive. '#' has already been read. */ @@ -542,6 +521,12 @@ handle_directive (pfile) U_CHAR *ident; long old_written = CPP_WRITTEN (pfile); + if (CPP_IS_MACRO_BUFFER (CPP_BUFFER (pfile))) + { + cpp_ice (pfile, "handle_directive called on macro buffer"); + return 0; + } + cpp_skip_hspace (pfile); c = PEEKC (); @@ -629,71 +614,88 @@ pass_thru_directive (buf, len, pfile, keyword) CPP_PUTS_Q (pfile, buf, len); } -/* Check a purported macro name SYMNAME, and yield its length. */ +/* Subroutine of do_define: determine the name of the macro to be + defined. */ -int -check_macro_name (pfile, symname) +static int +get_macro_name (pfile) cpp_reader *pfile; - const U_CHAR *symname; { - const U_CHAR *p; - int sym_length; + long here, len; - for (p = symname; is_idchar(*p); p++) - ; - sym_length = p - symname; - if (sym_length == 0 - || (sym_length == 1 && *symname == 'L' && (*p == '\'' || *p == '"'))) - cpp_error (pfile, "invalid macro name"); - else if (!is_idstart(*symname) - || (! strncmp (symname, "defined", 7) && sym_length == 7)) { - U_CHAR *msg; /* what pain... */ - msg = (U_CHAR *) alloca (sym_length + 1); - bcopy (symname, msg, sym_length); - msg[sym_length] = 0; - cpp_error (pfile, "invalid macro name `%s'", msg); - } - return sym_length; + here = CPP_WRITTEN (pfile); + pfile->no_macro_expand++; + if (get_directive_token (pfile) != CPP_NAME) + { + cpp_error (pfile, "`#define' must be followed by an identifier"); + goto invalid; + } + + len = CPP_WRITTEN (pfile) - here; + if (len == 7 && !strncmp (pfile->token_buffer + here, "defined", 7)) + { + cpp_error (pfile, "`defined' is not a legal macro name"); + goto invalid; + } + + pfile->no_macro_expand--; + return len; + + invalid: + skip_rest_of_line (pfile); + pfile->no_macro_expand--; + return 0; } /* Process a #define command. KEYWORD is the keyword-table entry for #define, - or NULL for a "predefined" macro, - or the keyword-table entry for #pragma in the case of a #pragma poison. */ + or NULL for a "predefined" macro. */ static int do_define (pfile, keyword) cpp_reader *pfile; const struct directive *keyword; { - MACRODEF mdef; HASHNODE *hp; + DEFINITION *def; long here; - U_CHAR *macro, *buf, *end; + int len, c; + int funlike = 0; + U_CHAR *sym; here = CPP_WRITTEN (pfile); - copy_rest_of_line (pfile); - - /* Copy out the line so we can pop the token buffer. */ - buf = pfile->token_buffer + here; - end = CPP_PWRITTEN (pfile); - macro = (U_CHAR *) alloca (end - buf + 1); - memcpy (macro, buf, end - buf + 1); - end = macro + (end - buf); - - CPP_SET_WRITTEN (pfile, here); - - mdef = create_definition (macro, end, pfile); - if (mdef.defn == 0) + len = get_macro_name (pfile); + if (len == 0) return 0; - if ((hp = cpp_lookup (pfile, mdef.symnam, mdef.symlen)) != NULL) + /* Copy out the name so we can pop the token buffer. */ + len = CPP_WRITTEN (pfile) - here; + sym = (U_CHAR *) alloca (len + 1); + memcpy (sym, pfile->token_buffer + here, len); + sym[len] = '\0'; + CPP_SET_WRITTEN (pfile, here); + + /* If the next character, with no intervening whitespace, is '(', + then this is a function-like macro. */ + c = PEEKC (); + if (c == '(') + funlike = 1; + else if (c != '\n' && !is_hspace (c)) + /* Otherwise, C99 requires white space after the name. We treat it + as an object-like macro if this happens, with a warning. */ + cpp_pedwarn (pfile, "missing white space after `#define %.*s'", len, sym); + + def = create_definition (pfile, funlike); + if (def == 0) + return 0; + + if ((hp = cpp_lookup (pfile, sym, len)) != NULL) { int ok; /* Redefining a macro is ok if the definitions are the same. */ if (hp->type == T_MACRO) - ok = ! compare_defs (pfile, mdef.defn, hp->value.defn); + ok = ! compare_defs (pfile, def, hp->value.defn); /* Redefining a constant is ok with -D. */ else if (hp->type == T_CONST || hp->type == T_STDC) ok = ! CPP_OPTIONS (pfile)->done_initializing; @@ -704,14 +706,15 @@ do_define (pfile, keyword) if (! ok) { if (hp->type == T_POISON) - cpp_error (pfile, "redefining poisoned `%.*s'", - mdef.symlen, mdef.symnam); + cpp_error (pfile, "redefining poisoned `%.*s'", len, sym); else - cpp_pedwarn (pfile, "`%.*s' redefined", mdef.symlen, mdef.symnam); + cpp_pedwarn (pfile, "`%.*s' redefined", len, sym); if (hp->type == T_MACRO && CPP_OPTIONS (pfile)->done_initializing) - cpp_pedwarn_with_file_and_line (pfile, hp->value.defn->file, - hp->value.defn->line, -1, + { + 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) { @@ -719,19 +722,19 @@ do_define (pfile, keyword) if (hp->type == T_MACRO) free_definition (hp->value.defn); hp->type = T_MACRO; - hp->value.defn = mdef.defn; + hp->value.defn = def; } } else - cpp_install (pfile, mdef.symnam, mdef.symlen, T_MACRO, (char *)mdef.defn); + cpp_install (pfile, sym, len, T_MACRO, (char *) def); if (keyword != NULL && keyword->type == T_DEFINE) { if (CPP_OPTIONS (pfile)->debug_output || CPP_OPTIONS (pfile)->dump_macros == dump_definitions) - dump_definition (pfile, mdef.symnam, mdef.symlen, mdef.defn); + dump_definition (pfile, sym, len, def); else if (CPP_OPTIONS (pfile)->dump_macros == dump_names) - pass_thru_directive (mdef.symnam, mdef.symlen, pfile, keyword); + pass_thru_directive (sym, len, pfile, keyword); } return 0; @@ -766,6 +769,7 @@ cpp_push_buffer (pfile, buffer, length) new->alimit = new->rlimit = buffer + length; new->prev = buf; new->mark = -1; + new->line_base = NULL; CPP_BUFFER (pfile) = new; return new; @@ -1309,7 +1313,7 @@ read_line_number (pfile, num) } else { - if (token != CPP_VSPACE && token != CPP_EOF && token != CPP_POP) + if (token != CPP_VSPACE && token != CPP_EOF) cpp_error (pfile, "invalid format `#line' command"); return 0; } @@ -1467,15 +1471,14 @@ do_undef (pfile, keyword) len = limit - buf; name = (U_CHAR *) alloca (len + 1); memcpy (name, buf, len); - name[limit - buf] = '\0'; + name[len] = '\0'; token = get_directive_token (pfile); - if (token != CPP_VSPACE && token != CPP_POP) + if (token != CPP_VSPACE) { cpp_pedwarn (pfile, "junk on line after #undef"); skip_rest_of_line (pfile); } - CPP_SET_WRITTEN (pfile, here); while ((hp = cpp_lookup (pfile, name, len)) != NULL) @@ -1950,11 +1953,9 @@ eval_if_expression (pfile) HOST_WIDEST_INT value; long old_written = CPP_WRITTEN (pfile); - /* Work around bug in cpp_get_token where it may mistake an - assertion for a directive. */ - pfile->only_seen_white = 0; - + pfile->parsing_if_directive++; value = cpp_parse_expr (pfile); + pfile->parsing_if_directive--; skip_rest_of_line (pfile); CPP_SET_WRITTEN (pfile, old_written); /* Pop */ @@ -2148,13 +2149,6 @@ skip_if_group (pfile) U_CHAR *beg_of_line; long old_written; - if (CPP_OPTIONS (pfile)->output_conditionals) - { - CPP_PUTS (pfile, "#failed\n", 8); - pfile->lineno++; - output_line_command (pfile, same_file); - } - old_written = CPP_WRITTEN (pfile); for (;;) @@ -2166,8 +2160,6 @@ skip_if_group (pfile) c = GETC(); if (c == '\n') { - if (CPP_OPTIONS (pfile)->output_conditionals) - CPP_PUTC (pfile, c); CPP_BUMP_LINE (pfile); continue; } @@ -2180,41 +2172,19 @@ skip_if_group (pfile) return; /* Caller will issue error. */ FORWARD(-1); - if (CPP_OPTIONS (pfile)->output_conditionals) - { - CPP_PUTS (pfile, beg_of_line, CPP_BUFFER (pfile)->cur - beg_of_line); - copy_rest_of_line (pfile); - } - else - { - copy_rest_of_line (pfile); - CPP_SET_WRITTEN (pfile, old_written); /* discard it */ - } + skip_rest_of_line (pfile); c = GETC(); if (c == EOF) return; /* Caller will issue error. */ else - { - /* \n */ - if (CPP_OPTIONS (pfile)->output_conditionals) - { - CPP_PUTC (pfile, c); - pfile->lineno++; - } - CPP_BUMP_LINE (pfile); - } + CPP_BUMP_LINE (pfile); } /* Back up to the beginning of this line. Caller will process the directive. */ CPP_BUFFER (pfile)->cur = beg_of_line; pfile->only_seen_white = 1; - if (CPP_OPTIONS (pfile)->output_conditionals) - { - CPP_PUTS (pfile, "#endfailed\n", 11); - pfile->lineno++; - } } /* @@ -2443,6 +2413,27 @@ cpp_get_token (pfile) } case '#': + if (pfile->parsing_if_directive) + { + cpp_skip_hspace (pfile); + parse_assertion (pfile); + return CPP_ASSERTION; + } + + if (pfile->parsing_define_directive && ! CPP_TRADITIONAL (pfile)) + { + CPP_RESERVE (pfile, 3); + CPP_PUTC_Q (pfile, '#'); + CPP_NUL_TERMINATE_Q (pfile); + if (PEEKC () != '#') + return CPP_STRINGIZE; + + FORWARD (1); + CPP_PUTC_Q (pfile, '#'); + CPP_NUL_TERMINATE_Q (pfile); + return CPP_TOKPASTE; + } + if (!pfile->only_seen_white) goto randomchar; /* -traditional directives are recognized only with the # in @@ -2886,35 +2877,24 @@ parse_name (pfile, c) return; } -/* Parse a string starting with C. A single quoted string is treated - like a double -- some programs (e.g., troff) are perverse this way. - (However, a single quoted string is not allowed to extend over - multiple lines.) */ +/* Parse and skip over a string starting with C. A single quoted + string is treated like a double -- some programs (e.g., troff) are + perverse this way. (However, a single quoted string is not allowed + to extend over multiple lines.) */ static void -parse_string (pfile, c) +skip_string (pfile, c) cpp_reader *pfile; int c; { long start_line, start_column; - cpp_buf_line_and_col (cpp_file_buffer (pfile), &start_line, &start_column); - CPP_PUTC (pfile, c); while (1) { int cc = GETC(); - if (cc == EOF) + switch (cc) { - if (CPP_IS_MACRO_BUFFER (CPP_BUFFER (pfile))) - { - /* try harder: this string crosses a macro expansion - boundary. This can happen naturally if -traditional. - Otherwise, only -D can make a macro with an unmatched - quote. */ - cpp_pop_buffer (pfile); - continue; - } - + case EOF: cpp_error_with_line (pfile, start_line, start_column, "unterminated string or character constant"); if (pfile->multiline_string_line != start_line @@ -2923,22 +2903,20 @@ parse_string (pfile, c) pfile->multiline_string_line, -1, "possible real start of unterminated constant"); pfile->multiline_string_line = 0; - break; - } - CPP_PUTC (pfile, cc); - switch (cc) - { + return; + case '\n': CPP_BUMP_LINE (pfile); - pfile->lineno++; - /* In Fortran and assembly language, silently terminate strings of either variety at end of line. This is a kludge around not knowing where comments are in these languages. */ if (CPP_OPTIONS (pfile)->lang_fortran || CPP_OPTIONS (pfile)->lang_asm) - return; + { + FORWARD(-1); + return; + } /* Character constants may not extend over multiple lines. In Standard C, neither may strings. We accept multiline strings as an extension. */ @@ -2946,6 +2924,7 @@ parse_string (pfile, c) { cpp_error_with_line (pfile, start_line, start_column, "unterminated character constant"); + FORWARD(-1); return; } if (CPP_PEDANTIC (pfile) && pfile->multiline_string_line == 0) @@ -2956,7 +2935,6 @@ parse_string (pfile, c) break; case '\r': - CPP_ADJUST_WRITTEN (pfile, -1); if (CPP_BUFFER (pfile)->has_escapes) { cpp_ice (pfile, "\\r escape inside string constant"); @@ -2968,9 +2946,7 @@ parse_string (pfile, c) break; case '\\': - cc = GETC(); - if (cc != EOF) - CPP_PUTC (pfile, cc); + FORWARD(1); break; case '\"': @@ -2982,6 +2958,26 @@ parse_string (pfile, c) } } +/* Parse a string and copy it to the output. */ + +static void +parse_string (pfile, c) + cpp_reader *pfile; + int c; +{ + U_CHAR *start = CPP_BUFFER (pfile)->cur; /* XXX Layering violation */ + U_CHAR *limit; + + skip_string (pfile, c); + + limit = CPP_BUFFER (pfile)->cur; + CPP_RESERVE (pfile, limit - start + 2); + CPP_PUTC_Q (pfile, c); + for (; start < limit; start++) + if (*start != '\r') + CPP_PUTC_Q (pfile, *start); +} + /* Read an assertion into the token buffer, converting to canonical form: `#predicate(a n swe r)' The next non-whitespace character to read should be the first letter of the predicate. @@ -3199,33 +3195,11 @@ cpp_unassert (pfile, str) { if (cpp_push_buffer (pfile, str, strlen (str)) != NULL) { - do_assert (pfile, NULL); + do_unassert (pfile, NULL); cpp_pop_buffer (pfile); } } -int -cpp_read_check_assertion (pfile) - cpp_reader *pfile; -{ - U_CHAR *name; - int result; - long written = CPP_WRITTEN (pfile); - - FORWARD (1); /* Skip '#' */ - cpp_skip_hspace (pfile); - if (! parse_assertion (pfile)) - result = 0; - else - { - name = pfile->token_buffer + written; - result = cpp_defined (pfile, name, CPP_PWRITTEN (pfile) - name); - } - - CPP_SET_WRITTEN (pfile, written); - return result; -} - /* Remember the current position of PFILE so it may be returned to after looking ahead a bit. diff --git a/gcc/cpplib.h b/gcc/cpplib.h index 71726aadf46..6c16494ddfc 100644 --- a/gcc/cpplib.h +++ b/gcc/cpplib.h @@ -47,14 +47,17 @@ enum cpp_token { CPP_STRING, CPP_WSTRING, CPP_DIRECTIVE, - CPP_LPAREN, /* "(" */ - CPP_RPAREN, /* ")" */ - CPP_LBRACE, /* "{" */ - CPP_RBRACE, /* "}" */ - CPP_COMMA, /* "," */ - CPP_SEMICOLON,/* ";" */ - CPP_3DOTS, /* "..." */ - CPP_POP /* We're about to pop the buffer stack. */ + CPP_ASSERTION, /* #machine(a29k) */ + CPP_STRINGIZE, /* stringize macro argument */ + CPP_TOKPASTE, /* paste macro arg with next/prev token */ + CPP_LPAREN, /* "(" */ + CPP_RPAREN, /* ")" */ + CPP_LBRACE, /* "{" */ + CPP_RBRACE, /* "}" */ + CPP_COMMA, /* "," */ + CPP_SEMICOLON, /* ";" */ + CPP_3DOTS, /* "..." */ + CPP_POP /* We're about to pop the buffer stack. */ }; typedef enum cpp_token (*parse_underflow_t) PARAMS((cpp_reader *)); @@ -193,7 +196,6 @@ struct cpp_reader /* If non-zero, directives cause a hard error. Used when parsing macro arguments. */ - char no_directives; /* Print column number in error messages. */ @@ -205,6 +207,12 @@ struct cpp_reader /* If true, character between '<' and '>' are a single (string) token. */ char parsing_include_directive; + /* If true, # introduces an assertion (see do_assert) */ + char parsing_if_directive; + + /* If true, # and ## are the STRINGIZE and TOKPASTE operators */ + char parsing_define_directive; + /* True if escape sequences (as described for has_escapes in parse_buffer) should be emitted. */ char output_escapes; @@ -217,7 +225,7 @@ struct cpp_reader /* Nonzero means this file was included with a -imacros or -include command line and should not be recorded as an include file. */ - int no_record_file; + char no_record_file; long lineno; @@ -427,11 +435,6 @@ struct cpp_options { char no_line_commands; -/* Nonzero means output the text in failing conditionals, - inside #failed ... #endfailed. */ - - char output_conditionals; - /* Nonzero means -I- has been seen, so don't look for #include "foo" the source-file directory. */ char ignore_srcdir; @@ -689,14 +692,12 @@ extern int cpp_defined PARAMS ((cpp_reader *, const U_CHAR *, int)); extern void cpp_reader_init PARAMS ((cpp_reader *)); extern void cpp_options_init PARAMS ((cpp_options *)); extern int cpp_start_read PARAMS ((cpp_reader *, char *)); -extern int cpp_read_check_assertion PARAMS ((cpp_reader *)); extern void cpp_finish PARAMS ((cpp_reader *)); extern void quote_string PARAMS ((cpp_reader *, const char *)); extern void cpp_expand_to_buffer PARAMS ((cpp_reader *, const U_CHAR *, int)); extern void cpp_scan_buffer PARAMS ((cpp_reader *)); -extern int check_macro_name PARAMS ((cpp_reader *, const U_CHAR *)); /* Last arg to output_line_command. */ enum file_change_code {same_file, rename_file, enter_file, leave_file}; diff --git a/gcc/testsuite/gcc.dg/20000209-2.c b/gcc/testsuite/gcc.dg/20000209-2.c index 621a00b364f..6a9198f6496 100644 --- a/gcc/testsuite/gcc.dg/20000209-2.c +++ b/gcc/testsuite/gcc.dg/20000209-2.c @@ -1,5 +1,7 @@ /* { dg-do compile } */ -/* Distilled from glibc sources. Tests preprocessor corner cases. */ +/* { dg-options "-Wall" } */ +/* Distilled from glibc sources. Tests preprocessor corner cases. + Since it uses rest args, we must turn off -pedantic-errors. */ #define NO_PAREN(rest...) rest #define DEFINE_CATEGORY(category, items) \ diff --git a/gcc/testsuite/gcc.dg/strpaste-2.c b/gcc/testsuite/gcc.dg/strpaste-2.c new file mode 100644 index 00000000000..d1fcd91824d --- /dev/null +++ b/gcc/testsuite/gcc.dg/strpaste-2.c @@ -0,0 +1,23 @@ +/* { dg-do run } */ + +/* Test for odd corner cases in stringizing/pasting. + Taken more or less verbatim from C99 section 6.10.3.3. */ + +#include +#include + +#define hash_hash # ## # +#define mkstr(a) # a +#define in_between(a) mkstr(a) +#define join(c, d) in_between(c hash_hash d) + +const char p[] = join(x, y); +const char q[] = "x ## y"; + +int +main (void) +{ + if (strcmp (p, q)) + abort (); + return 0; +}