|
|
1.1 root 1: /* Type Analyzer for GNU C++.
2: Copyright (C) 1987, 1989, 1992, 1993 Free Software Foundation, Inc.
3: Hacked... nay, bludgeoned... by Mark Eichin ([email protected])
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
23: when compiling parse.c and spew.c. */
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 ();
48:
49: /* From lex.c: */
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:
69: /* Initialize token_obstack. Called once, from init_lex. */
70: void
71: init_spew ()
72: {
73: gcc_obstack_init(&token_obstack);
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:
137: /* Pull in enough tokens from real_yylex that the queue is N long beyond
138: the current token. */
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. */
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));
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:
236: /* from lex.c: */
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. */
240: extern int looking_for_typename;
241: int looking_for_template;
242:
243: extern struct obstack *current_obstack, *saveable_obstack;
244: tree got_scope;
245:
246: int
247: yylex()
248: {
249: struct token tmp_token;
250: tree trrr;
251:
252: retry:
253: #ifdef SPEW_DEBUG
254: if (spew_debug)
255: {
256: yylex_ctr ++;
257: fprintf(stderr, "\t\t## %d ##",yylex_ctr);
258: }
259: #endif
260:
261: /* if we've got tokens, send them */
262: if (num_tokens())
263: {
264: tmp_token= *nth_token(0);
265:
266: /* TMP_TOKEN.YYLVAL.TTYPE may have been allocated on the wrong obstack.
267: If we don't find it in CURRENT_OBSTACK's current or immediately
268: previous chunk, assume it was and copy it to the current obstack. */
269: if ((tmp_token.yychar == CONSTANT
270: || tmp_token.yychar == STRING)
271: && ! TREE_PERMANENT (tmp_token.yylval.ttype)
272: && ! probe_obstack (current_obstack, tmp_token.yylval.ttype, 2)
273: && ! probe_obstack (saveable_obstack, tmp_token.yylval.ttype, 2))
274: tmp_token.yylval.ttype = copy_node (tmp_token.yylval.ttype);
275: }
276: else
277: {
278: /* if not, grab the next one and think about it */
279: tmp_token.yychar = real_yylex ();
280: tmp_token.yylval = yylval;
281: tmp_token.end_of_file = end_of_file;
282: add_token(&tmp_token);
283: }
284:
285: /* many tokens just need to be returned. At first glance, all we
286: * have to do is send them back up, but some of them are needed to
287: * figure out local context. */
288: switch(tmp_token.yychar)
289: {
290: case EMPTY:
291: /* This is a lexical no-op. */
292: consume_token ();
293: #ifdef SPEW_DEBUG
294: if (spew_debug)
295: debug_yychar (tmp_token.yychar);
296: #endif
297: goto retry;
298:
299: case IDENTIFIER:
300: scan_tokens (1);
301: if (nth_token (1)->yychar == SCOPE)
302: /* Don't interfere with the setting from an 'aggr' prefix. */
303: looking_for_typename++;
304: else if (nth_token (1)->yychar == '<')
305: looking_for_template = 1;
306:
307: trrr = lookup_name (tmp_token.yylval.ttype, -2);
308:
309: if (trrr)
310: {
311: tmp_token.yychar = identifier_type (trrr);
312: switch (tmp_token.yychar)
313: {
314: case TYPENAME:
315: lastiddecl = identifier_typedecl_value (tmp_token.yylval.ttype);
316: if (lastiddecl != trrr)
317: {
318: lastiddecl = trrr;
319: if (got_scope)
320: tmp_token.yylval.ttype = DECL_NESTED_TYPENAME (trrr);
321: }
322: break;
323: case IDENTIFIER:
324: lastiddecl = trrr;
325: break;
326: case PTYPENAME:
327: lastiddecl = NULL_TREE;
328: break;
329: default:
330: my_friendly_abort (101);
331: }
332: }
333: else
334: lastiddecl = trrr;
335: got_scope = NULL_TREE;
336: /* and fall through to... */
337: case TYPENAME:
338: case PTYPENAME:
339: consume_token ();
340: if (looking_for_typename > 0)
341: looking_for_typename--;
342: looking_for_template = 0;
343: break;
344:
345: case SCSPEC:
346: /* do_aggr needs to check if the previous token was RID_FRIEND,
347: so just increment first_token instead of calling consume_token. */
348: first_token++;
349: break;
350: case TYPESPEC:
351: consume_token ();
352: break;
353:
354: case AGGR:
355: *nth_token(0) = tmp_token;
356: do_aggr ();
357: /* fall through to output... */
358: case ENUM:
359: /* Set this again, in case we are rescanning. */
360: looking_for_typename = 1;
361: /* fall through... */
362: default:
363: consume_token();
364: }
365:
366: yylval = tmp_token.yylval;
367: yychar = tmp_token.yychar;
368: end_of_file = tmp_token.end_of_file;
369: #ifdef SPEW_DEBUG
370: if (spew_debug)
371: debug_yychar(yychar);
372: #endif
373: return yychar;
374: }
375:
376: /* token[0] == AGGR (struct/union/enum)
377: * Thus, token[1] is either a TYPENAME or a TYPENAME_DEFN.
378: * If token[2] == '{' or ':' then it's TYPENAME_DEFN.
379: * It's also a definition if it's a forward declaration (as in 'struct Foo;')
380: * which we can tell lf token[2] == ';' *and* token[-1] != FRIEND.
381: */
382: static int
383: do_aggr ()
384: {
385: int yc1, yc2;
386:
387: scan_tokens (2);
388: yc1 = nth_token (1)->yychar;
389: if (yc1 != TYPENAME && yc1 != IDENTIFIER && yc1 != PTYPENAME)
390: return 0;
391: yc2 = nth_token (2)->yychar;
392: if (yc2 == ';')
393: {
394: /* It's a forward declaration iff we were not preceded by 'friend'. */
395: if (first_token > 0 && nth_token (-1)->yychar == SCSPEC
396: && nth_token (-1)->yylval.ttype == ridpointers[(int) RID_FRIEND])
397: return 0;
398: }
399: else if (yc2 != '{' && yc2 != ':')
400: return 0;
401:
402: switch (yc1)
403: {
404: case TYPENAME:
405: nth_token (1)->yychar = TYPENAME_DEFN;
406: break;
407: case PTYPENAME:
408: nth_token (1)->yychar = PTYPENAME_DEFN;
409: break;
410: case IDENTIFIER:
411: nth_token (1)->yychar = IDENTIFIER_DEFN;
412: break;
413: default:
414: my_friendly_abort (102);
415: }
416: return 0;
417: }
418:
419: #ifdef SPEW_DEBUG
420: /* debug_yychar takes a yychar (token number) value and prints its name. */
421: static int
422: debug_yychar (yy)
423: int yy;
424: {
425: /* In parse.y: */
426: extern char *debug_yytranslate ();
427:
428: int i;
429:
430: if(yy<256) {
431: fprintf (stderr, "<%d: %c >\n", yy, yy);
432: return 0;
433: }
434: fprintf (stderr, "<%d:%s>\n", yy, debug_yytranslate (yy));
435: return 1;
436: }
437:
438: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.