+/* An object of this type is pushed on a FIFO by the "outer" lexer. */
+typedef struct
+{
+ int token;
+ YYSTYPE value;
+} token_and_value;
+
+DEF_VEC_O (token_and_value);
+
+/* A FIFO of tokens that have been read but not yet returned to the
+ parser. */
+static VEC (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 struct 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;
+ char *copy;
+ struct field_of_this_result is_a_field_of_this;
+
+ copy = copy_name (yylval.sval);
+
+ sym = lookup_symbol (copy, 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, block, MODULE_DOMAIN, NULL);
+ if (sym.symbol == NULL)
+ sym = lookup_symbol (copy, 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;
+ char *copy;
+
+ if (context == NULL)
+ return classify_name (par_state, block);
+
+ type = check_typedef (context);
+ if (!type_aggregate_p (type))
+ return ERROR;
+
+ copy = copy_name (yylval.ssym.stoken);
+ yylval.ssym.sym = d_lookup_nested_symbol (type, copy, 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 && !VEC_empty (token_and_value, token_fifo))
+ 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;
+ VEC_safe_push (token_and_value, token_fifo, ¤t);
+ last_was_dot = current.token == '.';
+
+ while (1)
+ {
+ current.token = lex_one_token (pstate);
+ current.value = yylval;
+ VEC_safe_push (token_and_value, token_fifo, ¤t);
+
+ 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 = 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;
+
+ /* 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, 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)
+ {
+ obstack_free (&name_obstack, obstack_base (&name_obstack));
+ 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 = VEC_index (token_and_value, 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, 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. */
+ VEC_replace (token_and_value, token_fifo, 0, ¤t);
+ VEC_block_remove (token_and_value, token_fifo, 1,
+ next_to_examine - 1);
+ 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 = *VEC_index (token_and_value, token_fifo, 0);
+ next_to_examine = 1;
+ }
+ if (current.token != TYPENAME && current.token != '.')
+ goto do_pop;
+
+ obstack_free (&name_obstack, obstack_base (&name_obstack));
+ checkpoint = 0;
+ if (current.token == '.')
+ 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;
+ }
+
+ last_was_dot = current.token == '.';
+
+ 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 == 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)
+ {
+ 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;
+}
+