cpphash.c (struct arg, [...]): Const-ify strings.
authorZack Weinberg <zack@wolery.cumb.org>
Fri, 21 Apr 2000 17:18:50 +0000 (17:18 +0000)
committerZack Weinberg <zack@gcc.gnu.org>
Fri, 21 Apr 2000 17:18:50 +0000 (17:18 +0000)
* 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".

From-SVN: r33309

gcc/ChangeLog
gcc/cpphash.c
gcc/cpphash.h
gcc/cpplex.c
gcc/cpplib.c
gcc/cpplib.h

index 733d02d43e6064feb5483a4702be9b691d07b52b..f9ef0700408002a8bd5c5d1c9266d128f9bfa8b8 100644 (file)
@@ -1,5 +1,34 @@
 2000-04-21  Zack Weinberg  <zack@wolery.cumb.org>
 
+       * 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".
+
        * predict.c (estimate_probability): New heuristic: if a jump
        branches around a block with no successors, predict it taken.
        Disentangle control flow.
index 439cc805f453d7fb5a00322d86a865e65d8f02d7..c39ca9f5fa69c5bdfcbed2127aa9259d5e5e3eaf 100644 (file)
@@ -36,8 +36,6 @@ static int eq_HASHNODE                  PARAMS ((const void *, const void *));
 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 ((HASHNODE *, cpp_reader *));
 
 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:
 
@@ -508,241 +455,224 @@ collect_expansion (pfile, arglist)
   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;
 }
 
-static struct arglist *
-collect_formal_parameters (pfile)
+/* 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;
+
+  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)
+ scanned:
+  if (argc == 0)       /* function-like macro, no arguments */
     {
-      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;
+      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;
+           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;
 
- invalid:
-  if (argv)
-    free (argv);
-  if (namebuf)
-    free (namebuf);
-  return 0;
+      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;
-
-  line = CPP_BUF_LINE (CPP_BUFFER (pfile));
-  col = CPP_BUF_COL (CPP_BUFFER (pfile));
-  file = CPP_BUFFER (pfile)->nominal_fname;
+  int replacement = 1;  /* replacement begins at this token */
 
   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';
@@ -1394,12 +1317,8 @@ _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 b0ac3c654b78a985ba9540117cad204d02e630d4..2b8a5d1fa1a98b138ad31ddc24796e428bbe7f54 100644 (file)
@@ -272,7 +272,8 @@ extern HASHNODE **_cpp_lookup_slot  PARAMS ((cpp_reader *,
                                                 enum insert_option,
                                                 unsigned long *));
 extern void _cpp_free_definition       PARAMS ((DEFINITION *));
-extern DEFINITION *_cpp_create_definition PARAMS ((cpp_reader *, 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 deae87e94475fc4af75a6ccf99f2fb31f942c1d1..effb6ca05103c4065e0765fe77b4cd036ac46c86 100644 (file)
@@ -57,6 +57,8 @@ static void bump_column               PARAMS ((cpp_printer *, unsigned int,
 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 fb6b77099493fb3bfc8e633cb4edd1053d34be1c..f8815842f58ccaaa0d4fb1366156272a1992b459 100644 (file)
@@ -66,7 +66,6 @@ static int read_line_number           PARAMS ((cpp_reader *, int *));
 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, keyword)
   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;
+  _cpp_scan_line (pfile, list);
 
-  /* 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';
+  /* 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 6e3561ac01b632a2308b36b7db6df893d1264d4b..764d8e6c9e3c6d896a5f7d24a779f028e003ba58 100644 (file)
@@ -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,8 +438,12 @@ 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;
   /* Allocated size of token_buffer.  CPP_RESERVE allocates space.  */