/* Type Analyzer for GNU C++.
Copyright (C) 1987, 1989, 1992, 1993 Free Software Foundation, Inc.
Hacked... nay, bludgeoned... by Mark Eichin (eichin@cygnus.com)
This file is part of GNU CC.
GNU CC is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
GNU CC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNU CC; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
/* This file is the type analyzer for GNU C++. To debug it, define SPEW_DEBUG
when compiling cp-parse.c and cp-spew.c. */
/* This takes a token stream that hasn't decided much about types and
tries to figure out as much as it can, with excessive lookahead and
/* fifo of tokens recognized and available to parser. */
/* The values for YYCHAR will fit in a short. */
static struct token
frob_identifier ();
static struct token
hack_scope ();
static tree
hack_ptype ();
static tree
hack_more_ids ();
/* the declaration found for the last IDENTIFIER token read in.
yylex must look this up to detect typedefs, which get token type TYPENAME,
so it is left around in case the identifier is not a typedef but is
used in a context which makes it a reference to a variable. */
extern tree lastiddecl
; /* let our brains leak out here too */
extern int yychar
; /* the lookahead symbol */
extern YYSTYPE yylval
; /* the semantic value of the */
struct obstack token_obstack
;
static unsigned int yylex_ctr
= 0;
static int debug_yychar ();
static char follows_typename
[END_OF_SAVED_INPUT
+1];
static char follows_identifier
[END_OF_SAVED_INPUT
+1];
/* This is a hack!!! TEMPLATE_TYPE_SEEN_BEFORE_SCOPE consists of the name
* of the last template_type parsed in cp-parse.y if it is followed by a
* scope operator. It will be reset inside the next invocation of yylex().
* This is used for recognizing nested types inside templates.
tree template_type_seen_before_scope
;
/* Initialize token_obstack. Called once, from init_lex. */
static char *chars_following_identifier
= ".+-|/%^!?:";
static short toks_follow_ids
[] =
{ POINTSAT_LEFT_RIGHT
, ASSIGN
, RANGE
, OROR
, ANDAND
, MIN_MAX
, EQCOMPARE
,
ARITHCOMPARE
, LSHIFT
, RSHIFT
, UNARY
, PLUSPLUS
, MINUSMINUS
, POINTSAT
,
POINTSAT_STAR
, DOT_STAR
, CONSTANT
, STRING
, SIZEOF
, ENUM
, IF
,
ELSE
, WHILE
, DO
, FOR
, SWITCH
, CASE
, DEFAULT
, BREAK
, CONTINUE
,
RETURN
, GOTO
, ASM_KEYWORD
, GCC_ASM_KEYWORD
, TYPEOF
, ALIGNOF
, HEADOF
,
CLASSOF
, ATTRIBUTE
, AGGR
, VISSPEC
, DELETE
, RAISE
, RERAISE
, TRY
, EXCEPT
,
CATCH
, THROW
, ANSI_TRY
, ANSI_THROW
, EXTERN_LANG_STRING
, ALL
,
END_OF_SAVED_INPUT
, -1 };
static short toks_follow_types
[] =
{ IDENTIFIER
, TYPENAME
, SCOPED_TYPENAME
, SCSPEC
, TYPESPEC
, TYPE_QUAL
,
ELLIPSIS
, THIS
, OPERATOR
, DYNAMIC
, TEMPLATE
, SCOPE
, START_DECLARATOR
,
TYPENAME_COLON
, PAREN_STAR_PAREN
, TYPENAME_ELLIPSIS
, PTYPENAME
,
PRE_PARSED_FUNCTION_DECL
, PRE_PARSED_CLASS_DECL
, -1 };
gcc_obstack_init(&token_obstack
);
/* Initialize the arrays saying what tokens are definitely
(or possibly) valid following typenames and identifiers. */
while (*chars_following_identifier
)
follows_identifier
[*chars_following_identifier
++] = 1;
for (ps
= toks_follow_ids
; *ps
!= -1; ps
++)
follows_identifier
[*ps
] = 1;
for (ps
= toks_follow_types
; *ps
!= -1; ps
++)
follows_typename
[*ps
] = 1;
/* Use functions for debugging... */
/* Return the number of tokens available on the fifo. */
return (obstack_object_size(&token_obstack
)/sizeof(struct token
))
/* Fetch the token N down the line from the head of the fifo. */
/* could just have this do slurp_ implicitly, but this way is easier
my_friendly_assert (n
< num_tokens(), 298);
return ((struct token
*)obstack_base(&token_obstack
))+n
+first_token
;
/* Add a token to the token fifo. */
obstack_grow(&token_obstack
,t
,sizeof (struct token
));
/* Consume the next token out of the fifo. */
obstack_free(&token_obstack
, obstack_base (&token_obstack
));
/* ...otherwise use macros. */
((obstack_object_size(&token_obstack)/sizeof(struct token)) - first_token)
(((struct token*)obstack_base(&token_obstack))+(N)+first_token)
#define add_token(T) obstack_grow(&token_obstack, (T), sizeof (struct token))
#define consume_token() \
? (obstack_free (&token_obstack, obstack_base (&token_obstack)), \
/* Pull in enough tokens from real_yylex that the queue is N long. */
/* We cannot read past certain tokens, so make sure we don't. */
/* Never read past these characters: they might separate
the current input stream from one we save away later. */
if (tmp
->yychar
== '{' || tmp
->yychar
== ':')
while (num_tokens() <= n
)
obstack_blank(&token_obstack
,sizeof (struct token
));
tmp
= ((struct token
*)obstack_next_free (&token_obstack
))-1;
tmp
->yychar
= real_yylex();
tmp
->end_of_file
= end_of_file
;
while (num_tokens () <= n
)
obstack_blank(&token_obstack
,sizeof (struct token
));
tmp
= ((struct token
*)obstack_next_free (&token_obstack
))-1;
/* Create room for N tokens at the front of the fifo. This is used
to insert new tokens into the stream ahead of the current token. */
int old_token_count
= num_tokens ();
obstack_blank (&token_obstack
, (n
-first_token
) * sizeof (struct token
));
tmp
= (char *)alloca ((num_tokens () + (n
-first_token
))
* sizeof (struct token
));
/* This move does not rely on the system being able to handle
bcopy (nth_token (0), tmp
, old_token_count
* sizeof (struct token
));
bcopy (tmp
, nth_token (n
), old_token_count
* sizeof (struct token
));
probe_obstack (h
, obj
, nlevels
)
register struct _obstack_chunk
* lp
; /* below addr of any objects in this chunk */
register struct _obstack_chunk
* plp
; /* point to previous chunk if any */
/* We use >= rather than > since the object cannot be exactly at
the beginning of the chunk but might be an empty object exactly
at the end of an adjacent chunk. */
for (; nlevels
!= 0 && lp
!= 0 && ((tree
)lp
>= obj
|| (tree
)lp
->limit
< obj
);
return nlevels
!= 0 && lp
!= 0;
/* Value is 1 if we should try to make the next identifier look like a
typename (when it may be a local variable or a class variable).
Value is 0 if we treat this name in a default fashion.
Value is -1 if we must not see a type name. */
extern int looking_for_typename
;
extern struct obstack
*current_obstack
, *saveable_obstack
;
fprintf(stderr
, "\t\t## %d ##",yylex_ctr
);
/* This is a kludge for recognizing nested types in templates */
if (template_type_seen_before_scope
)
shift_tokens (2); /* Sync in hack_more_ids (yes, it's ugly) */
nth_token (1)->yychar
= SCOPE
;
yylval
.ttype
= hack_more_ids (0, template_type_seen_before_scope
);
template_type_seen_before_scope
= 0;
/* Sync back again, leaving SCOPE on the token stream, because we
* failed to substitute the original SCOPE token with a
* SCOPED_TYPENAME. See rule "template_type" in cp-parse.y */
yychar
= SCOPED_TYPENAME
;
/* if we've got tokens, send them */
tmp_token
= *nth_token(0);
/* TMP_TOKEN.YYLVAL.TTYPE may have been allocated on the wrong obstack.
If we don't find it in CURRENT_OBSTACK's current or immediately
previous chunk, assume it was and copy it to the current obstack. */
if ((tmp_token
.yychar
== CONSTANT
|| tmp_token
.yychar
== STRING
)
&& ! TREE_PERMANENT (tmp_token
.yylval
.ttype
)
&& ! probe_obstack (current_obstack
, tmp_token
.yylval
.ttype
, 2)
&& ! probe_obstack (saveable_obstack
, tmp_token
.yylval
.ttype
, 2))
tmp_token
.yylval
.ttype
= copy_node (tmp_token
.yylval
.ttype
);
/* if not, grab the next one and think about it */
tmp_token
.yychar
= real_yylex ();
tmp_token
.yylval
= yylval
;
tmp_token
.end_of_file
= end_of_file
;
/* many tokens just need to be returned. At first glance, all we
* have to do is send them back up, but some of them are needed to
* figure out local context. */
/* This is a lexical no-op. */
debug_yychar (tmp_token
.yychar
);
/* Note: this calls arbitrate_lookup. */
trrr
= lookup_name (tmp_token
.yylval
.ttype
, -2);
tmp_token
.yychar
= identifier_type (trrr
);
switch (tmp_token
.yychar
)
lastiddecl
= identifier_typedecl_value (tmp_token
.yylval
.ttype
);
if (lastiddecl
== NULL_TREE
)
/* This is for cases like
template<class A> X<A>::operator[] ...
since "X" is (presumably) a PTYPENAME; we might want to
avoid seeing the entire thing as a type name, but X<A>
It might not work right if the thing after the ::
can be a typename nested in X<A>, but I don't think the
PT code would be up to dealing with that anyways. --KR */
if (looking_for_typename
== -1)
if (nth_token(1)->yychar
== '<')
looking_for_typename
= 0;
/* and fall through to... */
/* if (new_token) add_token (&tmp_token); */
*nth_token(0) = tmp_token
;
tmp_token
= frob_identifier ();
if (looking_for_typename
< 0)
tmp_token
.yychar
= IDENTIFIER
;
looking_for_typename
= 0;
else if (lastiddecl
&& TREE_CODE (lastiddecl
) == TYPE_DECL
)
if (nth_token(0)->yychar
== IDENTIFIER
&& nth_token (1)->yychar
!= SCOPE
)
looking_for_typename
= -1;
looking_for_typename
= 0;
goto finish_typename_processing
;
looking_for_typename
= 0;
finish_typename_processing
:
/* Now see if we should insert a START_DECLARATOR token.
Here are the cases caught:
typespec ( * ID ) ( // ptr to function
typespec ( & ID ) ( // ref to function
typespec ( * ID ) [ // array of pointers
typespec ( & ID ) [ // array of references
This is a terrible kludge. */
if (nth_token (0)->yychar
== '('
&& (nth_token (1)->yychar
== '*'
|| nth_token (1)->yychar
== '&'))
if (nth_token (3)->yychar
== ')'
&& (nth_token (4)->yychar
== '('
|| nth_token (4)->yychar
== '['
|| nth_token (4)->yychar
== LEFT_RIGHT
)
&& (nth_token (2)->yychar
== IDENTIFIER
|| nth_token (2)->yychar
== TYPENAME
))
nth_token (0)->yychar
= START_DECLARATOR
;
typespec (ID::* qf)( // ptr to member function
typespec (ID::* qf)[ // array of ptr to member functions
if (nth_token (0)->yychar
== '('
&& (nth_token (1)->yychar
== IDENTIFIER
|| nth_token (1)->yychar
== TYPENAME
))
if (nth_token (2)->yychar
== SCOPE
&& nth_token (3)->yychar
== '*'
&& (nth_token (4)->yychar
== IDENTIFIER
|| nth_token (4)->yychar
== TYPENAME
)
&& nth_token (5)->yychar
== ')'
&& (nth_token (6)->yychar
== '('
|| nth_token (6)->yychar
== '['
|| nth_token (6)->yychar
== LEFT_RIGHT
))
nth_token (0)->yychar
= START_DECLARATOR
;
/* Handle casts. We are looking for one of:
`( TYPENAME' followed by `)', or
`( TYPENAME *' followed by one of `[,*,&,)', or
`( TYPENAME &' followed by one of `[,*,&,)', or
`( TYPENAME [' followed by `]'. We are punting
generality on scanning casts to array types. */
if (nth_token (1)->yychar
== IDENTIFIER
)
tree type
= identifier_typedecl_value (nth_token (1)->yylval
.ttype
);
switch (nth_token (2)->yychar
)
/* if (new_token) add_token (&tmp_token); */
*nth_token(0) = tmp_token
;
tmp_token
= hack_scope ();
*nth_token(0) = tmp_token
;
/* fall through to output... */
/* Set this again, in case we are rescanning. */
looking_for_typename
= 1;
debug_yychar(tmp_token
.yychar
);
yylval
= tmp_token
.yylval
;
yychar
= tmp_token
.yychar
;
end_of_file
= tmp_token
.end_of_file
;
if (tmp_token
.yychar
== SCOPED_TYPENAME
)
tree t2
= resolve_scope_to_name (NULL_TREE
, tmp_token
.yylval
.ttype
);
tmp_token
.yylval
.ttype
= t2
;
tmp_token
.yychar
= TYPENAME
;
/* couldn't get here, as is... */
tmp_token
.yychar
= TYPENAME
;
yylval
= tmp_token
.yylval
;
yychar
= tmp_token
.yychar
;
end_of_file
= tmp_token
.end_of_file
;
/* consume_token(); */ /* already eaten by frob_identifier?... */
/* token[0] == AGGR (struct/union/enum)
* thus, token[1] is either a TYPENAME or a TYPENAME_DEFN
* if token[2] == '{' or ':' then it's TYPENAME_DEFN
yc1
= nth_token (1)->yychar
;
if (yc1
!= TYPENAME
&& yc1
!= IDENTIFIER
&& yc1
!= PTYPENAME
)
yc2
= nth_token (2)->yychar
;
if (yc2
== '{' || yc2
== ':')
nth_token (1)->yychar
= TYPENAME_DEFN
;
nth_token (1)->yychar
= PTYPENAME_DEFN
;
nth_token (1)->yychar
= IDENTIFIER_DEFN
;
/* we could have a type, if it is followed by :: (if so, suck it all up); */
/* we could have a ptypename; */
/* we could have a normal identifier. */
if (nth_token(1)->yychar
== '<')
t1
= hack_ptype(); /* suck up the whole thing */
/* else fall out bottom */
if (nth_token(1)->yychar
== SCOPE
)
if (t1
&& TREE_CODE(t1
) == SCOPE_REF
)
t1
= hack_more_ids(0, nth_token (0)->yylval
.ttype
);
rt
.yychar
= SCOPED_TYPENAME
;
/* deal with types (enums?) in classes... */
/* Have to check for a type conversion operator
if (nth_token (2)->yychar
== OPERATOR
)
if (tok
->yychar
== IDENTIFIER
|| tok
->yychar
== TYPENAME
)
ta
= build_parse_node (SCOPE_REF
,
nth_token(0)->yylval
.ttype
,
tb
= resolve_scope_to_name (NULL_TREE
, ta
);
if (nth_token (2)->yychar
== OPERATOR
)
/* Have to keep these tokens around
so we can finish parsing the declaration.
int foo::operator bar::baz ();
where bar is a nested class in foo? */
nth_token (3)->yychar
= TYPENAME
;
nth_token (3)->yylval
.ttype
= tb
;
consume_token (); /* base type */
consume_token (); /* SCOPE */
consume_token (); /* member type */
rt
.end_of_file
= tok
->end_of_file
;
/* else fall out bottom */
/* When this function is called, nth_token(0) is the current
token we are scanning. This means that the next token we'll
scan is nth_token (1). Usually the next token we'll scan
is nth_token (0) (and the current token is in [yylval,yychar]). */
arbitrate_lookup (name
, exp_decl
, type_decl
)
tree name
, exp_decl
, type_decl
;
ch
= nth_token (1)->yychar
;
/* If we guessed wrong here, `build_functional_cast' can fix it. */
if (global_bindings_p ())
/* Probably a default parameter. */
/* Probably not an initialization. */
/* This needs special help because an expression inside the
brackets means nothing. */
ith_yychar
= nth_token (2+i
)->yychar
;
/* If we hit an undefined identifier, assume
the decl in arbitration is its type specifier. */
if (ith_yychar
== IDENTIFIER
&& lookup_name (nth_token (2+i
)->yylval
.ttype
, 0) == 0)
else if (ith_yychar
== ']')
/* There are only a few things we expect after a ']'
ith_yychar
= nth_token (2+i
)->yychar
;
/* These are inconclusive. */
if (ith_yychar
== LEFT_RIGHT
/* stmt or decl? We'll probably never know. */
else if (ith_yychar
== ';')
if (nth_token (3+i
)->yychar
== '{')
/* Whatever it is, it looks like we're processing an expr. */
/* see if the next token looks like it wants to be part
of a declaration list or an expression list. */
/* Some heuristics: if we are inside a function definition,
prefer the local declaration. */
if (! global_bindings_p ())
if (IDENTIFIER_LOCAL_VALUE (name
) == exp_decl
)
if (IDENTIFIER_LOCAL_VALUE (name
) != type_decl
&& IDENTIFIER_CLASS_VALUE (name
) == exp_decl
)
/* If these symbols follow in a list, we know it's a list of
if (follows_identifier
[nth_token (2)->yychar
])
/* If we see a id&, or id&) the we are probably in an argument list. */
&& (nth_token (2)->yychar
== ',' || nth_token (2)->yychar
== ')'))
/* Look for the first identifier or other distinguishing token
we find in the next several tokens. */
ith_yychar
= nth_token (2+i
)->yychar
;
if (ith_yychar
== IDENTIFIER
)
tree as_type
= lookup_name (nth_token (2+i
)->yylval
.ttype
, 1);
if (as_type
&& TREE_CODE (as_type
) != TYPE_DECL
)
/* An undeclared identifier or a typename means we're
probably looking at a typename. */
else if (ith_yychar
== EMPTY
|| follows_identifier
[ith_yychar
])
else if (follows_typename
[ith_yychar
])
/* stmt or decl? We'll probably never know. */
else if (ith_yychar
== ';')
if (follows_identifier
[ch
])
if (follows_typename
[ch
])
warning ("name `%s' could be type or expression; compiler assuming type",
IDENTIFIER_POINTER (DECL_NAME (type_decl
)));
/* now returns decl_node */
/* when we get here, we know that [0] is a ptype and [1] is '<'.
* now we loop over simple parameters. */
while((this_param
= *nth_token(n
)).yychar
!= '>')
/* if it is a type, add it to the list */
switch(this_param
.yychar
)
thistype
= this_param
.yylval
.ttype
;
thistype
= lookup_name(thistype
, 1);
thistype
= TREE_TYPE (thistype
);
tplist
= chainon (tplist
, build_tree_list (NULL_TREE
, thistype
));
tplist
= build_tree_list(NULL_TREE
, thistype
);
/* then suck up the comma */
this_param
= *nth_token(n
);
if (this_param
.yychar
== ',')
if (this_param
.yychar
== '>')
/* once we're done, lookup_template_class -> identifier */
tc
= lookup_template_class (nth_token(0)->yylval
.ttype
,tplist
);
/* then lookup_name on that to get a type, if there is one */
tc
= lookup_name (tc
, 1);
/* don't actually eat the trailing '>'... we can replace it! */
/* IDENTIFIER_TYPE_VALUE (DECL_NAME (tc)) = */
* The recursion should probably do consume_tokens(), since once we've started
* down an IDENTIFIER SCOPE ... chain, we don't need to back-track - we just
* get as much as we can, make SCOPE_REF's out of it, and return it.
struct token this_iter
, this2_iter
;
this_iter
= *nth_token(n
);
tmp_y
= nth_token(n
)->yychar
;
if (tmp_y
== IDENTIFIER
|| tmp_y
== TYPENAME
)
if (nth_token(n
+1)->yychar
== SCOPE
)
if (nth_token(n
+1+2)->yychar
== SCOPE
)
consume_token(); /* last IDENTIFIER (this_iter) */
consume_token(); /* last SCOPE */
this2_iter
= *nth_token(n
);
return build_parse_node (SCOPE_REF
, this_iter
.yylval
.ttype
, hmi
);
consume_token(); /* last IDENTIFIER (this2_iter) */
return build_parse_node (SCOPE_REF
, this_iter
.yylval
.ttype
,
this2_iter
.yylval
.ttype
);
/* consume_token(); */ /* last IDENTIFIER */
/* leave whatever else we got */
/* return this_iter.yylval.ttype; */
return NULL_TREE
; /* @@ may need to backtrack */
/* niklas@appli.se says: I didn't understand how the code above was intended
* to work, so I rewrote it (also changed the interface a bit). This code
* dives down an IDENTIFIER/TYPENAME SCOPE ... chain as long as the parsed
* type prefix constitutes recognizable (by resolve_scope_to_name) types.
* Interface changed like this:
* 1. Takes an extra argument containing the name of the the type recognized
* 2. Now returns the name of the type instead of a SCOPE_REF. */
if (nth_token (n
+ 1)->yychar
!= SCOPE
|| ((ch
= nth_token (n
+ 2)->yychar
) != IDENTIFIER
&& ch
!= TYPENAME
))
val
= build_parse_node (SCOPE_REF
, outer
, nth_token (n
+ 2)->yylval
.ttype
);
type
= resolve_scope_to_name (NULL_TREE
, val
);
val
= hack_more_ids (n
, type
);
/* we've got a :: - what follows is either a global var or a type. */
/* hmm, template names can be in the global scope too... */
if (nth_token(1)->yychar
== IDENTIFIER
)
/* @@ this is probably not right, but doesn't get hit yet */
t1
= build_parse_node (SCOPE_REF
,
NULL_TREE
, /* to get "global" scope */
hack_more_ids(0)); /* do some prefetching */
rt
.yychar
= /*SCOPED_*/TYPENAME
;
* PINST: PTYPE { saved_arg_count = arg_count($1) }
* '<' { arg_c = 0; } PARGS '>'
* (of course the arg counting doesn't work for recursion... Do it right.)
* PARGS: PARG { assert(arg_c == saved_arg_count); }
* | PARG ',' PARGS { arg_c++; }
* | ATYPE { basetype = $1; } '::' TYPEKIDS
* TYPEKIDS: TYPE { assert ($1 is a member of basetype); }
* | TYPEKIDS { basetype += $1} TYPE { assert( $3 is in basetype ); }
* TYPE '<': ac = args($0), base = CALL state1, state3
* TYPE '::': base=$0, state3
* if(ac < list length) punt
* PARG ",": add to list, state1
* PARG ">": add to list, return
* state3: ; begin TYPEKIDS
/* debug_yychar takes a yychar (token number) value and prints its name. */
extern char *debug_yytranslate ();
fprintf (stderr
, "<%d: %c >\n", yy
, yy
);
fprintf (stderr
, "<%d:%s>\n", yy
, debug_yytranslate (yy
));