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


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

cpplib: Fix spacing issues, optimize cpp_get_token.


This patch, plus testcase, fixes once and for all token spacing and
positioning issues for the stand-alone preprocessor.

Currently, nasty stuff like

#define str(x) #x
#define f(x) x
f
bar
f (g) str
(
1
2
) f
(bam) baz

produces

f
 bar
g "1 2"



  bam
      baz

With this patch it produces the more pretty and correct

f
bar
g "1 2" bam baz

It is also a good test that we get the "newlines in a macro argument
are whitespace" correct.

Combined in the patch is an optimization to cpp_get_token; moving the
"whilst skipping" loop into _cpp_lex_token where it properly belongs.
cpp_get_token is by far the most executed routine in cpplib; so this
should give a 1 or 2 percent performance win.

Bootstrapping x86 Linux, will commit if and when it succeeds.

Neil.

	* cppinit.c (initialize): Forgotten prototype.
	* cpplex.c (_cpp_lex_token): Loop until not skipping.
	Always clear PREV_WHITE upon meeting a new line.
	* cpplib.c (end_directive): Set pfile->skipping after
	skip_rest_of_line.
	* cpplib.h (cpp_reader): Remove macro_pos.
	* cppmacro.c (cpp_get_line): Don't do anything special inside
	macros.
	(parse_arg): Add PREV_WHITE if a token appears after new lines.
	(funlike_invocation_p): Save and restore the output position
	over a successful check for a '('.
	(enter_macro_context): Delete uses of macro_pos.
	(cpp_get_token): Don't use pfile->skipping.

	* gcc.dg/cpp/20000720-1.S: Remove duplicate testcase.
	* gcc.dg/cpp/poison.c: Update.
	* gcc.dg/cpp/spacing1.c: New testcase for all spacing issues.

Index: gcc/cppinit.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cppinit.c,v
retrieving revision 1.122
diff -u -p -r1.122 cppinit.c
--- cppinit.c	2000/11/28 21:34:29	1.122
+++ cppinit.c	2000/12/01 18:22:48
@@ -94,6 +94,7 @@ struct cpp_pending
 static void print_help                  PARAMS ((void));
 static void path_include		PARAMS ((cpp_reader *,
 						 char *, int));
+static void initialize			PARAMS ((void));
 static void initialize_builtins		PARAMS ((cpp_reader *));
 static void append_include_chain	PARAMS ((cpp_reader *,
 						 char *, int, int));
Index: gcc/cpplex.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cpplex.c,v
retrieving revision 1.121
diff -u -p -r1.121 cpplex.c
--- cpplex.c	2000/11/26 17:31:10	1.121
+++ cpplex.c	2000/12/01 18:22:52
@@ -850,8 +850,10 @@ _cpp_lex_token (pfile, result)
   cppchar_t c;
   cpp_buffer *buffer;
   const unsigned char *comment_start;
-  unsigned char bol = pfile->state.next_bol;
+  unsigned char bol;
 
+ skip:
+  bol = pfile->state.next_bol;
  done_directive:
   buffer = pfile->buffer;
   pfile->state.next_bol = 0;
@@ -894,13 +896,10 @@ _cpp_lex_token (pfile, result)
 	  handle_newline (buffer, c);
 	  bol = 1;
 	  pfile->lexer_pos.output_line = buffer->lineno;
-
-	  /* Newlines in arguments are white space (6.10.3.10).
-             Otherwise, clear any white space flag.  */
-	  if (pfile->state.parsing_args)
-	    result->flags |= PREV_WHITE;
-	  else
-	    result->flags &= ~PREV_WHITE;
+	  /* This is a new line, so clear any white space flag.
+	     Newlines in arguments are white space (6.10.3.10);
+	     parse_arg takes care of that.  */
+	  result->flags &= ~PREV_WHITE;
 	  goto next_char;
 	}
 
@@ -1275,6 +1274,9 @@ _cpp_lex_token (pfile, result)
       result->val.c = c;
       break;
     }
+
+  if (pfile->skipping)
+    goto skip;
 
   /* If not in a directive, this token invalidates controlling macros.  */
   if (!pfile->state.in_directive)
Index: gcc/cpplib.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cpplib.c,v
retrieving revision 1.223
diff -u -p -r1.223 cpplib.c
--- cpplib.c	2000/11/27 08:00:03	1.223
+++ cpplib.c	2000/12/01 18:22:56
@@ -247,13 +247,13 @@ end_directive (pfile, skip_line)
 {
   cpp_buffer *buffer = pfile->buffer;
 
-  /* Restore pfile->skipping before skip_rest_of_line.  This avoids
-     warning about poisoned identifiers in skipped #error lines.  */
-  pfile->skipping = buffer->was_skipping;
-
   /* We don't skip for an assembler #.  */
   if (skip_line)
     skip_rest_of_line (pfile);
+
+  /* Restore pfile->skipping after skip_rest_of_line.  Otherwise the
+     lexer might not return!  */
+  pfile->skipping = buffer->was_skipping;
 
   /* Restore state.  */
   pfile->la_write = pfile->la_saved;
Index: gcc/cpplib.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cpplib.h,v
retrieving revision 1.143
diff -u -p -r1.143 cpplib.h
--- cpplib.h	2000/11/28 21:34:30	1.143
+++ cpplib.h	2000/12/01 18:23:04
@@ -498,10 +498,8 @@ struct cpp_reader
   /* Lexer state.  */
   struct lexer_state state;
 
-  /* The position of the last lexed token, last lexed directive, and
-     last macro invocation.  */
+  /* The position of the last lexed token and last lexed directive.  */
   cpp_lexer_pos lexer_pos;
-  cpp_lexer_pos macro_pos;
   cpp_lexer_pos directive_pos;
 
   /* Memory pools.  */
Index: gcc/cppmacro.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cppmacro.c,v
retrieving revision 1.32
diff -u -p -r1.32 cppmacro.c
--- cppmacro.c	2000/11/28 21:34:29	1.32
+++ cppmacro.c	2000/12/01 18:23:04
@@ -236,10 +236,6 @@ const cpp_lexer_pos *
 cpp_get_line (pfile)
      cpp_reader *pfile;
 {
-  /* Within a macro expansion, return the position of the outermost
-     invocation.  */
-  if (pfile->context->prev)
-    return &pfile->macro_pos;
   return &pfile->lexer_pos;
 }
 
@@ -489,6 +485,7 @@ parse_arg (pfile, arg, var_args)
 {
   enum cpp_ttype result;
   unsigned int paren = 0;
+  unsigned int line;
 
   arg->first = (cpp_token *) POOL_FRONT (&pfile->argument_pool);
   for (;; arg->count++)
@@ -501,9 +498,13 @@ parse_arg (pfile, arg, var_args)
 	  token = &arg->first[arg->count];
 	}
 
+      /* Newlines in arguments are white space (6.10.3.10).  */
+      line = pfile->lexer_pos.output_line;
       cpp_get_token (pfile, token);
-      result = token->type;
+      if (line != pfile->lexer_pos.output_line)
+	token->flags |= PREV_WHITE;
 
+      result = token->type;
       if (result == CPP_OPEN_PAREN)
 	paren++;
       else if (result == CPP_CLOSE_PAREN && paren-- == 0)
@@ -608,7 +609,9 @@ funlike_invocation_p (pfile, node, list)
   cpp_context *orig_context;
   cpp_token maybe_paren;
   macro_arg *args = 0;
+  cpp_lexer_pos macro_pos;
 
+  macro_pos = pfile->lexer_pos;
   pfile->state.parsing_args = 1;
   pfile->state.prevent_expansion++;
   orig_context = pfile->context;
@@ -631,6 +634,9 @@ funlike_invocation_p (pfile, node, list)
 
   if (args)
     {
+      /* The macro's expansion appears where the name would have.  */
+      pfile->lexer_pos = macro_pos;
+
       if (node->value.macro->paramc > 0)
 	{
 	  /* Don't save tokens during pre-expansion.  */
@@ -660,10 +666,7 @@ enter_macro_context (pfile, node)
 
   /* Save the position of the outermost macro invocation.  */
   if (!pfile->context->prev)
-    {
-      pfile->macro_pos = pfile->lexer_pos;
-      lock_pools (pfile);
-    }
+    lock_pools (pfile);
 
   if (macro->fun_like && !funlike_invocation_p (pfile, node, &list))
     {
@@ -924,7 +927,7 @@ cpp_get_token (pfile, token)
 	  token->flags |= flags;
 	  flags = 0;
 	  /* PASTE_LEFT tokens can only appear in macro expansions.  */
-	  if (token->flags & PASTE_LEFT && !pfile->skipping)
+	  if (token->flags & PASTE_LEFT)
 	    paste_all_tokens (pfile, token);
 	}
       else
@@ -939,10 +942,6 @@ cpp_get_token (pfile, token)
 	  token->flags = 0;
 	  return;
 	}
-
-      /* Loop until we're not skipping.  */
-      if (pfile->skipping)
-	continue;
 
       if (token->type != CPP_NAME)
 	break;
Index: gcc/testsuite/gcc.dg/cpp/20000720-1.S
===================================================================
RCS file: 20000720-1.S
diff -N 20000720-1.S
--- /sourceware/cvs-tmp/cvsgTeyvk	Fri Dec  1 10:23:33 2000
+++ /dev/null	Tue May  5 13:32:27 1998
@@ -1,14 +0,0 @@
-/* { dg-do preprocess } */
-
-#define nop()		foobar
-	 nop
-	call b
-
-/*
-   { dg-final { if ![file exists 20000720-1.i] { return }         } }
-   { dg-final { if \{ [grep 20000720-1.i "nop.*call"] != "" \} \{ } }
-   { dg-final {     fail "20000720-1.S: new-line preservation"    } }
-   { dg-final { \} else \{                                        } }
-   { dg-final {     pass "20000720-1.S: new-line preservation"    } }
-   { dg-final { \}                                                } }
-*/
Index: gcc/testsuite/gcc.dg/cpp/poison.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/testsuite/gcc.dg/cpp/poison.c,v
retrieving revision 1.1
diff -u -p -r1.1 poison.c
--- poison.c	2000/06/27 22:26:11	1.1
+++ poison.c	2000/12/01 18:23:24
@@ -15,10 +15,10 @@ foo5			/* { dg-error "foo5" "use of foo5
 #define foo6 345	/* { dg-error "foo6" "def of foo6" } */
 #define foo6 456	/* { dg-error "foo6" "redef of foo6" } */
 #ifdef foo6		/* { dg-error "foo6" "#ifdef foo6" } */
-#error hey!  foo6 poisoned!
+#error hey!  foo6 poisoned! /* { dg-error "foo6" "poisoned identifiers" } */
 #endif
 #if defined(foo6)	/* { dg-error "foo6" "#if defined foo6" } */
-#error no, foo6 still poisoned!
+#error foo6 still poisoned! /* { dg-error "foo6" "poisoned identifiers" } */
 #else
 foo6			/* { dg-error "foo6" "use of foo6" } */
 #endif
Index: gcc/testsuite/gcc.dg/cpp/spacing1.c
===================================================================
RCS file: spacing1.c
diff -N spacing1.c
--- /dev/null	Tue May  5 13:32:27 1998
+++ spacing1.c	Fri Dec  1 10:23:24 2000
@@ -0,0 +1,38 @@
+/* Copyright (C) 2000 Free Software Foundation, Inc.  */
+
+/* { dg-do preprocess } */
+
+/* This tests correct spacing of macro expansion output, as well as
+   the line it falls on.  This is quite subtle; it involves newlines
+   within macro arguments becoming spaces, but not if it turns out to
+   not be a macro invocation.  Also, */
+
+#define str(x) #x
+#define f(x) x
+
+/* The correct output is shown here.  Note the spaces, and the way
+   everything after the invocation of f appears on the same line.
+
+f
+bar
+g "1 2" bam baz
+
+*/
+
+f
+bar
+f (g) str
+(
+1
+2
+) f
+(bam) baz
+
+/*
+   { dg-final { if ![file exists spacing1.i] { return }                   } }
+   { dg-final { if \{ [grep spacing1.i "f.*bar"] == "" \} \{              } }
+   { dg-final { if \{ [grep spacing1.i "^bar"] != "" \}   \{              } }
+   { dg-final { if \{ [grep spacing1.i "g \"1 2\" bam baz"] != "" \} \{   } }
+   { dg-final { return \} \} \}                                           } }
+   { dg-final { fail "spacing1.c: spacing and new-line preservation"      } }
+*/

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