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