This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[patch] beginnings of the macro rewrite
- To: gcc-patches at gcc dot gnu dot org
- Subject: [patch] beginnings of the macro rewrite
- From: Zack Weinberg <zack at wolery dot cumb dot org>
- Date: Fri, 21 Apr 2000 10:18:46 -0700
- Cc: neilb at earthling dot net
This patch changes the #define logic to make use of token lists
briefly. We convert back to the old structure, but we already get
significant benefits - simpler code, fewer reallocations, etc.
IMPORTANT: This drops support for traditional macros. I will put it
back if people complain loudly enough. If no one cares then I will
probably drop -traditional entirely, sometime next week.
-Wtraditional still works.
zw
* cpphash.c (struct arg, struct arglist): Const-ify strings.
(warn_trad_stringify, duplicate_arg_p): New helper functions.
(collect_expansion): Rewrite to scan over a token list.
Remove -traditional support.
(collect_formal_parameters): Rename to collect_params; rewrite
to scan over a token list.
(_cpp_create_definition): Adjust to scan a token list.
(_cpp_macroexpand): Remove -traditional support.
(_cpp_compare_defs): Whitespace is now canonicalized.
(comp_def_part): Delete function.
* cpphash.h: Update prototypes.
* cpplex.c (init_token_list): Don't set lineno if there is no
buffer.
(pedantic_whitespace): New function.
(_cpp_scan_line): Mark tokens that had hspace before. Don't
consume a newline. Use pedantic_whitespace.
(_cpp_lex_token): Remove support for -traditional macros.
(_cpp_get_define_token): Delete.
(_cpp_get_directive_token): Do the real work here. Use
pedantic_whitespace.
(_cpp_init_input_buffer): Initialize pfile->directbuf.
* cpplib.c (get_macro_name): Delete.
(do_define): Read the entire line into pfile->directbuf, then
feed the token list to _cpp_create_definition.
* cpplib.h (HSPACE_BEFORE): new define.
(struct cpp_reader): Add a toklist member, "directbuf".
===================================================================
Index: cpphash.c
--- cpphash.c 2000/04/20 19:33:10 1.70
+++ cpphash.c 2000/04/21 17:09:18
@@ -36,8 +36,6 @@ static int eq_HASHNODE PARAMS ((const
static void del_HASHNODE PARAMS ((void *));
static int dump_hash_helper PARAMS ((void **, void *));
-static int comp_def_part PARAMS ((int, U_CHAR *, int, U_CHAR *,
- int, int));
static void push_macro_expansion PARAMS ((cpp_reader *,
U_CHAR *, int, HASHNODE *));
static int unsafe_chars PARAMS ((cpp_reader *, int, int));
@@ -61,21 +59,27 @@ static void special_symbol PARAMS ((HAS
struct arg
{
- U_CHAR *name;
- int len;
+ const U_CHAR *name;
+ unsigned int len;
char rest_arg;
};
struct arglist
{
U_CHAR *namebuf;
- struct arg *argv;
+ const struct arg *argv;
int argc;
};
-static DEFINITION *collect_expansion PARAMS ((cpp_reader *, struct arglist *));
-static struct arglist *collect_formal_parameters PARAMS ((cpp_reader *));
+static DEFINITION *collect_expansion PARAMS ((cpp_reader *, cpp_toklist *,
+ struct arglist *, unsigned int));
+static unsigned int collect_params PARAMS ((cpp_reader *, cpp_toklist *,
+ struct arglist *));
+
+static void warn_trad_stringify PARAMS ((cpp_reader *, U_CHAR *, size_t,
+ unsigned int, const struct arg *));
+static int duplicate_arg_p PARAMS ((U_CHAR *, U_CHAR *));
/* This structure represents one parsed argument in a macro call.
`raw' points to the argument text as written (`raw_length' is its length).
@@ -275,28 +279,64 @@ macro_cleanup (pbuf, pfile)
return 0;
}
+/* Issue warnings for macro argument names seen inside strings. */
+static void
+warn_trad_stringify (pfile, p, len, argc, argv)
+ cpp_reader *pfile;
+ U_CHAR *p;
+ size_t len;
+ unsigned int argc;
+ const struct arg *argv;
+
+{
+ U_CHAR *limit;
+ unsigned int i;
+
+ limit = p + len;
+ for (;;)
+ {
+ while (p < limit && !is_idstart (*p)) p++;
+ if (p >= limit)
+ break;
+
+ for (i = 0; i < argc; i++)
+ if (!strncmp (p, argv[i].name, argv[i].len)
+ && ! is_idchar (p[argv[i].len]))
+ {
+ cpp_warning (pfile,
+ "macro argument \"%s\" would be stringified in traditional C",
+ argv[i].name);
+ break;
+ }
+ p++;
+ while (p < limit && is_idchar (*p)) p++;
+ if (p >= limit)
+ break;
+ }
+}
+
/* 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
+ 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.
-
- A good half of this is devoted to supporting -traditional.
- Kill me now. */
+ function-like macro with no arguments. */
static DEFINITION *
-collect_expansion (pfile, arglist)
+collect_expansion (pfile, list, arglist, replacement)
cpp_reader *pfile;
+ cpp_toklist *list;
struct arglist *arglist;
+ unsigned int replacement;
{
DEFINITION *defn;
struct reflist *pat = 0, *endpat = 0;
enum cpp_ttype token;
- long start, here, last;
- int i;
- int argc;
+ long start, last;
+ unsigned int i;
+ int j, argc;
size_t len;
- struct arg *argv;
+ const struct arg *argv;
U_CHAR *tok, *exp;
enum { START = 0, NORM, ARG, STRIZE, PASTE } last_token = START;
@@ -311,15 +351,16 @@ collect_expansion (pfile, arglist)
argc = 0;
}
+ /* We copy the expansion text into the token_buffer, then out to
+ its proper home. */
last = start = CPP_WRITTEN (pfile);
- last -= 2; /* two extra chars for the leading escape */
- for (;;)
+ CPP_PUTS (pfile, "\r ", 2);
+
+ for (i = replacement; i < list->tokens_used; i++)
{
- /* Macro expansion is off, so we are guaranteed not to see POP
- or EOF. */
- here = CPP_WRITTEN (pfile);
- token = _cpp_get_define_token (pfile);
- tok = pfile->token_buffer + here;
+ token = list->tokens[i].type;
+ tok = list->tokens[i].val.name.offset + list->namebuf;
+ len = list->tokens[i].val.name.len;
switch (token)
{
case CPP_POP:
@@ -329,90 +370,54 @@ collect_expansion (pfile, arglist)
case CPP_VSPACE:
goto done;
- case CPP_HSPACE:
- if (last_token == STRIZE || last_token == PASTE
- || last_token == START)
- CPP_SET_WRITTEN (pfile, here);
- break;
-
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.) */
- if (arglist == NULL)
- goto norm;
- /* # is not special immediately after PASTE.
- (Implied by 6.10.3.3 para 4.) */
- if (last_token == PASTE)
+ 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.) */
+ if (arglist == NULL || last_token == PASTE)
goto norm;
last_token = STRIZE;
- CPP_SET_WRITTEN (pfile, here); /* delete from replacement text */
break;
case CPP_PASTE:
- /* 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)
+ if (last_token == PASTE)
/* ## ## - the second ## is ordinary. */
goto norm;
else if (last_token == START)
cpp_error (pfile, "`##' at start of macro definition");
-
- /* 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)
+
+ else if (last_token == ARG)
+ /* If the last token was an argument, mark it raw_after. */
+ endpat->raw_after = 1;
+ else 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 and it's in the middle of the line.
- _cpp_lex_token won't return a COMMENT if there was trailing
- space. */
- CPP_SET_WRITTEN (pfile, here);
- if (last_token == START)
- break;
- if (is_hspace (pfile->token_buffer[here-1]))
- 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_WTRADITIONAL (pfile))
- goto maybe_trad_stringify;
- else
- goto norm;
+ if (argc && CPP_WTRADITIONAL (pfile))
+ warn_trad_stringify (pfile, tok, len, argc, argv);
+ goto norm;
case CPP_NAME:
- for (i = 0; i < argc; i++)
- if (!strncmp (tok, argv[i].name, argv[i].len)
- && tok + argv[i].len == CPP_PWRITTEN (pfile))
+ for (j = 0; j < argc; j++)
+ if (argv[j].len == len
+ && !strncmp (tok, argv[j].name, argv[j].len))
goto addref;
/* fall through */
default:
norm:
if (last_token == STRIZE)
- cpp_error (pfile, "`#' is not followed by a macro argument name");
+ 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;
break;
}
@@ -421,85 +426,27 @@ collect_expansion (pfile, arglist)
addref:
{
struct reflist *tpat;
-
+ if (last_token != PASTE && (list->tokens[i].flags & HSPACE_BEFORE))
+ CPP_PUTC (pfile, ' ');
+
/* 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;
+ tpat->rest_args = argv[j].rest_arg;
+ tpat->argno = j;
+ tpat->nchars = CPP_WRITTEN (pfile) - last;
if (endpat == NULL)
pat = tpat;
else
endpat->next = tpat;
endpat = tpat;
- last = here;
+ last = CPP_WRITTEN (pfile);
}
- CPP_SET_WRITTEN (pfile, here); /* discard arg name */
last_token = ARG;
- continue;
-
- maybe_trad_stringify:
- last_token = NORM;
- {
- 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_WTRADITIONAL (pfile))
- 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:
@@ -507,242 +454,225 @@ collect_expansion (pfile, arglist)
cpp_error (pfile, "`#' is not followed by a macro argument name");
else if (last_token == PASTE)
cpp_error (pfile, "`##' at end of macro definition");
-
- if (last_token == START)
- {
- /* Empty macro definition. */
- exp = (U_CHAR *) xstrdup ("\r \r ");
- len = 1;
- }
- else
- {
- /* Trim trailing white space from definition. */
- here = CPP_WRITTEN (pfile);
- while (here > last && is_hspace (pfile->token_buffer [here-1]))
- here--;
- CPP_SET_WRITTEN (pfile, here);
- len = CPP_WRITTEN (pfile) - start + 1;
- /* space for no-concat markers at either end */
- exp = (U_CHAR *) xmalloc (len + 4);
- 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_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 + 3;
+ defn->length = len;
defn->expansion = exp;
defn->pattern = pat;
- defn->rest_args = 0;
+ defn->rest_args = argv && argv[argc - 1].rest_arg;
if (arglist)
{
defn->nargs = argc;
defn->argnames = arglist->namebuf;
if (argv)
- {
- defn->rest_args = argv[argc - 1].rest_arg;
- free (argv);
- }
- free (arglist);
+ free ((PTR) argv);
}
else
{
defn->nargs = -1;
defn->argnames = 0;
- defn->rest_args = 0;
}
return defn;
}
+
+/* Is argument NEW, which has just been added to the argument list,
+ a duplicate of a previous argument name? */
+static int
+duplicate_arg_p (args, new)
+ U_CHAR *args, *new;
+{
+ size_t newlen = strlen (new) + 1;
+ size_t oldlen;
-static struct arglist *
-collect_formal_parameters (pfile)
+ while (args < new)
+ {
+ oldlen = strlen (args) + 1;
+ if (!memcmp (args, new, MIN (oldlen, newlen)))
+ return 1;
+ args += oldlen;
+ }
+ return 0;
+}
+
+static unsigned int
+collect_params (pfile, list, arglist)
cpp_reader *pfile;
+ cpp_toklist *list;
+ struct arglist *arglist;
{
- struct arglist *result = 0;
struct arg *argv = 0;
- U_CHAR *namebuf = (U_CHAR *) xstrdup ("");
+ U_CHAR *namebuf, *p, *tok;
+ unsigned int len, argslen;
+ unsigned int argc, a, i, j;
- U_CHAR *name, *tok;
- size_t argslen = 1;
- int len;
- int argc = 0;
- int i;
- enum cpp_ttype token;
- long old_written;
-
- old_written = CPP_WRITTEN (pfile);
- token = _cpp_get_directive_token (pfile);
- if (token != CPP_OPEN_PAREN)
+ /* The formal parameters list starts at token 1. */
+ if (list->tokens[1].type != CPP_OPEN_PAREN)
{
cpp_ice (pfile, "first token = %d not %d in collect_formal_parameters",
- token, CPP_OPEN_PAREN);
- goto invalid;
+ list->tokens[1].type, CPP_OPEN_PAREN);
+ return 0;
}
-
- argv = (struct arg *) xmalloc (sizeof (struct arg));
- argv[argc].len = 0;
- argv[argc].rest_arg = 0;
- for (;;)
- {
- CPP_SET_WRITTEN (pfile, old_written);
- token = _cpp_get_directive_token (pfile);
- switch (token)
- {
- case CPP_NAME:
- tok = pfile->token_buffer + old_written;
- len = CPP_PWRITTEN (pfile) - tok;
- if (namebuf
- && (name = (U_CHAR *) strstr (namebuf, tok))
- && name[len] == ','
- && (name == namebuf || name[-1] == ','))
- {
- cpp_error (pfile, "duplicate macro argument name `%s'", tok);
- continue;
- }
- if (CPP_PEDANTIC (pfile) && CPP_OPTION (pfile, c99)
- && len == sizeof "__VA_ARGS__" - 1
- && !strncmp (tok, "__VA_ARGS__", len))
- cpp_pedwarn (pfile,
- "C99 does not permit use of `__VA_ARGS__' as a macro argument name");
- namebuf = (U_CHAR *) 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 = (struct arg *) xrealloc (argv, (argc + 1)*sizeof(struct arg));
- argv[argc].len = 0;
- break;
-
- case CPP_CLOSE_PAREN:
- goto done;
+ /* Scan once and count the number of parameters; also check for
+ syntax errors here. */
+ argc = 0;
+ argslen = 0;
+ for (i = 2; i < list->tokens_used; i++)
+ switch (list->tokens[i].type)
+ {
+ case CPP_NAME:
+ argslen += list->tokens[i].val.name.len + 1;
+ argc++;
+ break;
+ case CPP_COMMA:
+ break;
+ case CPP_CLOSE_PAREN:
+ goto scanned;
+ case CPP_VSPACE:
+ cpp_error_with_line (pfile, list->line, list->tokens[i].col,
+ "missing right paren in macro argument list");
+ return 0;
- case CPP_ELLIPSIS:
- goto rest_arg;
+ default:
+ cpp_error_with_line (pfile, list->line, list->tokens[i].col,
+ "syntax error in #define");
+ return 0;
- case CPP_VSPACE:
- cpp_error (pfile, "missing right paren in macro argument list");
- goto invalid;
+ case CPP_ELLIPSIS:
+ if (list->tokens[i-1].type != CPP_NAME)
+ {
+ argslen += sizeof "__VA_ARGS__";
+ argc++;
+ }
+ i++;
+ if (list->tokens[i].type != CPP_CLOSE_PAREN)
+ {
+ cpp_error_with_line (pfile, list->line, list->tokens[i].col,
+ "another parameter follows \"...\"");
+ return 0;
+ }
+ goto scanned;
+ }
- default:
- cpp_error (pfile, "syntax error in #define");
- goto invalid;
- }
- }
+ cpp_ice (pfile, "collect_params: unreachable - i=%d, ntokens=%d, type=%d",
+ i, list->tokens_used, list->tokens[i-1].type);
+ return 0;
- 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_OPTION (pfile, c99))
- cpp_pedwarn (pfile, "C89 does not permit varargs macros");
-
- len = sizeof "__VA_ARGS__" - 1;
- namebuf = (U_CHAR *) xrealloc (namebuf, argslen + len + 1);
- name = &namebuf[argslen - 1];
- argslen += len;
- memcpy (name, "__VA_ARGS__", len);
- argv[argc].len = len;
+ scanned:
+ if (argc == 0) /* function-like macro, no arguments */
+ {
+ arglist->argc = 0;
+ arglist->argv = 0;
+ arglist->namebuf = 0;
+ return i + 1;
}
- else
- if (CPP_PEDANTIC (pfile))
- cpp_pedwarn (pfile, "ISO C does not permit named varargs macros");
-
- argv[argc].rest_arg = 1;
-
- token = _cpp_get_directive_token (pfile);
- if (token != CPP_CLOSE_PAREN)
+ if (argslen == 0)
{
- cpp_error (pfile, "another parameter follows `...'");
- goto invalid;
+ cpp_ice (pfile, "collect_params: argc=%d argslen=0", argc);
+ return 0;
}
- 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;
- namebuf[len - 1] = '\0';
- }
+ /* Now allocate space and copy the suckers. */
+ argv = (struct arg *) xmalloc (argc * sizeof (struct arg));
+ namebuf = (U_CHAR *) xmalloc (argslen);
+ p = namebuf;
+ a = 0;
+ for (j = 2; j < i; j++)
+ switch (list->tokens[j].type)
+ {
+ case CPP_NAME:
+ tok = list->tokens[j].val.name.offset + list->namebuf;
+ len = list->tokens[j].val.name.len;
+ memcpy (p, tok, len);
+ p[len] = '\0';
+ if (duplicate_arg_p (namebuf, p))
+ {
+ cpp_error (pfile, "duplicate macro argument name \"%s\"", tok);
+ a++;
+ break;
+ }
+ if (CPP_PEDANTIC (pfile) && CPP_OPTION (pfile, c99)
+ && len == sizeof "__VA_ARGS__" - 1
+ && !strcmp (p, "__VA_ARGS__"))
+ cpp_pedwarn (pfile,
+ "C99 does not permit use of __VA_ARGS__ as a macro argument name");
+ argv[a].len = len;
+ argv[a].name = p;
+ argv[a].rest_arg = 0;
+ p += len;
+ a++;
+ break;
- CPP_SET_WRITTEN (pfile, old_written);
+ case CPP_COMMA:
+ break;
- 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;
- }
+ case CPP_ELLIPSIS:
+ if (list->tokens[j-1].type != CPP_NAME)
+ {
+ if (CPP_PEDANTIC (pfile) && ! CPP_OPTION (pfile, c99))
+ cpp_pedwarn (pfile, "C89 does not permit varargs macros");
- return result;
-
- invalid:
- if (argv)
- free (argv);
- if (namebuf)
- free (namebuf);
- return 0;
+ argv[a].len = sizeof "__VA_ARGS__" - 1;
+ argv[a].name = p;
+ argv[a].rest_arg = 1;
+ strcpy (p, "__VA_ARGS__");
+ }
+ else
+ {
+ if (CPP_PEDANTIC (pfile))
+ cpp_pedwarn (pfile,
+ "ISO C does not permit named varargs macros");
+ argv[a-1].rest_arg = 1;
+ }
+ break;
+
+ default:
+ cpp_ice (pfile, "collect_params: impossible token type %d",
+ list->tokens[j].type);
+ }
+
+ arglist->argc = argc;
+ arglist->argv = argv;
+ arglist->namebuf = namebuf;
+ return i + 1;
}
-/* 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. */
+/* Create a DEFINITION node for a macro. The replacement text
+ (including formal parameters if present) is in LIST. If FUNLIKE is
+ true, this is a function-like macro. */
DEFINITION *
-_cpp_create_definition (pfile, funlike)
+_cpp_create_definition (pfile, list, funlike)
cpp_reader *pfile;
+ cpp_toklist *list;
int funlike;
{
- struct arglist *args = 0;
- unsigned int line, col;
- const char *file;
+ struct arglist args;
DEFINITION *defn;
+ int replacement = 1; /* replacement begins at this token */
- line = CPP_BUF_LINE (CPP_BUFFER (pfile));
- col = CPP_BUF_COL (CPP_BUFFER (pfile));
- file = CPP_BUFFER (pfile)->nominal_fname;
-
if (funlike)
{
- args = collect_formal_parameters (pfile);
- if (args == 0)
+ replacement = collect_params (pfile, list, &args);
+ if (replacement == 0)
return 0;
}
- defn = collect_expansion (pfile, args);
+ defn = collect_expansion (pfile, list, funlike ? &args : 0, replacement);
if (defn == 0)
return 0;
- defn->line = line;
- defn->file = file;
- defn->col = col;
+ defn->file = CPP_BUFFER (pfile)->nominal_fname;
+ defn->line = list->line;
+ defn->col = list->tokens[0].col;
return defn;
}
@@ -1098,11 +1028,8 @@ _cpp_macroexpand (pfile, hp)
}
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)
+ if (i == nargs - 1 && defn->rest_args)
rest_zero = 1;
else if (i == 0)
cpp_error (pfile, "macro `%s' used without args", hp->name);
@@ -1158,8 +1085,7 @@ _cpp_macroexpand (pfile, hp)
int need_space = -1;
i = 0;
arg->stringified = CPP_WRITTEN (pfile);
- if (!CPP_TRADITIONAL (pfile))
- CPP_PUTC (pfile, '\"'); /* insert beginning quote */
+ CPP_PUTC (pfile, '\"'); /* insert beginning quote */
for (; i < arglen; i++)
{
c = (ARG_BASE + arg->raw)[i];
@@ -1214,14 +1140,13 @@ _cpp_macroexpand (pfile, hp)
CPP_ADJUST_WRITTEN (pfile, 4);
}
}
- if (!CPP_TRADITIONAL (pfile))
- CPP_PUTC (pfile, '\"'); /* insert ending quote */
+ CPP_PUTC (pfile, '\"'); /* insert ending quote */
arg->stringified_length
= CPP_WRITTEN (pfile) - arg->stringified;
}
xbuf_len += args[ap->argno].stringified_length;
}
- else if (ap->raw_before || ap->raw_after || CPP_TRADITIONAL (pfile))
+ 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;
@@ -1288,7 +1213,7 @@ _cpp_macroexpand (pfile, hp)
arg->stringified_length);
totlen += arg->stringified_length;
}
- else if (ap->raw_before || ap->raw_after || CPP_TRADITIONAL (pfile))
+ else if (ap->raw_before || ap->raw_after)
{
U_CHAR *p1 = ARG_BASE + arg->raw;
U_CHAR *l1 = p1 + arg->raw_length;
@@ -1340,7 +1265,6 @@ _cpp_macroexpand (pfile, hp)
{
U_CHAR *expanded = ARG_BASE + arg->expanded;
if (!ap->raw_before && totlen > 0 && arg->expand_length
- && !CPP_TRADITIONAL (pfile)
&& unsafe_chars (pfile, xbuf[totlen - 1], expanded[0]))
{
xbuf[totlen++] = '\r';
@@ -1351,7 +1275,6 @@ _cpp_macroexpand (pfile, hp)
totlen += arg->expand_length;
if (!ap->raw_after && totlen > 0 && offset < defn->length
- && !CPP_TRADITIONAL (pfile)
&& unsafe_chars (pfile, xbuf[totlen - 1], exp[offset]))
{
xbuf[totlen++] = '\r';
@@ -1393,13 +1316,9 @@ _cpp_macroexpand (pfile, hp)
/* Pop the space we've used in the token_buffer for argument expansion. */
CPP_SET_WRITTEN (pfile, old_written);
-
- /* Recursive macro use sometimes works traditionally.
- #define foo(x,y) bar (x (y,0), y)
- foo (foo, baz) */
- if (!CPP_TRADITIONAL (pfile))
- hp->type = T_DISABLED;
+ /* Per C89, a macro cannot be expanded recursively. */
+ hp->type = T_DISABLED;
}
/* Return 1 iff a token ending in C1 followed directly by a token C2
@@ -1520,12 +1439,11 @@ _cpp_compare_defs (pfile, d1, d2)
DEFINITION *d1, *d2;
{
struct reflist *a1, *a2;
- U_CHAR *p1 = d1->expansion;
- U_CHAR *p2 = d2->expansion;
- int first = 1;
if (d1->nargs != d2->nargs)
return 1;
+ if (strcmp (d1->expansion, d2->expansion))
+ return 1;
if (CPP_PEDANTIC (pfile)
&& d1->argnames && d2->argnames)
{
@@ -1545,74 +1463,17 @@ _cpp_compare_defs (pfile, d1, d2)
for (a1 = d1->pattern, a2 = d2->pattern; a1 && a2;
a1 = a1->next, a2 = a2->next)
{
- if (!((a1->nchars == a2->nchars && !strncmp (p1, p2, a1->nchars))
- || !comp_def_part (first, p1, a1->nchars, p2, a2->nchars, 0))
+ if (a1->nchars != a2->nchars
|| a1->argno != a2->argno
|| a1->stringify != a2->stringify
|| a1->raw_before != a2->raw_before
|| a1->raw_after != a2->raw_after)
return 1;
- first = 0;
- p1 += a1->nchars;
- p2 += a2->nchars;
}
if (a1 != a2)
return 1;
-
- return comp_def_part (first, p1, d1->length - (p1 - d1->expansion),
- p2, d2->length - (p2 - d2->expansion), 1);
-}
-/* Return 1 if two parts of two macro definitions are effectively different.
- One of the parts starts at BEG1 and has LEN1 chars;
- the other has LEN2 chars at BEG2.
- Any sequence of whitespace matches any other sequence of whitespace.
- FIRST means these parts are the first of a macro definition;
- so ignore leading whitespace entirely.
- LAST means these parts are the last of a macro definition;
- so ignore trailing whitespace entirely. */
-
-static int
-comp_def_part (first, beg1, len1, beg2, len2, last)
- int first;
- U_CHAR *beg1, *beg2;
- int len1, len2;
- int last;
-{
- register U_CHAR *end1 = beg1 + len1;
- register U_CHAR *end2 = beg2 + len2;
- if (first)
- {
- while (beg1 != end1 && is_space(*beg1))
- beg1++;
- while (beg2 != end2 && is_space(*beg2))
- beg2++;
- }
- if (last)
- {
- while (beg1 != end1 && is_space(end1[-1]))
- end1--;
- while (beg2 != end2 && is_space(end2[-1]))
- end2--;
- }
- while (beg1 != end1 && beg2 != end2)
- {
- if (is_space(*beg1) && is_space(*beg2))
- {
- while (beg1 != end1 && is_space(*beg1))
- beg1++;
- while (beg2 != end2 && is_space(*beg2))
- beg2++;
- }
- else if (*beg1 == *beg2)
- {
- beg1++;
- beg2++;
- }
- else
- break;
- }
- return (beg1 != end1) || (beg2 != end2);
+ return 0;
}
/* Dump the definition of macro MACRO on stdout. The format is suitable
===================================================================
Index: cpphash.h
--- cpphash.h 2000/04/20 19:33:11 1.35
+++ cpphash.h 2000/04/21 17:09:18
@@ -272,7 +272,8 @@ extern HASHNODE **_cpp_lookup_slot PARAM
enum insert_option,
unsigned long *));
extern void _cpp_free_definition PARAMS ((DEFINITION *));
-extern DEFINITION *_cpp_create_definition PARAMS ((cpp_reader *, int));
+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 *,
===================================================================
Index: cpplex.c
--- cpplex.c 2000/04/20 19:33:11 1.19
+++ cpplex.c 2000/04/21 17:09:18
@@ -57,6 +57,8 @@ static void bump_column PARAMS ((cpp_pr
static void expand_name_space PARAMS ((cpp_toklist *));
static void expand_token_space PARAMS ((cpp_toklist *));
static void init_token_list PARAMS ((cpp_reader *, cpp_toklist *, int));
+static void pedantic_whitespace PARAMS ((cpp_reader *, U_CHAR *,
+ unsigned int));
/* Re-allocates PFILE->token_buffer so it will hold at least N more chars. */
@@ -474,7 +476,8 @@ init_token_list (pfile, list, recycle)
list->namebuf = (unsigned char *) xmalloc (list->name_cap);
}
- list->line = pfile->buffer->lineno;
+ if (pfile->buffer)
+ list->line = pfile->buffer->lineno;
list->dir_handler = 0;
list->dir_flags = 0;
}
@@ -490,11 +493,13 @@ _cpp_scan_line (pfile, list)
int i, col;
long written, len;
enum cpp_ttype type;
+ int space_before;
init_token_list (pfile, list, 1);
written = CPP_WRITTEN (pfile);
i = 0;
+ space_before = 0;
for (;;)
{
col = CPP_BUFFER (pfile)->cur - CPP_BUFFER (pfile)->line_base;
@@ -502,17 +507,26 @@ _cpp_scan_line (pfile, list)
len = CPP_WRITTEN (pfile) - written;
CPP_SET_WRITTEN (pfile, written);
if (type == CPP_HSPACE)
- continue;
+ {
+ if (CPP_PEDANTIC (pfile))
+ pedantic_whitespace (pfile, pfile->token_buffer + written, len);
+ space_before = 1;
+ continue;
+ }
if (list->tokens_used >= list->tokens_cap)
expand_token_space (list);
if (list->name_used + len >= list->name_cap)
expand_name_space (list);
+ if (type == CPP_MACRO)
+ type = CPP_NAME;
+
list->tokens_used++;
list->tokens[i].type = type;
list->tokens[i].col = col;
-
+ list->tokens[i].flags = space_before ? HSPACE_BEFORE : 0;
+
if (type == CPP_VSPACE)
break;
@@ -521,8 +535,12 @@ _cpp_scan_line (pfile, list)
memcpy (list->namebuf + list->name_used, CPP_PWRITTEN (pfile), len);
list->name_used += len;
i++;
+ space_before = 0;
}
list->tokens[i].aux = CPP_BUFFER (pfile)->lineno + 1;
+
+ /* XXX Temporary kluge: put back the newline. */
+ FORWARD(-1);
}
@@ -1034,14 +1052,8 @@ _cpp_lex_token (pfile)
For -traditional, a comment is equivalent to nothing. */
if (!CPP_OPTION (pfile, discard_comments))
return CPP_COMMENT;
- else if (CPP_TRADITIONAL (pfile)
- && ! is_space (PEEKC ()))
- {
- if (pfile->parsing_define_directive)
- return CPP_COMMENT;
- else
- goto get_next;
- }
+ else if (CPP_TRADITIONAL (pfile))
+ goto get_next;
else
{
CPP_PUTC (pfile, c);
@@ -1060,7 +1072,7 @@ _cpp_lex_token (pfile)
return CPP_OTHER;
}
- if (pfile->parsing_define_directive && ! CPP_TRADITIONAL (pfile))
+ if (pfile->parsing_define_directive)
{
c2 = PEEKC ();
if (c2 == '#')
@@ -1510,6 +1522,26 @@ maybe_macroexpand (pfile, written)
return 1;
}
+/* Complain about \v or \f in a preprocessing directive (constraint
+ violation, C99 6.10 para 5). Caller has checked CPP_PEDANTIC. */
+static void
+pedantic_whitespace (pfile, p, len)
+ cpp_reader *pfile;
+ U_CHAR *p;
+ unsigned int len;
+{
+ while (len)
+ {
+ if (*p == '\v')
+ cpp_pedwarn (pfile, "vertical tab in preprocessing directive");
+ else if (*p == '\f')
+ cpp_pedwarn (pfile, "form feed in preprocessing directive");
+ p++;
+ len--;
+ }
+}
+
+
enum cpp_ttype
cpp_get_token (pfile)
cpp_reader *pfile;
@@ -1591,14 +1623,10 @@ cpp_get_non_space_token (pfile)
}
/* Like cpp_get_token, except that it does not execute directives,
- does not consume vertical space, and automatically pops off macro
- buffers.
-
- XXX This function will exist only till collect_expansion doesn't
- need to see whitespace anymore, then it'll be merged with
- _cpp_get_directive_token (below). */
+ does not consume vertical space, discards horizontal space, and
+ automatically pops off macro buffers. */
enum cpp_ttype
-_cpp_get_define_token (pfile)
+_cpp_get_directive_token (pfile)
cpp_reader *pfile;
{
long old_written;
@@ -1620,18 +1648,10 @@ _cpp_get_define_token (pfile)
case CPP_HSPACE:
if (CPP_PEDANTIC (pfile))
- {
- U_CHAR *p, *limit;
- p = pfile->token_buffer + old_written;
- limit = CPP_PWRITTEN (pfile);
- while (p < limit)
- {
- if (*p == '\v' || *p == '\f')
- cpp_pedwarn (pfile, "%s in preprocessing directive",
- *p == '\f' ? "formfeed" : "vertical tab");
- p++;
- }
- }
+ pedantic_whitespace (pfile, pfile->token_buffer + old_written,
+ CPP_WRITTEN (pfile) - old_written);
+ CPP_SET_WRITTEN (pfile, old_written);
+ goto get_next;
return CPP_HSPACE;
case CPP_DIRECTIVE:
@@ -1660,23 +1680,6 @@ _cpp_get_define_token (pfile)
}
}
-/* Just like _cpp_get_define_token except that it discards horizontal
- whitespace. */
-
-enum cpp_ttype
-_cpp_get_directive_token (pfile)
- cpp_reader *pfile;
-{
- int old_written = CPP_WRITTEN (pfile);
- for (;;)
- {
- enum cpp_ttype token = _cpp_get_define_token (pfile);
- if (token != CPP_COMMENT && token != CPP_HSPACE)
- return token;
- CPP_SET_WRITTEN (pfile, old_written);
- }
-}
-
/* Determine the current line and column. Used only by read_and_prescan. */
static U_CHAR *
find_position (start, limit, linep)
@@ -2008,6 +2011,7 @@ _cpp_init_input_buffer (pfile)
U_CHAR *tmp;
init_chartab ();
+ init_token_list (pfile, &pfile->directbuf, 0);
/* Determine the appropriate size for the input buffer. Normal C
source files are smaller than eight K. */
Index: cpplib.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cpplib.c,v
retrieving revision 1.150
diff -u -p -r1.150 cpplib.c
--- cpplib.c 2000/04/20 19:33:11 1.150
+++ cpplib.c 2000/04/21 17:09:18
@@ -66,7 +66,6 @@ static int read_line_number PARAMS ((cp
static U_CHAR *detect_if_not_defined PARAMS ((cpp_reader *));
static int consider_directive_while_skipping
PARAMS ((cpp_reader *, IF_STACK *));
-static int get_macro_name PARAMS ((cpp_reader *));
/* Values for the flags field of the table below. KANDR and COND
directives come from traditional (K&R) C. The difference is, if we
@@ -310,36 +309,6 @@ pass_thru_directive (buf, len, pfile, ke
CPP_PUTS_Q (pfile, buf, len);
}
-/* Subroutine of do_define: determine the name of the macro to be
- defined. */
-
-static int
-get_macro_name (pfile)
- cpp_reader *pfile;
-{
- long here, len;
-
- here = CPP_WRITTEN (pfile);
- if (_cpp_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;
- }
-
- return len;
-
- invalid:
- _cpp_skip_rest_of_line (pfile);
- return 0;
-}
-
/* Process a #define command. */
static int
@@ -348,47 +317,60 @@ do_define (pfile)
{
HASHNODE **slot;
DEFINITION *def = 0;
- long here;
unsigned long hash;
int len;
int funlike = 0, empty = 0;
U_CHAR *sym;
- enum cpp_ttype token;
+ cpp_toklist *list = &pfile->directbuf;
pfile->no_macro_expand++;
pfile->parsing_define_directive++;
CPP_OPTION (pfile, discard_comments)++;
- here = CPP_WRITTEN (pfile);
- len = get_macro_name (pfile);
- if (len == 0)
- goto out;
-
- /* 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_scan_line (pfile, list);
+ /* First token on the line must be a NAME. There must be at least
+ one token (the VSPACE at the end). */
+ if (list->tokens[0].type != CPP_NAME)
+ {
+ cpp_error_with_line (pfile, list->line, list->tokens[0].col,
+ "#define must be followed by an identifier");
+ goto out;
+ }
+
+ sym = list->namebuf + list->tokens[0].val.name.offset;
+ len = list->tokens[0].val.name.len;
+
+ /* That NAME is not allowed to be "defined". (Not clear if the
+ standard requires this.) */
+ if (len == 7 && !strncmp (sym, "defined", 7))
+ {
+ cpp_error_with_line (pfile, list->line, list->tokens[0].col,
+ "\"defined\" is not a legal macro name");
+ goto out;
+ }
+
+
+ if (list->tokens_used == 2 && list->tokens[1].type == CPP_VSPACE)
+ empty = 0; /* Empty definition of object-like macro. */
+
/* If the next character, with no intervening whitespace, is '(',
- then this is a function-like macro.
- XXX Layering violation. */
- CPP_SET_MARK (pfile);
- token = _cpp_get_directive_token (pfile);
- if (token == CPP_VSPACE)
- empty = 0; /* Empty definition of object like macro. */
- else if (token == CPP_OPEN_PAREN && ADJACENT_TO_MARK (pfile))
- funlike = 1;
- else if (ADJACENT_TO_MARK (pfile))
- /* If this is an object-like macro, C99 requires white space after
- the name. */
- cpp_pedwarn (pfile, "missing white space after `#define %.*s'", len, sym);
- CPP_GOTO_MARK (pfile);
- CPP_SET_WRITTEN (pfile, here);
+ 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, funlike);
+ def = _cpp_create_definition (pfile, list, funlike);
if (def == 0)
goto out;
}
===================================================================
Index: cpplib.h
--- cpplib.h 2000/04/20 19:33:11 1.80
+++ cpplib.h 2000/04/21 17:09:18
@@ -135,6 +135,9 @@ struct cpp_name
unsigned int offset; /* from list->namebuf */
};
+/* Per token flags. */
+#define HSPACE_BEFORE (1 << 0) /* token preceded by hspace */
+
/* A preprocessing token.
This has been carefully packed and should occupy 16 bytes on
both 32- and 64-bit hosts. */
@@ -146,7 +149,7 @@ struct cpp_token
#else
unsigned char type;
#endif
- unsigned char flags; /* flags - not presently used */
+ unsigned char flags; /* flags - see above */
unsigned int aux; /* hash of a NAME, or something -
see uses in the code */
union
@@ -435,7 +438,11 @@ struct cpp_options
struct cpp_reader
{
+ /* Top of buffer stack. */
cpp_buffer *buffer;
+
+ /* Token list used by get_directive_token. */
+ cpp_toklist directbuf;
/* A buffer used for both for cpp_get_token's output, and also internally. */
unsigned char *token_buffer;