This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

macro expander code rearrangement


This patch rearranges a lot of the code in the macro expander to make
it easier to read.  It also adds a few trivial-case optimizations,
e.g. an empty macro doesn't bother pushing a buffer anymore.

There are bugs in special_symbol which I will send a separate patch
for; this one is way too long already.

zw

	* 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.

===================================================================
Index: cpphash.c
--- cpphash.c	2000/04/22 23:02:08	1.72
+++ cpphash.c	2000/04/23 16:46:07
@@ -34,14 +34,17 @@ Foundation, 59 Temple Place - Suite 330,
 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, has
   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, 
   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,
   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,
 	  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,
 	{
 	case CPP_STRING:
 	case CPP_CHAR:
-	  if (argc)
+	  if (argc == 0)
+	    goto norm;
+	  if (CPP_TRADITIONAL (pfile))
 	    {
-	      if (CPP_TRADITIONAL (pfile))
-		{
-		  last = trad_stringify (pfile, tok, len, argc, argv,
-					 &pat, &endpat, last);
-		  break;
-		}
+	      last = trad_stringify (pfile, tok, len, argc, argv,
+				     &pat, &endpat, last);
+	      break;
+	    }
+	  else
+	    {
 	      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,
 	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,
   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;
     }
-  else
-    start_line = start_column = 0;
+
+  /* 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;
+    }
 
-  /* 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 macro wants zero args, we parsed the arglist for checking only.
+     Read directly from the macro definition.  */
+  if (defn->nargs == 0 || defn->pattern == 0)
+    {
+      CPP_SET_WRITTEN (pfile, old_written);
+      pfile->output_escapes--;
+      push_macro_expansion (pfile, defn->expansion, defn->length, hp);
+      return;
+    }
 
-  if (nargs >= 0)
+  funlike_macroexpand (pfile, hp, args);
+  pfile->output_escapes--;
+}
+
+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)
     {
-      enum cpp_ttype token;
+      start_line = CPP_BUF_LINE (ip);
+      start_column = CPP_BUF_COL (ip);
+    }
+  else
+    start_line = start_column = 0;
 
-      args = (struct argdata *) alloca ((nargs + 1) * sizeof (struct argdata));
+  /* 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;
+
+  /* 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);
 
-      for (i = 0; i < nargs; i++)
+  token = CPP_EOF;
+  do
+    {
+      if (i < MAX (nargs, 1))
 	{
-	  args[i].raw = args[i].expanded = 0;
-	  args[i].raw_length = 0;
-	  args[i].expand_length = args[i].stringified_length = -1;
+	  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;
 
-      /* 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);
+  /* 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)
+    {
+      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;
+    }
+
+  /* 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);
+    }
+}
+
+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];
 
-      token = CPP_EOF;
-      do
+      if (!in_string)
 	{
-	  if (rest_args)
-	    continue;
-	  if (i < nargs || (nargs == 0 && i == 0))
+	  /* Delete "\r " and "\r-" escapes.  */
+	  if (c == '\r')
 	    {
-	      /* 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;
+	      i++;
+	      continue;
 	    }
-	  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++;
+	  /* 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;
 	}
-      while (token == CPP_COMMA);
-      CPP_OPTION (pfile, discard_comments)--;
-      pfile->no_macro_expand--;
-      pfile->no_directives--;
-      if (token != CPP_CLOSE_PAREN)
-	return;
 
-      /* 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)
+      if (escaped)
+	escaped = 0;
+      else
 	{
-	  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;
+	  if (c == '\\')
+	    escaped = 1;
+	  if (in_string)
+	    {
+	      if (c == in_string)
+		in_string = 0;
+	    }
+	  else if (c == '\"' || c == '\'')
+	    in_string = c;
 	}
 
-      /* 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)
+      /* Escape these chars */
+      if (c == '\"' || (in_string && c == '\\'))
+	CPP_PUTC (pfile, '\\');
+      if (ISPRINT (c))
+	CPP_PUTC (pfile, c);
+      else
 	{
-	  cpp_error (pfile, "arguments given to macro `%s'", hp->name);
+	  CPP_RESERVE (pfile, 4);
+	  sprintf ((char *) CPP_PWRITTEN (pfile), "\\%03o", (unsigned int) c);
+	  CPP_ADJUST_WRITTEN (pfile, 4);
 	}
-      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)
-	{
-	  cpp_error (pfile,
-		     "macro `%s' used with too many (%d) args", hp->name, i);
-	}
     }
+  CPP_PUTC (pfile, '\"');	/* insert ending quote */
+  arg->stringified_length  = CPP_WRITTEN (pfile) - arg->stringified;
+}
 
-  /* If macro wants zero args, we parsed the arglist for checking only.
-     Read directly from the macro definition.  */
-  if (nargs <= 0)
-    {
-      xbuf = defn->expansion;
-      xbuf_len = defn->length;
-    }
-  else
+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)
     {
-      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;
-
-      /* Macro really takes args.  Compute the expansion of this call.  */
-
-      /* 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)
+	{
+	  /* 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
 	{
-	  if (ap->stringify)
+	  /* 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)
 	    {
-	      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];
+	      args[ap->argno].expanded = CPP_WRITTEN (pfile);
+	      _cpp_expand_to_buffer (pfile, ARG_BASE + args[ap->argno].raw,
+				     args[ap->argno].raw_length);
 
-		      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;
+	      args[ap->argno].expand_length
+		= CPP_WRITTEN (pfile) - args[ap->argno].expanded;
 	    }
-	  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)
-		{
-		  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;
-		}
-
-	      /* Add 4 for two \r-space markers to prevent
-	         token concatenation.  */
-	      xbuf_len += args[ap->argno].expand_length + 4;
-	    }
+	  /* 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);
+  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)
+  /* 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)))
 	{
-	  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)))
-	    {
-	      /* 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--;
-	    }
+	  /* 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)
+      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, 
     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,93 +1786,109 @@ _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++)
+      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)
 	{
-	  argv[i] = x;
-	  argl[i] = strlen (x);
-	  x += argl[i] + 1;
+	  /* 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);
 	}
-      
-      /* 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);
-
-      /* 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;
-      }
-
-      i = defn->length - (x - defn->expansion) - 2;
-      if (*x == '\r') x += 2, i -= 2;
-      if (i > 0) CPP_PUTS (pfile, x, i);
+      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');
 }
 
+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);
+
+  /* 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;
+    }
+
+  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.  */
 static int
 dump_hash_helper (h, p)
@@ -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: cpphash.h
--- cpphash.h	2000/04/21 17:18:49	1.36
+++ cpphash.h	2000/04/23 16:46:07
@@ -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	PARAM
 						 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: cppinit.c
--- cppinit.c	2000/04/18 21:49:16	1.77
+++ cppinit.c	2000/04/23 16:46:07
@@ -635,7 +635,7 @@ static const struct builtin builtin_arra
   { "__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: cpplex.c
--- cpplex.c	2000/04/22 23:02:08	1.21
+++ cpplex.c	2000/04/23 16:46:07
@@ -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: cpplib.c
--- cpplib.c	2000/04/22 23:02:08	1.152
+++ cpplib.c	2000/04/23 16:46:08
@@ -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);

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]