+ case LOC_TYPEDEF:
+ yylval.tsym.type = SYMBOL_TYPE (yylval.ssym.sym.symbol);
+ return TYPENAME;
+
+ default:
+ return NAME;
+ }
+ internal_error (__FILE__, __LINE__, _("not reached"));
+}
+
+/* The outer level of a two-level lexer. This calls the inner lexer
+ to return tokens. It then either returns these tokens, or
+ aggregates them into a larger token. This lets us work around a
+ problem in our parsing approach, where the parser could not
+ distinguish between qualified names and qualified types at the
+ right point.
+
+ This approach is still not ideal, because it mishandles template
+ types. See the comment in lex_one_token for an example. However,
+ this is still an improvement over the earlier approach, and will
+ suffice until we move to better parsing technology. */
+
+static int
+yylex (void)
+{
+ token_and_value current;
+ 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;
+ int is_quoted_name;
+
+ if (popping && !VEC_empty (token_and_value, token_fifo))
+ 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 (pstate, &is_quoted_name);
+ if (current.token == NAME)
+ current.token = classify_name (pstate, expression_context_block,
+ is_quoted_name);
+ if (parse_language (pstate)->la_language != language_cplus
+ || (current.token != TYPENAME && current.token != COLONCOLON
+ && current.token != FILENAME))
+ return current.token;
+
+ /* Read any sequence of alternating "::" and name-like tokens into
+ the token FIFO. */
+ current.value = yylval;
+ VEC_safe_push (token_and_value, token_fifo, ¤t);
+ last_was_coloncolon = current.token == COLONCOLON;
+ while (1)
+ {
+ int ignore;
+
+ /* We ignore quoted names other than the very first one.
+ Subsequent ones do not have any special meaning. */
+ current.token = lex_one_token (pstate, &ignore);
+ current.value = yylval;
+ VEC_safe_push (token_and_value, token_fifo, ¤t);
+
+ 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));
+ checkpoint = 0;
+ if (current.token == FILENAME)
+ search_block = current.value.bval;
+ else if (current.token == COLONCOLON)
+ search_block = NULL;
+ else
+ {
+ 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;
+ }
+
+ first_was_coloncolon = current.token == COLONCOLON;
+ last_was_coloncolon = first_was_coloncolon;
+
+ while (next_to_examine <= last_to_examine)
+ {
+ token_and_value *next;
+
+ next = VEC_index (token_and_value, token_fifo, next_to_examine);
+ ++next_to_examine;
+
+ if (next->token == NAME && last_was_coloncolon)
+ {
+ int classification;
+
+ yylval = next->value;
+ classification = classify_inner_name (pstate, 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)
+ break;
+
+ /* Accept up to this token. */
+ checkpoint = next_to_examine;
+
+ /* Update the partial name we are constructing. */
+ if (context_type != NULL)
+ {
+ /* 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);
+
+ yylval.sval.ptr = (const char *) obstack_base (&name_obstack);
+ yylval.sval.length = obstack_object_size (&name_obstack);
+ current.value = yylval;
+ current.token = classification;
+
+ last_was_coloncolon = 0;
+
+ if (classification == NAME)
+ break;
+
+ context_type = yylval.tsym.type;
+ }
+ else if (next->token == COLONCOLON && !last_was_coloncolon)
+ last_was_coloncolon = 1;
+ else
+ {
+ /* We've reached the end of the name. */
+ break;
+ }
+ }
+
+ /* If we have a replacement token, install it as the first token in
+ the FIFO, and delete the other constituent tokens. */
+ if (checkpoint > 0)
+ {
+ current.value.sval.ptr
+ = (const char *) obstack_copy0 (&expansion_obstack,
+ current.value.sval.ptr,
+ current.value.sval.length);
+
+ VEC_replace (token_and_value, token_fifo, 0, ¤t);
+ 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;
+ return current.token;