|
|
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.