+/* An object of this type is pushed on a FIFO by the "outer" lexer. */
+struct token_and_value
+{
+ int token;
+ YYSTYPE value;
+};
+
+
+/* A FIFO of tokens that have been read but not yet returned to the
+ parser. */
+static std::vector<token_and_value> token_fifo;
+
+/* Non-zero if the lexer should return tokens from the FIFO. */
+static int popping;
+
+/* Temporary storage for yylex; this holds symbol names as they are
+ built up. */
+static auto_obstack name_obstack;
+
+/* Classify an IDENTIFIER token. The contents of the token are in `yylval'.
+ Updates yylval and returns the new token type. BLOCK is the block
+ in which lookups start; this can be NULL to mean the global scope. */
+
+static int
+classify_name (struct parser_state *par_state, const struct block *block)
+{
+ struct block_symbol sym;
+ struct field_of_this_result is_a_field_of_this;
+
+ std::string copy = copy_name (yylval.sval);
+
+ sym = lookup_symbol (copy.c_str (), block, VAR_DOMAIN, &is_a_field_of_this);
+ if (sym.symbol && SYMBOL_CLASS (sym.symbol) == LOC_TYPEDEF)
+ {
+ yylval.tsym.type = SYMBOL_TYPE (sym.symbol);
+ return TYPENAME;
+ }
+ else if (sym.symbol == NULL)
+ {
+ /* Look-up first for a module name, then a type. */
+ sym = lookup_symbol (copy.c_str (), block, MODULE_DOMAIN, NULL);
+ if (sym.symbol == NULL)
+ sym = lookup_symbol (copy.c_str (), block, STRUCT_DOMAIN, NULL);
+
+ if (sym.symbol != NULL)
+ {
+ yylval.tsym.type = SYMBOL_TYPE (sym.symbol);
+ return TYPENAME;
+ }
+
+ return UNKNOWN_NAME;
+ }
+
+ return IDENTIFIER;
+}
+
+/* Like classify_name, but used by the inner loop of the lexer, when a
+ name might have already been seen. CONTEXT is the context type, or
+ NULL if this is the first component of a name. */
+
+static int
+classify_inner_name (struct parser_state *par_state,
+ const struct block *block, struct type *context)
+{
+ struct type *type;
+
+ if (context == NULL)
+ return classify_name (par_state, block);
+
+ type = check_typedef (context);
+ if (!type_aggregate_p (type))
+ return ERROR;
+
+ std::string copy = copy_name (yylval.ssym.stoken);
+ yylval.ssym.sym = d_lookup_nested_symbol (type, copy.c_str (), block);
+
+ if (yylval.ssym.sym.symbol == NULL)
+ return ERROR;
+
+ if (SYMBOL_CLASS (yylval.ssym.sym.symbol) == LOC_TYPEDEF)
+ {
+ yylval.tsym.type = SYMBOL_TYPE (yylval.ssym.sym.symbol);
+ return TYPENAME;
+ }
+
+ return IDENTIFIER;
+}
+
+/* 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. */
+
+static int
+yylex (void)
+{
+ token_and_value current;
+ int last_was_dot;
+ struct type *context_type = NULL;
+ int last_to_examine, next_to_examine, checkpoint;
+ const struct block *search_block;
+
+ if (popping && !token_fifo.empty ())
+ goto do_pop;
+ popping = 0;
+
+ /* Read the first token and decide what to do. */
+ current.token = lex_one_token (pstate);
+ if (current.token != IDENTIFIER && current.token != '.')
+ return current.token;
+
+ /* Read any sequence of alternating "." and identifier tokens into
+ the token FIFO. */
+ current.value = yylval;
+ token_fifo.push_back (current);
+ last_was_dot = current.token == '.';
+
+ while (1)
+ {
+ current.token = lex_one_token (pstate);
+ current.value = yylval;
+ token_fifo.push_back (current);
+
+ if ((last_was_dot && current.token != IDENTIFIER)
+ || (!last_was_dot && current.token != '.'))
+ break;
+
+ last_was_dot = !last_was_dot;
+ }
+ popping = 1;
+
+ /* We always read one extra token, so compute the number of tokens
+ to examine accordingly. */
+ last_to_examine = token_fifo.size () - 2;
+ next_to_examine = 0;
+
+ current = token_fifo[next_to_examine];
+ ++next_to_examine;
+
+ /* If we are not dealing with a typename, now is the time to find out. */
+ if (current.token == IDENTIFIER)
+ {
+ yylval = current.value;
+ current.token = classify_name (pstate, pstate->expression_context_block);
+ current.value = yylval;
+ }
+
+ /* If the IDENTIFIER is not known, it could be a package symbol,
+ first try building up a name until we find the qualified module. */
+ if (current.token == UNKNOWN_NAME)
+ {
+ name_obstack.clear ();
+ obstack_grow (&name_obstack, current.value.sval.ptr,
+ current.value.sval.length);
+
+ last_was_dot = 0;
+
+ while (next_to_examine <= last_to_examine)
+ {
+ token_and_value next;
+
+ next = token_fifo[next_to_examine];
+ ++next_to_examine;
+
+ if (next.token == IDENTIFIER && last_was_dot)
+ {
+ /* Update the partial name we are constructing. */
+ obstack_grow_str (&name_obstack, ".");
+ obstack_grow (&name_obstack, next.value.sval.ptr,
+ next.value.sval.length);
+
+ yylval.sval.ptr = (char *) obstack_base (&name_obstack);
+ yylval.sval.length = obstack_object_size (&name_obstack);
+
+ current.token = classify_name (pstate,
+ pstate->expression_context_block);
+ current.value = yylval;
+
+ /* We keep going until we find a TYPENAME. */
+ if (current.token == TYPENAME)
+ {
+ /* Install it as the first token in the FIFO. */
+ token_fifo[0] = current;
+ token_fifo.erase (token_fifo.begin () + 1,
+ token_fifo.begin () + next_to_examine);
+ break;
+ }
+ }
+ else if (next.token == '.' && !last_was_dot)
+ last_was_dot = 1;
+ else
+ {
+ /* We've reached the end of the name. */
+ break;
+ }
+ }
+
+ /* Reset our current token back to the start, if we found nothing
+ this means that we will just jump to do pop. */
+ current = token_fifo[0];
+ next_to_examine = 1;
+ }
+ if (current.token != TYPENAME && current.token != '.')
+ goto do_pop;
+
+ name_obstack.clear ();
+ checkpoint = 0;
+ if (current.token == '.')
+ search_block = NULL;
+ else
+ {
+ gdb_assert (current.token == TYPENAME);
+ search_block = pstate->expression_context_block;
+ obstack_grow (&name_obstack, current.value.sval.ptr,
+ current.value.sval.length);
+ context_type = current.value.tsym.type;
+ checkpoint = 1;
+ }
+
+ last_was_dot = current.token == '.';
+
+ while (next_to_examine <= last_to_examine)
+ {
+ token_and_value next;
+
+ next = token_fifo[next_to_examine];
+ ++next_to_examine;
+
+ if (next.token == IDENTIFIER && last_was_dot)
+ {
+ 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 != IDENTIFIER)
+ 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 = (char *) obstack_base (&name_obstack);
+ yylval.sval.length = obstack_object_size (&name_obstack);
+ current.value = yylval;
+ current.token = classification;
+
+ last_was_dot = 0;
+
+ if (classification == IDENTIFIER)
+ break;
+
+ context_type = yylval.tsym.type;
+ }
+ else if (next.token == '.' && !last_was_dot)
+ last_was_dot = 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)
+ {
+ token_fifo[0] = current;
+ if (checkpoint > 1)
+ token_fifo.erase (token_fifo.begin () + 1,
+ token_fifo.begin () + checkpoint);
+ }
+
+ do_pop:
+ current = token_fifo[0];
+ token_fifo.erase (token_fifo.begin ());
+ yylval = current.value;
+ return current.token;
+}
+