]>
Commit | Line | Data |
---|---|---|
8d08fdba | 1 | /* Type Analyzer for GNU C++. |
8ecb1d92 | 2 | Copyright (C) 1987, 89, 92, 93, 94, 1995 Free Software Foundation, Inc. |
8d08fdba MS |
3 | Hacked... nay, bludgeoned... by Mark Eichin (eichin@cygnus.com) |
4 | ||
5 | This file is part of GNU CC. | |
6 | ||
7 | GNU CC is free software; you can redistribute it and/or modify | |
8 | it under the terms of the GNU General Public License as published by | |
9 | the Free Software Foundation; either version 2, or (at your option) | |
10 | any later version. | |
11 | ||
12 | GNU CC is distributed in the hope that it will be useful, | |
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 | GNU General Public License for more details. | |
16 | ||
17 | You should have received a copy of the GNU General Public License | |
18 | along with GNU CC; see the file COPYING. If not, write to | |
e9fa0c7c RK |
19 | the Free Software Foundation, 59 Temple Place - Suite 330, |
20 | Boston, MA 02111-1307, USA. */ | |
8d08fdba MS |
21 | |
22 | ||
23 | /* This file is the type analyzer for GNU C++. To debug it, define SPEW_DEBUG | |
51c184be | 24 | when compiling parse.c and spew.c. */ |
8d08fdba MS |
25 | |
26 | #include "config.h" | |
27 | #include <stdio.h> | |
28 | #include "input.h" | |
29 | #include "tree.h" | |
30 | #include "lex.h" | |
8d08fdba | 31 | #include "cp-tree.h" |
46b02c6d | 32 | #include "parse.h" |
8d08fdba MS |
33 | #include "flags.h" |
34 | #include "obstack.h" | |
35 | ||
36 | /* This takes a token stream that hasn't decided much about types and | |
37 | tries to figure out as much as it can, with excessive lookahead and | |
e92cc029 | 38 | backtracking. */ |
8d08fdba | 39 | |
e92cc029 | 40 | /* fifo of tokens recognized and available to parser. */ |
8d08fdba MS |
41 | struct token { |
42 | /* The values for YYCHAR will fit in a short. */ | |
43 | short yychar; | |
44 | short end_of_file; | |
45 | YYSTYPE yylval; | |
46 | }; | |
47 | ||
49c249e1 JM |
48 | static int do_aggr PROTO((void)); |
49 | static int probe_obstack PROTO((struct obstack *, tree, unsigned int)); | |
50 | static void scan_tokens PROTO((int)); | |
8d08fdba | 51 | |
51c184be | 52 | /* From lex.c: */ |
8d08fdba MS |
53 | /* the declaration found for the last IDENTIFIER token read in. |
54 | yylex must look this up to detect typedefs, which get token type TYPENAME, | |
55 | so it is left around in case the identifier is not a typedef but is | |
56 | used in a context which makes it a reference to a variable. */ | |
57 | extern tree lastiddecl; /* let our brains leak out here too */ | |
58 | extern int yychar; /* the lookahead symbol */ | |
59 | extern YYSTYPE yylval; /* the semantic value of the */ | |
60 | /* lookahead symbol */ | |
61 | extern int end_of_file; | |
62 | ||
63 | struct obstack token_obstack; | |
64 | int first_token; | |
65 | ||
66 | #ifdef SPEW_DEBUG | |
67 | int spew_debug = 0; | |
68 | static unsigned int yylex_ctr = 0; | |
69 | static int debug_yychar (); | |
70 | #endif | |
71 | ||
8d08fdba | 72 | /* Initialize token_obstack. Called once, from init_lex. */ |
e92cc029 | 73 | |
8d08fdba MS |
74 | void |
75 | init_spew () | |
76 | { | |
fc378698 | 77 | gcc_obstack_init (&token_obstack); |
8d08fdba MS |
78 | } |
79 | ||
80 | #ifdef SPEW_DEBUG | |
81 | /* Use functions for debugging... */ | |
82 | ||
e92cc029 MS |
83 | /* Return the number of tokens available on the fifo. */ |
84 | ||
8d08fdba MS |
85 | static int |
86 | num_tokens () | |
87 | { | |
fc378698 | 88 | return (obstack_object_size (&token_obstack) / sizeof (struct token)) |
8d08fdba MS |
89 | - first_token; |
90 | } | |
91 | ||
e92cc029 MS |
92 | /* Fetch the token N down the line from the head of the fifo. */ |
93 | ||
8d08fdba MS |
94 | static struct token* |
95 | nth_token (n) | |
96 | int n; | |
97 | { | |
98 | /* could just have this do slurp_ implicitly, but this way is easier | |
e92cc029 | 99 | to debug... */ |
fc378698 MS |
100 | my_friendly_assert (n < num_tokens (), 298); |
101 | return ((struct token*)obstack_base (&token_obstack)) + n + first_token; | |
8d08fdba MS |
102 | } |
103 | ||
e92cc029 MS |
104 | /* Add a token to the token fifo. */ |
105 | ||
8d08fdba MS |
106 | static void |
107 | add_token (t) | |
108 | struct token* t; | |
109 | { | |
fc378698 | 110 | obstack_grow (&token_obstack, t, sizeof (struct token)); |
8d08fdba MS |
111 | } |
112 | ||
113 | /* Consume the next token out of the fifo. */ | |
e92cc029 | 114 | |
8d08fdba | 115 | static void |
fc378698 | 116 | consume_token () |
8d08fdba | 117 | { |
fc378698 | 118 | if (num_tokens () == 1) |
8d08fdba | 119 | { |
fc378698 | 120 | obstack_free (&token_obstack, obstack_base (&token_obstack)); |
8d08fdba MS |
121 | first_token = 0; |
122 | } | |
123 | else | |
124 | first_token++; | |
125 | } | |
126 | ||
127 | #else | |
128 | /* ...otherwise use macros. */ | |
129 | ||
130 | #define num_tokens() \ | |
fc378698 | 131 | ((obstack_object_size (&token_obstack) / sizeof (struct token)) - first_token) |
8d08fdba MS |
132 | |
133 | #define nth_token(N) \ | |
fc378698 | 134 | (((struct token*)obstack_base (&token_obstack))+(N)+first_token) |
8d08fdba | 135 | |
fc378698 | 136 | #define add_token(T) obstack_grow (&token_obstack, (T), sizeof (struct token)) |
8d08fdba MS |
137 | |
138 | #define consume_token() \ | |
fc378698 | 139 | (num_tokens () == 1 \ |
8d08fdba MS |
140 | ? (obstack_free (&token_obstack, obstack_base (&token_obstack)), \ |
141 | (first_token = 0)) \ | |
142 | : first_token++) | |
143 | #endif | |
144 | ||
a28e3c7f MS |
145 | /* Pull in enough tokens from real_yylex that the queue is N long beyond |
146 | the current token. */ | |
8d08fdba MS |
147 | |
148 | static void | |
149 | scan_tokens (n) | |
150 | int n; | |
151 | { | |
152 | int i; | |
153 | struct token *tmp; | |
154 | ||
155 | /* We cannot read past certain tokens, so make sure we don't. */ | |
156 | i = num_tokens (); | |
157 | if (i > n) | |
158 | return; | |
159 | while (i-- > 0) | |
160 | { | |
161 | tmp = nth_token (i); | |
162 | /* Never read past these characters: they might separate | |
163 | the current input stream from one we save away later. */ | |
164 | if (tmp->yychar == '{' || tmp->yychar == ':' || tmp->yychar == ';') | |
165 | goto pad_tokens; | |
166 | } | |
167 | ||
fc378698 | 168 | while (num_tokens () <= n) |
8d08fdba | 169 | { |
fc378698 | 170 | obstack_blank (&token_obstack, sizeof (struct token)); |
8d08fdba | 171 | tmp = ((struct token *)obstack_next_free (&token_obstack))-1; |
fc378698 | 172 | tmp->yychar = real_yylex (); |
8d08fdba MS |
173 | tmp->end_of_file = end_of_file; |
174 | tmp->yylval = yylval; | |
175 | end_of_file = 0; | |
176 | if (tmp->yychar == '{' | |
177 | || tmp->yychar == ':' | |
178 | || tmp->yychar == ';') | |
179 | { | |
180 | pad_tokens: | |
181 | while (num_tokens () <= n) | |
182 | { | |
fc378698 | 183 | obstack_blank (&token_obstack, sizeof (struct token)); |
8d08fdba MS |
184 | tmp = ((struct token *)obstack_next_free (&token_obstack))-1; |
185 | tmp->yychar = EMPTY; | |
186 | tmp->end_of_file = 0; | |
187 | } | |
188 | } | |
189 | } | |
190 | } | |
191 | ||
df4791b9 JL |
192 | /* Like _obstack_allocated_p, but stop after checking NLEVELS chunks. */ |
193 | ||
8d08fdba MS |
194 | static int |
195 | probe_obstack (h, obj, nlevels) | |
196 | struct obstack *h; | |
197 | tree obj; | |
198 | unsigned int nlevels; | |
199 | { | |
200 | register struct _obstack_chunk* lp; /* below addr of any objects in this chunk */ | |
201 | register struct _obstack_chunk* plp; /* point to previous chunk if any */ | |
202 | ||
203 | lp = (h)->chunk; | |
204 | /* We use >= rather than > since the object cannot be exactly at | |
205 | the beginning of the chunk but might be an empty object exactly | |
e92cc029 | 206 | at the end of an adjacent chunk. */ |
8d08fdba MS |
207 | for (; nlevels != 0 && lp != 0 && ((tree)lp >= obj || (tree)lp->limit < obj); |
208 | nlevels -= 1) | |
209 | { | |
210 | plp = lp->prev; | |
211 | lp = plp; | |
212 | } | |
213 | return nlevels != 0 && lp != 0; | |
214 | } | |
215 | ||
51c184be | 216 | /* from lex.c: */ |
a28e3c7f MS |
217 | /* Value is 1 (or 2) if we should try to make the next identifier look like |
218 | a typename (when it may be a local variable or a class variable). | |
e92cc029 | 219 | Value is 0 if we treat this name in a default fashion. */ |
8d08fdba | 220 | extern int looking_for_typename; |
a0a33927 | 221 | int looking_for_template; |
42976354 | 222 | extern int do_snarf_defarg; |
8d08fdba MS |
223 | |
224 | extern struct obstack *current_obstack, *saveable_obstack; | |
a28e3c7f | 225 | tree got_scope; |
e1cd6e56 | 226 | tree got_object; |
8d08fdba | 227 | |
f30432d7 | 228 | int |
fc378698 | 229 | peekyylex () |
f30432d7 MS |
230 | { |
231 | scan_tokens (0); | |
232 | return nth_token (0)->yychar; | |
233 | } | |
234 | ||
8d08fdba | 235 | int |
fc378698 | 236 | yylex () |
8d08fdba MS |
237 | { |
238 | struct token tmp_token; | |
239 | tree trrr; | |
240 | ||
241 | retry: | |
242 | #ifdef SPEW_DEBUG | |
243 | if (spew_debug) | |
244 | { | |
245 | yylex_ctr ++; | |
fc378698 | 246 | fprintf (stderr, "\t\t## %d ##", yylex_ctr); |
8d08fdba MS |
247 | } |
248 | #endif | |
8d08fdba | 249 | |
42976354 BK |
250 | if (do_snarf_defarg) |
251 | { | |
252 | my_friendly_assert (num_tokens () == 0, 2837); | |
253 | tmp_token.yychar = DEFARG; | |
254 | tmp_token.yylval.ttype = snarf_defarg (); | |
255 | tmp_token.end_of_file = 0; | |
256 | do_snarf_defarg = 0; | |
257 | add_token (&tmp_token); | |
258 | } | |
259 | ||
8d08fdba | 260 | /* if we've got tokens, send them */ |
42976354 | 261 | else if (num_tokens ()) |
8d08fdba | 262 | { |
fc378698 | 263 | tmp_token= *nth_token (0); |
8d08fdba MS |
264 | |
265 | /* TMP_TOKEN.YYLVAL.TTYPE may have been allocated on the wrong obstack. | |
266 | If we don't find it in CURRENT_OBSTACK's current or immediately | |
267 | previous chunk, assume it was and copy it to the current obstack. */ | |
268 | if ((tmp_token.yychar == CONSTANT | |
269 | || tmp_token.yychar == STRING) | |
270 | && ! TREE_PERMANENT (tmp_token.yylval.ttype) | |
271 | && ! probe_obstack (current_obstack, tmp_token.yylval.ttype, 2) | |
272 | && ! probe_obstack (saveable_obstack, tmp_token.yylval.ttype, 2)) | |
273 | tmp_token.yylval.ttype = copy_node (tmp_token.yylval.ttype); | |
274 | } | |
275 | else | |
276 | { | |
277 | /* if not, grab the next one and think about it */ | |
278 | tmp_token.yychar = real_yylex (); | |
279 | tmp_token.yylval = yylval; | |
280 | tmp_token.end_of_file = end_of_file; | |
fc378698 | 281 | add_token (&tmp_token); |
8d08fdba MS |
282 | } |
283 | ||
284 | /* many tokens just need to be returned. At first glance, all we | |
e92cc029 MS |
285 | have to do is send them back up, but some of them are needed to |
286 | figure out local context. */ | |
fc378698 | 287 | switch (tmp_token.yychar) |
8d08fdba MS |
288 | { |
289 | case EMPTY: | |
290 | /* This is a lexical no-op. */ | |
291 | consume_token (); | |
292 | #ifdef SPEW_DEBUG | |
293 | if (spew_debug) | |
294 | debug_yychar (tmp_token.yychar); | |
295 | #endif | |
296 | goto retry; | |
297 | ||
298 | case IDENTIFIER: | |
a28e3c7f MS |
299 | scan_tokens (1); |
300 | if (nth_token (1)->yychar == SCOPE) | |
301 | /* Don't interfere with the setting from an 'aggr' prefix. */ | |
302 | looking_for_typename++; | |
a0a33927 MS |
303 | else if (nth_token (1)->yychar == '<') |
304 | looking_for_template = 1; | |
a28e3c7f | 305 | |
8d08fdba | 306 | trrr = lookup_name (tmp_token.yylval.ttype, -2); |
a28e3c7f | 307 | |
8d08fdba MS |
308 | if (trrr) |
309 | { | |
310 | tmp_token.yychar = identifier_type (trrr); | |
311 | switch (tmp_token.yychar) | |
312 | { | |
313 | case TYPENAME: | |
a80e4195 | 314 | case SELFNAME: |
cf776105 | 315 | case NSNAME: |
5951f637 | 316 | lastiddecl = trrr; |
eb66be0e MS |
317 | if (got_scope) |
318 | tmp_token.yylval.ttype = trrr; | |
8d08fdba | 319 | break; |
cf776105 | 320 | |
386b8a85 | 321 | case PFUNCNAME: |
8d08fdba | 322 | case IDENTIFIER: |
8d08fdba | 323 | case PTYPENAME: |
a9aedbc2 | 324 | lastiddecl = trrr; |
a9aedbc2 | 325 | break; |
cf776105 | 326 | |
8d08fdba MS |
327 | default: |
328 | my_friendly_abort (101); | |
329 | } | |
330 | } | |
331 | else | |
332 | lastiddecl = trrr; | |
7177d104 | 333 | got_scope = NULL_TREE; |
e92cc029 | 334 | /* and fall through to... */ |
e1cd6e56 | 335 | case IDENTIFIER_DEFN: |
8d08fdba | 336 | case TYPENAME: |
e1cd6e56 | 337 | case TYPENAME_DEFN: |
8d08fdba | 338 | case PTYPENAME: |
e1cd6e56 | 339 | case PTYPENAME_DEFN: |
a28e3c7f MS |
340 | consume_token (); |
341 | if (looking_for_typename > 0) | |
342 | looking_for_typename--; | |
a0a33927 | 343 | looking_for_template = 0; |
8d08fdba MS |
344 | break; |
345 | ||
346 | case SCSPEC: | |
9e9ff709 MS |
347 | case NEW: |
348 | /* do_aggr needs to check if the previous token was RID_NEW, | |
349 | so just increment first_token instead of calling consume_token. */ | |
350 | ++first_token; | |
a28e3c7f | 351 | break; |
9e9ff709 | 352 | |
8d08fdba MS |
353 | case TYPESPEC: |
354 | consume_token (); | |
8d08fdba MS |
355 | break; |
356 | ||
8d08fdba | 357 | case AGGR: |
fc378698 | 358 | *nth_token (0) = tmp_token; |
8d08fdba | 359 | do_aggr (); |
e92cc029 | 360 | /* fall through to output... */ |
8d08fdba MS |
361 | case ENUM: |
362 | /* Set this again, in case we are rescanning. */ | |
363 | looking_for_typename = 1; | |
e92cc029 | 364 | /* fall through... */ |
8d08fdba | 365 | default: |
fc378698 | 366 | consume_token (); |
8d08fdba MS |
367 | } |
368 | ||
5566b478 | 369 | got_object = NULL_TREE; |
8d08fdba MS |
370 | yylval = tmp_token.yylval; |
371 | yychar = tmp_token.yychar; | |
372 | end_of_file = tmp_token.end_of_file; | |
373 | #ifdef SPEW_DEBUG | |
374 | if (spew_debug) | |
fc378698 | 375 | debug_yychar (yychar); |
8d08fdba | 376 | #endif |
386b8a85 | 377 | |
8d08fdba MS |
378 | return yychar; |
379 | } | |
380 | ||
381 | /* token[0] == AGGR (struct/union/enum) | |
e92cc029 MS |
382 | Thus, token[1] is either a TYPENAME or a TYPENAME_DEFN. |
383 | If token[2] == '{' or ':' then it's TYPENAME_DEFN. | |
384 | It's also a definition if it's a forward declaration (as in 'struct Foo;') | |
385 | which we can tell if token[2] == ';' *and* token[-1] != FRIEND or NEW. */ | |
386 | ||
8d08fdba MS |
387 | static int |
388 | do_aggr () | |
389 | { | |
390 | int yc1, yc2; | |
391 | ||
392 | scan_tokens (2); | |
393 | yc1 = nth_token (1)->yychar; | |
394 | if (yc1 != TYPENAME && yc1 != IDENTIFIER && yc1 != PTYPENAME) | |
395 | return 0; | |
396 | yc2 = nth_token (2)->yychar; | |
397 | if (yc2 == ';') | |
398 | { | |
9e9ff709 | 399 | /* It's a forward declaration iff we were not preceded by |
e92cc029 | 400 | 'friend' or `new'. */ |
9e9ff709 MS |
401 | if (first_token > 0) |
402 | { | |
403 | if (nth_token (-1)->yychar == SCSPEC | |
404 | && nth_token (-1)->yylval.ttype == ridpointers[(int) RID_FRIEND]) | |
405 | return 0; | |
406 | if (nth_token (-1)->yychar == NEW) | |
407 | return 0; | |
408 | } | |
8d08fdba MS |
409 | } |
410 | else if (yc2 != '{' && yc2 != ':') | |
411 | return 0; | |
412 | ||
413 | switch (yc1) | |
414 | { | |
415 | case TYPENAME: | |
416 | nth_token (1)->yychar = TYPENAME_DEFN; | |
417 | break; | |
418 | case PTYPENAME: | |
419 | nth_token (1)->yychar = PTYPENAME_DEFN; | |
420 | break; | |
421 | case IDENTIFIER: | |
422 | nth_token (1)->yychar = IDENTIFIER_DEFN; | |
423 | break; | |
424 | default: | |
425 | my_friendly_abort (102); | |
426 | } | |
427 | return 0; | |
428 | } | |
8d08fdba MS |
429 | |
430 | #ifdef SPEW_DEBUG | |
e92cc029 MS |
431 | /* debug_yychar takes a yychar (token number) value and prints its name. */ |
432 | ||
8d08fdba MS |
433 | static int |
434 | debug_yychar (yy) | |
435 | int yy; | |
436 | { | |
51c184be | 437 | /* In parse.y: */ |
8d08fdba MS |
438 | extern char *debug_yytranslate (); |
439 | ||
440 | int i; | |
441 | ||
fc378698 | 442 | if (yy<256) { |
8d08fdba MS |
443 | fprintf (stderr, "<%d: %c >\n", yy, yy); |
444 | return 0; | |
445 | } | |
446 | fprintf (stderr, "<%d:%s>\n", yy, debug_yytranslate (yy)); | |
447 | return 1; | |
448 | } | |
449 | ||
450 | #endif |