aboutsummaryrefslogtreecommitdiff
path: root/gcc/cpphash.c
diff options
context:
space:
mode:
authorZack Weinberg <zack@wolery.cumb.org>2000-03-01 00:57:09 +0000
committerZack Weinberg <zack@gcc.gnu.org>2000-03-01 00:57:09 +0000
commitba412f14ad13a1e71af1aebe1ee97c6591e1f12e (patch)
tree68077897eecebf1187d9c261fbded410af33eaf4 /gcc/cpphash.c
parent38769add25b9fb5b4d60e98c60ab2d6fb8bf0854 (diff)
downloadgcc-ba412f14ad13a1e71af1aebe1ee97c6591e1f12e.zip
gcc-ba412f14ad13a1e71af1aebe1ee97c6591e1f12e.tar.gz
gcc-ba412f14ad13a1e71af1aebe1ee97c6591e1f12e.tar.bz2
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
Diffstat (limited to 'gcc/cpphash.c')
-rw-r--r--gcc/cpphash.c882
1 files changed, 429 insertions, 453 deletions
diff --git a/gcc/cpphash.c b/gcc/cpphash.c
index 9d79979..c5c20ac 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;
+};
+
+struct arglist
+{
+ U_CHAR *namebuf;
+ struct arg *argv;
+ int argc;
};
-static DEFINITION *collect_expansion PARAMS ((cpp_reader *, U_CHAR *, U_CHAR *,
- int, struct arglist *));
+
+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';
-
- /* 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)
+ 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;
+
+ if (arglist)
{
- cpp_ice (pfile, "limit < buf in collect_expansion");
- limit = buf; /* treat it like a null defn */
+ argv = arglist->argv;
+ argc = arglist->argc;
}
-
- /* 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] == '#')
+ else
{
- cpp_error (pfile, "`##' at start of macro definition");
- p += 2;
+ argv = 0;
+ argc = 0;
}
- /* Process the main body of the definition. */
- while (p < limit)
+ last = start = CPP_WRITTEN (pfile);
+ last -= 2; /* two extra chars for the leading escape */
+ for (;;)
{
- int skipped_arg = 0;
- register U_CHAR c = *p++;
+ /* 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. */
- *exp_p++ = c;
-
- if (!CPP_TRADITIONAL (pfile))
+ while (PEEKC () == '\r')
{
- 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;
- }
+ FORWARD (1);
+ CPP_BUMP_LINE (pfile);
}
- else
+ if (PEEKC () == '\n')
+ goto done;
+ here = CPP_WRITTEN (pfile);
+ token = cpp_get_token (pfile);
+ tok = pfile->token_buffer + here;
+ switch (token)
{
- /* 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 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 '\\':
- /* 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 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 '/':
- 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++;
- }
+ 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;
- /* Handle the start of a symbol. */
- if (is_idchar(c) && nargs > 0)
- {
- U_CHAR *id_beg = p - 1;
- int id_len;
+ 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;
- --exp_p;
- while (p != limit && is_idchar(*p))
- p++;
- id_len = p - id_beg;
+ case CPP_STRING:
+ case CPP_CHAR:
+ if (last_token == STRIZE)
+ cpp_error (pfile, "`#' is not followed by a macro argument name");
- if (is_idstart(c)
- && !(id_len == 1 && c == 'L' && (*p == '\'' || *p == '"')))
- {
- register struct arglist *arg;
+ 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;
- for (arg = arglist; arg != NULL; arg = arg->next)
- {
- struct reflist *tpat;
+ 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;
- 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;
- }
- }
- }
+ maybe_trad_stringify:
+ {
+ U_CHAR *base, *p, *limit;
+ struct reflist *tpat;
- /* 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");
- }
+ 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);
}
-
- if (!CPP_TRADITIONAL (pfile) && expected_delimiter == 0)
+ else
{
- /* 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++ = ' ';
+ defn->nargs = -1;
+ defn->argnames = 0;
+ defn->rest_args = 0;
}
-
- *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;
+static struct arglist *
+collect_formal_parameters (pfile)
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;
+ struct arglist *result = 0;
+ struct arg *argv = 0;
+ U_CHAR *namebuf = xstrdup ("");
- while (is_hspace(*bp))
- bp++;
+ U_CHAR *name, *tok;
+ size_t argslen = 1;
+ int len;
+ int argc = 0;
+ int i;
+ enum cpp_token token;
+ long old_written;
- symname = bp; /* remember where it starts */
+ 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;
+ }
- sym_length = check_macro_name (pfile, bp);
- bp += sym_length;
+ 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;
- /* 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. */
+ case CPP_COMMA:
+ argc++;
+ argv = xrealloc (argv, (argc + 1)*sizeof(struct arg));
+ argv[argc].len = 0;
+ break;
- if (*bp == '(')
- {
- struct arglist *arg_ptrs = NULL;
- int argno = 0;
+ case CPP_RPAREN:
+ goto done;
- bp++; /* skip '(' */
- SKIP_WHITE_SPACE (bp);
+ case CPP_3DOTS:
+ goto rest_arg;
- /* Loop over macro argument names. */
- while (*bp != ')')
- {
- struct arglist *temp;
+ case CPP_VSPACE:
+ cpp_error (pfile, "missing right paren in macro argument list");
+ goto invalid;
- temp = (struct arglist *) alloca (sizeof (struct arglist));
- temp->name = bp;
- temp->next = arg_ptrs;
- temp->argno = argno++;
- temp->rest_args = 0;
- arg_ptrs = temp;
+ default:
+ cpp_error (pfile, "syntax error in #define");
+ goto invalid;
+ }
+ }
- if (rest_args)
- cpp_pedwarn (pfile, "another parameter follows `%s'",
- rest_extension);
+ 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");
- if (!is_idstart(*bp))
- cpp_pedwarn (pfile, "invalid character in macro parameter name");
+ len = sizeof "__VA_ARGS__" - 1;
+ namebuf = xrealloc (namebuf, argslen + len + 1);
+ name = &namebuf[argslen - 1];
+ argslen += len;
+ memcpy (name, "__VA_ARGS__", len);
- /* 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;
+ 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;
+ }
- 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;
- }
- }
- }
+ 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;
+ }
- ++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;
+ CPP_SET_WRITTEN (pfile, old_written);
- /* 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;
- }
+ result = (struct arglist *) xmalloc (sizeof (struct arglist));
+ if (namebuf[0] != '\0')
+ {
+ result->namebuf = namebuf;
+ result->argc = argc + 1;
+ result->argv = argv;
}
else
{
- /* Simple expansion or empty definition. */
+ free (namebuf);
+ result->namebuf = 0;
+ result->argc = 0;
+ result->argv = 0;
+ }
- 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 *) "";
+ 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;
-
- return mdef;
+ pfile->no_macro_expand--;
+ pfile->parsing_define_directive--;
+ CPP_OPTIONS (pfile)->discard_comments--;
+ return defn;
-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;