cpplib: Parse traditional function-like macro definitions

Neil Booth neil@daikokuya.demon.co.uk
Thu Jun 6 15:55:00 GMT 2002


Neil Booth wrote:-

> Bootstrapping x86 Linux.  I've checked the code works, in the sense
> that it creates correct macro definitions, though nothing uses it yet.
> 
> Neil.

Bah, the thing with having dozens of patches lying around is it's too
easy to send the wrong one 8-)

Here's the correct patch.

Neil.

	* cpptrad.c (struct block, BLOCK_HEADER_LEN, BLOCK_LEN,
	scan_parameters, save_replacement_text, replacement_length): New.
	(scan_out_logical_line): Take a macro and save parameters if
	non-NULL.
	(_cpp_logical_line_trad): Update.
	(_cpp_create_trad_definition): Update to handle function-like
	macros.
	* cpplex.c (new_buff): Update.
	(struct dummy, DEFAULT_ALIGNMENT, CPP_ALIGN): Move...
	* cpphash.h: ...here.
	(CPP_ALIGN2, _cpp_save_parameter): New.
	* cppmacro.c (save_parameter): Rename, export.
	(parse_params): Update.

Index: cpptrad.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cpptrad.c,v
retrieving revision 1.4
diff -u -p -r1.4 cpptrad.c
--- cpptrad.c	5 Jun 2002 20:27:11 -0000	1.4
+++ cpptrad.c	6 Jun 2002 22:55:32 -0000
@@ -21,6 +21,29 @@ Foundation, 59 Temple Place - Suite 330,
 #include "cpplib.h"
 #include "cpphash.h"
 
+/* The replacement text of a function-like macro is stored as a
+   contiguous sequence of aligned blocks.  Each block represents the
+   portion of text from the start of the previous block (or the start
+   of the macro replacement text in the case of the first block) to
+   the next parameter, or the end of the replacement list if there
+   are none left.
+
+   Each block consists of an unsigned int, which is the length of text
+   contained in the third part, an unsigned short, which is the
+   one-based index of the argument that immediately follows that text,
+   and the text itself.  The final block in the macro expansion is
+   recognizable as it has an argument index of zero.  */
+
+struct block
+{
+  unsigned int text_len;
+  unsigned short arg_index;
+  uchar text[1];
+};
+
+#define BLOCK_HEADER_LEN offsetof (struct block, text)
+#define BLOCK_LEN(TEXT_LEN) CPP_ALIGN (BLOCK_HEADER_LEN + TEXT_LEN)
+
 /* Lexing TODO: Handle -C, maybe -CC, and space in escaped newlines.
    Stop cpplex.c from recognizing comments and directives during its
    lexing pass.  Get rid of line_base usage - seems pointless?  Do we
@@ -32,10 +55,14 @@ static const uchar *skip_escaped_newline
 static const uchar *skip_whitespace PARAMS ((cpp_reader *, const uchar *));
 static cpp_hashnode *lex_identifier PARAMS ((cpp_reader *, const uchar *));
 static const uchar *skip_comment PARAMS ((cpp_reader *, const uchar *));
-static void scan_out_logical_line PARAMS ((cpp_reader *pfile));
+static void scan_out_logical_line PARAMS ((cpp_reader *pfile, cpp_macro *));
 static void check_output_buffer PARAMS ((cpp_reader *, size_t));
 static void restore_buff PARAMS ((cpp_reader *));
 static void push_replacement_text PARAMS ((cpp_reader *, cpp_hashnode *));
+static bool scan_parameters PARAMS ((cpp_reader *, cpp_macro *));
+static void save_replacement_text PARAMS ((cpp_reader *, cpp_macro *,
+					   unsigned int));
+static unsigned int replacement_length PARAMS ((cpp_macro *));
 
 /* Ensures we have N bytes' space in the output buffer, and
    reallocates it if not.  */
@@ -272,7 +299,7 @@ _cpp_read_logical_line_trad (pfile)
   CUR (pfile->context) = buffer->cur;
   RLIMIT (pfile->context) = buffer->rlimit;
   pfile->trad_out_cur = pfile->trad_out_base;
-  scan_out_logical_line (pfile);
+  scan_out_logical_line (pfile, NULL);
   buffer->cur = CUR (pfile->context);
 
   pfile->trad_line = pfile->line;
@@ -284,10 +311,15 @@ _cpp_read_logical_line_trad (pfile)
 
 /* Copies the next logical line in the current buffer to the output
    buffer.  The output is guaranteed to terminate with a NUL
-   character.  */
+   character.
+
+   If MACRO is non-NULL, then we are scanning the replacement list of
+   MACRO, and we call save_replacement_text every time we meet an
+   argument.  */
 static void
-scan_out_logical_line (pfile)
+scan_out_logical_line (pfile, macro)
      cpp_reader *pfile;
+     cpp_macro *macro;
 {
   cpp_context *context;
   const uchar *cur;
@@ -379,21 +411,30 @@ scan_out_logical_line (pfile)
 	case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R':
 	case 'S': case 'T': case 'U': case 'V': case 'W': case 'X':
 	case 'Y': case 'Z':
-	  {
-	    cpp_hashnode *node;
+	  if (quote == 0 || macro)
+	    {
+	      cpp_hashnode *node;
+
+	      pfile->trad_out_cur = --out;
+	      node = lex_identifier (pfile, cur - 1);
 
-	    pfile->trad_out_cur = --out;
-	    node = lex_identifier (pfile, cur - 1);
-	    if (node->type == NT_MACRO)
-	      {
-		/* Remove the macro name from the output.  */
-		pfile->trad_out_cur = out;
-		push_replacement_text (pfile, node);
-		goto new_context;
-	      }
-	    out = pfile->trad_out_cur;
-	    cur = CUR (context);
-	  }
+	      if (node->type == NT_MACRO && !pfile->state.prevent_expansion)
+		{
+		  /* Remove the macro name from the output.  */
+		  pfile->trad_out_cur = out;
+		  push_replacement_text (pfile, node);
+		  goto new_context;
+		}
+	      else if (macro && node->arg_index)
+		{
+		  /* Remove the macro name from the output.  */
+		  pfile->trad_out_cur = out;
+		  save_replacement_text (pfile, macro, node->arg_index);
+		}
+
+	      out = pfile->trad_out_cur;
+	      cur = CUR (context);
+	    }
 	  break;
 
 	default:
@@ -417,36 +458,168 @@ push_replacement_text (pfile, node)
 			  macro->exp.text + macro->count);
 }
 
-/* Analyze and save the replacement text of a macro.  */
+/* Read and record the parameters, if any, of a function-like macro
+   definition.  Destroys pfile->trad_out_cur.
+
+   Returns true on success, false on failure (syntax error or a
+   duplicate parameter).  On success, CUR (pfile->context) is just
+   past the closing parenthesis.  */
+static bool
+scan_parameters (pfile, macro)
+     cpp_reader *pfile;
+     cpp_macro *macro;
+{
+  const uchar *cur = CUR (pfile->context) + 1;
+  bool ok;
+
+  for (;;)
+    {
+      cur = skip_whitespace (pfile, cur);
+
+      if (ISIDST (*cur))
+	{
+	  ok = false;
+	  if (_cpp_save_parameter (pfile, macro, lex_identifier (pfile, cur)))
+	    break;
+	  cur = skip_whitespace (pfile, CUR (pfile->context));
+	  if (*cur == ',')
+	    {
+	      cur++;
+	      continue;
+	    }
+	  ok = (*cur == ')');
+	  break;
+	}
+
+      ok = (*cur == ')' && macro->paramc == 0);
+      break;
+    }
+
+  CUR (pfile->context) = cur + (*cur == ')');
+
+  return ok;
+}
+
+/* Calculate the length of the replacement text of MACRO.  */
+static unsigned int
+replacement_length (macro)
+     cpp_macro *macro;
+{
+  unsigned int result = 0;
+  const uchar *exp = macro->exp.text;
+
+  for (;;)
+    {
+      struct block *block = (struct block *) exp;
+
+      result += block->text_len;
+      if (block->arg_index == 0)
+	return result;
+      exp += BLOCK_LEN (block->text_len);
+    }
+}
+
+/* Save the text from pfile->trad_out_base to pfile->trad_out_cur as
+   the replacement text for the current macro, followed by argument
+   ARG_INDEX, with zero indicating the end of the replacement
+   text.  */
+static void
+save_replacement_text (pfile, macro, arg_index)
+     cpp_reader *pfile;
+     cpp_macro *macro;
+     unsigned int arg_index;
+{
+  size_t len = pfile->trad_out_cur - pfile->trad_out_base;
+  uchar *exp;
+
+  if (macro->paramc == 0)
+    {
+      /* Object-like and function-like macros without parameters
+	 simply store their NUL-terminated replacement text.  */
+      exp = _cpp_unaligned_alloc (pfile, len + 1);
+      memcpy (exp, pfile->trad_out_base, len);
+      exp[len] = '\0';
+      macro->exp.text = exp;
+      macro->count = len;
+    }
+  else
+    {
+      /* Store the text's length (unsigned int), the argument index
+	 (unsigned short, base 1) and then the text.  */
+      size_t blen = BLOCK_LEN (len);
+      struct block *block;
+
+      if (macro->count + blen > BUFF_ROOM (pfile->a_buff))
+	_cpp_extend_buff (pfile, &pfile->a_buff, macro->count + blen);
+
+      exp = BUFF_FRONT (pfile->a_buff);
+      block = (struct block *) (exp + macro->count);
+      macro->exp.text = exp;
+
+      /* Write out the block information.  */
+      block->text_len = len;
+      block->arg_index = arg_index;
+      memcpy (block->text, pfile->trad_out_base, len);
+
+      /* Lex the rest into the start of the output buffer.  */
+      pfile->trad_out_cur = pfile->trad_out_base;
+
+      /* If this is the end of the macro, count up the bytes of text
+	 in the replacement list, excluding the parameter names, and
+	 save this in macro->count, else store the total bytes in the
+	 replacement text so far (including block headers).  */
+      if (arg_index == 0)
+	macro->count = replacement_length (macro);
+      else
+	macro->count += blen;
+    }
+}
+
+/* Analyze and save the replacement text of a macro.  Returns true on
+   success.  */
 bool
 _cpp_create_trad_definition (pfile, macro)
      cpp_reader *pfile;
      cpp_macro *macro;
 {
-  const uchar *cur, *limit;
-  uchar *exp;
-  size_t len;
+  const uchar *cur;
+  uchar *limit;
 
   /* Skip leading whitespace now.  */
   CUR (pfile->context) = skip_whitespace (pfile, CUR (pfile->context));
 
+  /* Is this a function-like macro?  */
+  if (* CUR (pfile->context) == '(')
+    {
+      /* Setting macro to NULL indicates an error occurred.  */
+      if (!scan_parameters (pfile, macro))
+	macro = NULL;
+      else
+	{
+	  /* Success.  Commit the parameter array.  */
+	  macro->params = (cpp_hashnode **) BUFF_FRONT (pfile->a_buff);
+	  BUFF_FRONT (pfile->a_buff) = (uchar *) &macro->params[macro->paramc];
+	  macro->fun_like = 1;
+	}
+
+      CUR (pfile->context) = skip_whitespace (pfile, CUR (pfile->context));
+    }
+
   pfile->trad_out_cur = pfile->trad_out_base;
-  scan_out_logical_line (pfile);
+  pfile->state.prevent_expansion++;
+  scan_out_logical_line (pfile, macro);
+  pfile->state.prevent_expansion--;
+
+  if (!macro)
+    return false;
 
   /* Skip trailing white space.  */
   cur = pfile->trad_out_base;
   limit = pfile->trad_out_cur;
   while (limit > cur && is_space (limit[-1]))
     limit--;
-
-  len = (size_t) (limit - cur);
-  exp = _cpp_unaligned_alloc (pfile, len + 1);
-  memcpy (exp, cur, len);
-  exp[len] = '\0';
-
-  macro->exp.text = exp;
-  /* Include NUL.  */
-  macro->count = len;
+  pfile->trad_out_cur = limit;
+  save_replacement_text (pfile, macro, 0);
 
   return true;
 }
Index: cpplex.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cpplex.c,v
retrieving revision 1.208
diff -u -p -r1.208 cpplex.c
--- cpplex.c	22 May 2002 22:02:13 -0000	1.208
+++ cpplex.c	6 Jun 2002 22:55:32 -0000
@@ -2011,19 +2011,6 @@ cpp_interpret_charconst (pfile, token, p
   #error BUFF_SIZE_UPPER_BOUND must be at least as large as MIN_BUFF_SIZE!
 #endif
 
-struct dummy
-{
-  char c;
-  union
-  {
-    double d;
-    int *p;
-  } u;
-};
-
-#define DEFAULT_ALIGNMENT (offsetof (struct dummy, u))
-#define CPP_ALIGN(size, align) (((size) + ((align) - 1)) & ~((align) - 1))
-
 /* Create a new allocation buffer.  Place the control block at the end
    of the buffer, so that buffer overflows will cause immediate chaos.  */
 static _cpp_buff *
@@ -2035,7 +2022,7 @@ new_buff (len)
 
   if (len < MIN_BUFF_SIZE)
     len = MIN_BUFF_SIZE;
-  len = CPP_ALIGN (len, DEFAULT_ALIGNMENT);
+  len = CPP_ALIGN (len);
 
   base = xmalloc (len + sizeof (_cpp_buff));
   result = (_cpp_buff *) (base + len);
Index: cppmacro.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cppmacro.c,v
retrieving revision 1.110
diff -u -p -r1.110 cppmacro.c
--- cppmacro.c	5 Jun 2002 20:27:12 -0000	1.110
+++ cppmacro.c	6 Jun 2002 22:55:33 -0000
@@ -70,7 +70,6 @@ static cpp_token *alloc_expansion_token 
 static cpp_token *lex_expansion_token PARAMS ((cpp_reader *, cpp_macro *));
 static bool warn_of_redefinition PARAMS ((cpp_reader *, const cpp_hashnode *,
 					  const cpp_macro *));
-static int save_parameter PARAMS ((cpp_reader *, cpp_macro *, cpp_hashnode *));
 static int parse_params PARAMS ((cpp_reader *, cpp_macro *));
 static void check_trad_stringification PARAMS ((cpp_reader *,
 						const cpp_macro *,
@@ -1197,8 +1196,8 @@ _cpp_free_definition (h)
 
 /* Save parameter NODE to the parameter list of macro MACRO.  Returns
    zero on success, non-zero if the parameter is a duplicate.  */
-static int
-save_parameter (pfile, macro, node)
+bool
+_cpp_save_parameter (pfile, macro, node)
      cpp_reader *pfile;
      cpp_macro *macro;
      cpp_hashnode *node;
@@ -1255,7 +1254,7 @@ parse_params (pfile, macro)
 	    }
 	  prev_ident = 1;
 
-	  if (save_parameter (pfile, macro, token->val.node))
+	  if (_cpp_save_parameter (pfile, macro, token->val.node))
 	    return 0;
 	  continue;
 
@@ -1277,7 +1276,8 @@ parse_params (pfile, macro)
 	  macro->variadic = 1;
 	  if (!prev_ident)
 	    {
-	      save_parameter (pfile, macro, pfile->spec_nodes.n__VA_ARGS__);
+	      _cpp_save_parameter (pfile, macro,
+				   pfile->spec_nodes.n__VA_ARGS__);
 	      pfile->state.va_args_ok = 1;
 	      if (! CPP_OPTION (pfile, c99) && CPP_OPTION (pfile, pedantic))
 		cpp_error (pfile, DL_PEDWARN,
Index: cpphash.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cpphash.h,v
retrieving revision 1.156
diff -u -p -r1.156 cpphash.h
--- cpphash.h	5 Jun 2002 20:27:12 -0000	1.156
+++ cpphash.h	6 Jun 2002 22:55:33 -0000
@@ -50,6 +50,21 @@ typedef unsigned char uchar;
    efficiency, and partly to limit runaway recursion.  */
 #define CPP_STACK_MAX 200
 
+/* Host alignment handling.  */
+struct dummy
+{
+  char c;
+  union
+  {
+    double d;
+    int *p;
+  } u;
+};
+
+#define DEFAULT_ALIGNMENT offsetof (struct dummy, u)
+#define CPP_ALIGN2(size, align) (((size) + ((align) - 1)) & ~((align) - 1))
+#define CPP_ALIGN(size) CPP_ALIGN2 (size, DEFAULT_ALIGNMENT)
+
 /* Each macro definition is recorded in a cpp_macro structure.
    Variadic macros cannot occur with traditional cpp.  */
 struct cpp_macro
@@ -428,7 +443,8 @@ extern bool _cpp_create_definition	PARAM
 extern void _cpp_pop_context		PARAMS ((cpp_reader *));
 extern void _cpp_push_text_context	PARAMS ((cpp_reader *, cpp_hashnode *,
 						 const uchar *, const uchar*));
-extern bool _cpp_create_trad_definition PARAMS ((cpp_reader *, cpp_macro *));
+extern bool _cpp_save_parameter		PARAMS ((cpp_reader *, cpp_macro *,
+						 cpp_hashnode *));
 
 /* In cpphash.c */
 extern void _cpp_init_hashtable		PARAMS ((cpp_reader *, hash_table *));
@@ -483,6 +499,7 @@ extern void _cpp_overlay_buffer PARAMS (
 					 size_t));
 extern cpp_hashnode *_cpp_lex_identifier_trad PARAMS ((cpp_reader *));
 extern void _cpp_set_trad_context PARAMS ((cpp_reader *));
+extern bool _cpp_create_trad_definition PARAMS ((cpp_reader *, cpp_macro *));
 
 /* Utility routines and macros.  */
 #define DSC(str) (const uchar *)str, sizeof str - 1



More information about the Gcc-patches mailing list