source: trunk/third/gcc/cp/spew.c @ 8834

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