[project @ 1996-07-19 18:36:04 by partain]
[ghc-hetmet.git] / glafp-utils / etags / jbw-fixes
1 From jbw@bigbird.bu.edu Tue Aug 18 08:07:53 1992
2 From: jbw@bigbird.bu.edu (Joe Wells)
3 Newsgroups: comp.emacs
4 Subject: Re: How do I include symbols defined with #define in TAGS ?
5 Date: 16 Aug 92 23:27:25 GMT
6 Distribution: comp.emacs
7 Organization: Boston University Computer Science Department
8 In-reply-to: podi@ESD.3Com.COM's message of 14 Aug 92 17:53:29 GMT
9
10 In article <podi.713814809@chamundi.NSD.3Com.COM> podi@ESD.3Com.COM (Podibanda Kuruppu) writes:
11
12    Keywords: Symbols defined by #defines in TAGS
13
14    I would greatly appreciate it if someone could tell me if I could
15    include symbols ( defined in .h files with #defines ) in a TAG file.
16
17 Enclosed below is an earlier article with my solution to this.
18
19 -- 
20 Enjoy,
21
22 Joe Wells <jbw@cs.bu.edu>
23 Member of the League for Programming Freedom --- send e-mail for details
24
25 ----------------------------------------------------------------------
26 Date: Sat, 4 Apr 92 00:46:52 -0500
27 From: jbw@bigbird.bu.edu (Joe Wells)
28 Message-Id: <9204040546.AA15208@bigbird.bu.edu>
29 To: bug-gnu-emacs@prep.ai.mit.edu
30 Subject: numerous bug fixes for etags
31
32 Enclosed is a patch with numerous changes for etags.  The following are
33 the changes and bugs fixed:
34
35 1. Improvement: don't waste time calling strncmp (with "struct", "union",
36    "enum", "typedef") if the lengths are different.
37
38 2. Bug: pfnote placed a NUL in the line buffer after the tag token which caused
39    things like `{' or `/*' to be ignored, thus severely screwing up the
40    parser.  Or it did something horrible, I don't remember for sure.
41
42 3. Improvement: record defining occurrences of struct/union/enum tags.
43    This works even if combined with a typedef definition, for example:
44
45      typedef struct XXX {
46        .....
47      } YYY;
48
49 4. Bug: when a tag token was the last item on the line before the newline
50    character, garbage would be seen as the token.  This is because when a
51    NUL was seen in the buffer the buffer was replaced with the next line.
52
53 5. Bug: tag tokens immediately followed by a `{' with no intervening space
54    were not recorded.  This was only a problem because of improvement 3
55    above.
56
57 6. Bug: a newline in the middle of a comment zeroed the `number' variable.
58    (Just for good measure I made it not zero `number' in strings even when
59    the newline is not preceded by `\', in case someone wants to run etags
60    on illegal code :-)  (`number' is used only on lines that begin with
61    `#'.)
62
63 7. Bug: handling of #define lines was severely broken.  I don't actually
64    remember what etags did with them, but it was really bad.  It now
65    records macro definitions.
66
67 8. Bug: when a tag token was the last item on the line except for
68    whitespace, etags would replace the contents of the line buffer and
69    then later do various string comparisons and inspections against
70    garbage values instead of against the token.  Fixing this required
71    copying the token into a buffer.  (This is roughly the same as bug 4
72    above, but in a different function.)
73
74 9. Bug: when a tag token was the last item on the line before the newline
75    (and under various other circumstances), etags would skip over the NUL
76    in the buffer and skip to the first non-whitespace character in the
77    buffer.
78
79 10. Improvement (possibly bug fix): parse typedefs even when we aren't
80     going to print them out.  I seem to remember that this fixed some bug,
81     but I don't remember the specific case that would trigger the bug.
82
83 11. An unfinished attempt to detect and record global variable
84     definitions.
85
86 The changes are to the 18.57 version of etags, but the only change in
87 18.58 to the C code handling is to initialize some variables when starting
88 on a new file, so these changes are orthogonal.
89
90 -- 
91 Enjoy,
92
93 Joe Wells <jbw@cs.bu.edu>
94
95 Member of the League for Programming Freedom --- send e-mail for details
96
97 ----------------------------------------------------------------------
98 --- etags.c-dist        Tue Jan  8 14:08:38 1991
99 +++ etags.c     Sat Apr  4 00:41:22 1992
100 @@ -62,7 +62,10 @@
101  
102  /* cause token checking for typedef, struct, union, enum to distinguish
103     keywords from identifier-prefixes (e.g. struct vs struct_tag).  */
104 -#define istoken(s, tok, len) (!strncmp(s,tok,len) && endtoken(*((s)+(len))))
105 +#define istoken(s, t, len) \
106 +  (((len) == (sizeof (t) -1)) && \
107 +   ((strncmp(s, t, len)) == 0) && \
108 +   (endtoken(*((s)+(len)))))
109  
110  struct nd_st {                 /* sorting structure                    */
111         char    *name;                  /* function or type name        */
112 @@ -505,6 +508,7 @@
113  {
114    register char *fp;
115    register NODE *np;
116 +  char save;
117    char *altname;
118    char tem[51];
119  
120 @@ -538,6 +542,7 @@
121    np->left = np->right = 0;
122    if (eflag)
123      {
124 +      save = linestart[linelen];
125        linestart[linelen] = 0;
126      }
127    else if (xflag == 0)
128 @@ -546,6 +551,7 @@
129        linestart = tem;
130      }
131    np->pat = savestr (linestart);
132 +  linestart[linelen] = save;
133    if (head == NULL)
134      head = np;
135    else
136 @@ -725,6 +731,17 @@
137    number = 0; \
138  }
139  
140 +/* These two are part of a never-finished attempt to record global */
141 +/* variable definitions.  This is nearly impossible in C without the full */
142 +/* power of a C compiler due to C's stupid grammar. */
143 +logical infunc;
144 +int idents_in_decl;
145 +
146 +/* indicates whether the next token (if any) is the tag corresponding to */
147 +/* `struct', `union', or `enum' */
148 +logical next_token_is_tag;
149 +
150 +
151  C_entries ()
152  {
153    register int c;
154 @@ -731,6 +748,15 @@
155    register char *token, *tp, *lp;
156    logical incomm, inquote, inchar, midtoken;
157    int level;
158 +
159 +  /* there are certain things that must be done when the end of line is */
160 +  /* encountered, but they must be delayed until after other things are */
161 +  /* done. */
162 +  logical new_line_flag;
163 +
164 +  /* same as new_line_flag for left braces. */
165 +  logical left_brace_flag;
166 +
167    char tok[BUFSIZ];
168  
169    lineno = 0;
170 @@ -739,17 +765,22 @@
171    *lp = 0;
172  
173    number = 0;
174 -  gotone = midtoken = inquote = inchar = incomm = FALSE;
175 +  gotone = midtoken = inquote = inchar = incomm = infunc = FALSE;
176 +  new_line_flag = FALSE;
177 +  left_brace_flag = FALSE;
178    level = 0;
179 +  idents_in_decl = 0;
180 +  next_token_is_tag = FALSE;
181  
182    while (!feof (inf))
183      {
184        c = *lp++;
185        if (c == 0)
186 -       {
187 -         CNL;
188 -         gotone = FALSE;
189 -       }
190 +       new_line_flag = TRUE;
191 +#ifdef DEBUG
192 +      if (next_token_is_tag)
193 +       fprintf (stderr, "E: c: [%c], lp[-2]: [%c]\n", c, lp[-2]);
194 +#endif /* DEBUG */
195        if (c == '\\')
196         {
197           c = *lp++;
198 @@ -756,15 +787,18 @@
199           if (c == 0)
200             CNL_SAVE_NUMBER;
201           c = ' ';
202 +         /* is this correct?  I thought escaped newlines disappeared even */
203 +         /* before the token breaker got to see things. */ 
204         } 
205        else if (incomm)
206         {
207 +         new_line_flag = FALSE;
208           if (c == '*')
209             {
210               while ((c = *lp++) == '*')
211                 continue;
212               if (c == 0)
213 -               CNL;
214 +               CNL_SAVE_NUMBER;
215               if (c == '/')
216                 incomm = FALSE;
217             }
218 @@ -771,6 +805,7 @@
219         }
220        else if (inquote)
221         {
222 +         new_line_flag = FALSE;
223           /*
224           * Too dumb to know about \" not being magic, but
225           * they usually occur in pairs anyway.
226 @@ -781,6 +816,7 @@
227         }
228        else if (inchar)
229         {
230 +         new_line_flag = FALSE;
231           if (c == '\'')
232             inchar = FALSE;
233           continue;
234 @@ -809,8 +845,8 @@
235             {
236               tydef=middle;
237             }
238 -         level++;
239 -         continue;
240 +         left_brace_flag = TRUE;
241 +         break;
242         case '}':
243           if (lp == lb.buffer + 1)
244             level = 0;  /* reset */
245 @@ -820,8 +856,17 @@
246             {
247               tydef=end;
248             }
249 +         if (level == 0 && infunc)
250 +           {
251 +             idents_in_decl = 0;
252 +             infunc = FALSE;
253 +           }
254           continue;
255         }
256 +#ifdef DEBUG
257 +      if (next_token_is_tag)
258 +       fprintf (stderr, "D: c: [%c], lp[-2]: [%c]\n", c, lp[-2]);
259 +#endif /* DEBUG */
260        if (!level && !inquote && !incomm && gotone == FALSE)
261         {
262           if (midtoken)
263 @@ -852,6 +897,11 @@
264                                    tp-token+1);
265                           tok[tp-token+1] = 0;
266                           pfnote(tok, f, lb1.buffer, endpos, line, linestart);
267 +#ifdef DEBUG
268 +                         fprintf (stderr,
269 +                                "f: %d, infunc %d, tok: %s\nlb1.buffer: %s\n",
270 +                                  f, infunc, tok, lb1.buffer);
271 +#endif /* DEBUG */
272                         }
273                       else
274                         {
275 @@ -858,8 +908,15 @@
276                           strncpy (tok, token, tp-token+1);
277                           tok[tp-token+1] = 0;
278                           pfnote(tok, f, lb.buffer, endpos, line, linestart);
279 +#ifdef DEBUG
280 +                         fprintf (stderr,
281 +                                "f: %d, infunc %d, tok: %s\nlb.buffer:  %s\n",
282 +                                  f, infunc, tok, lb.buffer);
283 +#endif /* DEBUG */
284                         }
285                       gotone = f;       /* function */
286 +                     if (f)
287 +                       infunc = TRUE;
288                     }
289                   midtoken = FALSE;
290                   token = lp - 1;
291 @@ -873,8 +930,32 @@
292               midtoken = TRUE;
293             }
294         }
295 +#ifdef DEBUG
296 +      if (next_token_is_tag)
297 +       fprintf (stderr, "F: c: [%c], lp[-2]: [%c]\n", c, lp[-2]);
298 +#endif /* DEBUG */
299 +      if (left_brace_flag)
300 +       {
301 +         left_brace_flag = FALSE;
302 +         next_token_is_tag = FALSE;
303 +         level++;
304 +       }
305 +      if (new_line_flag)
306 +       {
307 +         new_line_flag = FALSE;
308 +         number = 0;
309 +         gotone = FALSE;
310 +       }
311 +      if (lp > lb.buffer && lp[-1] == 0)
312 +       CNL_SAVE_NUMBER;
313        if (c == ';'  &&  tydef==end)    /* clean with typedefs */
314         tydef=none;
315 +      if (c == ';' && level == 0 && !infunc)
316 +       idents_in_decl = 0;
317 +#ifdef DEBUG
318 +      if (next_token_is_tag)
319 +       fprintf (stderr, "G: c: [%c], lp[-2]: [%c]\n", c, lp[-2]);
320 +#endif /* DEBUG */
321      }
322  }
323  
324 @@ -891,70 +972,176 @@
325    reg char *lp = *lpp;
326    reg char c;
327    static logical next_token_is_func;
328 +
329 +  /* indicates that the next token will be a macro defined with #define */
330 +  static logical next_token_is_macro;
331 +
332    logical firsttok;    /* T if have seen first token in ()'s */
333 -  int bad, win;
334 +  int bad = FALSE, win = FALSE;
335 +  int length = (lp - 1) - token;
336 +  
337 +  /* used to keep a copy of the token when we have to fill the line buffer */
338 +  /* with the contents of the next line */
339 +  static char *tok_buffer = NULL;
340 +  static long tok_buffer_size = 0;
341  
342    *f = 1;                      /* a function */
343    c = lp[-1];
344 -  bad = FALSE;
345    if (!number)
346      {          /* space is not allowed in macro defs   */
347 -      while (iswhite(c))
348 +      while ((c == 0) || iswhite(c))
349         {
350 -         c = *lp++;
351 -         if (c == 0)
352 +#ifdef DEBUG
353 +         if (next_token_is_tag)
354 +           fprintf (stderr, "C: token: %s, c: [%c], lp - token: %d\n",
355 +                    token, c, lp - token);
356 +#endif /* DEBUG */
357 +         while (c == 0)
358             {
359               if (feof (inf))
360 -               break;
361 +               goto break_while_1;
362 +             if (token != tok_buffer)
363 +               {
364 +                 if (length + 1 > tok_buffer_size)
365 +                   if (tok_buffer_size == 0)
366 +                     {
367 +                       tok_buffer_size = length + 1;
368 +                       tok_buffer = (char *) xmalloc (tok_buffer_size);
369 +                     }
370 +                   else
371 +                     {
372 +                       tok_buffer_size = length + 1;
373 +                       tok_buffer =
374 +                         (char *) xrealloc (tok_buffer, tok_buffer_size);
375 +                     }
376 +                 strncpy (tok_buffer, token, length);
377 +                 tok_buffer[length] = '\0';
378 +                 token = tok_buffer;
379 +               }
380               CNL;
381 +             c = *lp++;
382             }
383 +         while ((c != 0) && iswhite(c))
384 +           c = *lp++;
385         }
386 -      /* the following tries to make it so that a #define a b(c)       */
387 -      /* doesn't count as a define of b.                               */
388 +    break_while_1:
389 +      ;
390      }
391    else
392      {
393 +      /* the following tries to make it so that a #define a b(c)       */
394 +      /* doesn't count as a define of b.                               */
395        number++;
396 -      if (number >= 4  || (number==2 && strncmp (token, "define", 6)))
397 -       {
398 -         gotone = TRUE;
399 -       badone:
400 +#ifdef DEBUG
401 +      fprintf (stderr, "number: %d, n_t_i_m: %d, token: %s\n",
402 +              number, next_token_is_macro, token);
403 +#endif /* DEBUG */
404 +      if (number == 2 && strncmp (token, "define", 6) == 0)
405 +       next_token_is_macro = TRUE;
406 +      else if (number == 3 && next_token_is_macro)
407 +       {
408 +         next_token_is_macro = FALSE;
409 +         while ((c != 0) && iswhite(c))
410 +           {
411 +#ifdef DEBUG
412 +             fprintf (stderr, "c: %c, %d\n", c, c);
413 +#endif /* DEBUG */
414 +             c = *lp++;
415 +           }
416 +#ifdef DEBUG
417 +         fprintf (stderr, "c: %c, %d\n", c, c);
418 +#endif /* DEBUG */
419 +         if (c == 0)           /* ignore plain "#define FLAG" */
420           bad = TRUE;
421 +         else
422 +           win = TRUE;
423 +         /* speed up skipping the rest of this line */
424 +         gotone = TRUE;
425 +         /* never treat a macro as a function, because it doesn't have a */
426 +         /* function body, which is what "f" really stands for (now). */
427 +         *f = FALSE;
428           goto ret;
429         }
430 +      else
431 +       /* speed up skipping the rest of this line */
432 +       gotone = TRUE;
433 +      goto badone;
434      }
435 +  idents_in_decl ++;
436 +#ifdef DEBUG
437 +  fprintf (stderr,
438 +          "A: iid: %d, tydef: %d, ntit: %d, ntif: %d, c: %c, token: %.*s\n",
439 +          idents_in_decl, tydef, next_token_is_tag, next_token_is_func, c,
440 +          length + 5, token);
441 +#endif /* DEBUG */
442    /* check for the typedef cases               */
443 -  if (tflag && istoken(token, "typedef", 7))
444 +  if (istoken (token, "typedef", length))
445      {
446        tydef=begin;
447        goto badone;
448      }
449 -  if (tydef==begin && (istoken(token, "struct", 6) ||
450 -                      istoken(token, "union", 5) || istoken(token, "enum", 4)))
451 -  {
452 +#ifdef DEBUG
453 +  fprintf (stderr, "D\n");
454 +#endif /* DEBUG */
455 +  if (istoken (token, "struct", length) ||
456 +      istoken (token, "union", length) ||
457 +      istoken (token, "enum", length))
458 +    {
459 +      next_token_is_tag = 1;
460 +#ifdef DEBUG
461 +      fprintf (stderr, "A: token: %s\n", token);
462 +#endif /* DEBUG */
463 +      if (tydef == begin)
464      tydef=tag_ok;      
465      goto badone;
466    }
467 -  if (tydef==tag_ok)
468 +  else if (next_token_is_tag)
469      {
470 +#ifdef DEBUG
471 +      fprintf (stderr, "B: token: %s, c: [%c]\n", token, c);
472 +#endif /* DEBUG */
473 +      if (tydef==tag_ok)
474        tydef=middle;
475 -      goto badone;
476 +      next_token_is_tag = 0;
477 +      *f = 0;
478 +      /* only notice when a tag is being defined, not when it is merely */
479 +      /* being used. */
480 +      if (c == '{')
481 +       win = TRUE;
482 +      else
483 +       bad = TRUE;
484 +      goto ret;
485      }
486 +#ifdef DEBUG
487 +  fprintf (stderr, "E\n");
488 +#endif /* DEBUG */
489    if (tydef==begin)            /* e.g. typedef ->int<- */
490      {
491        tydef=end;
492        goto badone;
493      }
494 +#ifdef DEBUG
495 +  fprintf (stderr, "F\n");
496 +#endif /* DEBUG */
497    if (tydef==middle && level == 0) /* e.g. typedef struct tag ->struct_t<- */
498      {
499        tydef=end;
500      }
501 +#ifdef DEBUG
502 +  fprintf (stderr, "G\n");
503 +#endif /* DEBUG */
504    if (tydef==end)
505      {
506        *f = 0;
507 -      win = 1;
508 +#ifdef DEBUG
509 +      fprintf (stderr, "C token: %s\n", token);
510 +#endif /* DEBUG */
511 +      win = tflag;
512        goto ret;
513      }
514 +#ifdef DEBUG
515 +  fprintf (stderr, "H\n");
516 +#endif /* DEBUG */
517    /* Detect GNUmacs's function-defining macros. */
518    if (!number && !strncmp (token, "DEF", 3))
519          
520 @@ -962,6 +1149,9 @@
521        next_token_is_func = 1;
522        goto badone;
523      }
524 +#ifdef DEBUG
525 +  fprintf (stderr, "I\n");
526 +#endif /* DEBUG */
527    if (next_token_is_func)
528      {
529        next_token_is_func = 0;
530 @@ -968,9 +1158,15 @@
531        win = 1;
532        goto ret;
533      }
534 +#ifdef DEBUG
535 +  fprintf (stderr, "J\n");
536 +#endif /* DEBUG */
537    if (c != '(')
538      goto badone;
539    firsttok = FALSE;
540 +#ifdef DEBUG
541 +  fprintf (stderr, "K\n");
542 +#endif /* DEBUG */
543    while ((c = *lp++) != ')')
544      {
545        if (c == 0)
546 @@ -999,9 +1195,20 @@
547         }
548      }
549    win = isgood (c);
550 +  
551  ret:
552 +#ifdef DEBUG
553 +  fprintf (stderr,
554 +          "B: iid: %d, tydef: %d, ntit: %d, ntif: %d, c: %c, token: %.*s\n",
555 +          idents_in_decl, tydef, next_token_is_tag, next_token_is_func, c,
556 +          length + 5, token);
557 +#endif /* DEBUG */
558    *lpp = lp - 1;
559    return !bad && win;
560 +
561 + badone:
562 +  bad = TRUE;
563 +  goto ret;
564  }
565  
566  getline (atchar)
567 ----------------------------------------------------------------------
568