[3/3] RFC: fix PR exp/15109

Tom Tromey tromey@redhat.com
Thu Feb 14 21:34:00 GMT 2013


PR exp/15109 concerns gdb's 'FILENAME'::NAME extension.
In particular, while this works fine in C, it fails now in C++.

I tracked this down to a bug in yylex.  It wasn't considering this case.

While looking at this and trying to figure out how to wedge FILENAME
handling into the loop, I decided instead to change how yylex treats
tokens.

The difficulty I found in fixing the existing code was that there were
more ways to need a "do-nothing return" -- but this meant more extensive
bookkeeping to ensure that no token was ever lost.  In fact, one problem
exposed by the PR is that the current code was dropping the "::" token.

Now it works in a way that is more certain to preserve all tokens.  It
reads an alternating sequence of "::" and NAME tokens and pushes them
all on the token FIFO.  Then it does a second pass, deciding which
initial tokens can be handled and therefore removed from the FIFO.

I find the result cleaner, though the formatting of the patch obscures
this somewhat.

Built and regtested on x86-64 Fedora 16.  A couple of new tests are
included.

A nice follow-up cleanup would be to change most of this code to avoid
'yylval' entirely and leave that just to the outermost lexer layer.

Tom

	PR exp/15109:
	* c-exp.y (yylex): Rewrite to push all tokens onto the FIFO.
	Handle FILENAME token.

	* gdb.cp/cpexprs.exp: Add test for FILENAME:: case.
	* gdb.cp/misc.exp: Add test for FILENAME:: case.
---
 gdb/c-exp.y                      |  129 +++++++++++++++++++++++---------------
 gdb/testsuite/gdb.cp/cpexprs.exp |    3 +
 gdb/testsuite/gdb.cp/misc.exp    |    3 +
 3 files changed, 84 insertions(+), 51 deletions(-)

diff --git a/gdb/c-exp.y b/gdb/c-exp.y
index 313a63f..0ab1cde 100644
--- a/gdb/c-exp.y
+++ b/gdb/c-exp.y
@@ -2917,58 +2917,91 @@ static int
 yylex (void)
 {
   token_and_value current;
-  int first_was_coloncolon, last_was_coloncolon, first_iter;
+  int first_was_coloncolon, last_was_coloncolon;
   struct type *context_type = NULL;
+  int last_to_examine, next_to_examine, checkpoint;
+  const struct block *search_block;
 
   if (popping && !VEC_empty (token_and_value, token_fifo))
-    {
-      token_and_value tv = *VEC_index (token_and_value, token_fifo, 0);
-      VEC_ordered_remove (token_and_value, token_fifo, 0);
-      yylval = tv.value;
-      return tv.token;
-    }
+    goto do_pop;
   popping = 0;
 
+  /* Read the first token and decide what to do.  Most of the
+     subsequent code is C++-only; but also depends on seeing a "::" or
+     name-like token.  */
   current.token = lex_one_token ();
   if (current.token == NAME)
     current.token = classify_name (expression_context_block);
   if (parse_language->la_language != language_cplus
-      || (current.token != TYPENAME && current.token != COLONCOLON))
+      || (current.token != TYPENAME && current.token != COLONCOLON
+	  && current.token != FILENAME))
     return current.token;
 
-  first_was_coloncolon = current.token == COLONCOLON;
-  last_was_coloncolon = first_was_coloncolon;
+  /* Read any sequence of alternating "::" and name-like tokens into
+     the token FIFO.  */
+  current.value = yylval;
+  VEC_safe_push (token_and_value, token_fifo, &current);
+  last_was_coloncolon = current.token == COLONCOLON;
+  while (1)
+    {
+      current.token = lex_one_token ();
+      current.value = yylval;
+      VEC_safe_push (token_and_value, token_fifo, &current);
+
+      if ((last_was_coloncolon && current.token != NAME)
+	  || (!last_was_coloncolon && current.token != COLONCOLON))
+	break;
+      last_was_coloncolon = !last_was_coloncolon;
+    }
+  popping = 1;
+
+  /* We always read one extra token, so compute the number of tokens
+     to examine accordingly.  */
+  last_to_examine = VEC_length (token_and_value, token_fifo) - 2;
+  next_to_examine = 0;
+
+  current = *VEC_index (token_and_value, token_fifo, next_to_examine);
+  ++next_to_examine;
+
   obstack_free (&name_obstack, obstack_base (&name_obstack));
-  if (!last_was_coloncolon)
+  checkpoint = 0;
+  if (current.token == FILENAME)
+    search_block = current.value.bval;
+  else if (current.token == COLONCOLON)
+    search_block = NULL;
+  else
     {
-      obstack_grow (&name_obstack, yylval.sval.ptr, yylval.sval.length);
-      context_type = yylval.tsym.type;
+      gdb_assert (current.token == TYPENAME);
+      search_block = expression_context_block;
+      obstack_grow (&name_obstack, current.value.sval.ptr,
+		    current.value.sval.length);
+      context_type = current.value.tsym.type;
+      checkpoint = 1;
     }
-  current.value = yylval;
-  first_iter = 1;
-  while (1)
+
+  first_was_coloncolon = current.token == COLONCOLON;
+  last_was_coloncolon = first_was_coloncolon;
+
+  while (next_to_examine <= last_to_examine)
     {
-      token_and_value next;
+      token_and_value *next;
 
-      next.token = lex_one_token ();
-      next.value = yylval;
+      next = VEC_index (token_and_value, token_fifo, next_to_examine);
+      ++next_to_examine;
 
-      if (next.token == NAME && last_was_coloncolon)
+      if (next->token == NAME && last_was_coloncolon)
 	{
 	  int classification;
 
-	  classification = classify_inner_name (first_was_coloncolon
-						? NULL
-						: expression_context_block,
-						context_type);
+	  yylval = next->value;
+	  classification = classify_inner_name (search_block, context_type);
 	  /* We keep going until we either run out of names, or until
 	     we have a qualified name which is not a type.  */
 	  if (classification != TYPENAME && classification != NAME)
-	    {
-	      /* Push the final component and leave the loop.  */
-	      VEC_safe_push (token_and_value, token_fifo, &next);
-	      break;
-	    }
+	    break;
+
+	  /* Accept up to this token.  */
+	  checkpoint = next_to_examine;
 
 	  /* Update the partial name we are constructing.  */
 	  if (context_type != NULL)
@@ -2976,8 +3009,8 @@ yylex (void)
 	      /* We don't want to put a leading "::" into the name.  */
 	      obstack_grow_str (&name_obstack, "::");
 	    }
-	  obstack_grow (&name_obstack, next.value.sval.ptr,
-			next.value.sval.length);
+	  obstack_grow (&name_obstack, next->value.sval.ptr,
+			next->value.sval.length);
 
 	  yylval.sval.ptr = obstack_base (&name_obstack);
 	  yylval.sval.length = obstack_object_size (&name_obstack);
@@ -2991,38 +3024,32 @@ yylex (void)
 
 	  context_type = yylval.tsym.type;
 	}
-      else if (next.token == COLONCOLON && !last_was_coloncolon)
+      else if (next->token == COLONCOLON && !last_was_coloncolon)
 	last_was_coloncolon = 1;
       else
 	{
 	  /* We've reached the end of the name.  */
-	  VEC_safe_push (token_and_value, token_fifo, &next);
 	  break;
 	}
-
-      first_iter = 0;
     }
 
-  popping = 1;
-
-  /* If we ended with a "::", insert it too.  */
-  if (last_was_coloncolon)
+  /* If we have a replacement token, install it as the first token in
+     the FIFO, and delete the other constituent tokens.  */
+  if (checkpoint > 0)
     {
-      token_and_value cc;
-      memset (&cc, 0, sizeof (token_and_value));
-      if (first_was_coloncolon && first_iter)
-	{
-	  yylval = cc.value;
-	  return COLONCOLON;
-	}
-      cc.token = COLONCOLON;
-      VEC_safe_insert (token_and_value, token_fifo, 0, &cc);
+      current.value.sval.ptr = obstack_copy0 (&expansion_obstack,
+					      current.value.sval.ptr,
+					      current.value.sval.length);
+
+      VEC_replace (token_and_value, token_fifo, 0, &current);
+      if (checkpoint > 1)
+	VEC_block_remove (token_and_value, token_fifo, 1, checkpoint - 1);
     }
 
+ do_pop:
+  current = *VEC_index (token_and_value, token_fifo, 0);
+  VEC_ordered_remove (token_and_value, token_fifo, 0);
   yylval = current.value;
-  yylval.sval.ptr = obstack_copy0 (&expansion_obstack,
-				   yylval.sval.ptr,
-				   yylval.sval.length);
   return current.token;
 }
 
diff --git a/gdb/testsuite/gdb.cp/cpexprs.exp b/gdb/testsuite/gdb.cp/cpexprs.exp
index ec49135..52a293b 100644
--- a/gdb/testsuite/gdb.cp/cpexprs.exp
+++ b/gdb/testsuite/gdb.cp/cpexprs.exp
@@ -731,5 +731,8 @@ gdb_test "p CV_f(int)"   { = {int \(int\)} 0x[0-9a-f]+ <CV_f\(int\)>}
 gdb_test "p CV_f(CV::t)" { = {int \(int\)} 0x[0-9a-f]+ <CV_f\(int\)>}
 gdb_test "p CV_f(CV::i)" " = 43"
 
+gdb_test "p CV_f('cpexprs.cc'::CV::t)" \
+    { = {int \(int\)} 0x[0-9a-f]+ <CV_f\(int\)>}
+
 gdb_exit
 return 0
diff --git a/gdb/testsuite/gdb.cp/misc.exp b/gdb/testsuite/gdb.cp/misc.exp
index bcb0c2b..bd2353a 100644
--- a/gdb/testsuite/gdb.cp/misc.exp
+++ b/gdb/testsuite/gdb.cp/misc.exp
@@ -107,3 +107,6 @@ gdb_test "print (bool)17.93" "\\$\[0-9\]* = true" "(bool)17.93"
 gdb_test "print (bool)0.0" "\\$\[0-9\]* = false" "(bool)0.0"
 gdb_test "print (int)true" "\\$\[0-9\]* = 1" "(int)true"
 gdb_test "print (int)false" "\\$\[0-9\]* = 0" "(int)false"
+
+gdb_test "print 'misc.cc'::v_bool" " = true" \
+    "expression using block qualifier"
-- 
1.7.7.6



More information about the Gdb-patches mailing list