]> gcc.gnu.org Git - gcc.git/commitdiff
cpphash.h (struct definition): Move file, line, col members...
authorZack Weinberg <zack@gcc.gnu.org>
Sun, 23 Apr 2000 17:03:31 +0000 (17:03 +0000)
committerZack Weinberg <zack@gcc.gnu.org>
Sun, 23 Apr 2000 17:03:31 +0000 (17:03 +0000)
* cpphash.h (struct definition): Move file, line, col members...
(struct hashnode): ... here.  Also add 'disabled' flag.
(enum node_type): Add T_VOID, T_XCONST, T_FMACRO, and
T_IDENTITY.  Remove T_DISABLED.
Update prototypes.

* cpphash.c (_cpp_dump_definition): Split out dump_DEFINITION.
(collect_expansion): Split into collect_objlike_expansion and
collect_funlike_expansion.
(_cpp_macroexpand): Split out scan_arguments, stringify, and
funlike_macroexpand.
(_cpp_compare_defs): Rename compare_defs, make static.
(_cpp_make_hashnode): Initialize hp->disabled.
(macro_cleanup): Adjust for new token types.  Clear
m->disabled.
(_cpp_create_definition): Move code here to determine what
sort of macro it is, and code to check for redefinitions, from
do_define.  Implement a few simple cases without creating a
full DEFINITION.
(_cpp_macroexpand, special_symbol, _cpp_dump_definition):
Handle the simple cases.
(push_macro_expansion): Set buf->has_escapes and hp->disabled
here.

* cppinit.c (builtin_array): Change MCONST to XCONST
everywhere.
* cpplex.c (maybe_macroexpand): Handle IDENTITY macros here;
fix check for disabled and function-like macros.
* cpplib.c (do_define): Move most logic to
_cpp_create_definition.
(do_undef): Handle new special token types.

From-SVN: r33355

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

index 6fe6d37877ce570b618dc939fffbba0420037218..6351846ed5f8aae4c98c2d457c4e48caa2f79528 100644 (file)
@@ -1,3 +1,37 @@
+2000-04-23  Zack Weinberg  <zack@wolery.cumb.org>
+
+       * cpphash.h (struct definition): Move file, line, col members...
+       (struct hashnode): ... here.  Also add 'disabled' flag.
+       (enum node_type): Add T_VOID, T_XCONST, T_FMACRO, and
+       T_IDENTITY.  Remove T_DISABLED.               
+       Update prototypes.
+
+       * cpphash.c (_cpp_dump_definition): Split out dump_DEFINITION.     
+       (collect_expansion): Split into collect_objlike_expansion and
+       collect_funlike_expansion.                                 
+       (_cpp_macroexpand): Split out scan_arguments, stringify, and
+       funlike_macroexpand.
+       (_cpp_compare_defs): Rename compare_defs, make static.
+       (_cpp_make_hashnode): Initialize hp->disabled.  
+       (macro_cleanup): Adjust for new token types.  Clear
+       m->disabled.
+       (_cpp_create_definition): Move code here to determine what     
+       sort of macro it is, and code to check for redefinitions, from
+       do_define.  Implement a few simple cases without creating a   
+       full DEFINITION.
+       (_cpp_macroexpand, special_symbol, _cpp_dump_definition):
+       Handle the simple cases.                                 
+       (push_macro_expansion): Set buf->has_escapes and hp->disabled
+       here.
+
+       * cppinit.c (builtin_array): Change MCONST to XCONST
+       everywhere.
+       * cpplex.c (maybe_macroexpand): Handle IDENTITY macros here;
+       fix check for disabled and function-like macros.
+       * cpplib.c (do_define): Move most logic to
+       _cpp_create_definition.
+       (do_undef): Handle new special token types.
+
 Sun Apr 23 14:27:44 MET DST 2000  Jan Hubicka  <jh@suse.cz>
 
        * loop.c (maybe_eliminate_biv_1): Use GET_CODE (x) == CONST_INT instead
@@ -53,31 +87,31 @@ Sat Apr 22 22:35:38 MET DST 2000  Jan Hubicka  <jh@suse.cz>
 
        * Makefile.in (diagnostic.o): Depends on diagnostic.h
 
-        * diagnostic.c: Tweak.  Rationalize the output logic.  Adjust
+       * diagnostic.c: Tweak.  Rationalize the output logic.  Adjust
        various function prototypes.
-        (diagnostic.h): #include.
-        (struct output_buffer): Move into diagnostic.h.
-        (get_output_prefix): Rename to output_get_prefix.  Export.
-        (init_output_buffer): Export. Break out.  Ajust intialization.
-        (output_space_left, output_append): Export.
-        (output_newline): Rename to output_add_newline.  Export.
+       (diagnostic.h): #include.
+       (struct output_buffer): Move into diagnostic.h.
+       (get_output_prefix): Rename to output_get_prefix.  Export.
+       (init_output_buffer): Export. Break out.  Ajust intialization.
+       (output_space_left, output_append): Export.
+       (output_newline): Rename to output_add_newline.  Export.
        (output_clear): Nullify additional output_buffer fields.
-        (output_puts): Rename to output_add_string.  Export.
-        (dump_output): Rename to output_flush_on.  Export.
-        (build_location_prefix): Constify return-type.
-        (emit_output_prefix): Rename to output_emit_prefix. Export.
-        (set_real_maximum_length): New function.
-        (output_set_maximum_length): Ditto
-        (output_clear): Ditto.
-        (output_add_character): Ditto.
-        (output_add_integer): Ditto.
-        (output_add_space): Ditto.
-        (output_format): Ditto.
-        (output_printf): Adjust buffer initialization.
-        (vline_wrapper_message_with_location): Ditto.
-        (v_message_with_decl): Ditto.  Adjust call to output_puts
+       (output_puts): Rename to output_add_string.  Export.
+       (dump_output): Rename to output_flush_on.  Export.
+       (build_location_prefix): Constify return-type.
+       (emit_output_prefix): Rename to output_emit_prefix. Export.
+       (set_real_maximum_length): New function.
+       (output_set_maximum_length): Ditto
+       (output_clear): Ditto.
+       (output_add_character): Ditto.
+       (output_add_integer): Ditto.
+       (output_add_space): Ditto.
+       (output_format): Ditto.
+       (output_printf): Adjust buffer initialization.
+       (vline_wrapper_message_with_location): Ditto.
+       (v_message_with_decl): Ditto.  Adjust call to output_puts
        and get_output_prefix.
-        (default_print_error_function): Adjust buffer intialization.
+       (default_print_error_function): Adjust buffer intialization.
 
 Sat Apr 22 06:45:04 2000  Richard Kenner  <kenner@vlsi1.ultra.nyu.edu>
 
index 26d03fec05514df1c818a6846d0a09116c7d5e26..cc704657abe7f7cf1fb6a0a3b2396aceb452dc22 100644 (file)
@@ -34,14 +34,17 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 static unsigned int hash_HASHNODE PARAMS ((const void *));
 static int eq_HASHNODE           PARAMS ((const void *, const void *));
 static void del_HASHNODE         PARAMS ((void *));
+static void dump_DEFINITION      PARAMS ((cpp_reader *, DEFINITION *));
 static int dump_hash_helper      PARAMS ((void **, void *));
 
-static void push_macro_expansion PARAMS ((cpp_reader *,
-                                         U_CHAR *, int, HASHNODE *));
+static void push_macro_expansion PARAMS ((cpp_reader *, const U_CHAR *,
+                                         int, HASHNODE *));
 static int unsafe_chars                 PARAMS ((cpp_reader *, int, int));
 static int macro_cleanup        PARAMS ((cpp_buffer *, cpp_reader *));
 static enum cpp_ttype macarg    PARAMS ((cpp_reader *, int));
-static void special_symbol      PARAMS ((HASHNODE *, cpp_reader *));
+static void special_symbol      PARAMS ((cpp_reader *, HASHNODE *));
+static int compare_defs                 PARAMS ((cpp_reader *, DEFINITION *,
+                                         DEFINITION *));
 
 /* Initial hash table size.  (It can grow if necessary - see hashtab.c.)  */
 #define HASHSIZE 500
@@ -72,8 +75,11 @@ struct arglist
 };
 
 
-static DEFINITION *collect_expansion PARAMS ((cpp_reader *, cpp_toklist *,
-                                             struct arglist *, unsigned int));
+static DEFINITION *
+collect_objlike_expansion PARAMS ((cpp_reader *, cpp_toklist *));
+static DEFINITION *
+collect_funlike_expansion PARAMS ((cpp_reader *, cpp_toklist *,
+                                  struct arglist *, unsigned int));
 static unsigned int collect_params PARAMS ((cpp_reader *, cpp_toklist *,
                                            struct arglist *));
 
@@ -105,6 +111,12 @@ struct argdata
   int stringified_length;
 };
 
+static void scan_arguments     PARAMS ((cpp_reader *, DEFINITION *,
+                                         struct argdata *, const U_CHAR *));
+static void stringify          PARAMS ((cpp_reader *, struct argdata *));
+static void funlike_macroexpand        PARAMS ((cpp_reader *, HASHNODE *,
+                                        struct argdata *));
+
 /* Calculate hash of a string of length LEN.  */
 unsigned int
 _cpp_calc_hash (str, len)
@@ -174,6 +186,7 @@ _cpp_make_hashnode (name, len, type, hash)
   hp->length = len;
   hp->name = p;
   hp->hash = hash;
+  hp->disabled = 0;
 
   memcpy (p, name, len);
   p[len] = 0;
@@ -277,10 +290,13 @@ macro_cleanup (pbuf, pfile)
      cpp_buffer *pbuf;
      cpp_reader *pfile ATTRIBUTE_UNUSED;
 {
-  HASHNODE *macro = pbuf->macro;
-  if (macro->type == T_DISABLED)
-    macro->type = T_MACRO;
-  if (macro->type != T_MACRO || pbuf->buf != macro->value.defn->expansion)
+  HASHNODE *m = pbuf->macro;
+  
+  m->disabled = 0;
+  if (m->type == T_FMACRO && pbuf->buf != m->value.defn->expansion)
+    free ((PTR) pbuf->buf);
+  else if (m->type != T_MACRO && m->type != T_FMACRO && m->type != T_CONST
+          && m->type != T_MCONST && m->type != T_XCONST)
     free ((PTR) pbuf->buf);
   return 0;
 }
@@ -398,16 +414,90 @@ trad_stringify (pfile, base, len, argc, argv, pat, endpat, last)
   return last;
 }
 
+/* Read a replacement list for an object-like macro, and build the
+   DEFINITION structure.  LIST contains the replacement list,
+   beginning at 1.  */
+static DEFINITION *
+collect_objlike_expansion (pfile, list)
+     cpp_reader *pfile;
+     cpp_toklist *list;
+{
+  DEFINITION *defn;
+  unsigned int i;
+  unsigned int start;
+  int last_was_paste = 0;
+  U_CHAR *exp;
+  size_t len;
 
-/* Read a replacement list for a macro, and build the DEFINITION
-   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.  */
+  /* We copy the expansion text into the token_buffer, then out to
+     its proper home.  */
+  start = CPP_WRITTEN (pfile);
+  CPP_PUTS (pfile, "\r ", 2);
+
+  for (i = 1; i < list->tokens_used; i++)
+    {
+      switch (list->tokens[i].type)
+       {
+       case CPP_POP:
+       case CPP_EOF:
+         cpp_ice (pfile, "EOF in collect_expansion");
+         /* fall through */
+       case CPP_VSPACE:
+         goto done;
+
+       case CPP_PASTE:
+         /* ## is not special if it appears right after another ##;
+            nor is it special if -traditional.  */
+         if (last_was_paste || CPP_TRADITIONAL (pfile))
+           break;
+         if (i == 1)
+           cpp_error (pfile, "`##' at start of macro definition");
+
+         last_was_paste = 1;
+         continue;
+
+       default:;
+       }
+
+      if (i > 1 && !last_was_paste && (list->tokens[i].flags & HSPACE_BEFORE))
+       CPP_PUTC (pfile, ' ');
+
+      CPP_PUTS (pfile,
+               list->tokens[i].val.name.offset + list->namebuf,
+               list->tokens[i].val.name.len);
+      last_was_paste = 0;
+    }
+ done:
+
+  if (last_was_paste)
+    cpp_error (pfile, "`##' at end of macro definition");
+
+  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;
+  defn->expansion = exp;
+  defn->pattern = 0;
+  defn->rest_args = 0;
+  defn->argnames = 0;
+  defn->nargs = -1;
+
+  return defn;
+}
+
+/* Read a replacement list for a function-like macro, and build the
+   DEFINITION structure.  LIST contains the replacement list,
+   beginning at REPLACEMENT.  ARGLIST specifies the formal parameters
+   to look for in the text of the definition.  */
 
 static DEFINITION *
-collect_expansion (pfile, list, arglist, replacement)
+collect_funlike_expansion (pfile, list, arglist, replacement)
      cpp_reader *pfile;
      cpp_toklist *list;
      struct arglist *arglist;
@@ -424,16 +514,8 @@ collect_expansion (pfile, list, arglist, replacement)
   U_CHAR *tok, *exp;
   enum { START = 0, NORM, ARG, STRIZE, PASTE } last_token = START;
 
-  if (arglist)
-    {
-      argv = arglist->argv;
-      argc = arglist->argc;
-    }
-  else
-    {
-      argv = 0;
-      argc = 0;
-    }
+  argv = arglist->argv;
+  argc = arglist->argc;
 
   /* We copy the expansion text into the token_buffer, then out to
      its proper home.  */
@@ -455,12 +537,11 @@ collect_expansion (pfile, list, arglist, replacement)
          goto done;
 
        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.)
-            However, it is not special after PASTE. (Implied by
-            6.10.3.3 para 4.)  Nor is it special if -traditional.  */
-         if (arglist == NULL || last_token == PASTE
-             || CPP_TRADITIONAL (pfile))
+         /* # is special in 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.)  Nor is it special
+            if -traditional.  */
+         if (last_token == PASTE || CPP_TRADITIONAL (pfile))
            break;
          last_token = STRIZE;
          continue;
@@ -497,18 +578,20 @@ collect_expansion (pfile, list, arglist, replacement)
        {
        case CPP_STRING:
        case CPP_CHAR:
-         if (argc)
+         if (argc == 0)
+           goto norm;
+         if (CPP_TRADITIONAL (pfile))
+           {
+             last = trad_stringify (pfile, tok, len, argc, argv,
+                                    &pat, &endpat, last);
+             break;
+           }
+         else
            {
-             if (CPP_TRADITIONAL (pfile))
-               {
-                 last = trad_stringify (pfile, tok, len, argc, argv,
-                                        &pat, &endpat, last);
-                 break;
-               }
              if (CPP_WTRADITIONAL (pfile))
                warn_trad_stringify (pfile, tok, len, argc, argv);
+             goto norm;
            }
-         goto norm;
          
        case CPP_NAME:
          for (j = 0; j < argc; j++)
@@ -521,9 +604,6 @@ collect_expansion (pfile, list, arglist, replacement)
        norm:
          if (last_token == STRIZE)
            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;
        }
@@ -563,19 +643,11 @@ collect_expansion (pfile, list, arglist, replacement)
   defn->length = len;
   defn->expansion = exp;
   defn->pattern = pat;
-  defn->rest_args = argv && argv[argc - 1].rest_arg;
-  if (arglist)
-    {
-      defn->nargs = argc;
-      defn->argnames = arglist->namebuf;
-      if (argv)
-       free ((PTR) argv);
-    }
-  else
-    {
-      defn->nargs = -1;
-      defn->argnames = 0;
-    }
+  defn->rest_args = argc && argv[argc - 1].rest_arg;
+  defn->nargs = argc;
+  defn->argnames = arglist->namebuf;
+  if (argv)
+    free ((PTR) argv);
   return defn;
 }
 
@@ -745,31 +817,134 @@ collect_params (pfile, list, arglist)
    (including formal parameters if present) is in LIST.  If FUNLIKE is
    true, this is a function-like macro.  */
 
-DEFINITION *
-_cpp_create_definition (pfile, list, funlike)
+int
+_cpp_create_definition (pfile, list, hp)
      cpp_reader *pfile;
      cpp_toklist *list;
-     int funlike;
+     HASHNODE *hp;
 {
-  struct arglist args;
-  DEFINITION *defn;
-  int replacement = 1;  /* replacement begins at this token */
+  DEFINITION *defn = 0;
+  U_CHAR *cpval = 0;
+  enum node_type ntype;
+  int ok;
+
+  /* Special-case a few simple and common idioms:
+     #define TOKEN   // nothing
+     #define TOKEN TOKEN
+     #define TOKEN OTHERTOKEN
+
+     Might also be good to special-case these:
+
+     #define FUNC()  // nothing
+     #define FUNC(a, b, ...) // nothing
+     #define FUNC(a, b, c) FUNC(a, b, c)
+     #define FUNC(a, b, c) foobar(a, b, c)  */
+
+  if (list->tokens_used == 2)
+    ntype = T_EMPTY;    /* Empty definition of object-like macro.  */
+  else if (list->tokens_used == 3 && list->tokens[1].type == CPP_NAME)
+    {
+      if (list->tokens[0].val.name.len == list->tokens[1].val.name.len
+         && !strncmp (list->tokens[0].val.name.offset + list->namebuf,
+                      list->tokens[1].val.name.offset + list->namebuf,
+                      list->tokens[0].val.name.len))
+       ntype = T_IDENTITY;
+      else
+       {
+         ntype = T_MCONST;
+         cpval = xmalloc (list->tokens[1].val.name.len + 1);
+         memcpy (cpval, list->tokens[1].val.name.offset + list->namebuf,
+                 list->tokens[1].val.name.len);
+         cpval[list->tokens[1].val.name.len] = '\0';
+       }
+    }
 
-  if (funlike)
+  /* The macro is function-like only if the next character,
+     with no intervening whitespace, is '('.  */
+  else if (list->tokens[1].type == CPP_OPEN_PAREN
+          && ! (list->tokens[1].flags & HSPACE_BEFORE))
     {
+      struct arglist args;
+      int replacement;
+
       replacement = collect_params (pfile, list, &args);
       if (replacement == 0)
        return 0;
+      defn = collect_funlike_expansion (pfile, list, &args, replacement);
+      if (defn == 0)
+       return 0;
+
+      ntype = T_FMACRO;
     }
 
-  defn = collect_expansion (pfile, list, funlike ? &args : 0, replacement);
-  if (defn == 0)
-    return 0;
+  /* 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 & CPP_OPEN_PAREN))
+       cpp_pedwarn (pfile,
+                    "The C standard requires whitespace after #define %s",
+                    hp->name);
 
-  defn->file = CPP_BUFFER (pfile)->nominal_fname;
-  defn->line = list->line;
-  defn->col  = list->tokens[0].col;
-  return defn;
+      defn = collect_objlike_expansion (pfile, list);
+      if (defn == 0)
+       return 0;
+
+      ntype = T_MACRO;
+    }
+
+  /* Check for a redefinition, and its legality.  Redefining a macro
+     of whatever stripe is ok if the definitions are the same.
+     Redefining a built-in _constant_ (T_CONST or T_XCONST) is ok only
+     with -D.  Otherwise a redefinition is not ok.  */
+
+  switch (hp->type)
+    {
+    case T_VOID:  ok = 1; break;
+    default:     ok = 0; break;
+
+    case T_MACRO: case T_FMACRO:
+      ok = (ntype == hp->type && !compare_defs (pfile, defn, hp->value.defn));
+      break;
+    case T_IDENTITY:
+    case T_EMPTY:
+      ok = (ntype == hp->type);
+      break;
+    case T_MCONST:
+      ok = (ntype == hp->type && !strcmp (cpval, hp->value.cpval));
+      break;
+    case T_CONST:
+    case T_XCONST:
+      ok = ! pfile->done_initializing;
+      break;
+    }
+
+  /* Print the warning or error if it's not ok.  */
+  if (! ok)
+    {
+      cpp_pedwarn (pfile, "\"%s\" redefined", hp->name);
+      if (pfile->done_initializing)
+       cpp_pedwarn_with_file_and_line (pfile, hp->file, hp->line, hp->col,
+                       "this is the location of the previous definition");
+    }
+
+  /* And replace the old definition (if any).  */
+
+  if (hp->type == T_MACRO || hp->type == T_FMACRO)
+    _cpp_free_definition (hp->value.defn);
+  else if (hp->type == T_MCONST || hp->type == T_XCONST)
+    free ((PTR) hp->value.cpval);
+
+  if (ntype == T_MACRO || ntype == T_FMACRO)
+    hp->value.defn = defn;
+  else
+    hp->value.cpval = cpval;
+
+  hp->type = ntype;
+  hp->file = CPP_BUFFER (pfile)->nominal_fname;
+  hp->line = list->line;
+  hp->col  = list->tokens[0].col;
+  return 1;
 }
 
 /*
@@ -874,9 +1049,9 @@ _cpp_quote_string (pfile, src)
 
 #define DSC(str) (const U_CHAR *)str, sizeof str - 1
 static void
-special_symbol (hp, pfile)
-     HASHNODE *hp;
+special_symbol (pfile, hp)
      cpp_reader *pfile;
+     HASHNODE *hp;
 {
   const char *buf;
   cpp_buffer *ip;
@@ -929,6 +1104,7 @@ special_symbol (hp, pfile)
       /* else fall through */
     case T_CONST:
     case T_MCONST:
+    case T_XCONST:
     constant:
       buf = hp->value.cpval;
       if (!buf)
@@ -1005,430 +1181,429 @@ _cpp_macroexpand (pfile, hp)
      cpp_reader *pfile;
      HASHNODE *hp;
 {
-  int nargs;
   DEFINITION *defn;
-  register U_CHAR *xbuf;
-  unsigned int start_line, start_column;
-  cpp_buffer *ip;
-  int xbuf_len;
-  struct argdata *args = 0;
-  long old_written = CPP_WRITTEN (pfile);
-  int rest_args, rest_zero = 0;
-  register int i;
+  struct argdata *args;
+  unsigned int old_written;
+  int i;
 
-  ip = cpp_file_buffer (pfile);
-  if (ip)
+  /* Object like macro - most common case.  */
+  if (hp->type == T_MACRO)
     {
-      start_line = CPP_BUF_LINE (ip);
-      start_column = CPP_BUF_COL (ip);
+      push_macro_expansion (pfile, hp->value.defn->expansion,
+                           hp->value.defn->length, hp);
+      return;
+    }
+
+  /* Or might it be a constant string?  */
+  if (hp->type == T_MCONST || hp->type == T_CONST || hp->type == T_XCONST)
+    {
+      const U_CHAR *cpval = hp->value.cpval;
+      if (!cpval || *cpval == '\0')
+       cpval = (const U_CHAR *) "\r \r ";
+      push_macro_expansion (pfile, cpval, strlen (cpval), hp);
+      return;
     }
-  else
-    start_line = start_column = 0;
 
-  /* Check for and handle special symbols. */
-  if (hp->type != T_MACRO)
+  /* Or a special symbol?  */
+  if (hp->type != T_FMACRO)
     {
-      special_symbol (hp, pfile);
-      xbuf_len = CPP_WRITTEN (pfile) - old_written;
-      xbuf = (U_CHAR *) xmalloc (xbuf_len + 1);
+      U_CHAR *xbuf;
+      unsigned int len, old_written = CPP_WRITTEN (pfile);
+      
+      special_symbol (pfile, hp);
+      len = CPP_WRITTEN (pfile) - old_written;
       CPP_SET_WRITTEN (pfile, old_written);
-      memcpy (xbuf, CPP_PWRITTEN (pfile), xbuf_len + 1);
-      push_macro_expansion (pfile, xbuf, xbuf_len, hp);
-      CPP_BUFFER (pfile)->has_escapes = 1;
+      xbuf = (U_CHAR *) xmalloc (len + 1);
+      memcpy (xbuf, CPP_PWRITTEN (pfile), len);
+      xbuf[len] = '\0';
+      push_macro_expansion (pfile, xbuf, len, hp);
       return;
     }
 
+  /* Okay, it's a full-on function-like macro...  */
+  old_written = CPP_WRITTEN (pfile);
   defn = hp->value.defn;
-  nargs = defn->nargs;
+
+  args = alloca (MAX (defn->nargs, 1) * sizeof (struct argdata));
+  for (i = 0; i < MAX (defn->nargs, 1); i++)
+    {
+      args[i].raw = args[i].expanded = 0;
+      args[i].raw_length = 0;
+      args[i].expand_length = args[i].stringified_length = -1;
+    }
+
   pfile->output_escapes++;
+  scan_arguments (pfile, defn, args, hp->name);
 
-  if (nargs >= 0)
+  /* If macro wants zero args, we parsed the arglist for checking only.
+     Read directly from the macro definition.  */
+  if (defn->nargs == 0 || defn->pattern == 0)
     {
-      enum cpp_ttype token;
+      CPP_SET_WRITTEN (pfile, old_written);
+      pfile->output_escapes--;
+      push_macro_expansion (pfile, defn->expansion, defn->length, hp);
+      return;
+    }
 
-      args = (struct argdata *) alloca ((nargs + 1) * sizeof (struct argdata));
+  funlike_macroexpand (pfile, hp, args);
+  pfile->output_escapes--;
+}
 
-      for (i = 0; i < nargs; i++)
-       {
-         args[i].raw = args[i].expanded = 0;
-         args[i].raw_length = 0;
-         args[i].expand_length = args[i].stringified_length = -1;
-       }
+static void
+scan_arguments (pfile, defn, args, name)
+     cpp_reader *pfile;
+     DEFINITION *defn;
+     struct argdata *args;
+     const U_CHAR *name;
+{
+  enum cpp_ttype token;
+  unsigned int start_line, start_column;
+  unsigned int nargs = defn->nargs;
+  unsigned int i;
+  
+  cpp_buffer *ip = cpp_file_buffer (pfile);
+  if (ip)
+    {
+      start_line = CPP_BUF_LINE (ip);
+      start_column = CPP_BUF_COL (ip);
+    }
+  else
+    start_line = start_column = 0;
 
-      /* Parse all the macro args that are supplied.  I counts them.
-         The first NARGS args are stored in ARGS.
-         The rest are discarded.  If rest_args is set then we assume
-         macarg absorbed the rest of the args.  */
-      i = 0;
-      rest_args = 0;
-
-      /* Skip over the opening parenthesis.  */
-      CPP_OPTION (pfile, discard_comments)++;
-      pfile->no_macro_expand++;
-      pfile->no_directives++;
-
-      token = cpp_get_non_space_token (pfile);
-      if (token != CPP_OPEN_PAREN)
-       cpp_ice (pfile, "macroexpand: unexpected token %d (wanted LPAREN)",
-                token);
-      CPP_ADJUST_WRITTEN (pfile, -1);
-
-      token = CPP_EOF;
-      do
-       {
-         if (rest_args)
-           continue;
-         if (i < nargs || (nargs == 0 && i == 0))
-           {
-             /* if we are working on last arg which absorbs rest of args... */
-             if (i == nargs - 1 && defn->rest_args)
-               rest_args = 1;
-             args[i].raw = CPP_WRITTEN (pfile);
-             token = macarg (pfile, rest_args);
-             args[i].raw_length = CPP_WRITTEN (pfile) - args[i].raw;
-           }
-         else
-           token = macarg (pfile, 0);
-         if (token == CPP_EOF || token == CPP_POP)
-           cpp_error_with_line (pfile, start_line, start_column,
-                                "unterminated macro call");
-         i++;
-       }
-      while (token == CPP_COMMA);
-      CPP_OPTION (pfile, discard_comments)--;
-      pfile->no_macro_expand--;
-      pfile->no_directives--;
-      if (token != CPP_CLOSE_PAREN)
-       return;
+  /* Parse all the macro args that are supplied.  I counts them.  The
+     first NARGS args are stored in ARGS.  The rest are discarded.  If
+     rest_args is set then we assume macarg absorbed the rest of the
+     args.  */
+  i = 0;
 
-      /* foo ( ) is equivalent to foo () unless foo takes exactly one
-        argument, in which case the former is allowed and the latter
-        is not.  XXX C99 is silent on this rule, but it seems
-        inconsistent to me.  */
-      if (i == 1 && nargs != 1)
-       {
-         register U_CHAR *bp = ARG_BASE + args[0].raw;
-         register U_CHAR *lim = bp + args[0].raw_length;
-           while (bp != lim && is_space(*bp))
-             bp++;
-         if (bp == lim)
-           i = 0;
-       }
+  /* Skip over the opening parenthesis.  */
+  CPP_OPTION (pfile, discard_comments)++;
+  pfile->no_macro_expand++;
+  pfile->no_directives++;
 
-      /* Don't output an error message if we have already output one for
-         a parse error above.  */
-      rest_zero = 0;
-      if (nargs == 0 && i > 0)
-       {
-         cpp_error (pfile, "arguments given to macro `%s'", hp->name);
-       }
-      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)
-           rest_zero = 1;
-         else if (i == 0)
-           cpp_error (pfile, "macro `%s' used without args", hp->name);
-         else if (i == 1)
-           cpp_error (pfile, "macro `%s' used with just one arg", hp->name);
-         else
-           cpp_error (pfile, "macro `%s' used with only %d args",
-                      hp->name, i);
-       }
-      else if (i > nargs)
+  token = cpp_get_non_space_token (pfile);
+  if (token != CPP_OPEN_PAREN)
+    cpp_ice (pfile, "macroexpand: unexpected token %d (wanted LPAREN)",
+            token);
+  CPP_ADJUST_WRITTEN (pfile, -1);
+
+  token = CPP_EOF;
+  do
+    {
+      if (i < MAX (nargs, 1))
        {
-         cpp_error (pfile,
-                    "macro `%s' used with too many (%d) args", hp->name, i);
+         args[i].raw = CPP_WRITTEN (pfile);
+         token = macarg (pfile, (i == nargs - 1 && defn->rest_args));
+         args[i].raw_length = CPP_WRITTEN (pfile) - args[i].raw;
        }
+      else
+       token = macarg (pfile, 0);
+      if (token == CPP_EOF || token == CPP_POP)
+       cpp_error_with_line (pfile, start_line, start_column,
+                            "unterminated macro call");
+      i++;
     }
+  while (token == CPP_COMMA);
+  CPP_OPTION (pfile, discard_comments)--;
+  pfile->no_macro_expand--;
+  pfile->no_directives--;
+  if (token != CPP_CLOSE_PAREN)
+    return;
 
-  /* If macro wants zero args, we parsed the arglist for checking only.
-     Read directly from the macro definition.  */
-  if (nargs <= 0)
+  /* foo ( ) is equivalent to foo () unless foo takes exactly one
+     argument, in which case the former is allowed and the latter
+     is not.  XXX C99 is silent on this rule, but it seems
+     inconsistent to me.  */
+  if (i == 1 && nargs == 0)
     {
-      xbuf = defn->expansion;
-      xbuf_len = defn->length;
+      register U_CHAR *bp = ARG_BASE + args[0].raw;
+      register U_CHAR *lim = bp + args[0].raw_length;
+      while (bp != lim && is_space(*bp))
+       bp++;
+      if (bp == lim)
+       i = 0;
     }
-  else
-    {
-      register U_CHAR *exp = defn->expansion;
-      register int offset;     /* offset in expansion,
-                                  copied a piece at a time */
-      register int totlen;     /* total amount of exp buffer filled so far */
 
-      register struct reflist *ap, *last_ap;
+  /* Don't output an error message if we have already output one for
+     a parse error above.  */
+  if (nargs == 0 && i > 0)
+    {
+      cpp_error (pfile, "arguments given to macro `%s'", name);
+    }
+  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)
+       ;
+      else if (i == 0)
+       cpp_error (pfile, "macro `%s' used without args", name);
+      else if (i == 1)
+       cpp_error (pfile, "macro `%s' used with just one arg", name);
+      else
+       cpp_error (pfile, "macro `%s' used with only %d args", name, i);
+    }
+  else if (i > nargs)
+    {
+      cpp_error (pfile, "macro `%s' used with too many (%d) args", name, i);
+    }
+}
 
-      /* Macro really takes args.  Compute the expansion of this call.  */
+static void
+stringify (pfile, arg)
+     cpp_reader *pfile;
+     struct argdata *arg;
+{
+  int arglen = arg->raw_length;
+  int escaped = 0;
+  int in_string = 0;
+  int c;
+  int i;
+  /* Initially need_space is -1.  Otherwise, 1 means the previous
+     character was a space, but we suppressed it; 0 means the previous
+     character was a non-space.  */
+  int need_space = -1;
+  i = 0;
+  arg->stringified = CPP_WRITTEN (pfile);
+  CPP_PUTC (pfile, '\"');      /* insert beginning quote */
+  for (; i < arglen; i++)
+    {
+      c = (ARG_BASE + arg->raw)[i];
 
-      /* Compute length in characters of the macro's expansion.
-         Also count number of times each arg is used.  */
-      xbuf_len = defn->length;
-      for (ap = defn->pattern; ap != NULL; ap = ap->next)
+      if (!in_string)
        {
-         if (ap->stringify)
+         /* Delete "\r " and "\r-" escapes.  */
+         if (c == '\r')
            {
-             register struct argdata *arg = &args[ap->argno];
-             /* Stringify if it hasn't already been */
-             if (arg->stringified_length < 0)
-               {
-                 int arglen = arg->raw_length;
-                 int escaped = 0;
-                 int in_string = 0;
-                 int c;
-                 /* Initially need_space is -1.  Otherwise, 1 means the
-                    previous character was a space, but we suppressed it;
-                    0 means the previous character was a non-space.  */
-                 int need_space = -1;
-                 i = 0;
-                 arg->stringified = CPP_WRITTEN (pfile);
-                 CPP_PUTC (pfile, '\"');       /* insert beginning quote */
-                 for (; i < arglen; i++)
-                   {
-                     c = (ARG_BASE + arg->raw)[i];
-
-                     if (!in_string)
-                       {
-                         /* Delete "\r " and "\r-" escapes.  */
-                         if (c == '\r')
-                           {
-                             i++;
-                             continue;
-                           }
-                         /* Internal sequences of whitespace are
-                            replaced by one space except within
-                            a string or char token. */
-                         else if (is_space(c))
-                           {
-                             if (need_space == 0)
-                               need_space = 1;
-                             continue;
-                           }
-                         else if (need_space > 0)
-                           CPP_PUTC (pfile, ' ');
-                         need_space = 0;
-                       }
-
-                     if (escaped)
-                       escaped = 0;
-                     else
-                       {
-                         if (c == '\\')
-                           escaped = 1;
-                         if (in_string)
-                           {
-                             if (c == in_string)
-                               in_string = 0;
-                           }
-                         else if (c == '\"' || c == '\'')
-                           in_string = c;
-                       }
-
-                     /* Escape these chars */
-                     if (c == '\"' || (in_string && c == '\\'))
-                       CPP_PUTC (pfile, '\\');
-                     if (ISPRINT (c))
-                       CPP_PUTC (pfile, c);
-                     else
-                       {
-                         CPP_RESERVE (pfile, 4);
-                         sprintf ((char *) CPP_PWRITTEN (pfile), "\\%03o",
-                                  (unsigned int) c);
-                         CPP_ADJUST_WRITTEN (pfile, 4);
-                       }
-                   }
-                 CPP_PUTC (pfile, '\"');       /* insert ending quote */
-                 arg->stringified_length
-                   = CPP_WRITTEN (pfile) - arg->stringified;
-               }
-             xbuf_len += args[ap->argno].stringified_length;
+             i++;
+             continue;
            }
-         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;
-         else
+         /* Internal sequences of whitespace are replaced by one
+            space except within a string or char token. */
+         else if (is_space(c))
            {
-             /* We have an ordinary (expanded) occurrence of the arg.
-                So compute its expansion, if we have not already.  */
-             if (args[ap->argno].expand_length < 0)
-               {
-                 args[ap->argno].expanded = CPP_WRITTEN (pfile);
-                 _cpp_expand_to_buffer (pfile,
-                                        ARG_BASE + args[ap->argno].raw,
-                                        args[ap->argno].raw_length);
-
-                 args[ap->argno].expand_length
-                   = CPP_WRITTEN (pfile) - args[ap->argno].expanded;
-               }
+             if (need_space == 0)
+               need_space = 1;
+             continue;
+           }
+         else if (need_space > 0)
+           CPP_PUTC (pfile, ' ');
+         need_space = 0;
+       }
 
-             /* Add 4 for two \r-space markers to prevent
-                token concatenation.  */
-             xbuf_len += args[ap->argno].expand_length + 4;
+      if (escaped)
+       escaped = 0;
+      else
+       {
+         if (c == '\\')
+           escaped = 1;
+         if (in_string)
+           {
+             if (c == in_string)
+               in_string = 0;
            }
+         else if (c == '\"' || c == '\'')
+           in_string = c;
        }
 
-      xbuf = (U_CHAR *) xmalloc (xbuf_len + 1);
+      /* Escape these chars */
+      if (c == '\"' || (in_string && c == '\\'))
+       CPP_PUTC (pfile, '\\');
+      if (ISPRINT (c))
+       CPP_PUTC (pfile, c);
+      else
+       {
+         CPP_RESERVE (pfile, 4);
+         sprintf ((char *) CPP_PWRITTEN (pfile), "\\%03o", (unsigned int) c);
+         CPP_ADJUST_WRITTEN (pfile, 4);
+       }
+    }
+  CPP_PUTC (pfile, '\"');      /* insert ending quote */
+  arg->stringified_length  = CPP_WRITTEN (pfile) - arg->stringified;
+}
 
-      /* Generate in XBUF the complete expansion
-         with arguments substituted in.
-         TOTLEN is the total size generated so far.
-         OFFSET is the index in the definition
-         of where we are copying from.  */
-      offset = totlen = 0;
-      for (last_ap = NULL, ap = defn->pattern; ap != NULL;
-          last_ap = ap, ap = ap->next)
+static void
+funlike_macroexpand (pfile, hp, args)
+     cpp_reader *pfile;
+     HASHNODE *hp;
+     struct argdata *args;
+{
+  DEFINITION *defn = hp->value.defn;
+  register U_CHAR *xbuf;
+  int xbuf_len;
+  long old_written = CPP_WRITTEN (pfile);
+  U_CHAR *exp = defn->expansion;
+  int offset;  /* offset in expansion, copied a piece at a time */
+  int totlen;  /* total amount of exp buffer filled so far */
+  struct reflist *ap, *last_ap;
+  int i;
+
+  /* Compute length in characters of the macro's expansion.
+     Also count number of times each arg is used.  */
+  xbuf_len = defn->length;
+  for (ap = defn->pattern; ap != NULL; ap = ap->next)
+    {
+      if (ap->stringify)
        {
-         register struct argdata *arg = &args[ap->argno];
-         int count_before = totlen;
-
-         /* Add chars to XBUF.  */
-         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.  */
-         if (rest_zero && totlen > count_before
-             && ((ap->rest_args && ap->raw_before)
-                 || (last_ap != NULL && last_ap->rest_args
-                     && last_ap->raw_after)))
+         /* Stringify if it hasn't already been */
+         if (args[ap->argno].stringified_length < 0)
+           stringify (pfile, &args[ap->argno]);
+         xbuf_len += args[ap->argno].stringified_length;
+       }
+      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;
+      else
+       {
+         /* We have an ordinary (expanded) occurrence of the arg.
+            So compute its expansion, if we have not already.  */
+         if (args[ap->argno].expand_length < 0)
            {
-             /* Delete final whitespace.  */
-             while (totlen > count_before && is_space(xbuf[totlen - 1]))
-               totlen--;
+             args[ap->argno].expanded = CPP_WRITTEN (pfile);
+             _cpp_expand_to_buffer (pfile, ARG_BASE + args[ap->argno].raw,
+                                    args[ap->argno].raw_length);
 
-             /* Delete the nonwhites before them.  */
-             while (totlen > count_before && !is_space(xbuf[totlen - 1]))
-               totlen--;
+             args[ap->argno].expand_length
+               = CPP_WRITTEN (pfile) - args[ap->argno].expanded;
            }
 
-         if (ap->stringify != 0)
-           {
-             memcpy (xbuf + totlen, ARG_BASE + arg->stringified,
-                     arg->stringified_length);
-             totlen += arg->stringified_length;
-           }
-         else if (ap->raw_before || ap->raw_after)
+         /* Add 4 for two \r-space markers to prevent
+            token concatenation.  */
+         xbuf_len += args[ap->argno].expand_length + 4;
+       }
+    }
+
+  xbuf = (U_CHAR *) xmalloc (xbuf_len + 1);
+
+  /* Generate in XBUF the complete expansion with arguments
+     substituted in.  TOTLEN is the total size generated so far.
+     OFFSET is the index in the definition of where we are copying
+     from.  */
+  offset = totlen = 0;
+  for (last_ap = NULL, ap = defn->pattern; ap != NULL;
+       last_ap = ap, ap = ap->next)
+    {
+      register struct argdata *arg = &args[ap->argno];
+      int count_before = totlen;
+
+      /* Add chars to XBUF.  */
+      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.  */
+      if (arg->raw_length == 0 && totlen > count_before
+         && ((ap->rest_args && ap->raw_before)
+             || (last_ap != NULL && last_ap->rest_args
+                 && last_ap->raw_after)))
+       {
+         /* Delete final whitespace.  */
+         while (totlen > count_before && is_space(xbuf[totlen - 1]))
+           totlen--;
+
+         /* Delete the nonwhites before them.  */
+         while (totlen > count_before && !is_space(xbuf[totlen - 1]))
+           totlen--;
+       }
+
+      if (ap->stringify != 0)
+       {
+         memcpy (xbuf + totlen, ARG_BASE + arg->stringified,
+                 arg->stringified_length);
+         totlen += arg->stringified_length;
+       }
+      else if (ap->raw_before || ap->raw_after)
+       {
+         U_CHAR *p1 = ARG_BASE + arg->raw;
+         U_CHAR *l1 = p1 + arg->raw_length;
+         if (ap->raw_before)
            {
-             U_CHAR *p1 = ARG_BASE + arg->raw;
-             U_CHAR *l1 = p1 + arg->raw_length;
-             if (ap->raw_before)
+             /* Arg is concatenated before: delete leading whitespace,
+                whitespace markers, and no-reexpansion markers.  */
+             while (p1 != l1)
                {
-                 /* Arg is concatenated before: delete leading whitespace,
-                    whitespace markers, and no-reexpansion markers.  */
-                 while (p1 != l1)
-                   {
-                     if (is_space(p1[0]))
-                       p1++;
-                     else if (p1[0] == '\r')
-                       p1 += 2;
-                     else
-                       break;
-                   }
+                 if (is_space(p1[0]))
+                   p1++;
+                 else if (p1[0] == '\r')
+                   p1 += 2;
+                 else
+                   break;
                }
-             if (ap->raw_after)
+           }
+         if (ap->raw_after)
+           {
+             /* Arg is concatenated after: delete trailing whitespace,
+                whitespace markers, and no-reexpansion markers.  */
+             while (p1 != l1)
                {
-                 /* Arg is concatenated after: delete trailing whitespace,
-                    whitespace markers, and no-reexpansion markers.  */
-                 while (p1 != l1)
+                 if (is_space(l1[-1]))
+                   l1--;
+                 else if (l1[-1] == '\r')
+                   l1--;
+                 else if (l1[-1] == '-')
                    {
-                     if (is_space(l1[-1]))
-                       l1--;
-                     else if (l1[-1] == '\r')
-                       l1--;
-                     else if (l1[-1] == '-')
-                       {
-                         if (l1 != p1 + 1 && l1[-2] == '\r')
-                           l1 -= 2;
-                         else
-                           break;
-                       }
+                     if (l1 != p1 + 1 && l1[-2] == '\r')
+                       l1 -= 2;
                      else
                        break;
                    }
+                 else
+                   break;
                }
-
-             /* Delete any no-reexpansion marker that precedes
-                an identifier at the beginning of the argument. */
-             if (p1[0] == '\r' && p1[1] == '-')
-               p1 += 2;
-
-             memcpy (xbuf + totlen, p1, l1 - p1);
-             totlen += l1 - p1;
            }
-         else
-           {
-             U_CHAR *expanded = ARG_BASE + arg->expanded;
-             if (!ap->raw_before && totlen > 0 && arg->expand_length
-                 && unsafe_chars (pfile, xbuf[totlen - 1], expanded[0]))
-               {
-                 xbuf[totlen++] = '\r';
-                 xbuf[totlen++] = ' ';
-               }
 
-             memcpy (xbuf + totlen, expanded, arg->expand_length);
-             totlen += arg->expand_length;
+         /* Delete any no-reexpansion marker that precedes
+            an identifier at the beginning of the argument. */
+         if (p1[0] == '\r' && p1[1] == '-')
+           p1 += 2;
 
-             if (!ap->raw_after && totlen > 0 && offset < defn->length
-                 && unsafe_chars (pfile, xbuf[totlen - 1], exp[offset]))
-               {
-                 xbuf[totlen++] = '\r';
-                 xbuf[totlen++] = ' ';
-               }
-           }
-
-         if (totlen > xbuf_len)
+         memcpy (xbuf + totlen, p1, l1 - p1);
+         totlen += l1 - p1;
+       }
+      else
+       {
+         U_CHAR *expanded = ARG_BASE + arg->expanded;
+         if (!ap->raw_before && totlen > 0 && arg->expand_length
+             && unsafe_chars (pfile, xbuf[totlen - 1], expanded[0]))
            {
-             cpp_ice (pfile, "buffer overrun in macroexpand");
-             return;
+             xbuf[totlen++] = '\r';
+             xbuf[totlen++] = ' ';
            }
-       }
 
-      /* if there is anything left of the definition
-         after handling the arg list, copy that in too.  */
+         memcpy (xbuf + totlen, expanded, arg->expand_length);
+         totlen += arg->expand_length;
 
-      for (i = offset; i < defn->length; i++)
-       {
-         /* if we've reached the end of the macro */
-         if (exp[i] == ')')
-           rest_zero = 0;
-         if (!(rest_zero && last_ap != NULL && last_ap->rest_args
-               && last_ap->raw_after))
-           xbuf[totlen++] = exp[i];
+         if (!ap->raw_after && totlen > 0 && offset < defn->length
+             && unsafe_chars (pfile, xbuf[totlen - 1], exp[offset]))
+           {
+             xbuf[totlen++] = '\r';
+             xbuf[totlen++] = ' ';
+           }
        }
-
-      xbuf[totlen] = 0;
-      xbuf_len = totlen;
-
     }
 
-  pfile->output_escapes--;
+  /* if there is anything left of the definition
+     after handling the arg list, copy that in too.  */
 
+  for (i = offset; i < defn->length; i++)
+    xbuf[totlen++] = exp[i];
+  xbuf[totlen] = 0;
+
+  if (totlen > xbuf_len)
+    /* Just die - we've trashed the heap at this point.  */
+    abort ();
+  
   /* Now put the expansion on the input stack
      so our caller will commence reading from it.  */
-  push_macro_expansion (pfile, xbuf, xbuf_len, hp);
-  CPP_BUFFER (pfile)->has_escapes = 1;
+  push_macro_expansion (pfile, xbuf, totlen, hp);
 
   /* Pop the space we've used in the token_buffer for argument expansion.  */
   CPP_SET_WRITTEN (pfile, old_written);
-
-  /* In C89, a macro cannot be expanded recursively.  Traditional C
-     permits it, but any use in an object-like macro must lead to
-     infinite recursion, so always follow C89 in object-like macros.
-
-     The only example known where this doesn't cause infinite recursion
-     in function-like macros is:
-       #define foo(x,y) bar(x(y, 0))
-       foo(foo, baz)
-     which expands to bar(foo(baz, 0)) in C89 and
-     bar(bar(baz(0, 0)) in K+R.  This looks pathological to me.
-     If someone has a real-world example I would love to see it.  */
-  if (nargs <= 0 || !CPP_TRADITIONAL (pfile))
-    hp->type = T_DISABLED;
 }
 
 /* Return 1 iff a token ending in C1 followed directly by a token C2
@@ -1501,7 +1676,7 @@ unsafe_chars (pfile, c1, c2)
 static void
 push_macro_expansion (pfile, xbuf, len, hp)
      cpp_reader *pfile;
-     register U_CHAR *xbuf;
+     const U_CHAR *xbuf;
      int len;
      HASHNODE *hp;
 {
@@ -1539,12 +1714,33 @@ push_macro_expansion (pfile, xbuf, len, hp)
     mbuf->cur += 2;
   mbuf->cleanup = macro_cleanup;
   mbuf->macro = hp;
+  mbuf->has_escapes = 1;
+
+  /* In C89, a macro cannot be expanded recursively.  Traditional C
+     permits it, but any use in an object-like macro must lead to
+     infinite recursion, so always follow C89 in object-like macros.
+     Likewise, in a function-like macro it must cause infinite
+     recursion unless we are actually doing something with the
+     arguments.
+
+     Even that criterion is too weak.  The only example known where
+     macro recursion isn't infinite is:
+       #define bar(x,y) foo(x(y, 0))
+       bar(bar, baz)
+     which expands to foo(bar(baz, 0)) in C89 and
+     foo(foo(baz(0, 0)) in K+R.  This looks pathological to me.
+     If someone has a real-world example I would love to see it.  */
+  if (hp->type != T_FMACRO
+      || hp->value.defn->nargs == 0
+      || hp->value.defn->pattern == 0
+      || !CPP_TRADITIONAL (pfile))
+    hp->disabled = 1;
 }
 
 /* Return zero if two DEFINITIONs are isomorphic.  */
 
-int
-_cpp_compare_defs (pfile, d1, d2)
+static int
+compare_defs (pfile, d1, d2)
      cpp_reader *pfile;
      DEFINITION *d1, *d2;
 {
@@ -1590,91 +1786,107 @@ _cpp_compare_defs (pfile, d1, d2)
    to be read back in again. */
 
 void
-_cpp_dump_definition (pfile, sym, len, defn)
+_cpp_dump_definition (pfile, hp)
      cpp_reader *pfile;
-     const U_CHAR *sym;
-     long len;
-     DEFINITION *defn;
+     HASHNODE *hp;
 {
-  CPP_RESERVE (pfile, len + sizeof "#define ");
-  CPP_PUTS_Q (pfile, "#define ", sizeof "#define " -1);
-  CPP_PUTS_Q (pfile, sym, len);
-
-  if (defn->nargs == -1)
+  CPP_RESERVE (pfile, hp->length + sizeof "#define ");
+  CPP_PUTS_Q (pfile, "#define ", sizeof "#define " - 1);
+  CPP_PUTS_Q (pfile, hp->name, hp->length);
+
+  if (hp->type == T_EMPTY)
+    /* do nothing */;
+  else if (hp->type == T_FMACRO)
+    dump_DEFINITION (pfile, hp->value.defn);
+  else
     {
       CPP_PUTC_Q (pfile, ' ');
 
-      /* The first and last two characters of a macro expansion are
-        always "\r "; this needs to be trimmed out.
-        So we need length-4 chars of space, plus one for the NUL.  */
-      CPP_RESERVE (pfile, defn->length - 4 + 1);
-      CPP_PUTS_Q (pfile, defn->expansion + 2, defn->length - 4);
-    }
-  else
-    {
-      struct reflist *r;
-      unsigned char **argv = (unsigned char **) alloca (defn->nargs *
-                                                       sizeof(char *));
-      int *argl = (int *) alloca (defn->nargs * sizeof(int));
-      unsigned char *x;
-      int i;
-
-      /* First extract the argument list. */
-      x = defn->argnames;
-      for (i = 0; i < defn->nargs; i++)
-       {
-         argv[i] = x;
-         argl[i] = strlen (x);
-         x += argl[i] + 1;
-       }
-      
-      /* Now print out the argument list. */
-      CPP_PUTC_Q (pfile, '(');
-      for (i = 0; i < defn->nargs; i++)
+      if (hp->type == T_IDENTITY)
+       CPP_PUTS (pfile, hp->name, hp->length);
+      else if (hp->type == T_MCONST)
+       CPP_PUTS (pfile, hp->value.cpval, strlen (hp->value.cpval));
+      else if (hp->type == T_MACRO)
        {
-         CPP_RESERVE (pfile, argl[i] + 2);
-         if (!(i == defn->nargs-1 && defn->rest_args
-               && !strcmp (argv[i], "__VA_ARGS__")))
-           CPP_PUTS_Q (pfile, argv[i], argl[i]);
-         if (i < defn->nargs-1)
-           CPP_PUTS_Q (pfile, ", ", 2);
+         /* The first and last two characters of a macro expansion are
+            always "\r "; this needs to be trimmed out.
+            So we need length-4 chars of space, plus one for the NUL.  */
+         CPP_RESERVE (pfile, hp->value.defn->length - 4 + 1);
+         CPP_PUTS_Q (pfile, hp->value.defn->expansion + 2,
+                     hp->value.defn->length - 4);
        }
-      if (defn->rest_args)
-       CPP_PUTS (pfile, "...", 3);
-      CPP_PUTS (pfile, ") ", 2);
+      else
+       cpp_ice (pfile, "invalid hash type %d in dump_definition", hp->type);
+    }
+  if (CPP_BUFFER (pfile) == 0 || ! pfile->done_initializing)
+    CPP_PUTC (pfile, '\n');
+}
 
-      /* Now the definition. */
-      x = defn->expansion;
-      for (r = defn->pattern; r; r = r->next)
-      {
-       i = r->nchars;
-       if (*x == '\r') x += 2, i -= 2;
-       /* i chars for macro text, plus the length of the macro
-          argument name, plus one for a stringify marker, plus two for
-          each concatenation marker. */
-       CPP_RESERVE (pfile,
-                    i + argl[r->argno] + r->stringify
-                    + (r->raw_before + r->raw_after) * 2);
-
-       if (i > 0) CPP_PUTS_Q (pfile, x, i);
-       if (r->raw_before)
-         CPP_PUTS_Q (pfile, "##", 2);
-       if (r->stringify)
-         CPP_PUTC_Q (pfile, '#');
-       CPP_PUTS_Q (pfile, argv[r->argno], argl[r->argno]);
-       if (r->raw_after && !(r->next && r->next->nchars == 0
-                             && r->next->raw_before))
-         CPP_PUTS_Q (pfile, "##", 2);
-
-       x += i;
-      }
+static void
+dump_DEFINITION (pfile, defn)
+     cpp_reader *pfile;
+     DEFINITION *defn;
+{
+  struct reflist *r;
+  unsigned char **argv = (unsigned char **) alloca (defn->nargs *
+                                                   sizeof(char *));
+  int *argl = (int *) alloca (defn->nargs * sizeof(int));
+  unsigned char *x;
+  int i;
+
+  /* First extract the argument list. */
+  x = defn->argnames;
+  for (i = 0; i < defn->nargs; i++)
+    {
+      argv[i] = x;
+      argl[i] = strlen (x);
+      x += argl[i] + 1;
+    }
+      
+  /* Now print out the argument list. */
+  CPP_PUTC_Q (pfile, '(');
+  for (i = 0; i < defn->nargs; i++)
+    {
+      CPP_RESERVE (pfile, argl[i] + 2);
+      if (!(i == defn->nargs-1 && defn->rest_args
+           && !strcmp (argv[i], "__VA_ARGS__")))
+       CPP_PUTS_Q (pfile, argv[i], argl[i]);
+      if (i < defn->nargs-1)
+       CPP_PUTS_Q (pfile, ", ", 2);
+    }
+  if (defn->rest_args)
+    CPP_PUTS (pfile, "...", 3);
+  CPP_PUTS (pfile, ") ", 2);
 
-      i = defn->length - (x - defn->expansion) - 2;
+  /* Now the definition. */
+  x = defn->expansion;
+  for (r = defn->pattern; r; r = r->next)
+    {
+      i = r->nchars;
       if (*x == '\r') x += 2, i -= 2;
-      if (i > 0) CPP_PUTS (pfile, x, i);
+      /* i chars for macro text, plus the length of the macro
+        argument name, plus one for a stringify marker, plus two for
+        each concatenation marker. */
+      CPP_RESERVE (pfile,
+                  i + argl[r->argno] + r->stringify
+                  + (r->raw_before + r->raw_after) * 2);
+
+      if (i > 0) CPP_PUTS_Q (pfile, x, i);
+      if (r->raw_before)
+       CPP_PUTS_Q (pfile, "##", 2);
+      if (r->stringify)
+       CPP_PUTC_Q (pfile, '#');
+      CPP_PUTS_Q (pfile, argv[r->argno], argl[r->argno]);
+      if (r->raw_after && !(r->next && r->next->nchars == 0
+                           && r->next->raw_before))
+       CPP_PUTS_Q (pfile, "##", 2);
+
+      x += i;
     }
-  if (CPP_BUFFER (pfile) == 0 || ! pfile->done_initializing)
-    CPP_PUTC (pfile, '\n');
+
+  i = defn->length - (x - defn->expansion) - 2;
+  if (*x == '\r') x += 2, i -= 2;
+  if (i > 0) CPP_PUTS (pfile, x, i);
 }
 
 /* Dump out the hash table.  */
@@ -1687,7 +1899,7 @@ dump_hash_helper (h, p)
   cpp_reader *pfile = (cpp_reader *)p;
 
   if (hp->type == T_MACRO)
-    _cpp_dump_definition (pfile, hp->name, hp->length, hp->value.defn);
+    _cpp_dump_definition (pfile, hp);
   return 1;
 }
 
index 2b8a5d1fa1a98b138ad31ddc24796e428bbe7f54..78185f2001d37c1e5727a2e9b69ef9ddc86dfacb 100644 (file)
@@ -64,9 +64,6 @@ struct definition
   int nargs;
   int length;                  /* length of expansion string */
   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 *pattern;
 
@@ -86,6 +83,7 @@ struct definition
 /* different flavors of hash nodes */
 enum node_type
 {
+  T_VOID = 0,     /* no definition yet */
   T_SPECLINE,     /* `__LINE__' */
   T_DATE,         /* `__DATE__' */
   T_FILE,         /* `__FILE__' */
@@ -94,10 +92,12 @@ enum node_type
   T_TIME,         /* `__TIME__' */
   T_STDC,         /* `__STDC__' */
   T_CONST,        /* Constant string, used by `__SIZE_TYPE__' etc */
-  T_MCONST,       /* Ditto, but the string is malloced memory */
-  T_MACRO,        /* macro defined by `#define' */
-  T_DISABLED,     /* macro temporarily turned off for rescan */
-  T_POISON,       /* macro defined with `#pragma poison' */
+  T_XCONST,       /* Ditto, but the string is malloced memory */
+  T_POISON,       /* poisoned identifier */
+  T_MCONST,       /* object-like macro defined to a single identifier */
+  T_MACRO,        /* general object-like macro */
+  T_FMACRO,       /* general function-like macro */
+  T_IDENTITY,     /* macro defined to itself */
   T_EMPTY         /* macro defined to nothing */
 };
 
@@ -118,6 +118,11 @@ struct hashnode
   unsigned long hash;          /* cached hash value */
   union hashval value;         /* pointer to expansion, or whatever */
   enum node_type type;         /* type of special token */
+  int disabled;                        /* macro turned off for rescan?  */
+
+  const char *file;            /* File, line, column of definition; */
+  int line;
+  int col;
 };
 
 /* List of directories to look for include files in. */
@@ -272,12 +277,9 @@ 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 *,
-                                                  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 *,
-                                                DEFINITION *));
+extern int _cpp_create_definition      PARAMS ((cpp_reader *,
+                                                cpp_toklist *, HASHNODE *));
+extern void _cpp_dump_definition       PARAMS ((cpp_reader *, HASHNODE *));
 extern void _cpp_quote_string          PARAMS ((cpp_reader *, const char *));
 extern void _cpp_macroexpand           PARAMS ((cpp_reader *, HASHNODE *));
 extern void _cpp_init_macro_hash       PARAMS ((cpp_reader *));
index d1e7c117b26b387abd02fc7e538c96a032b83b2a..957e6112fef874c49013ed5a6a1c0233db5c3f84 100644 (file)
@@ -635,7 +635,7 @@ static const struct builtin builtin_array[] =
   { "__LINE__",                        0, T_SPECLINE,          0 },
   { "__INCLUDE_LEVEL__",       0, T_INCLUDE_LEVEL,     0 },
 
-  { "__VERSION__",             0,               T_MCONST, DUMP|VERS },
+  { "__VERSION__",             0,               T_XCONST, DUMP|VERS },
   { "__USER_LABEL_PREFIX__",   0,               T_CONST,  DUMP|ULP  },
   { "__STDC__",                        "1",             T_STDC,   DUMP },
   { "__REGISTER_PREFIX__",     REGISTER_PREFIX, T_CONST,  DUMP },
index 3e6a89feac590e23c8bc0ec5cf0f37720f88eebe..f46b63892bb4728a25077afaf7813676d38a032b 100644 (file)
@@ -1455,7 +1455,7 @@ maybe_macroexpand (pfile, written)
 
   if (!hp)
     return 0;
-  if (hp->type == T_DISABLED)
+  if (hp->disabled || hp->type == T_IDENTITY)
     {
       if (pfile->output_escapes)
        {
@@ -1479,7 +1479,7 @@ maybe_macroexpand (pfile, written)
     }
 
   /* If macro wants an arglist, verify that a '(' follows.  */
-  if (hp->type == T_MACRO && hp->value.defn->nargs >= 0)
+  if (hp->type == T_FMACRO)
     {
       int macbuf_whitespace = 0;
       int c;
index 7f2554bfc06ec3a8f71ec971f16d98de9674dc36..5bb51623d3becad211fcac8160598ec09e580dd6 100644 (file)
@@ -316,10 +316,8 @@ do_define (pfile)
      cpp_reader *pfile;
 {
   HASHNODE **slot;
-  DEFINITION *def = 0;
   unsigned long hash;
   int len;
-  int funlike = 0, empty = 0;
   U_CHAR *sym;
   cpp_toklist *list = &pfile->directbuf;
 
@@ -350,90 +348,26 @@ do_define (pfile)
       goto out;
     }
 
-
-  if (list->tokens_used == 2 && list->tokens[1].type == CPP_VSPACE)
-    empty = 1;  /* Empty definition of object-like macro.  */
-
-  /* If the next character, with no intervening whitespace, is '(',
-     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, list, funlike);
-      if (def == 0)
-       goto out;
-    }
-
   slot = _cpp_lookup_slot (pfile, sym, len, INSERT, &hash);
   if (*slot)
     {
-      int ok;
-      HASHNODE *hp = *slot;
-
-      /* Redefining a macro is ok if the definitions are the same.  */
-      if (hp->type == T_MACRO)
-       ok = ! empty && ! _cpp_compare_defs (pfile, def, hp->value.defn);
-      else if (hp->type == T_EMPTY)
-       ok = empty;
-      /* Redefining a constant is ok with -D.  */
-      else if (hp->type == T_CONST || hp->type == T_STDC)
-        ok = ! pfile->done_initializing;
-      /* Otherwise it's not ok.  */
-      else
-       ok = 0;
-      /* Print the warning or error if it's not ok.  */
-      if (! ok)
+      /* Check for poisoned identifiers now.  All other checks
+        are done in cpphash.c.  */
+      if ((*slot)->type == T_POISON)
        {
-         if (hp->type == T_POISON)
-           cpp_error (pfile, "redefining poisoned `%.*s'", len, sym);
-         else
-           cpp_pedwarn (pfile, "`%.*s' redefined", len, sym);
-         if (hp->type == T_MACRO && pfile->done_initializing)
-           {
-             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)
-       {
-         /* Replace the old definition.  */
-         if (hp->type == T_MACRO)
-           _cpp_free_definition (hp->value.defn);
-         if (empty)
-           {
-             hp->type = T_EMPTY;
-             hp->value.defn = 0;
-           }
-         else
-           {
-             hp->type = T_MACRO;
-             hp->value.defn = def;
-           }
+         cpp_error (pfile, "redefining poisoned `%.*s'", len, sym);
+         goto out;
        }
     }
   else
-    {
-      HASHNODE *hp = _cpp_make_hashnode (sym, len, empty ? T_EMPTY : T_MACRO,
-                                        hash);
-      hp->value.defn = def;
-      *slot = hp;
-    }
+    *slot = _cpp_make_hashnode (sym, len, T_VOID, hash);
+    
+  if (_cpp_create_definition (pfile, list, *slot) == 0)
+    goto out;
 
   if (CPP_OPTION (pfile, debug_output)
       || CPP_OPTION (pfile, dump_macros) == dump_definitions)
-    _cpp_dump_definition (pfile, sym, len, def);
+    _cpp_dump_definition (pfile, *slot);
   else if (CPP_OPTION (pfile, dump_macros) == dump_names)
     pass_thru_directive (sym, len, pfile, T_DEFINE);
 
@@ -769,7 +703,9 @@ do_undef (pfile)
          if (CPP_OPTION (pfile, debug_output))
            pass_thru_directive (hp->name, len, pfile, T_UNDEF);
 
-         if (hp->type != T_MACRO && hp->type != T_EMPTY)
+         if (hp->type != T_MACRO && hp->type != T_FMACRO
+             && hp->type != T_MCONST
+             && hp->type != T_EMPTY && hp->type != T_IDENTITY)
            cpp_warning (pfile, "undefining `%s'", hp->name);
 
          htab_clear_slot (pfile->hashtab, (void **)slot);
This page took 0.125476 seconds and 5 git commands to generate.