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]

[patch] beginnings of the macro rewrite


This patch changes the #define logic to make use of token lists
briefly.  We convert back to the old structure, but we already get
significant benefits - simpler code, fewer reallocations, etc.

IMPORTANT: This drops support for traditional macros.  I will put it
back if people complain loudly enough.  If no one cares then I will
probably drop -traditional entirely, sometime next week.
-Wtraditional still works.

zw

	* cpphash.c (struct arg, struct arglist): Const-ify strings.
	(warn_trad_stringify, duplicate_arg_p): New helper functions.
	(collect_expansion): Rewrite to scan over a token list.
	Remove -traditional support.
	(collect_formal_parameters): Rename to collect_params; rewrite
	to scan over a token list.
	(_cpp_create_definition): Adjust to scan a token list.
	(_cpp_macroexpand): Remove -traditional support.
	(_cpp_compare_defs): Whitespace is now canonicalized.
	(comp_def_part): Delete function.

	* cpphash.h: Update prototypes.
	* cpplex.c (init_token_list): Don't set lineno if there is no
	buffer.
	(pedantic_whitespace): New function.
	(_cpp_scan_line): Mark tokens that had hspace before.  Don't
	consume a newline.  Use pedantic_whitespace.
	(_cpp_lex_token): Remove support for -traditional macros.
	(_cpp_get_define_token): Delete.
	(_cpp_get_directive_token): Do the real work here.  Use
	pedantic_whitespace.
	(_cpp_init_input_buffer): Initialize pfile->directbuf.

	* cpplib.c (get_macro_name): Delete.
	(do_define): Read the entire line into pfile->directbuf, then
	feed the token list to _cpp_create_definition.
	* cpplib.h (HSPACE_BEFORE): new define.
	(struct cpp_reader): Add a toklist member, "directbuf".

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


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