This is the mail archive of the gdb-patches@sources.redhat.com mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: RFA: first preprocessor macro expansion files



This is a revision of the patch I posted before.  I changed the macro
expander's lexical analyzer to produce the same error messages the
c-exp.y does, to keep the test suite happy.

Jim Blandy <jimb@redhat.com> writes:

> This change just adds the macro table and macro expander files to GDB.
> It doesn't have any effect on GDB's behavior.  Their .o files will go
> into libgdb.a, but since nobody yet calls the functions these files
> define, and they have no _initialize functions, they don't end up in
> the final GDB executable.

2002-05-08  Jim Blandy  <jimb@redhat.com>

	Add first preprocessor macro-expansion files.
	* macroexp.c, macroexp.h, macrotab.c, macrotab.h: New files.
	* Makefile.in (SFILES): Add macrotab.c, macroexp.c.
	(splay_tree_h, macroexp_h, macrotab_h): New variable.
	(HFILES_NO_SRCDIR): Add macrotab.h, macroexp.h.
	(COMMON_OBS): Add macrotab.o, macroexp.o.
	(macroexp.o, macrotab.o): New rules.

Index: gdb/Makefile.in
===================================================================
RCS file: /cvs/src/src/gdb/Makefile.in,v
retrieving revision 1.180.2.2
diff -c -r1.180.2.2 Makefile.in
*** gdb/Makefile.in	9 May 2002 15:03:28 -0000	1.180.2.2
--- gdb/Makefile.in	9 May 2002 15:06:12 -0000
***************
*** 539,544 ****
--- 539,545 ----
  	m2-exp.y m2-lang.c m2-typeprint.c m2-valprint.c main.c maint.c \
  	memattr.c mem-break.c minsyms.c mipsread.c nlmread.c objfiles.c \
  	p-exp.y p-lang.c p-typeprint.c p-valprint.c parse.c \
+ 	macrotab.c macroexp.c \
  	printcmd.c remote.c remote-nrom.c scm-exp.c scm-lang.c \
  	scm-valprint.c source.c stabsread.c stack.c symfile.c \
  	symmisc.c symtab.c linespec.c target.c thread.c top.c tracepoint.c \
***************
*** 571,576 ****
--- 572,578 ----
  remote-sim_h =	$(INCLUDE_DIR)/remote-sim.h
  demangle_h =    $(INCLUDE_DIR)/demangle.h
  obstack_h =     $(INCLUDE_DIR)/obstack.h
+ splay_tree_h =  $(INCLUDE_DIR)/splay-tree.h
  
  readline_headers = \
  	$(READLINE_SRC)/chardefs.h \
***************
*** 631,636 ****
--- 633,640 ----
  inferior_h =	inferior.h $(breakpoint_h)
  language_h =	language.h
  linespec_h =	linespec.h
+ macroexp_h =	macroexp.h
+ macrotab_h =    macrotab.h $(obstack_h) $(bcache_h)
  memattr_h =     memattr.h
  monitor_h =	monitor.h
  objfiles_h =	objfiles.h
***************
*** 669,674 ****
--- 673,679 ----
  	gdb-stabs.h $(inferior_h) language.h minimon.h monitor.h \
  	objfiles.h parser-defs.h serial.h solib.h \
  	symfile.h stabsread.h target.h terminal.h typeprint.h xcoffsolib.h \
+ 	macrotab.h macroexp.h \
  	c-lang.h ch-lang.h f-lang.h \
  	jv-lang.h \
  	m2-lang.h  p-lang.h \
***************
*** 711,716 ****
--- 716,722 ----
  	source.o values.o eval.o valops.o valarith.o valprint.o printcmd.o \
  	symtab.o symfile.o symmisc.o linespec.o infcmd.o infrun.o \
  	expprint.o environ.o stack.o thread.o \
+ 	macrotab.o macroexp.o \
  	event-loop.o event-top.o inf-loop.o completer.o \
  	gdbarch.o arch-utils.o gdbtypes.o copying.o $(DEPFILES) \
  	memattr.o mem-break.o target.o parse.o language.o $(YYOBJ) buildsym.o \
***************
*** 2111,2116 ****
--- 2117,2127 ----
  linespec.o: linespec.c $(linespec_h) $(defs_h) $(frame_h) $(value_h) \
  	$(objfiles_h) $(symfile_h) $(completer_h) $(symtab_h) \
  	$(demangle_h) $(command_h) $(cp_abi_h)
+ 
+ macroexp.o: macroexp.c $(defs_h) $(macrotab_h)
+ 
+ macrotab.o: macrotab.c $(defs_h) $(obstack_h) $(objfiles_h) $(symtab_h) \
+ 	$(macrotab_h) $(splay_tree_h) gdb_assert.h $(bcache_h)
  
  target.o: target.c $(bfd_h) $(defs_h) $(gdbcmd_h) $(inferior_h) \
  	$(objfiles_h) $(symfile_h) $(target_h) $(gdb_string_h) $(regcache_h)
Index: gdb/macrocmd.c
===================================================================
RCS file: gdb/macrocmd.c
diff -N gdb/macrocmd.c
Index: gdb/macroexp.c
===================================================================
RCS file: gdb/macroexp.c
diff -N gdb/macroexp.c
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- gdb/macroexp.c	9 May 2002 15:06:24 -0000
***************
*** 0 ****
--- 1,1169 ----
+ /* C preprocessor macro expansion for GDB.
+    Copyright 2002 Free Software Foundation, Inc.
+    Contributed by Red Hat, Inc.
+ 
+    This file is part of GDB.
+ 
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+ 
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+ 
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place - Suite 330,
+    Boston, MA 02111-1307, USA.  */
+ 
+ #include "defs.h"
+ #include "obstack.h"
+ #include "bcache.h"
+ #include "macrotab.h"
+ #include "macroexp.h"
+ #include "gdb_assert.h"
+ 
+ 
+ 
+ /* A resizeable, substringable string type.  */
+ 
+ 
+ /* A string type that we can resize, quickly append to, and use to
+    refer to substrings of other strings.  */
+ struct macro_buffer
+ {
+   /* An array of characters.  The first LEN bytes are the real text,
+      but there are SIZE bytes allocated to the array.  If SIZE is
+      zero, then this doesn't point to a malloc'ed block.  If SHARED is
+      non-zero, then this buffer is actually a pointer into some larger
+      string, and we shouldn't append characters to it, etc.  Because
+      of sharing, we can't assume in general that the text is
+      null-terminated.  */
+   char *text;
+ 
+   /* The number of characters in the string.  */
+   int len;
+ 
+   /* The number of characters allocated to the string.  If SHARED is
+      non-zero, this is meaningless; in this case, we set it to zero so
+      that any "do we have room to append something?" tests will fail,
+      so we don't always have to check SHARED before using this field.  */
+   int size;
+ 
+   /* Zero if TEXT can be safely realloc'ed (i.e., it's its own malloc
+      block).  Non-zero if TEXT is actually pointing into the middle of
+      some other block, and we shouldn't reallocate it.  */
+   int shared;
+ 
+   /* For detecting token splicing. 
+ 
+      This is the index in TEXT of the first character of the token
+      that abuts the end of TEXT.  If TEXT contains no tokens, then we
+      set this equal to LEN.  If TEXT ends in whitespace, then there is
+      no token abutting the end of TEXT (it's just whitespace), and
+      again, we set this equal to LEN.  We set this to -1 if we don't
+      know the nature of TEXT.  */
+   int last_token;
+ 
+   /* If this buffer is holding the result from get_token, then this 
+      is non-zero if it is an identifier token, zero otherwise.  */
+   int is_identifier;
+ };
+ 
+ 
+ /* Set the macro buffer *B to the empty string, guessing that its
+    final contents will fit in N bytes.  (It'll get resized if it
+    doesn't, so the guess doesn't have to be right.)  Allocate the
+    initial storage with xmalloc.  */
+ static void
+ init_buffer (struct macro_buffer *b, int n)
+ {
+   /* Small value for initial testing.  */
+   n = 1;
+ 
+   b->size = n;
+   if (n > 0)
+     b->text = (char *) xmalloc (n);
+   else
+     b->text = 0;
+   b->len = 0;
+   b->shared = 0;
+   b->last_token = -1;
+ }
+ 
+ 
+ /* Set the macro buffer *BUF to refer to the LEN bytes at ADDR, as a
+    shared substring.  */
+ static void
+ init_shared_buffer (struct macro_buffer *buf, char *addr, int len)
+ {
+   buf->text = addr;
+   buf->len = len;
+   buf->shared = 1;
+   buf->size = 0;
+   buf->last_token = -1;
+ }
+ 
+ 
+ /* Free the text of the buffer B.  Raise an error if B is shared.  */
+ static void
+ free_buffer (struct macro_buffer *b)
+ {
+   gdb_assert (! b->shared);
+   if (b->size)
+     xfree (b->text);
+ }
+ 
+ 
+ /* A cleanup function for macro buffers.  */
+ static void
+ cleanup_macro_buffer (void *untyped_buf)
+ {
+   free_buffer ((struct macro_buffer *) untyped_buf);
+ }
+ 
+ 
+ /* Resize the buffer B to be at least N bytes long.  Raise an error if
+    B shouldn't be resized.  */
+ static void
+ resize_buffer (struct macro_buffer *b, int n)
+ {
+   /* We shouldn't be trying to resize shared strings.  */
+   gdb_assert (! b->shared);
+   
+   if (b->size == 0)
+     b->size = n;
+   else
+     while (b->size <= n)
+       b->size *= 2;
+ 
+   b->text = xrealloc (b->text, b->size);
+ }
+ 
+ 
+ /* Append the character C to the buffer B.  */
+ static inline void
+ appendc (struct macro_buffer *b, int c)
+ {
+   int new_len = b->len + 1;
+ 
+   if (new_len > b->size)
+     resize_buffer (b, new_len);
+ 
+   b->text[b->len] = c;
+   b->len = new_len;
+ }
+ 
+ 
+ /* Append the LEN bytes at ADDR to the buffer B.  */
+ static inline void
+ appendmem (struct macro_buffer *b, char *addr, int len)
+ {
+   int new_len = b->len + len;
+ 
+   if (new_len > b->size)
+     resize_buffer (b, new_len);
+ 
+   memcpy (b->text + b->len, addr, len);
+   b->len = new_len;
+ }
+ 
+ 
+ 
+ /* Recognizing preprocessor tokens.  */
+ 
+ 
+ static int
+ is_whitespace (int c)
+ {
+   return (c == ' '
+           || c == '\t'
+           || c == '\n'
+           || c == '\v'
+           || c == '\f');
+ }
+ 
+ 
+ static int
+ is_digit (int c)
+ {
+   return ('0' <= c && c <= '9');
+ }
+ 
+ 
+ static int
+ is_identifier_nondigit (int c)
+ {
+   return (c == '_'
+           || ('a' <= c && c <= 'z')
+           || ('A' <= c && c <= 'Z'));
+ }
+ 
+ 
+ static void
+ set_token (struct macro_buffer *tok, char *start, char *end)
+ {
+   init_shared_buffer (tok, start, end - start);
+   tok->last_token = 0;
+ 
+   /* Presumed; get_identifier may overwrite this. */
+   tok->is_identifier = 0;
+ }
+ 
+ 
+ static int
+ get_comment (struct macro_buffer *tok, char *p, char *end)
+ {
+   if (p + 2 > end)
+     return 0;
+   else if (p[0] == '/'
+            && p[1] == '*')
+     {
+       char *tok_start = p;
+ 
+       p += 2;
+ 
+       for (; p < end; p++)
+         if (p + 2 <= end
+             && p[0] == '*'
+             && p[1] == '/')
+           {
+             p += 2;
+             set_token (tok, tok_start, p);
+             return 1;
+           }
+ 
+       error ("Unterminated comment in macro expansion.");
+     }
+   else if (p[0] == '/'
+            && p[1] == '/')
+     {
+       char *tok_start = p;
+ 
+       p += 2;
+       for (; p < end; p++)
+         if (*p == '\n')
+           break;
+ 
+       set_token (tok, tok_start, p);
+       return 1;
+     }
+   else
+     return 0;
+ }
+ 
+ 
+ static int
+ get_identifier (struct macro_buffer *tok, char *p, char *end)
+ {
+   if (p < end
+       && is_identifier_nondigit (*p))
+     {
+       char *tok_start = p;
+ 
+       while (p < end
+              && (is_identifier_nondigit (*p)
+                  || is_digit (*p)))
+         p++;
+ 
+       set_token (tok, tok_start, p);
+       tok->is_identifier = 1;
+       return 1;
+     }
+   else
+     return 0;
+ }
+ 
+ 
+ static int
+ get_pp_number (struct macro_buffer *tok, char *p, char *end)
+ {
+   if (p < end
+       && (is_digit (*p)
+           || *p == '.'))
+     {
+       char *tok_start = p;
+ 
+       while (p < end)
+         {
+           if (is_digit (*p)
+               || is_identifier_nondigit (*p)
+               || *p == '.')
+             p++;
+           else if (p + 2 <= end
+                    && strchr ("eEpP.", *p)
+                    && (p[1] == '+' || p[1] == '-'))
+             p += 2;
+           else
+             break;
+         }
+ 
+       set_token (tok, tok_start, p);
+       return 1;
+     }
+   else
+     return 0;
+ }
+ 
+ 
+ 
+ /* If the text starting at P going up to (but not including) END
+    starts with a character constant, set *TOK to point to that
+    character constant, and return 1.  Otherwise, return zero.
+    Signal an error if it contains a malformed or incomplete character
+    constant.  */
+ static int
+ get_character_constant (struct macro_buffer *tok, char *p, char *end)
+ {
+   /* ISO/IEC 9899:1999 (E)  Section 6.4.4.4  paragraph 1 
+      But of course, what really matters is that we handle it the same
+      way GDB's C/C++ lexer does.  So we call parse_escape in utils.c
+      to handle escape sequences.  */
+   if ((p + 1 <= end && *p == '\'')
+       || (p + 2 <= end && p[0] == 'L' && p[1] == '\''))
+     {
+       char *tok_start = p;
+       char *body_start;
+ 
+       if (*p == '\'')
+         p++;
+       else if (*p == 'L')
+         p += 2;
+       else
+         gdb_assert (0);
+ 
+       body_start = p;
+       for (;;)
+         {
+           if (p >= end)
+             error ("Invalid character constant.");
+           else if (*p == '\'')
+             {
+               if (p == body_start)
+                 error ("A character constant must contain at least one "
+                        "character.");
+               p++;
+               break;
+             }
+           else if (*p == '\\')
+             {
+               p++;
+               parse_escape (&p);
+             }
+           else
+             p++;
+         }
+ 
+       set_token (tok, tok_start, p);
+       return 1;
+     }
+   else
+     return 0;
+ }
+ 
+ 
+ /* If the text starting at P going up to (but not including) END
+    starts with a string literal, set *TOK to point to that string
+    literal, and return 1.  Otherwise, return zero.  Signal an error if
+    it contains a malformed or incomplete string literal.  */
+ static int
+ get_string_literal (struct macro_buffer *tok, char *p, char *end)
+ {
+   if ((p + 1 <= end
+        && *p == '\"')
+       || (p + 2 <= end
+           && p[0] == 'L'
+           && p[1] == '\"'))
+     {
+       char *tok_start = p;
+ 
+       if (*p == '\"')
+         p++;
+       else if (*p == 'L')
+         p += 2;
+       else
+         gdb_assert (0);
+ 
+       for (;;)
+         {
+           if (p >= end)
+             error ("Unterminated string in expression.");
+           else if (*p == '\"')
+             {
+               p++;
+               break;
+             }
+           else if (*p == '\n')
+             error ("Newline characters may not appear in string "
+                    "constants.");
+           else if (*p == '\\')
+             {
+               p++;
+               parse_escape (&p);
+             }
+           else
+             p++;
+         }
+ 
+       set_token (tok, tok_start, p);
+       return 1;
+     }
+   else
+     return 0;
+ }
+ 
+ 
+ static int
+ get_punctuator (struct macro_buffer *tok, char *p, char *end)
+ {
+   /* Here, speed is much less important than correctness and clarity.  */
+ 
+   /* ISO/IEC 9899:1999 (E)  Section 6.4.6  Paragraph 1  */
+   static const char * const punctuators[] = {
+     "[", "]", "(", ")", "{", "}", ".", "->", 
+     "++", "--", "&", "*", "+", "-", "~", "!",
+     "/", "%", "<<", ">>", "<", ">", "<=", ">=", "==", "!=", 
+     "^", "|", "&&", "||",
+     "?", ":", ";", "...",
+     "=", "*=", "/=", "%=", "+=", "-=", "<<=", ">>=", "&=", "^=", "|=",
+     ",", "#", "##",
+     "<:", ":>", "<%", "%>", "%:", "%:%:",
+     0
+   };
+ 
+   int i;
+ 
+   if (p + 1 <= end)
+     {
+       for (i = 0; punctuators[i]; i++)
+         {
+           const char *punctuator = punctuators[i];
+ 
+           if (p[0] == punctuator[0])
+             {
+               int len = strlen (punctuator);
+ 
+               if (p + len <= end
+                   && ! memcmp (p, punctuator, len))
+                 {
+                   set_token (tok, p, p + len);
+                   return 1;
+                 }
+             }
+         }
+     }
+ 
+   return 0;
+ }
+ 
+ 
+ /* Peel the next preprocessor token off of SRC, and put it in TOK.
+    Mutate TOK to refer to the first token in SRC, and mutate SRC to
+    refer to the text after that token.  SRC must be a shared buffer;
+    the resulting TOK will be shared, pointing into the same string SRC
+    does.  Initialize TOK's last_token field.  Return non-zero if we
+    succeed, or 0 if we didn't find any more tokens in SRC.  */
+ static int
+ get_token (struct macro_buffer *tok,
+            struct macro_buffer *src)
+ {
+   char *p = src->text;
+   char *end = p + src->len;
+ 
+   gdb_assert (src->shared);
+ 
+   /* From the ISO C standard, ISO/IEC 9899:1999 (E), section 6.4:
+ 
+      preprocessing-token: 
+          header-name
+          identifier
+          pp-number
+          character-constant
+          string-literal
+          punctuator
+          each non-white-space character that cannot be one of the above
+ 
+      We don't have to deal with header-name tokens, since those can
+      only occur after a #include, which we will never see.  */
+ 
+   while (p < end)
+     if (is_whitespace (*p))
+       p++;
+     else if (get_comment (tok, p, end))
+       p += tok->len;
+     else if (get_pp_number (tok, p, end)
+              || get_character_constant (tok, p, end)
+              || get_string_literal (tok, p, end)
+              /* Note: the grammar in the standard seems to be
+                 ambiguous: L'x' can be either a wide character
+                 constant, or an identifier followed by a normal
+                 character constant.  By trying `get_identifier' after
+                 we try get_character_constant and get_string_literal,
+                 we give the wide character syntax precedence.  Now,
+                 since GDB doesn't handle wide character constants
+                 anyway, is this the right thing to do?  */
+              || get_identifier (tok, p, end)
+              || get_punctuator (tok, p, end))
+       {
+         /* How many characters did we consume, including whitespace?  */
+         int consumed = p - src->text + tok->len;
+         src->text += consumed;
+         src->len -= consumed;
+         return 1;
+       }
+     else 
+       {
+         /* We have found a "non-whitespace character that cannot be
+            one of the above."  Make a token out of it.  */
+         int consumed;
+ 
+         set_token (tok, p, p + 1);
+         consumed = p - src->text + tok->len;
+         src->text += consumed;
+         src->len -= consumed;
+         return 1;
+       }
+ 
+   return 0;
+ }
+ 
+ 
+ 
+ /* Appending token strings, with and without splicing  */
+ 
+ 
+ /* Append the macro buffer SRC to the end of DEST, and ensure that
+    doing so doesn't splice the token at the end of SRC with the token
+    at the beginning of DEST.  SRC and DEST must have their last_token
+    fields set.  Upon return, DEST's last_token field is set correctly.
+ 
+    For example:
+ 
+    If DEST is "(" and SRC is "y", then we can return with
+    DEST set to "(y" --- we've simply appended the two buffers.
+ 
+    However, if DEST is "x" and SRC is "y", then we must not return
+    with DEST set to "xy" --- that would splice the two tokens "x" and
+    "y" together to make a single token "xy".  However, it would be
+    fine to return with DEST set to "x y".  Similarly, "<" and "<" must
+    yield "< <", not "<<", etc.  */
+ static void
+ append_tokens_without_splicing (struct macro_buffer *dest,
+                                 struct macro_buffer *src)
+ {
+   int original_dest_len = dest->len;
+   struct macro_buffer dest_tail, new_token;
+ 
+   gdb_assert (src->last_token != -1);
+   gdb_assert (dest->last_token != -1);
+   
+   /* First, just try appending the two, and call get_token to see if
+      we got a splice.  */
+   appendmem (dest, src->text, src->len);
+ 
+   /* If DEST originally had no token abutting its end, then we can't
+      have spliced anything, so we're done.  */
+   if (dest->last_token == original_dest_len)
+     {
+       dest->last_token = original_dest_len + src->last_token;
+       return;
+     }
+ 
+   /* Set DEST_TAIL to point to the last token in DEST, followed by
+      all the stuff we just appended.  */
+   init_shared_buffer (&dest_tail,
+                       dest->text + dest->last_token,
+                       dest->len - dest->last_token);
+ 
+   /* Re-parse DEST's last token.  We know that DEST used to contain
+      at least one token, so if it doesn't contain any after the
+      append, then we must have spliced "/" and "*" or "/" and "/" to
+      make a comment start.  (Just for the record, I got this right
+      the first time.  This is not a bug fix.)  */
+   if (get_token (&new_token, &dest_tail)
+       && (new_token.text + new_token.len
+           == dest->text + original_dest_len))
+     {
+       /* No splice, so we're done.  */
+       dest->last_token = original_dest_len + src->last_token;
+       return;
+     }
+ 
+   /* Okay, a simple append caused a splice.  Let's chop dest back to
+      its original length and try again, but separate the texts with a
+      space.  */
+   dest->len = original_dest_len;
+   appendc (dest, ' ');
+   appendmem (dest, src->text, src->len);
+ 
+   init_shared_buffer (&dest_tail,
+                       dest->text + dest->last_token,
+                       dest->len - dest->last_token);
+ 
+   /* Try to re-parse DEST's last token, as above.  */
+   if (get_token (&new_token, &dest_tail)
+       && (new_token.text + new_token.len
+           == dest->text + original_dest_len))
+     {
+       /* No splice, so we're done.  */
+       dest->last_token = original_dest_len + 1 + src->last_token;
+       return;
+     }
+ 
+   /* As far as I know, there's no case where inserting a space isn't
+      enough to prevent a splice.  */
+   internal_error (__FILE__, __LINE__,
+                   "unable to avoid splicing tokens during macro expansion");
+ }
+ 
+ 
+ 
+ /* Expanding macros!  */
+ 
+ 
+ /* A singly-linked list of the names of the macros we are currently 
+    expanding --- for detecting expansion loops.  */
+ struct macro_name_list {
+   const char *name;
+   struct macro_name_list *next;
+ };
+ 
+ 
+ /* Return non-zero if we are currently expanding the macro named NAME,
+    according to LIST; otherwise, return zero.
+ 
+    You know, it would be possible to get rid of all the NO_LOOP
+    arguments to these functions by simply generating a new lookup
+    function and baton which refuses to find the definition for a
+    particular macro, and otherwise delegates the decision to another
+    function/baton pair.  But that makes the linked list of excluded
+    macros chained through untyped baton pointers, which will make it
+    harder to debug.  :( */
+ static int
+ currently_rescanning (struct macro_name_list *list, const char *name)
+ {
+   for (; list; list = list->next)
+     if (! strcmp (name, list->name))
+       return 1;
+ 
+   return 0;
+ }
+ 
+ 
+ /* Gather the arguments to a macro expansion.
+ 
+    NAME is the name of the macro being invoked.  (It's only used for
+    printing error messages.)
+ 
+    Assume that SRC is the text of the macro invocation immediately
+    following the macro name.  For example, if we're processing the
+    text foo(bar, baz), then NAME would be foo and SRC will be (bar,
+    baz).
+ 
+    If SRC doesn't start with an open paren ( token at all, return
+    zero, leave SRC unchanged, and don't set *ARGC_P to anything.
+ 
+    If SRC doesn't contain a properly terminated argument list, then
+    raise an error.
+ 
+    Otherwise, return a pointer to the first element of an array of
+    macro buffers referring to the argument texts, and set *ARGC_P to
+    the number of arguments we found --- the number of elements in the
+    array.  The macro buffers share their text with SRC, and their
+    last_token fields are initialized.  The array is allocated with
+    xmalloc, and the caller is responsible for freeing it.
+ 
+    NOTE WELL: if SRC starts with a open paren ( token followed
+    immediately by a close paren ) token (e.g., the invocation looks
+    like "foo()"), we treat that as one argument, which happens to be
+    the empty list of tokens.  The caller should keep in mind that such
+    a sequence of tokens is a valid way to invoke one-parameter
+    function-like macros, but also a valid way to invoke zero-parameter
+    function-like macros.  Eeew.
+ 
+    Consume the tokens from SRC; after this call, SRC contains the text
+    following the invocation.  */
+ 
+ static struct macro_buffer *
+ gather_arguments (const char *name, struct macro_buffer *src, int *argc_p)
+ {
+   struct macro_buffer tok;
+   int args_len, args_size;
+   struct macro_buffer *args = 0;
+   struct cleanup *back_to = make_cleanup (free_current_contents, &args);
+ 
+   /* Does SRC start with an opening paren token?  Read from a copy of
+      SRC, so SRC itself is unaffected if we don't find an opening
+      paren.  */
+   {
+     struct macro_buffer temp;
+     init_shared_buffer (&temp, src->text, src->len);
+ 
+     if (! get_token (&tok, &temp)
+         || tok.len != 1
+         || tok.text[0] != '(')
+       {
+         discard_cleanups (back_to);
+         return 0;
+       }
+   }
+ 
+   /* Consume SRC's opening paren.  */
+   get_token (&tok, src);
+ 
+   args_len = 0;
+   args_size = 1;                /* small for initial testing */
+   args = (struct macro_buffer *) xmalloc (sizeof (*args) * args_size);
+ 
+   for (;;)
+     {
+       struct macro_buffer *arg;
+       int depth;
+ 
+       /* Make sure we have room for the next argument.  */
+       if (args_len >= args_size)
+         {
+           args_size *= 2;
+           args = xrealloc (args, sizeof (*args) * args_size);
+         }
+ 
+       /* Initialize the next argument.  */
+       arg = &args[args_len++];
+       set_token (arg, src->text, src->text);
+ 
+       /* Gather the argument's tokens.  */
+       depth = 0;
+       for (;;)
+         {
+           char *start = src->text;
+ 
+           if (! get_token (&tok, src))
+             error ("Malformed argument list for macro `%s'.", name);
+       
+           /* Is tok an opening paren?  */
+           if (tok.len == 1 && tok.text[0] == '(')
+             depth++;
+ 
+           /* Is tok is a closing paren?  */
+           else if (tok.len == 1 && tok.text[0] == ')')
+             {
+               /* If it's a closing paren at the top level, then that's
+                  the end of the argument list.  */
+               if (depth == 0)
+                 {
+                   discard_cleanups (back_to);
+                   *argc_p = args_len;
+                   return args;
+                 }
+ 
+               depth--;
+             }
+ 
+           /* If tok is a comma at top level, then that's the end of
+              the current argument.  */
+           else if (tok.len == 1 && tok.text[0] == ',' && depth == 0)
+             break;
+ 
+           /* Extend the current argument to enclose this token.  If
+              this is the current argument's first token, leave out any
+              leading whitespace, just for aesthetics.  */
+           if (arg->len == 0)
+             {
+               arg->text = tok.text;
+               arg->len = tok.len;
+               arg->last_token = 0;
+             }
+           else
+             {
+               arg->len = (tok.text + tok.len) - arg->text;
+               arg->last_token = tok.text - arg->text;
+             }
+         }
+     }
+ }
+ 
+ 
+ /* The `expand' and `substitute_args' functions both invoke `scan'
+    recursively, so we need a forward declaration somewhere.  */
+ static void scan (struct macro_buffer *dest,
+                   struct macro_buffer *src,
+                   struct macro_name_list *no_loop,
+                   macro_lookup_ftype *lookup_func,
+                   void *lookup_baton);
+ 
+ 
+ /* Given the macro definition DEF, being invoked with the actual
+    arguments given by ARGC and ARGV, substitute the arguments into the
+    replacement list, and store the result in DEST.
+ 
+    If it is necessary to expand macro invocations in one of the
+    arguments, use LOOKUP_FUNC and LOOKUP_BATON to find the macro
+    definitions, and don't expand invocations of the macros listed in
+    NO_LOOP.  */
+ static void
+ substitute_args (struct macro_buffer *dest, 
+                  struct macro_definition *def,
+                  int argc, struct macro_buffer *argv,
+                  struct macro_name_list *no_loop,
+                  macro_lookup_ftype *lookup_func,
+                  void *lookup_baton)
+ {
+   /* A macro buffer for the macro's replacement list.  */
+   struct macro_buffer replacement_list;
+ 
+   init_shared_buffer (&replacement_list, (char *) def->replacement,
+                       strlen (def->replacement));
+ 
+   gdb_assert (dest->len == 0);
+   dest->last_token = 0;
+ 
+   for (;;)
+     {
+       struct macro_buffer tok;
+       char *original_rl_start = replacement_list.text;
+       int substituted = 0;
+       
+       /* Find the next token in the replacement list.  */
+       if (! get_token (&tok, &replacement_list))
+         break;
+ 
+       /* Just for aesthetics.  If we skipped some whitespace, copy
+          that to DEST.  */
+       if (tok.text > original_rl_start)
+         {
+           appendmem (dest, original_rl_start, tok.text - original_rl_start);
+           dest->last_token = dest->len;
+         }
+ 
+       /* Is this token the stringification operator?  */
+       if (tok.len == 1
+           && tok.text[0] == '#')
+         error ("Stringification is not implemented yet.");
+ 
+       /* Is this token the splicing operator?  */
+       if (tok.len == 2
+           && tok.text[0] == '#'
+           && tok.text[1] == '#')
+         error ("Token splicing is not implemented yet.");
+ 
+       /* Is this token an identifier?  */
+       if (tok.is_identifier)
+         {
+           int i;
+ 
+           /* Is it the magic varargs parameter?  */
+           if (tok.len == 11
+               && ! memcmp (tok.text, "__VA_ARGS__", 11))
+             error ("Variable-arity macros not implemented yet.");
+ 
+           /* Is it one of the parameters?  */
+           for (i = 0; i < def->argc; i++)
+             if (tok.len == strlen (def->argv[i])
+                 && ! memcmp (tok.text, def->argv[i], tok.len))
+               {
+                 struct macro_buffer arg_src;
+ 
+                 /* Expand any macro invocations in the argument text,
+                    and append the result to dest.  Remember that scan
+                    mutates its source, so we need to scan a new buffer
+                    referring to the argument's text, not the argument
+                    itself.  */
+                 init_shared_buffer (&arg_src, argv[i].text, argv[i].len);
+                 scan (dest, &arg_src, no_loop, lookup_func, lookup_baton);
+                 substituted = 1;
+                 break;
+               }
+         }
+ 
+       /* If it wasn't a parameter, then just copy it across.  */
+       if (! substituted)
+         append_tokens_without_splicing (dest, &tok);
+     }
+ }
+ 
+ 
+ /* Expand a call to a macro named ID, whose definition is DEF.  Append
+    its expansion to DEST.  SRC is the input text following the ID
+    token.  We are currently rescanning the expansions of the macros
+    named in NO_LOOP; don't re-expand them.  Use LOOKUP_FUNC and
+    LOOKUP_BATON to find definitions for any nested macro references.  
+ 
+    Return 1 if we decided to expand it, zero otherwise.  (If it's a
+    function-like macro name that isn't followed by an argument list,
+    we don't expand it.)  If we return zero, leave SRC unchanged.  */
+ static int
+ expand (const char *id,
+         struct macro_definition *def, 
+         struct macro_buffer *dest,
+         struct macro_buffer *src,
+         struct macro_name_list *no_loop,
+         macro_lookup_ftype *lookup_func,
+         void *lookup_baton)
+ {
+   struct macro_name_list new_no_loop;
+ 
+   /* Create a new node to be added to the front of the no-expand list.
+      This list is appropriate for re-scanning replacement lists, but
+      it is *not* appropriate for scanning macro arguments; invocations
+      of the macro whose arguments we are gathering *do* get expanded
+      there.  */
+   new_no_loop.name = id;
+   new_no_loop.next = no_loop;
+ 
+   /* What kind of macro are we expanding?  */
+   if (def->kind == macro_object_like)
+     {
+       struct macro_buffer replacement_list;
+ 
+       init_shared_buffer (&replacement_list, (char *) def->replacement,
+                           strlen (def->replacement));
+ 
+       scan (dest, &replacement_list, &new_no_loop, lookup_func, lookup_baton);
+       return 1;
+     }
+   else if (def->kind == macro_function_like)
+     {
+       struct cleanup *back_to = make_cleanup (null_cleanup, 0);
+       int argc;
+       struct macro_buffer *argv = 0;
+       struct macro_buffer substituted;
+       struct macro_buffer substituted_src;
+ 
+       if (def->argc >= 1
+           && ! strcmp (def->argv[def->argc - 1], "..."))
+         error ("Varargs macros not implemented yet.");
+ 
+       make_cleanup (free_current_contents, &argv);
+       argv = gather_arguments (id, src, &argc);
+ 
+       /* If we couldn't find any argument list, then we don't expand
+          this macro.  */
+       if (! argv)
+         {
+           do_cleanups (back_to);
+           return 0;
+         }
+ 
+       /* Check that we're passing an acceptable number of arguments for
+          this macro.  */
+       if (argc != def->argc)
+         {
+           /* Remember that a sequence of tokens like "foo()" is a
+              valid invocation of a macro expecting either zero or one
+              arguments.  */
+           if (! (argc == 1
+                  && argv[0].len == 0
+                  && def->argc == 0))
+             error ("Wrong number of arguments to macro `%s' "
+                    "(expected %d, got %d).",
+                    id, def->argc, argc);
+         }
+ 
+       /* Note that we don't expand macro invocations in the arguments
+          yet --- we let subst_args take care of that.  Parameters that
+          appear as operands of the stringifying operator "#" or the
+          splicing operator "##" don't get macro references expanded,
+          so we can't really tell whether it's appropriate to macro-
+          expand an argument until we see how it's being used.  */
+       init_buffer (&substituted, 0);
+       make_cleanup (cleanup_macro_buffer, &substituted);
+       substitute_args (&substituted, def, argc, argv, no_loop,
+                        lookup_func, lookup_baton);
+ 
+       /* Now `substituted' is the macro's replacement list, with all
+          argument values substituted into it properly.  Re-scan it for
+          macro references, but don't expand invocations of this macro.
+ 
+          We create a new buffer, `substituted_src', which points into
+          `substituted', and scan that.  We can't scan `substituted'
+          itself, since the tokenization process moves the buffer's
+          text pointer around, and we still need to be able to find
+          `substituted's original text buffer after scanning it so we
+          can free it.  */
+       init_shared_buffer (&substituted_src, substituted.text, substituted.len);
+       scan (dest, &substituted_src, &new_no_loop, lookup_func, lookup_baton);
+ 
+       do_cleanups (back_to);
+ 
+       return 1;
+     }
+   else
+     internal_error (__FILE__, __LINE__, "bad macro definition kind");
+ }
+ 
+ 
+ /* If the single token in SRC_FIRST followed by the tokens in SRC_REST
+    constitute a macro invokation not forbidden in NO_LOOP, append its
+    expansion to DEST and return non-zero.  Otherwise, return zero, and
+    leave DEST unchanged.
+ 
+    SRC_FIRST and SRC_REST must be shared buffers; DEST must not be one.
+    SRC_FIRST must be a string built by get_token.  */
+ static int
+ maybe_expand (struct macro_buffer *dest,
+               struct macro_buffer *src_first,
+               struct macro_buffer *src_rest,
+               struct macro_name_list *no_loop,
+               macro_lookup_ftype *lookup_func,
+               void *lookup_baton)
+ {
+   gdb_assert (src_first->shared);
+   gdb_assert (src_rest->shared);
+   gdb_assert (! dest->shared);
+ 
+   /* Is this token an identifier?  */
+   if (src_first->is_identifier)
+     {
+       /* Make a null-terminated copy of it, since that's what our
+          lookup function expects.  */
+       char *id = xmalloc (src_first->len + 1);
+       struct cleanup *back_to = make_cleanup (xfree, id);
+       memcpy (id, src_first->text, src_first->len);
+       id[src_first->len] = 0;
+           
+       /* If we're currently re-scanning the result of expanding
+          this macro, don't expand it again.  */
+       if (! currently_rescanning (no_loop, id))
+         {
+           /* Does this identifier have a macro definition in scope?  */
+           struct macro_definition *def = lookup_func (id, lookup_baton);
+ 
+           if (def && expand (id, def, dest, src_rest, no_loop,
+                              lookup_func, lookup_baton))
+             {
+               do_cleanups (back_to);
+               return 1;
+             }
+         }
+ 
+       do_cleanups (back_to);
+     }
+ 
+   return 0;
+ }
+ 
+ 
+ /* Expand macro references in SRC, appending the results to DEST.
+    Assume we are re-scanning the result of expanding the macros named
+    in NO_LOOP, and don't try to re-expand references to them.
+ 
+    SRC must be a shared buffer; DEST must not be one.  */
+ static void
+ scan (struct macro_buffer *dest,
+       struct macro_buffer *src,
+       struct macro_name_list *no_loop,
+       macro_lookup_ftype *lookup_func,
+       void *lookup_baton)
+ {
+   gdb_assert (src->shared);
+   gdb_assert (! dest->shared);
+ 
+   for (;;)
+     {
+       struct macro_buffer tok;
+       char *original_src_start = src->text;
+ 
+       /* Find the next token in SRC.  */
+       if (! get_token (&tok, src))
+         break;
+ 
+       /* Just for aesthetics.  If we skipped some whitespace, copy
+          that to DEST.  */
+       if (tok.text > original_src_start)
+         {
+           appendmem (dest, original_src_start, tok.text - original_src_start);
+           dest->last_token = dest->len;
+         }
+ 
+       if (! maybe_expand (dest, &tok, src, no_loop, lookup_func, lookup_baton))
+         /* We didn't end up expanding tok as a macro reference, so
+            simply append it to dest.  */
+         append_tokens_without_splicing (dest, &tok);
+     }
+ 
+   /* Just for aesthetics.  If there was any trailing whitespace in
+      src, copy it to dest.  */
+   if (src->len)
+     {
+       appendmem (dest, src->text, src->len);
+       dest->last_token = dest->len;
+     }
+ }
+ 
+ 
+ char *
+ macro_expand (const char *source,
+               macro_lookup_ftype *lookup_func,
+               void *lookup_func_baton)
+ {
+   struct macro_buffer src, dest;
+   struct cleanup *back_to;
+ 
+   init_shared_buffer (&src, (char *) source, strlen (source));
+ 
+   init_buffer (&dest, 0);
+   dest.last_token = 0;
+   back_to = make_cleanup (cleanup_macro_buffer, &dest);
+ 
+   scan (&dest, &src, 0, lookup_func, lookup_func_baton);
+ 
+   appendc (&dest, '\0');
+ 
+   discard_cleanups (back_to);
+   return dest.text;
+ }
+ 
+ 
+ char *
+ macro_expand_once (const char *source,
+                    macro_lookup_ftype *lookup_func,
+                    void *lookup_func_baton)
+ {
+   error ("Expand-once not implemented yet.");
+ }
+ 
+ 
+ char *
+ macro_expand_next (char **lexptr,
+                    macro_lookup_ftype *lookup_func,
+                    void *lookup_baton)
+ {
+   struct macro_buffer src, dest, tok;
+   struct cleanup *back_to;
+ 
+   /* Set up SRC to refer to the input text, pointed to by *lexptr.  */
+   init_shared_buffer (&src, *lexptr, strlen (*lexptr));
+ 
+   /* Set up DEST to receive the expansion, if there is one.  */
+   init_buffer (&dest, 0);
+   dest.last_token = 0;
+   back_to = make_cleanup (cleanup_macro_buffer, &dest);
+ 
+   /* Get the text's first preprocessing token.  */
+   if (! get_token (&tok, &src))
+     {
+       do_cleanups (back_to);
+       return 0;
+     }
+ 
+   /* If it's a macro invocation, expand it.  */
+   if (maybe_expand (&dest, &tok, &src, 0, lookup_func, lookup_baton))
+     {
+       /* It was a macro invocation!  Package up the expansion as a
+          null-terminated string and return it.  Set *lexptr to the
+          start of the next token in the input.  */
+       appendc (&dest, '\0');
+       discard_cleanups (back_to);
+       *lexptr = src.text;
+       return dest.text;
+     }
+   else
+     {
+       /* It wasn't a macro invocation.  */
+       do_cleanups (back_to);
+       return 0;
+     }
+ }
Index: gdb/macroexp.h
===================================================================
RCS file: gdb/macroexp.h
diff -N gdb/macroexp.h
*** gdb/macroexp.h	1 Jan 1970 00:00:00 -0000
--- gdb/macroexp.h	9 May 2002 15:06:24 -0000
***************
*** 0 ****
--- 1,90 ----
+ /* Interface to C preprocessor macro expansion for GDB.
+    Copyright 2002 Free Software Foundation, Inc.
+    Contributed by Red Hat, Inc.
+ 
+    This file is part of GDB.
+ 
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+ 
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+ 
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place - Suite 330,
+    Boston, MA 02111-1307, USA.  */
+ 
+ 
+ #ifndef MACROEXP_H
+ #define MACROEXP_H
+ 
+ /* A function for looking up preprocessor macro definitions.  Return
+    the preprocessor definition of NAME in scope according to BATON, or
+    zero if NAME is not defined as a preprocessor macro.
+ 
+    The caller must not free or modify the definition returned.  It is
+    probably unwise for the caller to hold pointers to it for very
+    long; it probably lives in some objfile's obstacks.  */
+ typedef struct macro_definition *(macro_lookup_ftype) (const char *name,
+                                                        void *baton);
+ 
+ 
+ /* Expand any preprocessor macros in SOURCE, and return the expanded
+    text.  Use LOOKUP_FUNC and LOOKUP_FUNC_BATON to find identifiers'
+    preprocessor definitions.  SOURCE is a null-terminated string.  The
+    result is a null-terminated string, allocated using xmalloc; it is
+    the caller's responsibility to free it.  */
+ char *macro_expand (const char *source,
+                     macro_lookup_ftype *lookup_func,
+                     void *lookup_func_baton);
+ 
+ 
+ /* Expand all preprocessor macro references that appear explicitly in
+    SOURCE, but do not expand any new macro references introduced by
+    that first level of expansion.  Use LOOKUP_FUNC and
+    LOOKUP_FUNC_BATON to find identifiers' preprocessor definitions.
+    SOURCE is a null-terminated string.  The result is a
+    null-terminated string, allocated using xmalloc; it is the caller's
+    responsibility to free it.  */
+ char *macro_expand_once (const char *source,
+                          macro_lookup_ftype *lookup_func,
+                          void *lookup_func_baton);
+ 
+ 
+ /* If the null-terminated string pointed to by *LEXPTR begins with a
+    macro invocation, return the result of expanding that invocation as
+    a null-terminated string, and set *LEXPTR to the next character
+    after the invocation.  The result is completely expanded; it
+    contains no further macro invocations.
+ 
+    Otherwise, if *LEXPTR does not start with a macro invocation,
+    return zero, and leave *LEXPTR unchanged.
+ 
+    Use LOOKUP_FUNC and LOOKUP_BATON to find macro definitions.
+ 
+    If this function returns a string, the caller is responsible for
+    freeing it, using xfree.
+ 
+    We need this expand-one-token-at-a-time interface in order to
+    accomodate GDB's C expression parser, which may not consume the
+    entire string.  When the user enters a command like
+ 
+       (gdb) break *func+20 if x == 5
+ 
+    the parser is expected to consume `func+20', and then stop when it
+    sees the "if".  But of course, "if" appearing in a character string
+    or as part of a larger identifier doesn't count.  So you pretty
+    much have to do tokenization to find the end of the string that
+    needs to be macro-expanded.  Our C/C++ tokenizer isn't really
+    designed to be called by anything but the yacc parser engine.  */
+ char *macro_expand_next (char **lexptr,
+                          macro_lookup_ftype *lookup_func,
+                          void *lookup_baton);
+ 
+ 
+ #endif /* MACROEXP_H */
Index: gdb/macrotab.c
===================================================================
RCS file: gdb/macrotab.c
diff -N gdb/macrotab.c
*** gdb/macrotab.c	1 Jan 1970 00:00:00 -0000
--- gdb/macrotab.c	9 May 2002 15:06:24 -0000
***************
*** 0 ****
--- 1,862 ----
+ /* C preprocessor macro tables for GDB.
+    Copyright 2002 Free Software Foundation, Inc.
+    Contributed by Red Hat, Inc.
+ 
+    This file is part of GDB.
+ 
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+ 
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+ 
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place - Suite 330,
+    Boston, MA 02111-1307, USA.  */
+ 
+ #include "defs.h"
+ #include "obstack.h"
+ #include "splay-tree.h"
+ #include "symtab.h"
+ #include "symfile.h"
+ #include "objfiles.h"
+ #include "macrotab.h"
+ #include "gdb_assert.h"
+ #include "bcache.h"
+ #include "complaints.h"
+ 
+ 
+ /* The macro table structure.  */
+ 
+ struct macro_table
+ {
+   /* The obstack this table's data should be allocated in, or zero if
+      we should use xmalloc.  */
+   struct obstack *obstack;
+ 
+   /* The bcache we should use to hold macro names, argument names, and
+      definitions, or zero if we should use xmalloc.  */
+   struct bcache *bcache;
+ 
+   /* The main source file for this compilation unit --- the one whose
+      name was given to the compiler.  This is the root of the
+      #inclusion tree; everything else is #included from here.  */
+   struct macro_source_file *main_source;
+ 
+   /* The table of macro definitions.  This is a splay tree (an ordered
+      binary tree that stays balanced, effectively), sorted by macro
+      name.  Where a macro gets defined more than once (presumably with
+      an #undefinition in between), we sort the definitions by the
+      order they would appear in the preprocessor's output.  That is,
+      if `a.c' #includes `m.h' and then #includes `n.h', and both
+      header files #define X (with an #undef somewhere in between),
+      then the definition from `m.h' appears in our splay tree before
+      the one from `n.h'.
+ 
+      The splay tree's keys are `struct macro_key' pointers;
+      the values are `struct macro_definition' pointers.
+ 
+      The splay tree, its nodes, and the keys and values are allocated
+      in obstack, if it's non-zero, or with xmalloc otherwise.  The
+      macro names, argument names, argument name arrays, and definition
+      strings are all allocated in bcache, if non-zero, or with xmalloc
+      otherwise.  */
+   splay_tree definitions;
+ };
+ 
+ 
+ 
+ /* Allocation and freeing functions.  */
+ 
+ /* Allocate SIZE bytes of memory appropriately for the macro table T.
+    This just checks whether T has an obstack, or whether its pieces
+    should be allocated with xmalloc.  */
+ static void *
+ macro_alloc (int size, struct macro_table *t)
+ {
+   if (t->obstack)
+     return obstack_alloc (t->obstack, size);
+   else
+     return xmalloc (size);
+ }
+ 
+ 
+ static void
+ macro_free (void *object, struct macro_table *t)
+ {
+   gdb_assert (! t->obstack);
+   xfree (object);
+ }
+ 
+ 
+ /* If the macro table T has a bcache, then cache the LEN bytes at ADDR
+    there, and return the cached copy.  Otherwise, just xmalloc a copy
+    of the bytes, and return a pointer to that.  */
+ static const void *
+ macro_bcache (struct macro_table *t, const void *addr, int len)
+ {
+   if (t->bcache)
+     return bcache (addr, len, t->bcache);
+   else
+     {
+       void *copy = xmalloc (len);
+       memcpy (copy, addr, len);
+       return copy;
+     }
+ }
+ 
+ 
+ /* If the macro table T has a bcache, cache the null-terminated string
+    S there, and return a pointer to the cached copy.  Otherwise,
+    xmalloc a copy and return that.  */
+ static const char *
+ macro_bcache_str (struct macro_table *t, const char *s)
+ {
+   return (char *) macro_bcache (t, s, strlen (s) + 1);
+ }
+ 
+ 
+ /* Free a possibly bcached object OBJ.  That is, if the macro table T
+    has a bcache, it's an error; otherwise, xfree OBJ.  */
+ void
+ macro_bcache_free (struct macro_table *t, void *obj)
+ {
+   gdb_assert (! t->bcache);
+   xfree (obj);
+ }
+ 
+ 
+ 
+ /* Macro tree keys, w/their comparison, allocation, and freeing functions.  */
+ 
+ /* A key in the splay tree.  */
+ struct macro_key
+ {
+   /* The table we're in.  We only need this in order to free it, since
+      the splay tree library's key and value freeing functions require
+      that the key or value contain all the information needed to free
+      themselves.  */
+   struct macro_table *table;
+ 
+   /* The name of the macro.  This is in the table's bcache, if it has
+      one. */
+   const char *name;
+ 
+   /* The source file and line number where the definition's scope
+      begins.  This is also the line of the definition itself.  */
+   struct macro_source_file *start_file;
+   int start_line;
+ 
+   /* The first source file and line after the definition's scope.
+      (That is, the scope does not include this endpoint.)  If end_file
+      is zero, then the definition extends to the end of the
+      compilation unit.  */
+   struct macro_source_file *end_file;
+   int end_line;
+ };
+ 
+ 
+ /* Return the #inclusion depth of the source file FILE.  This is the
+    number of #inclusions it took to reach this file.  For the main
+    source file, the #inclusion depth is zero; for a file it #includes
+    directly, the depth would be one; and so on.  */
+ static int
+ inclusion_depth (struct macro_source_file *file)
+ {
+   int depth;
+ 
+   for (depth = 0; file->included_by; depth++)
+     file = file->included_by;
+ 
+   return depth;
+ }
+ 
+ 
+ /* Compare two source locations (from the same compilation unit).
+    This is part of the comparison function for the tree of
+    definitions.
+ 
+    LINE1 and LINE2 are line numbers in the source files FILE1 and
+    FILE2.  Return a value:
+    - less than zero if {LINE,FILE}1 comes before {LINE,FILE}2,
+    - greater than zero if {LINE,FILE}1 comes after {LINE,FILE}2, or
+    - zero if they are equal.
+ 
+    When the two locations are in different source files --- perhaps
+    one is in a header, while another is in the main source file --- we
+    order them by where they would appear in the fully pre-processed
+    sources, where all the #included files have been substituted into
+    their places.  */
+ static int
+ compare_locations (struct macro_source_file *file1, int line1, 
+                    struct macro_source_file *file2, int line2)
+ {
+   /* We want to treat positions in an #included file as coming *after*
+      the line containing the #include, but *before* the line after the
+      include.  As we walk up the #inclusion tree toward the main
+      source file, we update fileX and lineX as we go; includedX
+      indicates whether the original position was from the #included
+      file.  */
+   int included1 = 0;
+   int included2 = 0;
+ 
+   /* If a file is zero, that means "end of compilation unit."  Handle
+      that specially.  */
+   if (! file1)
+     {
+       if (! file2)
+         return 0;
+       else
+         return 1;
+     }
+   else if (! file2)
+     return -1;
+ 
+   /* If the two files are not the same, find their common ancestor in
+      the #inclusion tree.  */
+   if (file1 != file2)
+     {
+       /* If one file is deeper than the other, walk up the #inclusion
+          chain until the two files are at least at the same *depth*.
+          Then, walk up both files in synchrony until they're the same
+          file.  That file is the common ancestor.  */
+       int depth1 = inclusion_depth (file1);
+       int depth2 = inclusion_depth (file2);
+ 
+       /* Only one of these while loops will ever execute in any given
+          case.  */
+       while (depth1 > depth2)
+         {
+           line1 = file1->included_at_line;
+           file1 = file1->included_by;
+           included1 = 1;
+           depth1--;
+         }
+       while (depth2 > depth1)
+         {
+           line2 = file2->included_at_line;
+           file2 = file2->included_by;
+           included2 = 1;
+           depth2--;
+         }
+ 
+       /* Now both file1 and file2 are at the same depth.  Walk toward
+          the root of the tree until we find where the branches meet.  */
+       while (file1 != file2)
+         {
+           line1 = file1->included_at_line;
+           file1 = file1->included_by;
+           /* At this point, we know that the case the includedX flags
+              are trying to deal with won't come up, but we'll just
+              maintain them anyway.  */
+           included1 = 1;
+ 
+           line2 = file2->included_at_line;
+           file2 = file2->included_by;
+           included2 = 1;
+ 
+           /* Sanity check.  If file1 and file2 are really from the
+              same compilation unit, then they should both be part of
+              the same tree, and this shouldn't happen.  */
+           gdb_assert (file1 && file2);
+         }
+     }
+ 
+   /* Now we've got two line numbers in the same file.  */
+   if (line1 == line2)
+     {
+       /* They can't both be from #included files.  Then we shouldn't
+          have walked up this far.  */
+       gdb_assert (! included1 || ! included2);
+ 
+       /* Any #included position comes after a non-#included position
+          with the same line number in the #including file.  */
+       if (included1)
+         return 1;
+       else if (included2)
+         return -1;
+       else
+         return 0;
+     }
+   else
+     return line1 - line2;
+ }
+ 
+ 
+ /* Compare a macro key KEY against NAME, the source file FILE, and
+    line number LINE.
+ 
+    Sort definitions by name; for two definitions with the same name,
+    place the one whose definition comes earlier before the one whose
+    definition comes later.
+ 
+    Return -1, 0, or 1 if key comes before, is identical to, or comes
+    after NAME, FILE, and LINE.  */
+ static int
+ key_compare (struct macro_key *key,
+              const char *name, struct macro_source_file *file, int line)
+ {
+   int names = strcmp (key->name, name);
+   if (names)
+     return names;
+ 
+   return compare_locations (key->start_file, key->start_line,
+                             file, line);
+ }
+ 
+ 
+ /* The macro tree comparison function, typed for the splay tree
+    library's happiness.  */
+ static int
+ macro_tree_compare (splay_tree_key untyped_key1,
+                     splay_tree_key untyped_key2)
+ {
+   struct macro_key *key1 = (struct macro_key *) untyped_key1;
+   struct macro_key *key2 = (struct macro_key *) untyped_key2;
+ 
+   return key_compare (key1, key2->name, key2->start_file, key2->start_line);
+ }
+ 
+ 
+ /* Construct a new macro key node for a macro in table T whose name is
+    NAME, and whose scope starts at LINE in FILE; register the name in
+    the bcache.  */
+ static struct macro_key *
+ new_macro_key (struct macro_table *t,
+                const char *name,
+                struct macro_source_file *file,
+                int line)
+ {
+   struct macro_key *k = macro_alloc (sizeof (*k), t);
+ 
+   memset (k, 0, sizeof (*k));
+   k->table = t;
+   k->name = macro_bcache_str (t, name);
+   k->start_file = file;
+   k->start_line = line;
+   k->end_file = 0;
+ 
+   return k;
+ }
+ 
+ 
+ static void
+ macro_tree_delete_key (void *untyped_key)
+ {
+   struct macro_key *key = (struct macro_key *) untyped_key;
+ 
+   macro_bcache_free (key->table, (char *) key->name);
+   macro_free (key, key->table);
+ }
+ 
+ 
+ 
+ /* Building and querying the tree of #included files.  */
+ 
+ 
+ /* Allocate and initialize a new source file structure.  */
+ static struct macro_source_file *
+ new_source_file (struct macro_table *t,
+                  const char *filename)
+ {
+   /* Get space for the source file structure itself.  */
+   struct macro_source_file *f = macro_alloc (sizeof (*f), t);
+ 
+   memset (f, 0, sizeof (*f));
+   f->table = t;
+   f->filename = macro_bcache_str (t, filename);
+   f->includes = 0;
+ 
+   return f;
+ }
+ 
+ 
+ /* Free a source file, and all the source files it #included.  */
+ static void
+ free_macro_source_file (struct macro_source_file *src)
+ {
+   struct macro_source_file *child, *next_child;
+ 
+   /* Free this file's children.  */
+   for (child = src->includes; child; child = next_child)
+     {
+       next_child = child->next_included;
+       free_macro_source_file (child);
+     }
+ 
+   macro_bcache_free (src->table, (char *) src->filename);
+   macro_free (src, src->table);
+ }
+ 
+ 
+ struct macro_source_file *
+ macro_set_main (struct macro_table *t,
+                 const char *filename)
+ {
+   /* You can't change a table's main source file.  What would that do
+      to the tree?  */
+   gdb_assert (! t->main_source);
+ 
+   t->main_source = new_source_file (t, filename);
+ 
+   return t->main_source;
+ }
+ 
+ 
+ struct macro_source_file *
+ macro_main (struct macro_table *t)
+ {
+   gdb_assert (t->main_source);
+ 
+   return t->main_source;
+ }
+ 
+ 
+ struct macro_source_file *
+ macro_include (struct macro_source_file *source,
+                int line,
+                const char *included)
+ {
+   struct macro_source_file *new;
+   struct macro_source_file **link;
+ 
+   /* Find the right position in SOURCE's `includes' list for the new
+      file.  Scan until we find the first file we shouldn't follow ---
+      which is therefore the file we should directly precede --- or
+      reach the end of the list.  */
+   for (link = &source->includes;
+        *link && line < (*link)->included_at_line;
+        link = &(*link)->next_included)
+     ;
+ 
+   /* Did we find another file already #included at the same line as
+      the new one?  */
+   if (*link && line == (*link)->included_at_line)
+     {
+       /* This means the compiler is emitting bogus debug info.  (GCC
+          circa March 2002 did this.)  It also means that the splay
+          tree ordering function, macro_tree_compare, will abort,
+          because it can't tell which #inclusion came first.  But GDB
+          should tolerate bad debug info.  So:
+ 
+          First, squawk.  */
+       static struct complaint bogus_inclusion_line = {
+         "both `%s' and `%s' allegedly #included at %s:%d", 0, 0
+       };
+ 
+       complain (&bogus_inclusion_line, 
+                 included, (*link)->filename, source->filename, line);
+ 
+       /* Now, choose a new, unoccupied line number for this
+          #inclusion, after the alleged #inclusion line.  */
+       while (*link && line == (*link)->included_at_line)
+         {
+           /* This line number is taken, so try the next line.  */
+           line++;
+           link = &(*link)->next_included;
+         }
+     }
+ 
+   /* At this point, we know that LINE is an unused line number, and
+      *LINK points to the entry an #inclusion at that line should
+      precede.  */
+   new = new_source_file (source->table, included);
+   new->included_by = source;
+   new->included_at_line = line;
+   new->next_included = *link;
+   *link = new;
+ 
+   return new;
+ }
+ 
+ 
+ struct macro_source_file *
+ macro_lookup_inclusion (struct macro_source_file *source, const char *name)
+ {
+   /* Is SOURCE itself named NAME?  */
+   if (! strcmp (name, source->filename))
+     return source;
+ 
+   /* The filename in the source structure is probably a full path, but
+      NAME could be just the final component of the name.  */
+   {
+     int name_len = strlen (name);
+     int src_name_len = strlen (source->filename);
+ 
+     /* We do mean < here, and not <=; if the lengths are the same,
+        then the strcmp above should have triggered, and we need to
+        check for a slash here.  */
+     if (name_len < src_name_len
+         && source->filename[src_name_len - name_len - 1] == '/'
+         && ! strcmp (name, source->filename + src_name_len - name_len))
+       return source;
+   }
+ 
+   /* It's not us.  Try all our children, and return the lowest.  */
+   {
+     struct macro_source_file *child;
+     struct macro_source_file *best = 0;
+     int best_depth;
+ 
+     for (child = source->includes; child; child = child->next_included)
+       {
+         struct macro_source_file *result
+           = macro_lookup_inclusion (child, name);
+ 
+         if (result)
+           {
+             int result_depth = inclusion_depth (result);
+ 
+             if (! best || result_depth < best_depth)
+               {
+                 best = result;
+                 best_depth = result_depth;
+               }
+           }
+       }
+ 
+     return best;
+   }
+ }
+ 
+ 
+ 
+ /* Registering and looking up macro definitions.  */
+ 
+ 
+ /* Construct a definition for a macro in table T.  Cache all strings,
+    and the macro_definition structure itself, in T's bcache.  */
+ static struct macro_definition *
+ new_macro_definition (struct macro_table *t,
+                       enum macro_kind kind,
+                       int argc, const char **argv,
+                       const char *replacement)
+ {
+   struct macro_definition *d = macro_alloc (sizeof (*d), t);
+ 
+   memset (d, 0, sizeof (*d));
+   d->table = t;
+   d->kind = kind;
+   d->replacement = macro_bcache_str (t, replacement);
+ 
+   if (kind == macro_function_like)
+     {
+       int i;
+       const char **cached_argv;
+       int cached_argv_size = argc * sizeof (*cached_argv);
+ 
+       /* Bcache all the arguments.  */
+       cached_argv = alloca (cached_argv_size);
+       for (i = 0; i < argc; i++)
+         cached_argv[i] = macro_bcache_str (t, argv[i]);
+ 
+       /* Now bcache the array of argument pointers itself.  */
+       d->argv = macro_bcache (t, cached_argv, cached_argv_size);
+       d->argc = argc;
+     }
+ 
+   /* We don't bcache the entire definition structure because it's got
+      a pointer to the macro table in it; since each compilation unit
+      has its own macro table, you'd only get bcache hits for identical
+      definitions within a compilation unit, which seems unlikely.
+ 
+      "So, why do macro definitions have pointers to their macro tables
+      at all?"  Well, when the splay tree library wants to free a
+      node's value, it calls the value freeing function with nothing
+      but the value itself.  It makes the (apparently reasonable)
+      assumption that the value carries enough information to free
+      itself.  But not all macro tables have bcaches, so not all macro
+      definitions would be bcached.  There's no way to tell whether a
+      given definition is bcached without knowing which table the
+      definition belongs to.  ...  blah.  The thing's only sixteen
+      bytes anyway, and we can still bcache the name, args, and
+      definition, so we just don't bother bcaching the definition
+      structure itself.  */
+   return d;
+ }
+ 
+ 
+ /* Free a macro definition.  */
+ static void
+ macro_tree_delete_value (void *untyped_definition)
+ {
+   struct macro_definition *d = (struct macro_definition *) untyped_definition;
+   struct macro_table *t = d->table;
+ 
+   if (d->kind == macro_function_like)
+     {
+       int i;
+ 
+       for (i = 0; i < d->argc; i++)
+         macro_bcache_free (t, (char *) d->argv[i]);
+       macro_bcache_free (t, (char **) d->argv);
+     }
+   
+   macro_bcache_free (t, (char *) d->replacement);
+   macro_free (d, t);
+ }
+ 
+ 
+ /* Find the splay tree node for the definition of NAME at LINE in
+    SOURCE, or zero if there is none.  */
+ static splay_tree_node
+ find_definition (const char *name,
+                  struct macro_source_file *file,
+                  int line)
+ {
+   struct macro_table *t = file->table;
+   splay_tree_node n;
+ 
+   /* Construct a macro_key object, just for the query.  */
+   struct macro_key query;
+ 
+   query.name = name;
+   query.start_file = file;
+   query.start_line = line;
+   query.end_file = 0;
+ 
+   n = splay_tree_lookup (t->definitions, (splay_tree_key) &query);
+   if (! n)
+     {
+       /* It's okay for us to do two queries like this: the real work
+          of the searching is done when we splay, and splaying the tree
+          a second time at the same key is a constant time operation.
+          If this still bugs you, you could always just extend the
+          splay tree library with a predecessor-or-equal operation, and
+          use that.  */
+       splay_tree_node pred = splay_tree_predecessor (t->definitions,
+                                                      (splay_tree_key) &query);
+      
+       if (pred)
+         {
+           /* Make sure this predecessor actually has the right name.
+              We just want to search within a given name's definitions.  */
+           struct macro_key *found = (struct macro_key *) pred->key;
+ 
+           if (! strcmp (found->name, name))
+             n = pred;
+         }
+     }
+ 
+   if (n)
+     {
+       struct macro_key *found = (struct macro_key *) n->key;
+ 
+       /* Okay, so this definition has the right name, and its scope
+          begins before the given source location.  But does its scope
+          end after the given source location?  */
+       if (compare_locations (file, line, found->end_file, found->end_line) < 0)
+         return n;
+       else
+         return 0;
+     }
+   else
+     return 0;
+ }
+ 
+ 
+ /* If NAME already has a definition in scope at LINE in FILE, and
+    return the key.  Otherwise, return zero.  */
+ static struct macro_key *
+ check_for_redefinition (struct macro_source_file *source, int line,
+                         const char *name)
+ {
+   splay_tree_node n = find_definition (name, source, line);
+ 
+   /* This isn't really right.  There's nothing wrong with redefining a
+      macro if the new replacement list is the same as the old one.  */
+   if (n)
+     {
+       struct macro_key *found_key = (struct macro_key *) n->key;
+       static struct complaint macro_redefined = {
+         "macro `%s' redefined at %s:%d;"
+         "original definition at %s:%d", 0, 0
+       };
+       complain (&macro_redefined, name,
+                 source->filename, line,
+                 found_key->start_file->filename,
+                 found_key->start_line);
+       return found_key;
+     }
+   else
+     return 0;
+ }
+ 
+ 
+ void
+ macro_define_object (struct macro_source_file *source, int line,
+                      const char *name, const char *replacement)
+ {
+   struct macro_table *t = source->table;
+   struct macro_key *k;
+   struct macro_definition *d;
+ 
+   k = check_for_redefinition (source, line, name);
+ 
+   /* If we're redefining a symbol, and the existing key would be
+      identical to our new key, then the splay_tree_insert function
+      will try to delete the old definition.  When the definition is
+      living on an obstack, this isn't a happy thing.
+ 
+      Since this only happens in the presence of questionable debug
+      info, we just ignore all definitions after the first.  The only
+      case I know of where this arises is in GCC's output for
+      predefined macros, and all the definitions are the same in that
+      case.  */
+   if (k && ! key_compare (k, name, source, line))
+     return;
+ 
+   k = new_macro_key (t, name, source, line);
+   d = new_macro_definition (t, macro_object_like, 0, 0, replacement);
+   splay_tree_insert (t->definitions, (splay_tree_key) k, (splay_tree_value) d);
+ }
+ 
+ 
+ void
+ macro_define_function (struct macro_source_file *source, int line,
+                        const char *name, int argc, const char **argv,
+                        const char *replacement)
+ {
+   struct macro_table *t = source->table;
+   struct macro_key *k;
+   struct macro_definition *d;
+ 
+   k = check_for_redefinition (source, line, name);
+ 
+   /* See comments about duplicate keys in macro_define_object.  */
+   if (k && ! key_compare (k, name, source, line))
+     return;
+ 
+   /* We should also check here that all the argument names in ARGV are
+      distinct.  */
+ 
+   k = new_macro_key (t, name, source, line);
+   d = new_macro_definition (t, macro_function_like, argc, argv, replacement);
+   splay_tree_insert (t->definitions, (splay_tree_key) k, (splay_tree_value) d);
+ }
+ 
+ 
+ void
+ macro_undef (struct macro_source_file *source, int line,
+              const char *name)
+ {
+   splay_tree_node n = find_definition (name, source, line);
+ 
+   if (n)
+     {
+       /* This function is the only place a macro's end-of-scope
+          location gets set to anything other than "end of the
+          compilation unit" (i.e., end_file is zero).  So if this macro
+          already has its end-of-scope set, then we're probably seeing
+          a second #undefinition for the same #definition.  */
+       struct macro_key *key = (struct macro_key *) n->key;
+ 
+       if (key->end_file)
+         {
+           static struct complaint double_undef = {
+             "macro '%s' is #undefined twice, at %s:%d and %s:%d",
+             0, 0
+           };
+           complain (&double_undef, name, source->filename, line,
+                     key->end_file->filename, key->end_line);
+         }
+ 
+       /* Whatever the case, wipe out the old ending point, and 
+          make this the ending point.  */
+       key->end_file = source;
+       key->end_line = line;
+     }
+   else
+     {
+       /* According to the ISO C standard, an #undef for a symbol that
+          has no macro definition in scope is ignored.  So we should
+          ignore it too.  */
+ #if 0
+       static struct complaint no_macro_to_undefine = {
+         "no definition for macro `%s' in scope to #undef at %s:%d",
+         0, 0
+       };
+       complain (&no_macro_to_undefine, name, source->filename, line);
+ #endif
+     }
+ }
+ 
+ 
+ struct macro_definition *
+ macro_lookup_definition (struct macro_source_file *source,
+                          int line, const char *name)
+ {
+   splay_tree_node n = find_definition (name, source, line);
+ 
+   if (n)
+     return (struct macro_definition *) n->value;
+   else
+     return 0;
+ }
+ 
+ 
+ struct macro_source_file *
+ macro_definition_location (struct macro_source_file *source,
+                            int line,
+                            const char *name,
+                            int *definition_line)
+ {
+   splay_tree_node n = find_definition (name, source, line);
+ 
+   if (n)
+     {
+       struct macro_key *key = (struct macro_key *) n->key;
+       *definition_line = key->start_line;
+       return key->start_file;
+     }
+   else
+     return 0;
+ }
+ 
+ 
+ 
+ /* Creating and freeing macro tables.  */
+ 
+ 
+ struct macro_table *
+ new_macro_table (struct obstack *obstack,
+                  struct bcache *b)
+ {
+   struct macro_table *t;
+ 
+   /* First, get storage for the `struct macro_table' itself.  */
+   if (obstack)
+     t = obstack_alloc (obstack, sizeof (*t));
+   else
+     t = xmalloc (sizeof (*t));
+ 
+   memset (t, 0, sizeof (*t));
+   t->obstack = obstack;
+   t->bcache = b;
+   t->main_source = 0;
+   t->definitions = (splay_tree_new_with_allocator
+                     (macro_tree_compare,
+                      ((splay_tree_delete_key_fn) macro_tree_delete_key),
+                      ((splay_tree_delete_value_fn) macro_tree_delete_value),
+                      ((splay_tree_allocate_fn) macro_alloc),
+                      ((splay_tree_deallocate_fn) macro_free),
+                      t));
+   
+   return t;
+ }
+ 
+ 
+ void
+ free_macro_table (struct macro_table *table)
+ {
+   /* Free the source file tree.  */
+   free_macro_source_file (table->main_source);
+ 
+   /* Free the table of macro definitions.  */
+   splay_tree_delete (table->definitions);
+ }
Index: gdb/macrotab.h
===================================================================
RCS file: gdb/macrotab.h
diff -N gdb/macrotab.h
*** gdb/macrotab.h	1 Jan 1970 00:00:00 -0000
--- gdb/macrotab.h	9 May 2002 15:06:25 -0000
***************
*** 0 ****
--- 1,295 ----
+ /* Interface to C preprocessor macro tables for GDB.
+    Copyright 2002 Free Software Foundation, Inc.
+    Contributed by Red Hat, Inc.
+ 
+    This file is part of GDB.
+ 
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+ 
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+ 
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place - Suite 330,
+    Boston, MA 02111-1307, USA.  */
+ 
+ #ifndef MACROTAB_H
+ #define MACROTAB_H
+ 
+ #include "obstack.h"
+ #include "bcache.h"
+ 
+ /* How do we represent a source location?  I mean, how should we
+    represent them within GDB; the user wants to use all sorts of
+    ambiguous abbreviations, like "break 32" and "break foo.c:32"
+    ("foo.c" may have been #included into several compilation units),
+    but what do we disambiguate those things to?
+ 
+    - Answer 1: "Filename and line number."  (Or column number, if
+    you're picky.)  That's not quite good enough.  For example, the
+    same source file can be #included into several different
+    compilation units --- which #inclusion do you mean?
+ 
+    - Answer 2: "Compilation unit, filename, and line number."  This is
+    a pretty good answer; GDB's `struct symtab_and_line' basically
+    embodies this representation.  But it's still ambiguous; what if a
+    given compilation unit #includes the same file twice --- how can I
+    set a breakpoint on line 12 of the fifth #inclusion of "foo.c"?
+ 
+    - Answer 3: "Compilation unit, chain of #inclusions, and line
+    number."  This is analogous to the way GCC reports errors in
+    #include files:
+ 
+         $ gcc -c base.c
+         In file included from header2.h:8,
+                          from header1.h:3,
+                          from base.c:5:
+         header3.h:1: parse error before ')' token
+         $
+ 
+    GCC tells you exactly what path of #inclusions led you to the
+    problem.  It gives you complete information, in a way that the
+    following would not:
+ 
+         $ gcc -c base.c
+         header3.h:1: parse error before ')' token
+         $
+ 
+    Converting all of GDB to use this is a big task, and I'm not really
+    suggesting it should be a priority.  But this module's whole
+    purpose is to maintain structures describing the macro expansion
+    process, so I think it's appropriate for us to take a little care
+    to do that in a complete fashion.
+ 
+    In this interface, the first line of a file is numbered 1, not 0.
+    This is the same convention the rest of GDB uses.  */
+ 
+ 
+ /* A table of all the macro definitions for a given compilation unit.  */
+ struct macro_table;
+ 
+ 
+ /* A source file that participated in a compilation unit --- either a
+    main file, or an #included file.  If a file is #included more than
+    once, the presence of the `included_from' and `included_at_line'
+    members means that we need to make one instance of this structure
+    for each #inclusion.  Taken as a group, these structures form a
+    tree mapping the #inclusions that contributed to the compilation
+    unit, with the main source file as its root.
+ 
+    It's worth noting that libcpp has a simpler way of representing all
+    this, which we should consider switching to.  It might even be
+    suitable for ordinary non-macro line number info.
+ 
+    Suppose you take your main source file, and after each line
+    containing an #include directive you insert the text of the
+    #included file.  The result is a big file that pretty much
+    corresponds to the full text the compiler's going to see.  There's
+    a one-to-one correspondence between lines in the big file and
+    per-inclusion lines in the source files.  (Obviously, #include
+    directives that are #if'd out don't count.  And you'll need to
+    append a newline to any file that doesn't end in one, to avoid
+    splicing the last #included line with the next line of the
+    #including file.)
+ 
+    Libcpp calls line numbers in this big imaginary file "logical line
+    numbers", and has a data structure called a "line map" that can map
+    logical line numbers onto actual source filenames and line numbers,
+    and also tell you the chain of #inclusions responsible for any
+    particular logical line number.  Basically, this means you can pass
+    around a single line number and some kind of "compilation unit"
+    object and you get nice, unambiguous source code locations that
+    distinguish between multiple #inclusions of the same file, etc.
+ 
+    Pretty neat, huh?  */
+ 
+ struct macro_source_file
+ {
+ 
+   /* The macro table for the compilation unit this source location is
+      a part of.  */
+   struct macro_table *table;
+ 
+   /* A source file --- possibly a header file.  */
+   const char *filename;
+ 
+   /* The location we were #included from, or zero if we are the
+      compilation unit's main source file.  */
+   struct macro_source_file *included_by;
+ 
+   /* If `included_from' is non-zero, the line number in that source
+      file at which we were included.  */
+   int included_at_line;
+ 
+   /* Head of a linked list of the source files #included by this file;
+      our children in the #inclusion tree.  This list is sorted by its
+      elements' `included_at_line' values, which are unique.  (The
+      macro splay tree's ordering function needs this property.)  */
+   struct macro_source_file *includes;
+ 
+   /* The next file #included by our `included_from' file; our sibling
+      in the #inclusion tree.  */
+   struct macro_source_file *next_included;
+ };
+ 
+ 
+ /* Create a new, empty macro table.  Allocate it in OBSTACK, or use
+    xmalloc if OBSTACK is zero.  Use BCACHE to store all macro names,
+    arguments, definitions, and anything else that might be the same
+    amongst compilation units in an executable file; if BCACHE is zero,
+    don't cache these things.
+ 
+    Note that, if either OBSTACK or BCACHE are non-zero, then you
+    should only ever add information the macro table --- you should
+    never remove things from it.  You'll get an error if you try.  At
+    the moment, since we only provide obstacks and bcaches for macro
+    tables for symtabs, this restriction makes a nice sanity check.
+    Obstacks and bcaches are pretty much grow-only structures anyway.
+    However, if we find that it's occasionally useful to delete things
+    even from the symtab's tables, and the storage leak isn't a
+    problem, this restriction could be lifted.  */
+ struct macro_table *new_macro_table (struct obstack *obstack,
+                                      struct bcache *bcache);
+ 
+ 
+ /* Free TABLE, and any macro definitions, source file structures,
+    etc. it owns.  This will raise an internal error if TABLE was
+    allocated on an obstack, or if it uses a bcache.  */
+ void free_macro_table (struct macro_table *table);
+ 
+ 
+ /* Set FILENAME as the main source file of TABLE.  Return a source
+    file structure describing that file; if we record the #definition
+    of macros, or the #inclusion of other files into FILENAME, we'll
+    use that source file structure to indicate the context.
+ 
+    The "main source file" is the one that was given to the compiler;
+    all other source files that contributed to the compilation unit are
+    #included, directly or indirectly, from this one.
+ 
+    The macro table makes its own copy of FILENAME; the caller is
+    responsible for freeing FILENAME when it is no longer needed.  */
+ struct macro_source_file *macro_set_main (struct macro_table *table,
+                                           const char *filename);
+ 
+ 
+ /* Return the main source file of the macro table TABLE.  */
+ struct macro_source_file *macro_main (struct macro_table *table);
+ 
+ 
+ /* Record a #inclusion.
+    Record in SOURCE's macro table that, at line number LINE in SOURCE,
+    we #included the file INCLUDED.  Return a source file structure we
+    can use for symbols #defined or files #included into that.  If we've
+    already created a source file structure for this #inclusion, return
+    the same structure we created last time.
+ 
+    The first line of the source file has a line number of 1, not 0.
+ 
+    The macro table makes its own copy of INCLUDED; the caller is
+    responsible for freeing INCLUDED when it is no longer needed.  */
+ struct macro_source_file *macro_include (struct macro_source_file *source,
+                                          int line,
+                                          const char *included);
+ 
+ 
+ /* Find any source file structure for a file named NAME, either
+    included into SOURCE, or SOURCE itself.  Return zero if we have
+    none.  NAME is only the final portion of the filename, not the full
+    path.  e.g., `stdio.h', not `/usr/include/stdio.h'.  If NAME
+    appears more than once in the inclusion tree, return the
+    least-nested inclusion --- the one closest to the main source file.  */
+ struct macro_source_file *(macro_lookup_inclusion
+                            (struct macro_source_file *source,
+                             const char *name));
+ 
+ 
+ /* Record an object-like #definition (i.e., one with no parameter list).
+    Record in SOURCE's macro table that, at line number LINE in SOURCE,
+    we #defined a preprocessor symbol named NAME, whose replacement
+    string is REPLACEMENT.  This function makes copies of NAME and
+    REPLACEMENT; the caller is responsible for freeing them.  */
+ void macro_define_object (struct macro_source_file *source, int line,
+                           const char *name, const char *replacement);
+ 
+ 
+ /* Record an function-like #definition (i.e., one with a parameter list).
+ 
+    Record in SOURCE's macro table that, at line number LINE in SOURCE,
+    we #defined a preprocessor symbol named NAME, with ARGC arguments
+    whose names are given in ARGV, whose replacement string is REPLACEMENT.  If
+    the macro takes a variable number of arguments, then ARGC should be
+    one greater than the number of named arguments, and ARGV[ARGC-1]
+    should be the string "...".  This function makes its own copies of
+    NAME, ARGV, and REPLACEMENT; the caller is responsible for freeing
+    them.  */
+ void macro_define_function (struct macro_source_file *source, int line,
+                             const char *name, int argc, const char **argv,
+                             const char *replacement);
+ 
+ 
+ /* Record an #undefinition.
+    Record in SOURCE's macro table that, at line number LINE in SOURCE,
+    we removed the definition for the preprocessor symbol named NAME.  */
+ void macro_undef (struct macro_source_file *source, int line,
+                   const char *name);
+ 
+ 
+ /* Different kinds of macro definitions.  */
+ enum macro_kind
+ {
+   macro_object_like,
+   macro_function_like
+ };
+ 
+ 
+ /* A preprocessor symbol definition.  */
+ struct macro_definition
+ {
+   /* The table this definition lives in.  */
+   struct macro_table *table;
+ 
+   /* What kind of macro it is.  */
+   enum macro_kind kind;
+ 
+   /* If `kind' is `macro_function_like', the number of arguments it
+      takes, and their names.  The names, and the array of pointers to
+      them, are in the table's bcache, if it has one.  */
+   int argc;
+   const char * const *argv;
+ 
+   /* The replacement string (body) of the macro.  This is in the
+      table's bcache, if it has one.  */
+   const char *replacement;
+ };
+ 
+ 
+ /* Return a pointer to the macro definition for NAME in scope at line
+    number LINE of SOURCE.  If LINE is -1, return the definition in
+    effect at the end of the file.  The macro table owns the structure;
+    the caller need not free it.  Return zero if NAME is not #defined
+    at that point.  */
+ struct macro_definition *(macro_lookup_definition
+                           (struct macro_source_file *source,
+                            int line, const char *name));
+ 
+ 
+ /* Return the source location of the definition for NAME in scope at
+    line number LINE of SOURCE.  Set *DEFINITION_LINE to the line
+    number of the definition, and return a source file structure for
+    the file.  Return zero if NAME has no definition in scope at that
+    point, and leave *DEFINITION_LINE unchanged.  */
+ struct macro_source_file *(macro_definition_location
+                            (struct macro_source_file *source,
+                             int line,
+                             const char *name,
+                             int *definition_line));
+ 
+ 
+ #endif /* MACROTAB_H */


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