* cpplib.h (CPP_ASSERTION, CPP_STRINGIZE, CPP_TOKPASTE): New
authorzack <zack@138bc75d-0d04-0410-961f-82ee72b054a4>
Wed, 1 Mar 2000 00:57:09 +0000 (00:57 +0000)
committerzack <zack@138bc75d-0d04-0410-961f-82ee72b054a4>
Wed, 1 Mar 2000 00:57:09 +0000 (00:57 +0000)
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.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@32274 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/ChangeLog
gcc/cppexp.c
gcc/cpphash.c
gcc/cpphash.h
gcc/cppinit.c
gcc/cpplib.c
gcc/cpplib.h
gcc/testsuite/gcc.dg/20000209-2.c
gcc/testsuite/gcc.dg/strpaste-2.c [new file with mode: 0644]

index c65598e..c2638d3 100644 (file)
@@ -1,3 +1,64 @@
+2000-02-29  Zack Weinberg  <zack@wolery.cumb.org>
+
+       * cpplib.h (CPP_ASSERTION, CPP_STRINGIZE, CPP_TOKPASTE): New
+       token types.
+       (struct cpp_reader): Add parsing_if_directive and
+       parsing_define_directive flags.               
+       (struct cpp_options): Remove output_conditionals flag.
+       (check_macro_name): Delete prototype.
+
+       * cpphash.h (struct macrodef): Delete.
+       (struct reflist): Separate from struct definition.
+       (struct definition): Remove unused fields.  Add column number.
+       (create_definition): Returns a DEFINITION *.  Takes a
+       cpp_reader * and an int.
+
+       * cpphash.c (SKIP_WHITE_SPACE): Delete.
+       (PEEKC): Copy defn from cpplib.c.
+       (rest_extension, REST_EXTENSION_LENGTH): Delete.
+       (struct arg): New.
+       (struct arglist): Simplify.
+       (collect_expansion): Rewrite.  Get tokens by calling
+       cpp_get_token.  Add more error checking.
+       (collect_formal_parameters): New function, broken out of
+       create_definition and reworked to use get_directive_token.
+       (create_definition): All real work is now in collect_expansion
+       and collect_formal_parameters.  do_define handles finding the
+       macro name.  Return a DEFINITION, not a MACRODEF.
+       (macroexpand): Replace bcopy with memcpy throughout.  Replace
+       character-at-a-time copy loop with memcpy and pointer increments.
+       (compare-defs): d1->argnames / d2->argnames might be null.
+
+       * cpplib.c (copy_rest_of_line): Delete function.
+       (skip_rest_of_line): Do all the work ourselves.
+       (skip_string): New function.
+       (parse_string): Use skip_string.
+       (get_macro_name): New function.
+       (check_macro_name): Delete.
+       (copy_comment): Use CPP_RESERVE and CPP_PUTC_Q.
+       (cpp_skip_hspace): Use CPP_BUMP_LINE.
+       (handle_directive): ICE if we're called on a macro buffer.
+       (do_define): Determine macro name and type (funlike/objlike)
+       here.  Expunge all uses of MACRODEF.
+       (cpp_push_buffer): Set line_base to NULL.
+       (do_undef, read_line_number): Don't worry about getting a POP token.
+       (eval_if_expression): Set/reset parsing_if_directive around
+       cpp_parse_expr. Don't clear only_seen_white.
+       (skip_if_group): Remove output_conditionals logic.  Use
+       skip_rest_of_line.
+       (cpp_get_token): Return ASSERTION, STRINGIZE, and TOKPASTE
+       tokens under appropriate conditions.
+       (cpp_unassert): Call do_unassert not do_assert.  Oops.
+
+       * cppexp.c (parse_defined): New function, break out of
+       cpp_lex.
+       (cpp_lex): We now get CPP_ASSERTION tokens and can check them
+       ourselves, with cpp_defined.
+       * cppinit.c (cpp_handle_option, print_help): Delete -ifoutput.
+
+       * gcc.dg/20000209-2.c: Turn off -pedantic-errors.
+       * gcc.dg/strpaste-2.c: New.
+
 2000-02-29  Mark Mitchell  <mark@codesourcery.com>
 
        * fold-const.c (size_binop): Don't asert inputs are the same and
index f659559..ec9fecf 100644 (file)
@@ -81,6 +81,7 @@ static HOST_WIDEST_INT left_shift PARAMS ((cpp_reader *, HOST_WIDEST_INT, int, u
 static HOST_WIDEST_INT right_shift PARAMS ((cpp_reader *, HOST_WIDEST_INT, int, unsigned HOST_WIDEST_INT));
 static struct operation parse_number PARAMS ((cpp_reader *, U_CHAR *, U_CHAR *));
 static struct operation parse_charconst PARAMS ((cpp_reader *, U_CHAR *, U_CHAR *));
+static struct operation parse_defined PARAMS ((cpp_reader *));
 static struct operation cpp_lex PARAMS ((cpp_reader *, int));
 extern HOST_WIDEST_INT cpp_parse_expr PARAMS ((cpp_reader *));
 static HOST_WIDEST_INT cpp_parse_escape PARAMS ((cpp_reader *, U_CHAR **, HOST_WIDEST_INT));
@@ -349,6 +350,53 @@ parse_charconst (pfile, start, end)
   return op;
 }
 
+static struct operation
+parse_defined (pfile)
+     cpp_reader *pfile;
+{
+  int paren = 0, len;
+  U_CHAR *tok;
+  enum cpp_token token;
+  struct operation op;
+  long old_written = CPP_WRITTEN (pfile);
+
+  op.unsignedp = 0;
+  op.op = INT;
+
+  pfile->no_macro_expand++;
+  token = get_directive_token (pfile);
+  if (token == CPP_LPAREN)
+    {
+      paren++;
+      CPP_SET_WRITTEN (pfile, old_written);
+      token = get_directive_token (pfile);
+    }
+
+  if (token != CPP_NAME)
+    goto oops;
+
+  tok = pfile->token_buffer + old_written;
+  len = CPP_PWRITTEN (pfile) - tok;
+  op.value = cpp_defined (pfile, tok, len);
+
+  if (paren)
+    {
+      if (get_directive_token (pfile) != CPP_RPAREN)
+       goto oops;
+    }
+  CPP_SET_WRITTEN (pfile, old_written);
+  pfile->no_macro_expand--;
+  return op;
+
+ oops:
+  CPP_SET_WRITTEN (pfile, old_written);
+  pfile->no_macro_expand--;
+  cpp_error (pfile, "`defined' without an identifier");
+
+  op.op = ERROR;
+  return op;
+}
+
 
 struct token {
   const char *operator;
@@ -389,7 +437,7 @@ cpp_lex (pfile, skip_evaluation)
   tok_end = CPP_PWRITTEN (pfile);
   CPP_SET_WRITTEN (pfile, old_written);
   switch (token)
-  {
+    {
     case CPP_EOF: /* Should not happen ...  */
     case CPP_VSPACE:
       op.op = 0;
@@ -407,51 +455,22 @@ cpp_lex (pfile, skip_evaluation)
       return parse_charconst (pfile, tok_start, tok_end);
 
     case CPP_NAME:
+      if (!strcmp (tok_start, "defined"))
+       return parse_defined (pfile);
+
       op.op = INT;
       op.unsignedp = 0;
       op.value = 0;
-      if (strcmp (tok_start, "defined"))
-       {
-         if (CPP_WARN_UNDEF (pfile) && !skip_evaluation)
-           cpp_warning (pfile, "`%.*s' is not defined",
-                        (int) (tok_end - tok_start), tok_start);
-       }
-      else
-       {
-         int paren = 0, len;
-         U_CHAR *tok;
-
-         pfile->no_macro_expand++;
-         token = get_directive_token (pfile);
-         if (token == CPP_LPAREN)
-           {
-             paren++;
-             CPP_SET_WRITTEN (pfile, old_written);
-             token = get_directive_token (pfile);
-           }
 
-         if (token != CPP_NAME)
-           goto oops;
-
-         tok = pfile->token_buffer + old_written;
-         len = CPP_PWRITTEN (pfile) - tok;
-         if (cpp_defined (pfile, tok, len))
-           op.value = 1;
-
-         if (paren)
-           {
-             if (get_directive_token (pfile) != CPP_RPAREN)
-               goto oops;
-           }
-         CPP_SET_WRITTEN (pfile, old_written);
-         pfile->no_macro_expand--;
-       }
+      if (CPP_WARN_UNDEF (pfile) && !skip_evaluation)
+       cpp_warning (pfile, "`%.*s' is not defined",
+                    (int) (tok_end - tok_start), tok_start);
       return op;
 
-    oops:
-      CPP_SET_WRITTEN (pfile, old_written);
-      pfile->no_macro_expand--;
-      cpp_error (pfile, "`defined' without an identifier");
+    case CPP_ASSERTION:
+      op.op = INT;
+      op.unsignedp = 0;
+      op.value = cpp_defined (pfile, tok_start, tok_end - tok_start);
       return op;
 
     case CPP_OTHER:
@@ -468,13 +487,6 @@ cpp_lex (pfile, skip_evaluation)
          op.op = toktab->token; 
          return op;
        }
-      else if (tok_start + 1 == tok_end && *tok_start == '#')
-       {
-         CPP_FORWARD (CPP_BUFFER (pfile), -1);
-         op.op = INT;
-         op.value = cpp_read_check_assertion (pfile);
-         return op;
-       }
       /* fall through */
     default:
       op.op = *tok_start;
index 9d79979..c5c20ac 100644 (file)
@@ -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;
index c9273d5..278ad24 100644 (file)
@@ -18,15 +18,6 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 #ifndef __GCC_CPPHASH__
 #define __GCC_CPPHASH__
 
-/* Structure returned by create_definition */
-typedef struct macrodef MACRODEF;
-struct macrodef
-{
-  struct definition *defn;
-  const U_CHAR *symnam;
-  int symlen;
-};
-
 /* Structure allocated for every #define.  For a simple replacement
    such as
        #define foo bar ,
@@ -48,30 +39,35 @@ struct macrodef
      { (0, 1), (1, 1), (1, 1), ..., (1, 1), NULL }
    where (x, y) means (nchars, argno). */
 
+struct reflist
+{
+  struct reflist *next;
+  char stringify;              /* nonzero if this arg was preceded by a
+                                  # operator. */
+  char raw_before;             /* Nonzero if a ## operator before arg. */
+  char raw_after;              /* Nonzero if a ## operator after arg. */
+  char rest_args;              /* Nonzero if this arg. absorbs the rest */
+  int nchars;                  /* Number of literal chars to copy before
+                                  this arg occurrence.  */
+  int argno;                   /* Number of arg to substitute (origin-0) */
+};
+
 typedef struct definition DEFINITION;
-struct definition {
+struct definition
+{
   int nargs;
   int length;                  /* length of expansion string */
-  unsigned char *expansion;
+  U_CHAR *expansion;
   int line;                    /* Line number of definition */
+  int col;
   const char *file;            /* File of definition */
   char rest_args;              /* Nonzero if last arg. absorbs the rest */
-  struct reflist {
-    struct reflist *next;
-    char stringify;            /* nonzero if this arg was preceded by a
-                                  # operator. */
-    char raw_before;           /* Nonzero if a ## operator before arg. */
-    char raw_after;            /* Nonzero if a ## operator after arg. */
-    char rest_args;            /* Nonzero if this arg. absorbs the rest */
-    int nchars;                        /* Number of literal chars to copy before
-                                  this arg occurrence.  */
-    int argno;                 /* Number of arg to substitute (origin-0) */
-  } *pattern;
-  /* Names of macro args, concatenated in reverse order
-     with comma-space between them.
-     The only use of this is that we warn on redefinition
-     if this differs between the old and new definitions.  */
-  unsigned char *argnames;
+  struct reflist *pattern;
+
+  /* Names of macro args, concatenated in order with commas between
+     them.  The only use of this is that we warn on redefinition if
+     this differs between the old and new definitions.  */
+  U_CHAR *argnames;
 };
 
 /* different kinds of things that can appear in the value field
@@ -102,8 +98,7 @@ extern HASHNODE *cpp_lookup    PARAMS ((cpp_reader *, const U_CHAR *, int));
 extern void free_definition      PARAMS ((DEFINITION *));
 extern void delete_macro         PARAMS ((HASHNODE *));
 
-extern MACRODEF create_definition PARAMS ((U_CHAR *, U_CHAR *,
-                                          cpp_reader *));
+extern DEFINITION *create_definition PARAMS ((cpp_reader *, int));
 extern int compare_defs                  PARAMS ((cpp_reader *, DEFINITION *,
                                           DEFINITION *));
 extern void macroexpand                  PARAMS ((cpp_reader *, HASHNODE *));
index eb2124e..d6fbad2 100644 (file)
@@ -1256,9 +1256,6 @@ cpp_handle_option (pfile, argc, argv)
                opts->include_prefix_len = strlen (argv[i]);
              }
          }
-       else if (!strcmp (argv[i], "-ifoutput"))
-         opts->output_conditionals = 1;
-
        break;
       
       case 'o':
@@ -1736,7 +1733,6 @@ Switches:\n\
   -dD                       Preserve macro definitions in output\n\
   -dN                       As -dD except that only the names are preserved\n\
   -dI                       Include #include directives in the output\n\
-  -ifoutput                 Describe skipped code blocks in output \n\
   -P                        Do not generate #line directives\n\
   -$                        Do not allow '$' in identifiers\n\
   -remap                    Remap file names when including files.\n\
index 9f96297..8cdc241 100644 (file)
@@ -46,7 +46,8 @@ extern HOST_WIDEST_INT cpp_parse_expr PARAMS ((cpp_reader *));
 
 /* `struct directive' defines one #-directive, including how to handle it.  */
 
-struct directive {
+struct directive
+{
   int length;                  /* Length of name */
   int (*func)                  /* Function to handle directive */
     PARAMS ((cpp_reader *, const struct directive *));
@@ -93,7 +94,7 @@ static enum cpp_token null_underflow  PARAMS ((cpp_reader *));
 static int null_cleanup                        PARAMS ((cpp_buffer *, cpp_reader *));
 static int skip_comment                        PARAMS ((cpp_reader *, int));
 static int copy_comment                        PARAMS ((cpp_reader *, int));
-static void copy_rest_of_line          PARAMS ((cpp_reader *));
+static void skip_string                        PARAMS ((cpp_reader *, int));
 static void skip_rest_of_line          PARAMS ((cpp_reader *));
 static void cpp_skip_hspace            PARAMS ((cpp_reader *));
 static int handle_directive            PARAMS ((cpp_reader *));
@@ -108,6 +109,7 @@ static void skip_block_comment              PARAMS ((cpp_reader *));
 static void skip_line_comment          PARAMS ((cpp_reader *));
 static void parse_set_mark             PARAMS ((cpp_reader *));
 static void parse_goto_mark            PARAMS ((cpp_reader *));
+static int get_macro_name              PARAMS ((cpp_reader *));
 
 /* Here is the actual list of #-directives.
    This table is ordered by frequency of occurrence; the numbers
@@ -410,10 +412,13 @@ copy_comment (pfile, m)
   if (skip_comment (pfile, m) == m)
     return m;
 
-  CPP_PUTC (pfile, m);
-  for (limit = CPP_BUFFER (pfile)->cur; start <= limit; start++)
+  limit = CPP_BUFFER (pfile)->cur;
+  CPP_RESERVE (pfile, limit - start + 2);
+  CPP_PUTC_Q (pfile, m);
+  for (; start <= limit; start++)
     if (*start != '\r')
-      CPP_PUTC (pfile, *start);
+      CPP_PUTC_Q (pfile, *start);
+
   return ' ';
 }
 
@@ -447,7 +452,7 @@ cpp_skip_hspace (pfile)
                break;
            }
          else
-           CPP_BUFFER (pfile)->lineno++;
+           CPP_BUMP_LINE (pfile);
        }
       else if (c == '/' || c == '-')
        {
@@ -461,11 +466,10 @@ cpp_skip_hspace (pfile)
   FORWARD(-1);
 }
 
-/* Read the rest of the current line.
-   The line is appended to PFILE's output buffer.  */
+/* Read and discard the rest of the current line.  */
 
 static void
-copy_rest_of_line (pfile)
+skip_rest_of_line (pfile)
      cpp_reader *pfile;
 {
   for (;;)
@@ -476,32 +480,21 @@ copy_rest_of_line (pfile)
        case '\n':
          FORWARD(-1);
        case EOF:
-         CPP_NUL_TERMINATE (pfile);
          return;
 
        case '\r':
-         if (CPP_BUFFER (pfile)->has_escapes)
-           break;
-         else
-           {
-             CPP_BUFFER (pfile)->lineno++;
-             continue;
-           }
+         if (! CPP_BUFFER (pfile)->has_escapes)
+           CPP_BUMP_LINE (pfile);
+         break;
+         
        case '\'':
        case '\"':
-         parse_string (pfile, c);
-         continue;
+         skip_string (pfile, c);
+         break;
+
        case '/':
-         if (PEEKC() == '*')
-           {
-             if (CPP_TRADITIONAL (pfile))
-               CPP_PUTS (pfile, "/**/", 4);
-             skip_block_comment (pfile);
-             continue;
-           }
-         /* else fall through */
        case '-':
-         c = skip_comment (pfile, c);
+         skip_comment (pfile, c);
          break;
 
        case '\f':
@@ -512,23 +505,9 @@ copy_rest_of_line (pfile)
          break;
 
        }
-      CPP_PUTC (pfile, c);
     }
 }
 
-/* FIXME: It is almost definitely a performance win to make this do
-   the scan itself.  >75% of calls to copy_r_o_l are from here or
-   skip_if_group, which means the common case is to copy stuff into the
-   token_buffer only to discard it.  */
-static void
-skip_rest_of_line (pfile)
-     cpp_reader *pfile;
-{
-  long old = CPP_WRITTEN (pfile);
-  copy_rest_of_line (pfile);
-  CPP_SET_WRITTEN (pfile, old);
-}
-
 /* Handle a possible # directive.
    '#' has already been read.  */
 
@@ -542,6 +521,12 @@ handle_directive (pfile)
   U_CHAR *ident;
   long old_written = CPP_WRITTEN (pfile);
 
+  if (CPP_IS_MACRO_BUFFER (CPP_BUFFER (pfile)))
+    {
+      cpp_ice (pfile, "handle_directive called on macro buffer");
+      return 0;
+    }
+
   cpp_skip_hspace (pfile);
 
   c = PEEKC ();
@@ -629,71 +614,88 @@ pass_thru_directive (buf, len, pfile, keyword)
   CPP_PUTS_Q (pfile, buf, len);
 }
 
-/* Check a purported macro name SYMNAME, and yield its length.  */
+/* Subroutine of do_define: determine the name of the macro to be
+   defined.  */
 
-int
-check_macro_name (pfile, symname)
+static int
+get_macro_name (pfile)
      cpp_reader *pfile;
-     const U_CHAR *symname;
 {
-  const U_CHAR *p;
-  int sym_length;
-
-  for (p = symname; is_idchar(*p); p++)
-    ;
-  sym_length = p - symname;
-  if (sym_length == 0
-      || (sym_length == 1 && *symname == 'L' && (*p == '\'' || *p == '"')))
-    cpp_error (pfile, "invalid macro name");
-  else if (!is_idstart(*symname)
-          || (! strncmp (symname, "defined", 7) && sym_length == 7)) {
-    U_CHAR *msg;                       /* what pain...  */
-    msg = (U_CHAR *) alloca (sym_length + 1);
-    bcopy (symname, msg, sym_length);
-    msg[sym_length] = 0;
-    cpp_error (pfile, "invalid macro name `%s'", msg);
-  }
-  return sym_length;
+  long here, len;
+
+  here = CPP_WRITTEN (pfile);
+  pfile->no_macro_expand++;
+  if (get_directive_token (pfile) != CPP_NAME)
+    {
+      cpp_error (pfile, "`#define' must be followed by an identifier");
+      goto invalid;
+    }
+
+  len = CPP_WRITTEN (pfile) - here;
+  if (len == 7 && !strncmp (pfile->token_buffer + here, "defined", 7))
+    {
+      cpp_error (pfile, "`defined' is not a legal macro name");
+      goto invalid;
+    }
+
+  pfile->no_macro_expand--;
+  return len;
+
+ invalid:
+  skip_rest_of_line (pfile);
+  pfile->no_macro_expand--;
+  return 0;
 }
 
 /* Process a #define command.
    KEYWORD is the keyword-table entry for #define,
-   or NULL for a "predefined" macro,
-   or the keyword-table entry for #pragma in the case of a #pragma poison.  */
+   or NULL for a "predefined" macro.  */
 
 static int
 do_define (pfile, keyword)
      cpp_reader *pfile;
      const struct directive *keyword;
 {
-  MACRODEF mdef;
   HASHNODE *hp;
+  DEFINITION *def;
   long here;
-  U_CHAR *macro, *buf, *end;
+  int len, c;
+  int funlike = 0;
+  U_CHAR *sym;
 
   here = CPP_WRITTEN (pfile);
-  copy_rest_of_line (pfile);
-
-  /* Copy out the line so we can pop the token buffer. */
-  buf = pfile->token_buffer + here;
-  end = CPP_PWRITTEN (pfile);
-  macro = (U_CHAR *) alloca (end - buf + 1);
-  memcpy (macro, buf, end - buf + 1);
-  end = macro + (end - buf);
+  len = get_macro_name (pfile);
+  if (len == 0)
+    return 0;
 
+  /* Copy out the name so we can pop the token buffer.  */
+  len = CPP_WRITTEN (pfile) - here;
+  sym = (U_CHAR *) alloca (len + 1);
+  memcpy (sym, pfile->token_buffer + here, len);
+  sym[len] = '\0';
   CPP_SET_WRITTEN (pfile, here);
 
-  mdef = create_definition (macro, end, pfile);
-  if (mdef.defn == 0)
+  /* If the next character, with no intervening whitespace, is '(',
+     then this is a function-like macro.  */
+  c = PEEKC ();
+  if (c == '(')
+    funlike = 1;
+  else if (c != '\n' && !is_hspace (c))
+    /* Otherwise, C99 requires white space after the name.  We treat it
+       as an object-like macro if this happens, with a warning.  */
+    cpp_pedwarn (pfile, "missing white space after `#define %.*s'", len, sym);
+
+  def = create_definition (pfile, funlike);
+  if (def == 0)
     return 0;
 
-  if ((hp = cpp_lookup (pfile, mdef.symnam, mdef.symlen)) != NULL)
+  if ((hp = cpp_lookup (pfile, sym, len)) != NULL)
     {
       int ok;
 
       /* Redefining a macro is ok if the definitions are the same.  */
       if (hp->type == T_MACRO)
-       ok = ! compare_defs (pfile, mdef.defn, hp->value.defn);
+       ok = ! compare_defs (pfile, def, hp->value.defn);
       /* Redefining a constant is ok with -D.  */
       else if (hp->type == T_CONST || hp->type == T_STDC)
         ok = ! CPP_OPTIONS (pfile)->done_initializing;
@@ -704,14 +706,15 @@ do_define (pfile, keyword)
       if (! ok)
        {
          if (hp->type == T_POISON)
-           cpp_error (pfile, "redefining poisoned `%.*s'", 
-                      mdef.symlen, mdef.symnam);
+           cpp_error (pfile, "redefining poisoned `%.*s'", len, sym);
          else
-           cpp_pedwarn (pfile, "`%.*s' redefined", mdef.symlen, mdef.symnam);
+           cpp_pedwarn (pfile, "`%.*s' redefined", len, sym);
          if (hp->type == T_MACRO && CPP_OPTIONS (pfile)->done_initializing)
-           cpp_pedwarn_with_file_and_line (pfile, hp->value.defn->file,
-                                           hp->value.defn->line, -1,
+           {
+             DEFINITION *d = hp->value.defn;
+             cpp_pedwarn_with_file_and_line (pfile, d->file, d->line, d->col,
                        "this is the location of the previous definition");
+           }
        }
       if (hp->type != T_POISON)
        {
@@ -719,19 +722,19 @@ do_define (pfile, keyword)
          if (hp->type == T_MACRO)
            free_definition (hp->value.defn);
          hp->type = T_MACRO;
-         hp->value.defn = mdef.defn;
+         hp->value.defn = def;
        }
     }
   else
-    cpp_install (pfile, mdef.symnam, mdef.symlen, T_MACRO, (char *)mdef.defn);
+    cpp_install (pfile, sym, len, T_MACRO, (char *) def);
 
   if (keyword != NULL && keyword->type == T_DEFINE)
     {
       if (CPP_OPTIONS (pfile)->debug_output
          || CPP_OPTIONS (pfile)->dump_macros == dump_definitions)
-       dump_definition (pfile, mdef.symnam, mdef.symlen, mdef.defn);
+       dump_definition (pfile, sym, len, def);
       else if (CPP_OPTIONS (pfile)->dump_macros == dump_names)
-       pass_thru_directive (mdef.symnam, mdef.symlen, pfile, keyword);
+       pass_thru_directive (sym, len, pfile, keyword);
     }
 
   return 0;
@@ -766,6 +769,7 @@ cpp_push_buffer (pfile, buffer, length)
   new->alimit = new->rlimit = buffer + length;
   new->prev = buf;
   new->mark = -1;
+  new->line_base = NULL;
 
   CPP_BUFFER (pfile) = new;
   return new;
@@ -1309,7 +1313,7 @@ read_line_number (pfile, num)
     }
   else
     {
-      if (token != CPP_VSPACE && token != CPP_EOF && token != CPP_POP)
+      if (token != CPP_VSPACE && token != CPP_EOF)
        cpp_error (pfile, "invalid format `#line' command");
       return 0;
     }
@@ -1467,15 +1471,14 @@ do_undef (pfile, keyword)
   len = limit - buf;
   name = (U_CHAR *) alloca (len + 1);
   memcpy (name, buf, len);
-  name[limit - buf] = '\0';
+  name[len] = '\0';
 
   token = get_directive_token (pfile);
-  if (token != CPP_VSPACE && token != CPP_POP)
+  if (token != CPP_VSPACE)
   {
       cpp_pedwarn (pfile, "junk on line after #undef");
       skip_rest_of_line (pfile);
   }
-
   CPP_SET_WRITTEN (pfile, here);
 
   while ((hp = cpp_lookup (pfile, name, len)) != NULL)
@@ -1950,11 +1953,9 @@ eval_if_expression (pfile)
   HOST_WIDEST_INT value;
   long old_written = CPP_WRITTEN (pfile);
 
-  /* Work around bug in cpp_get_token where it may mistake an
-     assertion for a directive.  */
-  pfile->only_seen_white = 0;
-
+  pfile->parsing_if_directive++;
   value = cpp_parse_expr (pfile);
+  pfile->parsing_if_directive--;
 
   skip_rest_of_line (pfile);
   CPP_SET_WRITTEN (pfile, old_written); /* Pop */
@@ -2148,13 +2149,6 @@ skip_if_group (pfile)
   U_CHAR *beg_of_line;
   long old_written;
 
-  if (CPP_OPTIONS (pfile)->output_conditionals)
-    {
-      CPP_PUTS (pfile, "#failed\n", 8);
-      pfile->lineno++;
-      output_line_command (pfile, same_file);
-    }
-
   old_written = CPP_WRITTEN (pfile);
   
   for (;;)
@@ -2166,8 +2160,6 @@ skip_if_group (pfile)
       c = GETC();
       if (c == '\n')
        {
-         if (CPP_OPTIONS (pfile)->output_conditionals)
-           CPP_PUTC (pfile, c);
          CPP_BUMP_LINE (pfile);
          continue;
        }
@@ -2180,41 +2172,19 @@ skip_if_group (pfile)
        return;  /* Caller will issue error. */
 
       FORWARD(-1);
-      if (CPP_OPTIONS (pfile)->output_conditionals)
-       {
-         CPP_PUTS (pfile, beg_of_line, CPP_BUFFER (pfile)->cur - beg_of_line);
-         copy_rest_of_line (pfile);
-       }
-      else
-       {
-         copy_rest_of_line (pfile);
-         CPP_SET_WRITTEN (pfile, old_written);  /* discard it */
-       }
+      skip_rest_of_line (pfile);
 
       c = GETC();
       if (c == EOF)
        return;  /* Caller will issue error. */
       else
-       {
-         /* \n */
-         if (CPP_OPTIONS (pfile)->output_conditionals)
-           {
-             CPP_PUTC (pfile, c);
-             pfile->lineno++;
-           }
-         CPP_BUMP_LINE (pfile);
-       }
+       CPP_BUMP_LINE (pfile);
     }    
 
   /* Back up to the beginning of this line.  Caller will process the
      directive. */
   CPP_BUFFER (pfile)->cur = beg_of_line;
   pfile->only_seen_white = 1;
-  if (CPP_OPTIONS (pfile)->output_conditionals)
-    {
-      CPP_PUTS (pfile, "#endfailed\n", 11);
-      pfile->lineno++;
-    }
 }
 
 /*
@@ -2443,6 +2413,27 @@ cpp_get_token (pfile)
            }
 
        case '#':
+         if (pfile->parsing_if_directive)
+           {
+             cpp_skip_hspace (pfile);
+             parse_assertion (pfile);
+             return CPP_ASSERTION;
+           }
+
+         if (pfile->parsing_define_directive && ! CPP_TRADITIONAL (pfile))
+           {
+             CPP_RESERVE (pfile, 3);
+             CPP_PUTC_Q (pfile, '#');
+             CPP_NUL_TERMINATE_Q (pfile);
+             if (PEEKC () != '#')
+               return CPP_STRINGIZE;
+             
+             FORWARD (1);
+             CPP_PUTC_Q (pfile, '#');
+             CPP_NUL_TERMINATE_Q (pfile);
+             return CPP_TOKPASTE;
+           }
+
          if (!pfile->only_seen_white)
            goto randomchar;
          /* -traditional directives are recognized only with the # in
@@ -2886,35 +2877,24 @@ parse_name (pfile, c)
   return;
 }
 
-/* Parse a string starting with C.  A single quoted string is treated
-   like a double -- some programs (e.g., troff) are perverse this way.
-   (However, a single quoted string is not allowed to extend over
-   multiple lines.)  */
+/* Parse and skip over a string starting with C.  A single quoted
+   string is treated like a double -- some programs (e.g., troff) are
+   perverse this way.  (However, a single quoted string is not allowed
+   to extend over multiple lines.)  */
 static void
-parse_string (pfile, c)
+skip_string (pfile, c)
      cpp_reader *pfile;
      int c;
 {
   long start_line, start_column;
-  
   cpp_buf_line_and_col (cpp_file_buffer (pfile), &start_line, &start_column);
 
-  CPP_PUTC (pfile, c);
   while (1)
     {
       int cc = GETC();
-      if (cc == EOF)
+      switch (cc)
        {
-         if (CPP_IS_MACRO_BUFFER (CPP_BUFFER (pfile)))
-           {
-             /* try harder: this string crosses a macro expansion
-                boundary.  This can happen naturally if -traditional.
-                Otherwise, only -D can make a macro with an unmatched
-                quote.  */
-             cpp_pop_buffer (pfile);
-             continue;
-           }
-
+       case EOF:
          cpp_error_with_line (pfile, start_line, start_column,
                               "unterminated string or character constant");
          if (pfile->multiline_string_line != start_line
@@ -2923,22 +2903,20 @@ parse_string (pfile, c)
                                 pfile->multiline_string_line, -1,
                         "possible real start of unterminated constant");
          pfile->multiline_string_line = 0;
-         break;
-       }
-      CPP_PUTC (pfile, cc);
-      switch (cc)
-       {
+         return;
+
        case '\n':
          CPP_BUMP_LINE (pfile);
-         pfile->lineno++;
-
          /* In Fortran and assembly language, silently terminate
             strings of either variety at end of line.  This is a
             kludge around not knowing where comments are in these
             languages.  */
          if (CPP_OPTIONS (pfile)->lang_fortran
              || CPP_OPTIONS (pfile)->lang_asm)
-           return;
+           {
+             FORWARD(-1);
+             return;
+           }
          /* Character constants may not extend over multiple lines.
             In Standard C, neither may strings.  We accept multiline
             strings as an extension.  */
@@ -2946,6 +2924,7 @@ parse_string (pfile, c)
            {
              cpp_error_with_line (pfile, start_line, start_column,
                                   "unterminated character constant");
+             FORWARD(-1);
              return;
            }
          if (CPP_PEDANTIC (pfile) && pfile->multiline_string_line == 0)
@@ -2956,7 +2935,6 @@ parse_string (pfile, c)
          break;
 
        case '\r':
-         CPP_ADJUST_WRITTEN (pfile, -1);
          if (CPP_BUFFER (pfile)->has_escapes)
            {
              cpp_ice (pfile, "\\r escape inside string constant");
@@ -2968,9 +2946,7 @@ parse_string (pfile, c)
          break;
 
        case '\\':
-         cc = GETC();
-         if (cc != EOF)
-           CPP_PUTC (pfile, cc);
+         FORWARD(1);
          break;
 
        case '\"':
@@ -2982,6 +2958,26 @@ parse_string (pfile, c)
     }
 }
 
+/* Parse a string and copy it to the output.  */
+
+static void
+parse_string (pfile, c)
+     cpp_reader *pfile;
+     int c;
+{
+  U_CHAR *start = CPP_BUFFER (pfile)->cur;  /* XXX Layering violation */
+  U_CHAR *limit;
+
+  skip_string (pfile, c);
+
+  limit = CPP_BUFFER (pfile)->cur;
+  CPP_RESERVE (pfile, limit - start + 2);
+  CPP_PUTC_Q (pfile, c);
+  for (; start < limit; start++)
+    if (*start != '\r')
+      CPP_PUTC_Q (pfile, *start);
+}
+
 /* Read an assertion into the token buffer, converting to
    canonical form: `#predicate(a n swe r)'  The next non-whitespace
    character to read should be the first letter of the predicate.
@@ -3199,33 +3195,11 @@ cpp_unassert (pfile, str)
 {
   if (cpp_push_buffer (pfile, str, strlen (str)) != NULL)
     {
-      do_assert (pfile, NULL);
+      do_unassert (pfile, NULL);
       cpp_pop_buffer (pfile);
     }
 }  
 
-int
-cpp_read_check_assertion (pfile)
-     cpp_reader *pfile;
-{
-  U_CHAR *name;
-  int result;
-  long written = CPP_WRITTEN (pfile);
-  
-  FORWARD (1);  /* Skip '#' */
-  cpp_skip_hspace (pfile);
-  if (! parse_assertion (pfile))
-    result = 0;
-  else
-    {
-      name = pfile->token_buffer + written;
-      result = cpp_defined (pfile, name, CPP_PWRITTEN (pfile) - name);
-    }
-
-  CPP_SET_WRITTEN (pfile, written);
-  return result;
-}
-
 /* Remember the current position of PFILE so it may be returned to
    after looking ahead a bit.
 
index 71726aa..6c16494 100644 (file)
@@ -47,14 +47,17 @@ enum cpp_token {
   CPP_STRING,
   CPP_WSTRING,
   CPP_DIRECTIVE,
-  CPP_LPAREN,   /* "(" */
-  CPP_RPAREN,   /* ")" */
-  CPP_LBRACE,   /* "{" */
-  CPP_RBRACE,   /* "}" */
-  CPP_COMMA,    /* "," */
-  CPP_SEMICOLON,/* ";" */
-  CPP_3DOTS,    /* "..." */
-  CPP_POP      /* We're about to pop the buffer stack.  */
+  CPP_ASSERTION,       /* #machine(a29k) */
+  CPP_STRINGIZE,       /* stringize macro argument */
+  CPP_TOKPASTE,                /* paste macro arg with next/prev token */
+  CPP_LPAREN,          /* "(" */
+  CPP_RPAREN,          /* ")" */
+  CPP_LBRACE,          /* "{" */
+  CPP_RBRACE,          /* "}" */
+  CPP_COMMA,           /* "," */
+  CPP_SEMICOLON,       /* ";" */
+  CPP_3DOTS,           /* "..." */
+  CPP_POP              /* We're about to pop the buffer stack.  */
 };
 
 typedef enum cpp_token (*parse_underflow_t) PARAMS((cpp_reader *));
@@ -193,7 +196,6 @@ struct cpp_reader
 
   /* If non-zero, directives cause a hard error.  Used when parsing
      macro arguments.  */
-
   char no_directives;
 
   /* Print column number in error messages. */
@@ -205,6 +207,12 @@ struct cpp_reader
   /* If true, character between '<' and '>' are a single (string) token. */
   char parsing_include_directive;
 
+  /* If true, # introduces an assertion (see do_assert) */
+  char parsing_if_directive;
+
+  /* If true, # and ## are the STRINGIZE and TOKPASTE operators */
+  char parsing_define_directive;
+
   /* True if escape sequences (as described for has_escapes in
      parse_buffer) should be emitted. */
   char output_escapes;
@@ -217,7 +225,7 @@ struct cpp_reader
   /* Nonzero means this file was included with a -imacros or -include
      command line and should not be recorded as an include file.  */
 
-  int no_record_file;
+  char no_record_file;
 
   long lineno;
 
@@ -427,11 +435,6 @@ struct cpp_options {
 
   char no_line_commands;
 
-/* Nonzero means output the text in failing conditionals,
-   inside #failed ... #endfailed.  */
-
-  char output_conditionals;
-
   /* Nonzero means -I- has been seen,
      so don't look for #include "foo" the source-file directory.  */
   char ignore_srcdir;
@@ -689,14 +692,12 @@ extern int cpp_defined PARAMS ((cpp_reader *, const U_CHAR *, int));
 extern void cpp_reader_init PARAMS ((cpp_reader *));
 extern void cpp_options_init PARAMS ((cpp_options *));
 extern int cpp_start_read PARAMS ((cpp_reader *, char *));
-extern int cpp_read_check_assertion PARAMS ((cpp_reader *));
 extern void cpp_finish PARAMS ((cpp_reader *));
 
 extern void quote_string               PARAMS ((cpp_reader *, const char *));
 extern void cpp_expand_to_buffer       PARAMS ((cpp_reader *, const U_CHAR *,
                                                 int));
 extern void cpp_scan_buffer            PARAMS ((cpp_reader *));
-extern int check_macro_name            PARAMS ((cpp_reader *, const U_CHAR *));
 
 /* Last arg to output_line_command.  */
 enum file_change_code {same_file, rename_file, enter_file, leave_file};
index 621a00b..6a9198f 100644 (file)
@@ -1,5 +1,7 @@
 /* { dg-do compile } */
-/* Distilled from glibc sources.  Tests preprocessor corner cases.  */
+/* { dg-options "-Wall" } */
+/* Distilled from glibc sources.  Tests preprocessor corner cases.
+   Since it uses rest args, we must turn off -pedantic-errors.  */
 
 #define NO_PAREN(rest...) rest
 #define DEFINE_CATEGORY(category, items) \
diff --git a/gcc/testsuite/gcc.dg/strpaste-2.c b/gcc/testsuite/gcc.dg/strpaste-2.c
new file mode 100644 (file)
index 0000000..d1fcd91
--- /dev/null
@@ -0,0 +1,23 @@
+/* { dg-do run } */
+
+/* Test for odd corner cases in stringizing/pasting.
+   Taken more or less verbatim from C99 section 6.10.3.3.  */
+
+#include <stdlib.h>
+#include <string.h>
+
+#define hash_hash # ## #
+#define mkstr(a) # a
+#define in_between(a) mkstr(a)
+#define join(c, d) in_between(c hash_hash d)
+
+const char p[] = join(x, y);
+const char q[] = "x ## y";
+
+int
+main (void)
+{
+  if (strcmp (p, q))
+    abort ();
+  return 0;
+}