1 /* ebrowse.c --- parsing files for the ebrowse C++ browser
2 
3 Copyright (C) 1992-2021 Free Software Foundation, Inc.
4 
5 This file is part of GNU Emacs.
6 
7 GNU Emacs 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 3 of the License, or (at
10 your option) any later version.
11 
12 GNU Emacs 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 Emacs.  If not, see <https://www.gnu.org/licenses/>.  */
19 
20 
21 #include <config.h>
22 #include <stddef.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <ctype.h>
26 #include <assert.h>
27 #include <getopt.h>
28 
29 #include <flexmember.h>
30 #include <min-max.h>
31 #include <unlocked-io.h>
32 
33 /* The SunOS compiler doesn't have SEEK_END.  */
34 #ifndef SEEK_END
35 #define SEEK_END 2
36 #endif
37 
38 /* Files are read in chunks of this number of bytes.  */
39 
40 enum { READ_CHUNK_SIZE = 100 * 1024 };
41 
42 /* Value is true if strings X and Y compare equal.  */
43 
44 static bool
streq(char const * x,char const * y)45 streq (char const *x, char const *y)
46 {
47   return strcmp (x, y) == 0;
48 }
49 
50 static bool
filename_eq(char const * x,char const * y)51 filename_eq (char const *x, char const *y)
52 {
53 #ifdef __MSDOS__
54   return strcasecmp (x, y) == 0;
55 #elif defined WINDOWSNT
56   return stricmp (x, y) == 0;
57 #else
58   return streq (x, y);
59 #endif
60 }
61 
62 /* The default output file name.  */
63 
64 #define DEFAULT_OUTFILE "BROWSE"
65 
66 /* A version string written to the output file.  Change this whenever
67    the structure of the output file changes.  */
68 
69 #define EBROWSE_FILE_VERSION "ebrowse 5.0"
70 
71 /* The output file consists of a tree of Lisp objects, with major
72    nodes built out of Lisp structures.  These are the heads of the
73    Lisp structs with symbols identifying their type.  */
74 
75 #define TREE_HEADER_STRUCT	"[ebrowse-hs "
76 #define TREE_STRUCT		"[ebrowse-ts "
77 #define MEMBER_STRUCT		"[ebrowse-ms "
78 #define CLASS_STRUCT		"[ebrowse-cs "
79 
80 /* The name of the symbol table entry for global functions, variables,
81    defines etc.  This name also appears in the browser display.  */
82 
83 #define GLOBALS_NAME "*Globals*"
84 
85 /* Token definitions.  */
86 
87 enum token
88 {
89   YYEOF = 0,			/* end of file */
90   CSTRING = 256,		/* string constant */
91   CCHAR,			/* character constant */
92   CINT,				/* integral constant */
93   CFLOAT,			/* real constant */
94 
95   ELLIPSIS,			/* ... */
96   LSHIFTASGN,			/* <<= */
97   RSHIFTASGN,			/* >>= */
98   ARROWSTAR,			/* ->* */
99   IDENT,			/* identifier */
100   DIVASGN,			/* /= */
101   INC,				/* ++ */
102   ADDASGN,			/* += */
103   DEC,				/* -- */
104   ARROW,			/* -> */
105   SUBASGN,			/* -= */
106   MULASGN,			/* *= */
107   MODASGN,			/* %= */
108   LOR,				/* || */
109   ORASGN,			/* |= */
110   LAND,				/* && */
111   ANDASGN,			/* &= */
112   XORASGN,			/* ^= */
113   POINTSTAR,			/* .* */
114   DCOLON,			/* :: */
115   EQ,				/* == */
116   NE,				/* != */
117   LE,				/* <= */
118   LSHIFT,			/* << */
119   GE,				/* >= */
120   RSHIFT,			/* >> */
121 
122 /* Keywords.  The undef's are there because these
123    three symbols are very likely to be defined somewhere.  */
124 #undef BOOL
125 #undef TRUE
126 #undef FALSE
127 
128   ASM,				/* asm */
129   AUTO,				/* auto */
130   BREAK,			/* break */
131   CASE,				/* case  */
132   CATCH,			/* catch */
133   CHAR,				/* char */
134   CLASS,			/* class */
135   CONST,			/* const */
136   CONTINUE,			/* continue */
137   DEFAULT,			/* default */
138   DELETE,			/* delete */
139   DO,				/* do */
140   DOUBLE,			/* double */
141   ELSE,				/* else */
142   ENUM,				/* enum */
143   EXTERN,			/* extern */
144   FLOAT,			/* float */
145   FOR,				/* for */
146   FRIEND,			/* friend */
147   GOTO,				/* goto */
148   IF,				/* if */
149   T_INLINE,			/* inline */
150   INT,				/* int */
151   LONG,				/* long */
152   NEW,				/* new */
153   OPERATOR,			/* operator */
154   PRIVATE,			/* private */
155   PROTECTED,			/* protected */
156   PUBLIC,			/* public */
157   REGISTER,			/* register */
158   RETURN,			/* return */
159   SHORT,			/* short */
160   SIGNED,			/* signed */
161   SIZEOF,			/* sizeof */
162   STATIC,			/* static */
163   STRUCT,			/* struct */
164   SWITCH,			/* switch */
165   TEMPLATE,			/* template */
166   THIS,				/* this */
167   THROW,			/* throw */
168   TRY,				/* try */
169   TYPEDEF,			/* typedef */
170   UNION,			/* union */
171   UNSIGNED,			/* unsigned */
172   VIRTUAL,			/* virtual */
173   VOID,				/* void */
174   VOLATILE,			/* volatile */
175   WHILE,			/* while */
176   MUTABLE,			/* mutable */
177   BOOL,				/* bool */
178   TRUE,				/* true */
179   FALSE,			/* false */
180   SIGNATURE,			/* signature (GNU extension) */
181   NAMESPACE,			/* namespace */
182   EXPLICIT,			/* explicit */
183   TYPENAME,			/* typename */
184   CONST_CAST,			/* const_cast */
185   DYNAMIC_CAST,			/* dynamic_cast */
186   REINTERPRET_CAST,		/* reinterpret_cast */
187   STATIC_CAST,			/* static_cast */
188   TYPEID,			/* typeid */
189   USING,			/* using */
190   WCHAR,			/* wchar_t */
191   FINAL                         /* final */
192 };
193 
194 /* Storage classes, in a wider sense.  */
195 
196 enum sc
197 {
198   SC_UNKNOWN,
199   SC_MEMBER,			/* Is an instance member.  */
200   SC_STATIC,			/* Is static member.  */
201   SC_FRIEND,			/* Is friend function.  */
202   SC_TYPE			/* Is a type definition.  */
203 };
204 
205 /* Member visibility.  */
206 
207 enum visibility
208 {
209   V_PUBLIC,
210   V_PROTECTED,
211   V_PRIVATE
212 };
213 
214 /* Member flags.  */
215 
216 #define F_VIRTUAL	1	/* Is virtual function.  */
217 #define F_INLINE	2	/* Is inline function.  */
218 #define F_CONST		4	/* Is const.  */
219 #define F_PURE		8	/* Is pure virtual function.  */
220 #define F_MUTABLE	16	/* Is mutable.  */
221 #define F_TEMPLATE	32	/* Is a template.  */
222 #define F_EXPLICIT	64	/* Is explicit constructor.  */
223 #define F_THROW		128	/* Has a throw specification.  */
224 #define F_EXTERNC	256	/* Is declared extern "C".  */
225 #define F_DEFINE	512	/* Is a #define.  */
226 
227 /* Set and test a bit in an int.  */
228 
229 static void
set_flag(int * f,int flag)230 set_flag (int *f, int flag)
231 {
232   *f |= flag;
233 }
234 
235 static bool
has_flag(int f,int flag)236 has_flag (int f, int flag)
237 {
238   return (f & flag) != 0;
239 }
240 
241 /* Structure describing a class member.  */
242 
243 struct member
244 {
245   struct member *next;		/* Next in list of members.  */
246   struct member *anext;		/* Collision chain in member_table.  */
247   struct member **list;		/* Pointer to list in class.  */
248   unsigned param_hash;		/* Hash value for parameter types.  */
249   int vis;			/* Visibility (public, ...).  */
250   int flags;			/* See F_* above.  */
251   char *regexp;			/* Matching regular expression.  */
252   const char *filename;		/* Don't free this shared string.  */
253   int pos;			/* Buffer position of occurrence.  */
254   char *def_regexp;		/* Regular expression matching definition.  */
255   const char *def_filename;	/* File name of definition.  */
256   int def_pos;			/* Buffer position of definition.  */
257   char name[FLEXIBLE_ARRAY_MEMBER]; /* Member name.  */
258 };
259 
260 /* Structures of this type are used to connect class structures with
261    their super and subclasses.  */
262 
263 struct link
264 {
265   struct sym *sym;		/* The super or subclass.  */
266   struct link *next;		/* Next in list or NULL.  */
267 };
268 
269 /* Structure used to record namespace aliases.  */
270 
271 struct alias
272 {
273   struct alias *next;		/* Next in list.  */
274   struct sym *namesp;		/* Namespace in which defined.  */
275   struct link *aliasee;		/* List of aliased namespaces (A::B::C...).  */
276   char name[FLEXIBLE_ARRAY_MEMBER]; /* Alias name.  */
277 };
278 
279 /* The structure used to describe a class in the symbol table,
280    or a namespace in all_namespaces.  */
281 
282 struct sym
283 {
284   int flags;			/* Is class a template class?.  */
285   unsigned char visited;	/* Used to find circles.  */
286   struct sym *next;             /* Hash collision list.  */
287   struct link *subs;		/* List of subclasses.  */
288   struct link *supers;		/* List of superclasses.  */
289   struct member *vars;		/* List of instance variables.  */
290   struct member *fns;		/* List of instance functions.  */
291   struct member *static_vars;	/* List of static variables.  */
292   struct member *static_fns;	/* List of static functions.  */
293   struct member *friends;	/* List of friend functions.  */
294   struct member *types;		/* List of local types.  */
295   char *regexp;			/* Matching regular expression.  */
296   int pos;			/* Buffer position.  */
297   const char *filename;		/* File in which it can be found.  */
298   const char *sfilename; 	/* File in which members can be found.  */
299   struct sym *namesp;		/* Namespace in which defined. .  */
300   char name[FLEXIBLE_ARRAY_MEMBER]; /* Name of the class.  */
301 };
302 
303 /* Experimental: Print info for `--position-info'.  We print
304    '(CLASS-NAME SCOPE MEMBER-NAME).  */
305 
306 #define P_DEFN	1
307 #define P_DECL  2
308 
309 static int info_where;
310 static struct sym *info_cls = NULL;
311 static struct member *info_member = NULL;
312 
313 /* Experimental.  For option `--position-info', the buffer position we
314    are interested in.  When this position is reached, print out
315    information about what we know about that point.  */
316 
317 static int info_position = -1;
318 
319 /* Command line options structure for getopt_long.  */
320 
321 static struct option const options[] =
322 {
323   {"append", 			no_argument, 	   NULL, 'a'},
324   {"files", 			required_argument, NULL, 'f'},
325   {"help", 			no_argument, 	   NULL, -2},
326   {"min-regexp-length", 	required_argument, NULL, 'm'},
327   {"max-regexp-length", 	required_argument, NULL, 'M'},
328   {"no-nested-classes", 	no_argument, 	   NULL, 'n'},
329   {"no-regexps", 		no_argument, 	   NULL, 'x'},
330   {"no-structs-or-unions", 	no_argument, 	   NULL, 's'},
331   {"output-file", 		required_argument, NULL, 'o'},
332   {"position-info", 		required_argument, NULL, 'p'},
333   {"search-path", 		required_argument, NULL, 'I'},
334   {"verbose", 			no_argument, 	   NULL, 'v'},
335   {"version", 			no_argument, 	   NULL, -3},
336   {"very-verbose", 		no_argument, 	   NULL, 'V'},
337   {NULL, 			0, 		   NULL, 0}
338 };
339 
340 /* Semantic values of tokens.  Set by yylex..  */
341 
342 static unsigned yyival;		/* Set for token CINT.  */
343 static char *yytext;		/* Set for token IDENT.  */
344 static char *yytext_end;
345 
346 /* Output file.  */
347 
348 static FILE *yyout;
349 
350 /* Current line number.  */
351 
352 static int yyline;
353 
354 /* The name of the current input file.  */
355 
356 static const char *filename;
357 
358 /* Three character class vectors, and macros to test membership
359    of characters.  */
360 
361 static char is_ident[255];
362 static char is_digit[255];
363 static char is_white[255];
364 
365 #define IDENTP(C)	is_ident[(unsigned char) (C)]
366 #define DIGITP(C)	is_digit[(unsigned char) (C)]
367 #define WHITEP(C)	is_white[(unsigned char) (C)]
368 
369 /* Command line flags.  */
370 
371 static int f_append;
372 static int f_verbose;
373 static int f_very_verbose;
374 static int f_structs = 1;
375 static int f_regexps = 1;
376 static int f_nested_classes = 1;
377 
378 /* Maximum and minimum lengths of regular expressions matching a
379    member, class etc., for writing them to the output file.  These are
380    overridable from the command line.  */
381 
382 static int min_regexp = 5;
383 static int max_regexp = 50;
384 
385 /* Input buffer.  */
386 
387 static char *inbuffer;
388 static char *in;
389 static size_t inbuffer_size;
390 
391 /* Return the current buffer position in the input file.  */
392 
393 #define BUFFER_POS() (in - inbuffer)
394 
395 /* If current lookahead is CSTRING, the following points to the
396    first character in the string constant.  Used for recognizing
397    extern "C".  */
398 
399 static char *string_start;
400 
401 /* The size of the hash tables for classes.and members.  Should be
402    prime.  */
403 
404 #define TABLE_SIZE 1001
405 
406 /* The hash table for class symbols.  */
407 
408 static struct sym *class_table[TABLE_SIZE];
409 
410 /* Hash table containing all member structures.  This is generally
411    faster for member lookup than traversing the member lists of a
412    `struct sym'.  */
413 
414 static struct member *member_table[TABLE_SIZE];
415 
416 /* Hash table for namespace aliases */
417 
418 static struct alias *namespace_alias_table[TABLE_SIZE];
419 
420 /* The special class symbol used to hold global functions,
421    variables etc.  */
422 
423 static struct sym *global_symbols;
424 
425 /* The current namespace.  */
426 
427 static struct sym *current_namespace;
428 
429 /* The list of all known namespaces.  */
430 
431 static struct sym *all_namespaces;
432 
433 /* Stack of namespaces we're currently nested in, during the parse.  */
434 
435 static struct sym **namespace_stack;
436 static int namespace_stack_size;
437 static int namespace_sp;
438 
439 /* The current lookahead token.  */
440 
441 static int tk = -1;
442 
443 /* Structure describing a keyword.  */
444 
445 struct kw
446 {
447   const char *name;		/* Spelling.  */
448   int tk;			/* Token value.  */
449   struct kw *next;		/* Next in collision chain.  */
450 };
451 
452 /* Keywords are lookup up in a hash table of their own.  */
453 
454 #define KEYWORD_TABLE_SIZE 1001
455 static struct kw *keyword_table[KEYWORD_TABLE_SIZE];
456 
457 /* Search path.  */
458 
459 struct search_path
460 {
461   char *path;
462   struct search_path *next;
463 };
464 
465 static struct search_path *search_path;
466 static struct search_path *search_path_tail;
467 
468 /* Function prototypes.  */
469 
470 static char *matching_regexp (void);
471 static struct sym *add_sym (const char *, struct sym *);
472 static void add_global_defn (char *, char *, int, unsigned, int, int, int);
473 static void add_global_decl (char *, char *, int, unsigned, int, int, int);
474 static struct member *add_member (struct sym *, char *, int, int, unsigned);
475 static void class_definition (struct sym *, const char *, int, int, int);
476 static char *operator_name (int *);
477 static void parse_qualified_param_ident_or_type (char **);
478 
479 /***********************************************************************
480 			      Utilities
481  ***********************************************************************/
482 
483 /* Print an error in a printf-like style with the current input file
484    name and line number.  */
485 
486 static void
yyerror(const char * format,const char * s)487 yyerror (const char *format, const char *s)
488 {
489   fprintf (stderr, "%s:%d: ", filename, yyline);
490   fprintf (stderr, format, s);
491   putc ('\n', stderr);
492 }
493 
494 
495 /* Like malloc but print an error and exit if not enough memory is
496    available.  */
497 
498 static void * ATTRIBUTE_MALLOC
xmalloc(size_t nbytes)499 xmalloc (size_t nbytes)
500 {
501   void *p = malloc (nbytes);
502   if (p == NULL)
503     {
504       yyerror ("out of memory", NULL);
505       exit (EXIT_FAILURE);
506     }
507   return p;
508 }
509 
510 
511 /* Like realloc but print an error and exit if out of memory.  */
512 
513 static void *
xrealloc(void * p,size_t sz)514 xrealloc (void *p, size_t sz)
515 {
516   p = realloc (p, sz);
517   if (p == NULL)
518     {
519       yyerror ("out of memory", NULL);
520       exit (EXIT_FAILURE);
521     }
522   return p;
523 }
524 
525 
526 /* Like strdup, but print an error and exit if not enough memory is
527    available..  If S is null, return null.  */
528 
529 static char *
xstrdup(char * s)530 xstrdup (char *s)
531 {
532   if (s)
533     return strcpy (xmalloc (strlen (s) + 1), s);
534   return s;
535 }
536 
537 
538 
539 /***********************************************************************
540 			       Symbols
541  ***********************************************************************/
542 
543 /* Initialize the symbol table.  This currently only sets up the
544    special symbol for globals (`*Globals*').  */
545 
546 static void
init_sym(void)547 init_sym (void)
548 {
549   global_symbols = add_sym (GLOBALS_NAME, NULL);
550 }
551 
552 
553 /* Add a symbol for class NAME to the symbol table.  NESTED_IN_CLASS
554    is the class in which class NAME was found.  If it is null,
555    this means the scope of NAME is the current namespace.
556 
557    If a symbol for NAME already exists, return that.  Otherwise
558    create a new symbol and set it to default values.  */
559 
560 static struct sym *
add_sym(const char * name,struct sym * nested_in_class)561 add_sym (const char *name, struct sym *nested_in_class)
562 {
563   struct sym *sym;
564   unsigned h;
565   const char *s;
566   struct sym *scope = nested_in_class ? nested_in_class : current_namespace;
567 
568   for (s = name, h = 0; *s; ++s)
569     h = (h << 1) ^ *s;
570   h %= TABLE_SIZE;
571 
572   for (sym = class_table[h]; sym; sym = sym->next)
573     if (streq (name, sym->name)
574 	&& ((!sym->namesp && !scope)
575 	    || (sym->namesp && scope
576 		&& streq (sym->namesp->name, scope->name))))
577       break;
578 
579   if (sym == NULL)
580     {
581       if (f_very_verbose)
582 	{
583 	  putchar ('\t');
584 	  puts (name);
585 	}
586 
587       sym = xmalloc (FLEXSIZEOF (struct sym, name, strlen (name) + 1));
588       memset (sym, 0, offsetof (struct sym, name));
589       strcpy (sym->name, name);
590       sym->namesp = scope;
591       sym->next = class_table[h];
592       class_table[h] = sym;
593     }
594 
595   return sym;
596 }
597 
598 
599 /* Add links between superclass SUPER and subclass SUB.  */
600 
601 static void
add_link(struct sym * super,struct sym * sub)602 add_link (struct sym *super, struct sym *sub)
603 {
604   struct link *lnk, *lnk2, *p, *prev;
605 
606   /* See if a link already exists.  */
607   for (p = super->subs, prev = NULL;
608        p && strcmp (sub->name, p->sym->name) > 0;
609        prev = p, p = p->next)
610     ;
611 
612   /* Avoid duplicates.  */
613   if (p == NULL || p->sym != sub)
614     {
615       lnk = (struct link *) xmalloc (sizeof *lnk);
616       lnk2 = (struct link *) xmalloc (sizeof *lnk2);
617 
618       lnk->sym = sub;
619       lnk->next = p;
620 
621       if (prev)
622 	prev->next = lnk;
623       else
624 	super->subs = lnk;
625 
626       lnk2->sym = super;
627       lnk2->next = sub->supers;
628       sub->supers = lnk2;
629     }
630 }
631 
632 
633 /* Find in class CLS member NAME.
634 
635    VAR non-zero means look for a member variable; otherwise a function
636    is searched.  SC specifies what kind of member is searched---a
637    static, or per-instance member etc.  HASH is a hash code for the
638    parameter types of functions.  Value is a pointer to the member
639    found or null if not found.  */
640 
641 static struct member *
find_member(struct sym * cls,char * name,int var,int sc,unsigned int hash)642 find_member (struct sym *cls, char *name, int var, int sc, unsigned int hash)
643 {
644   struct member **list;
645   struct member *p;
646   unsigned name_hash = 0;
647   char *s;
648   int i;
649 
650   switch (sc)
651     {
652     case SC_FRIEND:
653       list = &cls->friends;
654       break;
655 
656     case SC_TYPE:
657       list = &cls->types;
658       break;
659 
660     case SC_STATIC:
661       list = var ? &cls->static_vars : &cls->static_fns;
662       break;
663 
664     default:
665       list = var ? &cls->vars : &cls->fns;
666       break;
667     }
668 
669   for (s = name; *s; ++s)
670     name_hash = (name_hash << 1) ^ *s;
671   i = name_hash % TABLE_SIZE;
672 
673   for (p = member_table[i]; p; p = p->anext)
674     if (p->list == list && p->param_hash == hash && streq (name, p->name))
675       break;
676 
677   return p;
678 }
679 
680 
681 /* Add to class CLS information for the declaration of member NAME.
682    REGEXP is a regexp matching the declaration, if non-null.  POS is
683    the position in the source where the declaration is found.  HASH is
684    a hash code for the parameter list of the member, if it's a
685    function.  VAR non-zero means member is a variable or type.  SC
686    specifies the type of member (instance member, static, ...).  VIS
687    is the member's visibility (public, protected, private).  FLAGS is
688    a bit set giving additional information about the member (see the
689    F_* defines).  */
690 
691 static void
add_member_decl(struct sym * cls,char * name,char * regexp,int pos,unsigned int hash,int var,int sc,int vis,int flags)692 add_member_decl (struct sym *cls, char *name, char *regexp, int pos, unsigned int hash, int var, int sc, int vis, int flags)
693 {
694   struct member *m;
695 
696   m = find_member (cls, name, var, sc, hash);
697   if (m == NULL)
698     m = add_member (cls, name, var, sc, hash);
699 
700   /* Have we seen a new filename?  If so record that.  */
701   if (!cls->filename || !filename_eq (cls->filename, filename))
702     m->filename = filename;
703 
704   m->regexp = regexp;
705   m->pos = pos;
706   m->flags = flags;
707 
708   switch (vis)
709     {
710     case PRIVATE:
711       m->vis = V_PRIVATE;
712       break;
713 
714     case PROTECTED:
715       m->vis = V_PROTECTED;
716       break;
717 
718     case PUBLIC:
719       m->vis = V_PUBLIC;
720       break;
721     }
722 
723   info_where = P_DECL;
724   info_cls = cls;
725   info_member = m;
726 }
727 
728 
729 /* Add to class CLS information for the definition of member NAME.
730    REGEXP is a regexp matching the declaration, if non-null.  POS is
731    the position in the source where the declaration is found.  HASH is
732    a hash code for the parameter list of the member, if it's a
733    function.  VAR non-zero means member is a variable or type.  SC
734    specifies the type of member (instance member, static, ...).  VIS
735    is the member's visibility (public, protected, private).  FLAGS is
736    a bit set giving additional information about the member (see the
737    F_* defines).  */
738 
739 static void
add_member_defn(struct sym * cls,char * name,char * regexp,int pos,unsigned int hash,int var,int sc,int flags)740 add_member_defn (struct sym *cls, char *name, char *regexp, int pos, unsigned int hash, int var, int sc, int flags)
741 {
742   struct member *m;
743 
744   if (sc == SC_UNKNOWN)
745     {
746       m = find_member (cls, name, var, SC_MEMBER, hash);
747       if (m == NULL)
748 	{
749 	  m = find_member (cls, name, var, SC_STATIC, hash);
750 	  if (m == NULL)
751 	    m = add_member (cls, name, var, sc, hash);
752 	}
753     }
754   else
755     {
756       m = find_member (cls, name, var, sc, hash);
757       if (m == NULL)
758 	m = add_member (cls, name, var, sc, hash);
759     }
760 
761   if (!cls->sfilename)
762     cls->sfilename = filename;
763 
764   if (!filename_eq (cls->sfilename, filename))
765     m->def_filename = filename;
766 
767   m->def_regexp = regexp;
768   m->def_pos = pos;
769   m->flags |= flags;
770 
771   info_where = P_DEFN;
772   info_cls = cls;
773   info_member = m;
774 }
775 
776 
777 /* Add a symbol for a define named NAME to the symbol table.
778    REGEXP is a regular expression matching the define in the source,
779    if it is non-null.  POS is the position in the file.  */
780 
781 static void
add_define(char * name,char * regexp,int pos)782 add_define (char *name, char *regexp, int pos)
783 {
784   add_global_defn (name, regexp, pos, 0, 1, SC_FRIEND, F_DEFINE);
785   add_global_decl (name, regexp, pos, 0, 1, SC_FRIEND, F_DEFINE);
786 }
787 
788 
789 /* Add information for the global definition of NAME.
790    REGEXP is a regexp matching the declaration, if non-null.  POS is
791    the position in the source where the declaration is found.  HASH is
792    a hash code for the parameter list of the member, if it's a
793    function.  VAR non-zero means member is a variable or type.  SC
794    specifies the type of member (instance member, static, ...).  VIS
795    is the member's visibility (public, protected, private).  FLAGS is
796    a bit set giving additional information about the member (see the
797    F_* defines).  */
798 
799 static void
add_global_defn(char * name,char * regexp,int pos,unsigned int hash,int var,int sc,int flags)800 add_global_defn (char *name, char *regexp, int pos, unsigned int hash, int var, int sc, int flags)
801 {
802   int i;
803   struct sym *sym;
804 
805   /* Try to find out for which classes a function is a friend, and add
806      what we know about it to them.  */
807   if (!var)
808     for (i = 0; i < TABLE_SIZE; ++i)
809       for (sym = class_table[i]; sym; sym = sym->next)
810 	if (sym != global_symbols && sym->friends)
811 	  if (find_member (sym, name, 0, SC_FRIEND, hash))
812 	    add_member_defn (sym, name, regexp, pos, hash, 0,
813 			     SC_FRIEND, flags);
814 
815   /* Add to global symbols.  */
816   add_member_defn (global_symbols, name, regexp, pos, hash, var, sc, flags);
817 }
818 
819 
820 /* Add information for the global declaration of NAME.
821    REGEXP is a regexp matching the declaration, if non-null.  POS is
822    the position in the source where the declaration is found.  HASH is
823    a hash code for the parameter list of the member, if it's a
824    function.  VAR non-zero means member is a variable or type.  SC
825    specifies the type of member (instance member, static, ...).  VIS
826    is the member's visibility (public, protected, private).  FLAGS is
827    a bit set giving additional information about the member (see the
828    F_* defines).  */
829 
830 static void
add_global_decl(char * name,char * regexp,int pos,unsigned int hash,int var,int sc,int flags)831 add_global_decl (char *name, char *regexp, int pos, unsigned int hash, int var, int sc, int flags)
832 {
833   /* Add declaration only if not already declared.  Header files must
834      be processed before source files for this to have the right effect.
835      I do not want to handle implicit declarations at the moment.  */
836   struct member *m;
837   struct member *found;
838 
839   m = found = find_member (global_symbols, name, var, sc, hash);
840   if (m == NULL)
841     m = add_member (global_symbols, name, var, sc, hash);
842 
843   /* Definition already seen => probably last declaration implicit.
844      Override.  This means that declarations must always be added to
845      the symbol table before definitions.  */
846   if (!found)
847     {
848       if (!global_symbols->filename
849 	  || !filename_eq (global_symbols->filename, filename))
850 	m->filename = filename;
851 
852       m->regexp = regexp;
853       m->pos = pos;
854       m->vis = V_PUBLIC;
855       m->flags = flags;
856 
857       info_where = P_DECL;
858       info_cls = global_symbols;
859       info_member = m;
860     }
861 }
862 
863 
864 /* Add a symbol for member NAME to class CLS.
865    VAR non-zero means it's a variable.  SC specifies the kind of
866    member.  HASH is a hash code for the parameter types of a function.
867    Value is a pointer to the member's structure.  */
868 
869 static struct member *
add_member(struct sym * cls,char * name,int var,int sc,unsigned int hash)870 add_member (struct sym *cls, char *name, int var, int sc, unsigned int hash)
871 {
872   struct member *m = xmalloc (FLEXSIZEOF (struct member, name,
873 					  strlen (name) + 1));
874   struct member **list;
875   struct member *p;
876   struct member *prev;
877   unsigned name_hash = 0;
878   int i;
879   char *s;
880 
881   strcpy (m->name, name);
882   m->param_hash = hash;
883 
884   m->vis = 0;
885   m->flags = 0;
886   m->regexp = NULL;
887   m->filename = NULL;
888   m->pos = 0;
889   m->def_regexp = NULL;
890   m->def_filename = NULL;
891   m->def_pos = 0;
892 
893   assert (cls != NULL);
894 
895   switch (sc)
896     {
897     case SC_FRIEND:
898       list = &cls->friends;
899       break;
900 
901     case SC_TYPE:
902       list = &cls->types;
903       break;
904 
905     case SC_STATIC:
906       list = var ? &cls->static_vars : &cls->static_fns;
907       break;
908 
909     default:
910       list = var ? &cls->vars : &cls->fns;
911       break;
912     }
913 
914   for (s = name; *s; ++s)
915     name_hash = (name_hash << 1) ^ *s;
916   i = name_hash % TABLE_SIZE;
917   m->anext = member_table[i];
918   member_table[i] = m;
919   m->list = list;
920 
921   /* Keep the member list sorted.  It's cheaper to do it here than to
922      sort them in Lisp.  */
923   for (prev = NULL, p = *list;
924        p && strcmp (name, p->name) > 0;
925        prev = p, p = p->next)
926     ;
927 
928   m->next = p;
929   if (prev)
930     prev->next = m;
931   else
932     *list = m;
933   return m;
934 }
935 
936 
937 /* Given the root R of a class tree, step through all subclasses
938    recursively, marking functions as virtual that are declared virtual
939    in base classes.  */
940 
941 static void
mark_virtual(struct sym * r)942 mark_virtual (struct sym *r)
943 {
944   struct link *p;
945   struct member *m, *m2;
946 
947   for (p = r->subs; p; p = p->next)
948     {
949       for (m = r->fns; m; m = m->next)
950         if (has_flag (m->flags, F_VIRTUAL))
951           {
952             for (m2 = p->sym->fns; m2; m2 = m2->next)
953               if (m->param_hash == m2->param_hash && streq (m->name, m2->name))
954                 set_flag (&m2->flags, F_VIRTUAL);
955           }
956 
957       mark_virtual (p->sym);
958     }
959 }
960 
961 
962 /* For all roots of the class tree, mark functions as virtual that
963    are virtual because of a virtual declaration in a base class.  */
964 
965 static void
mark_inherited_virtual(void)966 mark_inherited_virtual (void)
967 {
968   struct sym *r;
969   int i;
970 
971   for (i = 0; i < TABLE_SIZE; ++i)
972     for (r = class_table[i]; r; r = r->next)
973       if (r->supers == NULL)
974         mark_virtual (r);
975 }
976 
977 
978 /* Create and return a symbol for a namespace with name NAME.  */
979 
980 static struct sym *
make_namespace(char * name,struct sym * context)981 make_namespace (char *name, struct sym *context)
982 {
983   struct sym *s = xmalloc (FLEXSIZEOF (struct sym, name, strlen (name) + 1));
984   memset (s, 0, offsetof (struct sym, name));
985   strcpy (s->name, name);
986   s->next = all_namespaces;
987   s->namesp = context;
988   all_namespaces = s;
989   return s;
990 }
991 
992 
993 /* Find the symbol for namespace NAME.  If not found, return NULL */
994 
995 static struct sym *
check_namespace(char * name,struct sym * context)996 check_namespace (char *name, struct sym *context)
997 {
998   struct sym *p = NULL;
999 
1000   for (p = all_namespaces; p; p = p->next)
1001     {
1002       if (streq (p->name, name) && (p->namesp == context))
1003 	    break;
1004     }
1005 
1006   return p;
1007 }
1008 
1009 /* Find the symbol for namespace NAME.  If not found, add a new symbol
1010    for NAME to all_namespaces.  */
1011 
1012 static struct sym *
find_namespace(char * name,struct sym * context)1013 find_namespace (char *name, struct sym *context)
1014 {
1015   struct sym *p = check_namespace (name, context);
1016 
1017   if (p == NULL)
1018     p = make_namespace (name, context);
1019 
1020   return p;
1021 }
1022 
1023 
1024 /* Find namespace alias with name NAME. If not found return NULL. */
1025 
1026 static struct link *
check_namespace_alias(char * name)1027 check_namespace_alias (char *name)
1028 {
1029   struct link *p = NULL;
1030   struct alias *al;
1031   unsigned h;
1032   char *s;
1033 
1034   for (s = name, h = 0; *s; ++s)
1035     h = (h << 1) ^ *s;
1036   h %= TABLE_SIZE;
1037 
1038   for (al = namespace_alias_table[h]; al; al = al->next)
1039     if (streq (name, al->name) && (al->namesp == current_namespace))
1040       {
1041         p = al->aliasee;
1042         break;
1043       }
1044 
1045   return p;
1046 }
1047 
1048 /* Register the name NEW_NAME as an alias for namespace list OLD_NAME.  */
1049 
1050 static void
register_namespace_alias(char * new_name,struct link * old_name)1051 register_namespace_alias (char *new_name, struct link *old_name)
1052 {
1053   unsigned h;
1054   char *s;
1055   struct alias *al;
1056 
1057   for (s = new_name, h = 0; *s; ++s)
1058     h = (h << 1) ^ *s;
1059   h %= TABLE_SIZE;
1060 
1061 
1062   /* Is it already in the table of aliases?  */
1063   for (al = namespace_alias_table[h]; al; al = al->next)
1064     if (streq (new_name, al->name) && (al->namesp == current_namespace))
1065       return;
1066 
1067   al = xmalloc (FLEXSIZEOF (struct alias, name, strlen (new_name) + 1));
1068   strcpy (al->name, new_name);
1069   al->next = namespace_alias_table[h];
1070   al->namesp = current_namespace;
1071   al->aliasee = old_name;
1072   namespace_alias_table[h] = al;
1073 }
1074 
1075 
1076 /* Enter namespace with name NAME.  */
1077 
1078 static void
enter_namespace(char * name)1079 enter_namespace (char *name)
1080 {
1081   struct sym *p = find_namespace (name, current_namespace);
1082 
1083   if (namespace_sp == namespace_stack_size)
1084     {
1085       int size = max (10, 2 * namespace_stack_size);
1086       namespace_stack
1087 	= (struct sym **) xrealloc ((void *)namespace_stack,
1088 				    size * sizeof *namespace_stack);
1089       namespace_stack_size = size;
1090     }
1091 
1092   namespace_stack[namespace_sp++] = current_namespace;
1093   current_namespace = p;
1094 }
1095 
1096 
1097 /* Leave the current namespace.  */
1098 
1099 static void
leave_namespace(void)1100 leave_namespace (void)
1101 {
1102   assert (namespace_sp > 0);
1103   current_namespace = namespace_stack[--namespace_sp];
1104 }
1105 
1106 
1107 
1108 /***********************************************************************
1109 		       Writing the Output File
1110  ***********************************************************************/
1111 
1112 /* Write string S to the output file FP in a Lisp-readable form.
1113    If S is null, write out `()'.  */
1114 
1115 static void
putstr(const char * s,FILE * fp)1116 putstr (const char *s, FILE *fp)
1117 {
1118   if (!s)
1119     {
1120       putc ('(', fp);
1121       putc (')', fp);
1122       putc (' ', fp);
1123     }
1124   else
1125     {
1126       putc ('"', fp);
1127       fputs (s, fp);
1128       putc ('"', fp);
1129       putc (' ', fp);
1130     }
1131 }
1132 
1133 /* A dynamically allocated buffer for constructing a scope name.  */
1134 
1135 static char *scope_buffer;
1136 static int scope_buffer_size;
1137 static int scope_buffer_len;
1138 
1139 
1140 /* Make sure scope_buffer has enough room to add LEN chars to it.  */
1141 
1142 static void
ensure_scope_buffer_room(int len)1143 ensure_scope_buffer_room (int len)
1144 {
1145   if (scope_buffer_len + len >= scope_buffer_size)
1146     {
1147       int new_size = max (2 * scope_buffer_size, scope_buffer_len + len);
1148       scope_buffer = (char *) xrealloc (scope_buffer, new_size);
1149       scope_buffer_size = new_size;
1150     }
1151 }
1152 
1153 
1154 /* Recursively add the scope names of symbol P and the scopes of its
1155    namespaces to scope_buffer.  Value is a pointer to the complete
1156    scope name constructed.  */
1157 
1158 static char *
sym_scope_1(struct sym * p)1159 sym_scope_1 (struct sym *p)
1160 {
1161   int len;
1162 
1163   if (p->namesp)
1164     sym_scope_1 (p->namesp);
1165 
1166   if (*scope_buffer)
1167     {
1168       ensure_scope_buffer_room (3);
1169       strcpy (scope_buffer + scope_buffer_len, "::");
1170       scope_buffer_len += 2;
1171     }
1172 
1173   len = strlen (p->name);
1174   ensure_scope_buffer_room (len + 1);
1175   strcpy (scope_buffer + scope_buffer_len, p->name);
1176   scope_buffer_len += len;
1177 
1178   if (has_flag (p->flags, F_TEMPLATE))
1179     {
1180       ensure_scope_buffer_room (3);
1181       strcpy (scope_buffer + scope_buffer_len, "<>");
1182       scope_buffer_len += 2;
1183     }
1184 
1185   return scope_buffer;
1186 }
1187 
1188 
1189 /* Return the scope of symbol P in printed representation, i.e.
1190    as it would appear in a C*+ source file.  */
1191 
1192 static char *
sym_scope(struct sym * p)1193 sym_scope (struct sym *p)
1194 {
1195   if (!scope_buffer)
1196     {
1197       scope_buffer_size = 1024;
1198       scope_buffer = (char *) xmalloc (scope_buffer_size);
1199     }
1200 
1201   *scope_buffer = '\0';
1202   scope_buffer_len = 0;
1203 
1204   if (p->namesp)
1205     sym_scope_1 (p->namesp);
1206 
1207   return scope_buffer;
1208 }
1209 
1210 
1211 /* Dump the list of members M to file FP.  Value is the length of the
1212    list.  */
1213 
1214 static int
dump_members(FILE * fp,struct member * m)1215 dump_members (FILE *fp, struct member *m)
1216 {
1217   int n;
1218 
1219   putc ('(', fp);
1220 
1221   for (n = 0; m; m = m->next, ++n)
1222     {
1223       fputs (MEMBER_STRUCT, fp);
1224       putstr (m->name, fp);
1225       putstr (NULL, fp);		/* FIXME? scope for globals */
1226       fprintf (fp, "%u ", (unsigned) m->flags);
1227       putstr (m->filename, fp);
1228       putstr (m->regexp, fp);
1229       fprintf (fp, "%u ", (unsigned) m->pos);
1230       fprintf (fp, "%u ", (unsigned) m->vis);
1231       putc (' ', fp);
1232       putstr (m->def_filename, fp);
1233       putstr (m->def_regexp, fp);
1234       fprintf (fp, "%u", (unsigned) m->def_pos);
1235       putc (']', fp);
1236       putc ('\n', fp);
1237     }
1238 
1239   putc (')', fp);
1240   putc ('\n', fp);
1241   return n;
1242 }
1243 
1244 
1245 /* Dump class ROOT to stream FP.  */
1246 
1247 static void
dump_sym(FILE * fp,struct sym * root)1248 dump_sym (FILE *fp, struct sym *root)
1249 {
1250   fputs (CLASS_STRUCT, fp);
1251   putstr (root->name, fp);
1252 
1253   /* Print scope, if any.  */
1254   if (root->namesp)
1255     putstr (sym_scope (root), fp);
1256   else
1257     putstr (NULL, fp);
1258 
1259   /* Print flags.  */
1260   fprintf (fp, "%d", root->flags);
1261   putstr (root->filename, fp);
1262   putstr (root->regexp, fp);
1263   fprintf (fp, "%u", (unsigned) root->pos);
1264   putstr (root->sfilename, fp);
1265   putc (']', fp);
1266   putc ('\n', fp);
1267 }
1268 
1269 
1270 /* Dump class ROOT and its subclasses to file FP.  Value is the
1271    number of classes written.  */
1272 
1273 static int
dump_tree(FILE * fp,struct sym * root)1274 dump_tree (FILE *fp, struct sym *root)
1275 {
1276   struct link *lk;
1277   unsigned n = 0;
1278 
1279   dump_sym (fp, root);
1280 
1281   if (f_verbose)
1282     {
1283       putchar ('+');
1284       fflush (stdout);
1285     }
1286 
1287   putc ('(', fp);
1288 
1289   for (lk = root->subs; lk; lk = lk->next)
1290     {
1291       fputs (TREE_STRUCT, fp);
1292       n += dump_tree (fp, lk->sym);
1293       putc (']', fp);
1294     }
1295 
1296   putc (')', fp);
1297 
1298   dump_members (fp, root->vars);
1299   n += dump_members (fp, root->fns);
1300   dump_members (fp, root->static_vars);
1301   n += dump_members (fp, root->static_fns);
1302   n += dump_members (fp, root->friends);
1303   dump_members (fp, root->types);
1304 
1305   /* Superclasses.  */
1306   putc ('(', fp);
1307   putc (')', fp);
1308 
1309   /* Mark slot.  */
1310   putc ('(', fp);
1311   putc (')', fp);
1312 
1313   putc ('\n', fp);
1314   return n;
1315 }
1316 
1317 
1318 /* Dump the entire class tree to file FP.  */
1319 
1320 static void
dump_roots(FILE * fp)1321 dump_roots (FILE *fp)
1322 {
1323   int i, n = 0;
1324   struct sym *r;
1325 
1326   /* Output file header containing version string, command line
1327      options etc.  */
1328   if (!f_append)
1329     {
1330       fputs (TREE_HEADER_STRUCT, fp);
1331       putstr (EBROWSE_FILE_VERSION, fp);
1332 
1333       putc ('\"', fp);
1334       if (!f_structs)
1335 	fputs (" -s", fp);
1336       if (f_regexps)
1337 	fputs (" -x", fp);
1338       putc ('\"', fp);
1339       fputs (" ()", fp);
1340       fputs (" ()", fp);
1341       putc (']', fp);
1342     }
1343 
1344   /* Mark functions as virtual that are so because of functions
1345      declared virtual in base classes.  */
1346   mark_inherited_virtual ();
1347 
1348   /* Dump the roots of the graph.  */
1349   for (i = 0; i < TABLE_SIZE; ++i)
1350     for (r = class_table[i]; r; r = r->next)
1351       if (!r->supers)
1352         {
1353 	  fputs (TREE_STRUCT, fp);
1354           n += dump_tree (fp, r);
1355 	  putc (']', fp);
1356         }
1357 
1358   if (f_verbose)
1359     putchar ('\n');
1360 }
1361 
1362 
1363 
1364 /***********************************************************************
1365 				Scanner
1366  ***********************************************************************/
1367 
1368 #ifdef DEBUG
1369 #define INCREMENT_LINENO 			\
1370 do {						\
1371   if (f_very_verbose)				\
1372     {						\
1373       ++yyline;					\
1374       printf ("%d:\n", yyline);			\
1375     }						\
1376   else						\
1377     ++yyline;					\
1378 } while (0)
1379 #else
1380 #define INCREMENT_LINENO	++yyline
1381 #endif
1382 
1383 /* Define two macros for accessing the input buffer (current input
1384    file).  GET(C) sets C to the next input character and advances the
1385    input pointer.  UNGET retracts the input pointer.  */
1386 
1387 #define GET(C)	((C) = *in++)
1388 #define UNGET() (--in)
1389 
1390 
1391 /* Process a preprocessor line.  Value is the next character from the
1392    input buffer not consumed.  */
1393 
1394 static int
process_pp_line(void)1395 process_pp_line (void)
1396 {
1397   int in_comment = 0, in_string = 0;
1398   int c;
1399   char *p = yytext;
1400 
1401   /* Skip over white space.  The `#' has been consumed already.  */
1402   while (WHITEP (GET (c)))
1403     ;
1404 
1405   /* Read the preprocessor command (if any).  */
1406   while (IDENTP (c))
1407     {
1408       *p++ = c;
1409       GET (c);
1410     }
1411 
1412   /* Is it a `define'?  */
1413   *p = '\0';
1414 
1415   if (*yytext && streq (yytext, "define"))
1416     {
1417       p = yytext;
1418       while (WHITEP (c))
1419 	GET (c);
1420       while (IDENTP (c))
1421 	{
1422 	  *p++ = c;
1423 	  GET (c);
1424 	}
1425 
1426       *p = '\0';
1427 
1428       if (*yytext)
1429 	{
1430 	  char *regexp = matching_regexp ();
1431 	  int pos = BUFFER_POS ();
1432 	  add_define (yytext, regexp, pos);
1433 	}
1434     }
1435 
1436   while (c && (c != '\n' || in_comment || in_string))
1437     {
1438       if (c == '\\')
1439 	GET (c);
1440       else if (c == '/' && !in_comment)
1441 	{
1442 	  if (GET (c) == '*')
1443 	    in_comment = 1;
1444 	}
1445       else if (c == '*' && in_comment)
1446 	{
1447 	  if (GET (c) == '/')
1448 	    in_comment = 0;
1449 	}
1450       else if (c == '"')
1451 	in_string = !in_string;
1452 
1453       if (c == '\n')
1454 	INCREMENT_LINENO;
1455 
1456       GET (c);
1457     }
1458 
1459   return c;
1460 }
1461 
1462 
1463 /* Value is the next token from the input buffer.  */
1464 
1465 static int
yylex(void)1466 yylex (void)
1467 {
1468   int c;
1469   char end_char;
1470   char *p;
1471 
1472   for (;;)
1473     {
1474       while (WHITEP (GET (c)))
1475         ;
1476 
1477       switch (c)
1478         {
1479         case '\n':
1480           INCREMENT_LINENO;
1481           break;
1482 
1483         case '\r':
1484           break;
1485 
1486         case 0:
1487           /* End of file.  */
1488           return YYEOF;
1489 
1490         case '\\':
1491           GET (c);
1492           break;
1493 
1494         case '"':
1495         case '\'':
1496           /* String and character constants.  */
1497           end_char = c;
1498           string_start = in;
1499           while (GET (c) && c != end_char)
1500             {
1501               switch (c)
1502                 {
1503                 case '\\':
1504                   /* Escape sequences.  */
1505                   if (!GET (c))
1506                     {
1507                       if (end_char == '\'')
1508                         yyerror ("EOF in character constant", NULL);
1509                       else
1510                         yyerror ("EOF in string constant", NULL);
1511                       goto end_string;
1512                     }
1513                   else switch (c)
1514                     {
1515                     case '\n':
1516 		      INCREMENT_LINENO;
1517                     case 'a':
1518                     case 'b':
1519                     case 'f':
1520                     case 'n':
1521                     case 'r':
1522                     case 't':
1523                     case 'v':
1524                       break;
1525 
1526                     case 'x':
1527                       {
1528                         /* Hexadecimal escape sequence.  */
1529                         int i;
1530                         for (i = 0; i < 2; ++i)
1531                           {
1532                             GET (c);
1533 
1534                             if (c >= '0' && c <= '7')
1535                               ;
1536                             else if (c >= 'a' && c <= 'f')
1537                               ;
1538                             else if (c >= 'A' && c <= 'F')
1539                               ;
1540                             else
1541                               {
1542                                 UNGET ();
1543                                 break;
1544                               }
1545                           }
1546                       }
1547                       break;
1548 
1549                     case '0':
1550                       {
1551                         /* Octal escape sequence.  */
1552                         int i;
1553                         for (i = 0; i < 3; ++i)
1554                           {
1555                             GET (c);
1556 
1557                             if (c >= '0' && c <= '7')
1558                               ;
1559                             else
1560                               {
1561                                 UNGET ();
1562                                 break;
1563                               }
1564                           }
1565                       }
1566                       break;
1567 
1568                     default:
1569                       break;
1570                     }
1571                   break;
1572 
1573                 case '\n':
1574                   if (end_char == '\'')
1575                     yyerror ("newline in character constant", NULL);
1576                   else
1577                     yyerror ("newline in string constant", NULL);
1578                   INCREMENT_LINENO;
1579                   break;
1580 
1581                 default:
1582                   break;
1583                 }
1584             }
1585 
1586         end_string:
1587           return end_char == '\'' ? CCHAR : CSTRING;
1588 
1589         case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g':
1590         case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n':
1591         case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u':
1592         case 'v': case 'w': case 'x': case 'y': case 'z':
1593         case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G':
1594         case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N':
1595         case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U':
1596         case 'V': case 'W': case 'X': case 'Y': case 'Z': case '_':
1597           {
1598             /* Identifier and keywords.  */
1599             unsigned hash;
1600             struct kw *k;
1601 
1602             p = yytext;
1603             *p++ = hash = c;
1604 
1605             while (IDENTP (GET (*p)))
1606 	      {
1607 		hash = (hash << 1) ^ *p++;
1608 		if (p == yytext_end - 1)
1609 		  {
1610 		    int size = yytext_end - yytext;
1611 		    yytext = (char *) xrealloc (yytext, 2 * size);
1612 		    yytext_end = yytext + 2 * size;
1613 		    p = yytext + size - 1;
1614 		  }
1615 	      }
1616 
1617             UNGET ();
1618             *p = 0;
1619 
1620             for (k = keyword_table[hash % KEYWORD_TABLE_SIZE]; k; k = k->next)
1621               if (streq (k->name, yytext))
1622                 return k->tk;
1623 
1624             return IDENT;
1625           }
1626 
1627         case '/':
1628           /* C and C++ comments, '/' and '/='.  */
1629           switch (GET (c))
1630             {
1631             case '*':
1632               while (GET (c))
1633                 {
1634                   switch (c)
1635                     {
1636                     case '*':
1637                       if (GET (c) == '/')
1638                         goto comment_end;
1639                       UNGET ();
1640                       break;
1641                     case '\\':
1642                       GET (c);
1643                       break;
1644                     case '\n':
1645                       INCREMENT_LINENO;
1646                       break;
1647                     }
1648                 }
1649             comment_end:;
1650               break;
1651 
1652             case '=':
1653               return DIVASGN;
1654 
1655             case '/':
1656 	      while (GET (c) && c != '\n')
1657 		;
1658 	      /* Don't try to read past the end of the input buffer if
1659 		 the file ends in a C++ comment without a newline.  */
1660 	      if (c == 0)
1661 		return YYEOF;
1662 
1663 	      INCREMENT_LINENO;
1664 	      break;
1665 
1666             default:
1667               UNGET ();
1668               return '/';
1669             }
1670           break;
1671 
1672         case '+':
1673           if (GET (c) == '+')
1674             return INC;
1675           else if (c == '=')
1676             return ADDASGN;
1677           UNGET ();
1678           return '+';
1679 
1680         case '-':
1681           switch (GET (c))
1682             {
1683             case '-':
1684               return DEC;
1685             case '>':
1686               if (GET (c) == '*')
1687                 return ARROWSTAR;
1688               UNGET ();
1689               return ARROW;
1690             case '=':
1691               return SUBASGN;
1692             }
1693           UNGET ();
1694           return '-';
1695 
1696         case '*':
1697           if (GET (c) == '=')
1698             return MULASGN;
1699           UNGET ();
1700           return '*';
1701 
1702         case '%':
1703           if (GET (c) == '=')
1704             return MODASGN;
1705           UNGET ();
1706           return '%';
1707 
1708         case '|':
1709           if (GET (c) == '|')
1710             return LOR;
1711           else if (c == '=')
1712             return ORASGN;
1713           UNGET ();
1714           return '|';
1715 
1716         case '&':
1717           if (GET (c) == '&')
1718             return LAND;
1719           else if (c == '=')
1720             return ANDASGN;
1721           UNGET ();
1722           return '&';
1723 
1724         case '^':
1725           if (GET (c) == '=')
1726             return XORASGN;
1727           UNGET ();
1728           return '^';
1729 
1730         case '.':
1731           if (GET (c) == '*')
1732             return POINTSTAR;
1733           else if (c == '.')
1734             {
1735               if (GET (c) != '.')
1736                 yyerror ("invalid token '..' ('...' assumed)", NULL);
1737               UNGET ();
1738               return ELLIPSIS;
1739             }
1740           else if (!DIGITP (c))
1741             {
1742               UNGET ();
1743               return '.';
1744             }
1745           goto mantissa;
1746 
1747         case ':':
1748           if (GET (c) == ':')
1749             return DCOLON;
1750           UNGET ();
1751           return ':';
1752 
1753         case '=':
1754           if (GET (c) == '=')
1755             return EQ;
1756           UNGET ();
1757           return '=';
1758 
1759         case '!':
1760           if (GET (c) == '=')
1761             return NE;
1762           UNGET ();
1763           return '!';
1764 
1765         case '<':
1766           switch (GET (c))
1767             {
1768             case '=':
1769               return LE;
1770             case '<':
1771               if (GET (c) == '=')
1772                 return LSHIFTASGN;
1773               UNGET ();
1774               return LSHIFT;
1775             }
1776           UNGET ();
1777           return '<';
1778 
1779         case '>':
1780           switch (GET (c))
1781             {
1782             case '=':
1783               return GE;
1784             case '>':
1785               if (GET (c) == '=')
1786                 return RSHIFTASGN;
1787               UNGET ();
1788               return RSHIFT;
1789             }
1790           UNGET ();
1791           return '>';
1792 
1793         case '#':
1794           c = process_pp_line ();
1795           if (c == 0)
1796             return YYEOF;
1797           break;
1798 
1799         case '(': case ')': case '[': case ']': case '{': case '}':
1800         case ';': case ',': case '?': case '~':
1801           return c;
1802 
1803         case '0':
1804           yyival = 0;
1805 
1806           if (GET (c) == 'x' || c == 'X')
1807             {
1808               while (GET (c))
1809                 {
1810                   if (DIGITP (c))
1811                     yyival = yyival * 16 + c - '0';
1812                   else if (c >= 'a' && c <= 'f')
1813                     yyival = yyival * 16 + c - 'a' + 10;
1814                   else if (c >= 'A' && c <= 'F')
1815                     yyival = yyival * 16 + c - 'A' + 10;
1816                   else
1817                     break;
1818                 }
1819 
1820               goto int_suffixes;
1821             }
1822           else if (c == '.')
1823             goto mantissa;
1824 
1825           while (c >= '0' && c <= '7')
1826             {
1827               yyival = (yyival << 3) + c - '0';
1828               GET (c);
1829             }
1830 
1831         int_suffixes:
1832           /* Integer suffixes.  */
1833           while (isalpha (c))
1834             GET (c);
1835           UNGET ();
1836           return CINT;
1837 
1838         case '1': case '2': case '3': case '4': case '5': case '6':
1839         case '7': case '8': case '9':
1840           /* Integer or floating constant, part before '.'.  */
1841           yyival = c - '0';
1842 
1843           while (GET (c) && DIGITP (c))
1844             yyival = 10 * yyival + c - '0';
1845 
1846           if (c != '.')
1847             goto int_suffixes;
1848 
1849         mantissa:
1850           /* Digits following '.'.  */
1851           while (DIGITP (c))
1852             GET (c);
1853 
1854           /* Optional exponent.  */
1855           if (c == 'E' || c == 'e')
1856             {
1857               if (GET (c) == '-' || c == '+')
1858                 GET (c);
1859 
1860               while (DIGITP (c))
1861                 GET (c);
1862             }
1863 
1864           /* Optional type suffixes.  */
1865           while (isalpha (c))
1866             GET (c);
1867 	  UNGET ();
1868           return CFLOAT;
1869 
1870         default:
1871           break;
1872         }
1873     }
1874 }
1875 
1876 
1877 /* Actually local to matching_regexp.  These variables must be in
1878    global scope for the case that `static' gets defined away.  */
1879 
1880 static char *matching_regexp_buffer, *matching_regexp_end_buf;
1881 
1882 
1883 /* Value is the string from the start of the line to the current
1884    position in the input buffer, or maybe a bit more if that string is
1885    shorter than min_regexp.  */
1886 
1887 static char *
matching_regexp(void)1888 matching_regexp (void)
1889 {
1890   char *p;
1891   char *s;
1892   char *t;
1893 
1894   if (!f_regexps)
1895     return NULL;
1896 
1897   if (matching_regexp_buffer == NULL)
1898     {
1899       matching_regexp_buffer = (char *) xmalloc (max_regexp);
1900       matching_regexp_end_buf = &matching_regexp_buffer[max_regexp] - 1;
1901     }
1902 
1903   /* Scan back to previous newline of buffer start.  */
1904   for (p = in - 1; p > inbuffer && *p != '\n'; --p)
1905     ;
1906 
1907   if (*p == '\n')
1908     {
1909       while (in - p < min_regexp && p > inbuffer)
1910         {
1911           /* Line probably not significant enough */
1912           for (--p; p > inbuffer && *p != '\n'; --p)
1913             ;
1914         }
1915       if (*p == '\n')
1916         ++p;
1917     }
1918 
1919   /* Copy from end to make sure significant portions are included.
1920      This implies that in the browser a regular expressing of the form
1921      `^.*{regexp}' has to be used.  */
1922   for (s = matching_regexp_end_buf - 1, t = in;
1923        s > matching_regexp_buffer && t > p;)
1924     {
1925       *--s = *--t;
1926 
1927       if (*s == '"' || *s == '\\')
1928         *--s = '\\';
1929     }
1930 
1931   *(matching_regexp_end_buf - 1) = '\0';
1932   return xstrdup (s);
1933 }
1934 
1935 
1936 /* Return a printable representation of token T.  */
1937 
1938 static const char *
token_string(int t)1939 token_string (int t)
1940 {
1941   static char b[3];
1942 
1943   switch (t)
1944     {
1945     case CSTRING:               return "string constant";
1946     case CCHAR:                 return "char constant";
1947     case CINT:                  return "int constant";
1948     case CFLOAT:                return "floating constant";
1949     case ELLIPSIS:              return "...";
1950     case LSHIFTASGN:            return "<<=";
1951     case RSHIFTASGN:            return ">>=";
1952     case ARROWSTAR:             return "->*";
1953     case IDENT:                 return "identifier";
1954     case DIVASGN:               return "/=";
1955     case INC:                   return "++";
1956     case ADDASGN:               return "+=";
1957     case DEC:                   return "--";
1958     case ARROW:                 return "->";
1959     case SUBASGN:               return "-=";
1960     case MULASGN:               return "*=";
1961     case MODASGN:               return "%=";
1962     case LOR:                   return "||";
1963     case ORASGN:                return "|=";
1964     case LAND:                  return "&&";
1965     case ANDASGN:               return "&=";
1966     case XORASGN:               return "^=";
1967     case POINTSTAR:             return ".*";
1968     case DCOLON:                return "::";
1969     case EQ:                    return "==";
1970     case NE:                    return "!=";
1971     case LE:                    return "<=";
1972     case LSHIFT:                return "<<";
1973     case GE:                    return ">=";
1974     case RSHIFT:                return ">>";
1975     case ASM:                   return "asm";
1976     case AUTO:                  return "auto";
1977     case BREAK:                 return "break";
1978     case CASE:                  return "case";
1979     case CATCH:                 return "catch";
1980     case CHAR:                  return "char";
1981     case CLASS:                 return "class";
1982     case CONST:                 return "const";
1983     case CONTINUE:              return "continue";
1984     case DEFAULT:               return "default";
1985     case DELETE:                return "delete";
1986     case DO:                    return "do";
1987     case DOUBLE:                return "double";
1988     case ELSE:                  return "else";
1989     case ENUM:                  return "enum";
1990     case EXTERN:                return "extern";
1991     case FLOAT:                 return "float";
1992     case FOR:                   return "for";
1993     case FRIEND:                return "friend";
1994     case GOTO:                  return "goto";
1995     case IF:                    return "if";
1996     case T_INLINE:              return "inline";
1997     case INT:                   return "int";
1998     case LONG:                  return "long";
1999     case NEW:                   return "new";
2000     case OPERATOR:              return "operator";
2001     case PRIVATE:               return "private";
2002     case PROTECTED:             return "protected";
2003     case PUBLIC:                return "public";
2004     case REGISTER:              return "register";
2005     case RETURN:                return "return";
2006     case SHORT:                 return "short";
2007     case SIGNED:                return "signed";
2008     case SIZEOF:                return "sizeof";
2009     case STATIC:                return "static";
2010     case STRUCT:                return "struct";
2011     case SWITCH:                return "switch";
2012     case TEMPLATE:              return "template";
2013     case THIS:                  return "this";
2014     case THROW:                 return "throw";
2015     case TRY:                   return "try";
2016     case TYPEDEF:               return "typedef";
2017     case UNION:                 return "union";
2018     case UNSIGNED:              return "unsigned";
2019     case VIRTUAL:               return "virtual";
2020     case VOID:                  return "void";
2021     case VOLATILE:              return "volatile";
2022     case WHILE:                 return "while";
2023     case MUTABLE:		return "mutable";
2024     case BOOL:			return "bool";
2025     case TRUE:			return "true";
2026     case FALSE:			return "false";
2027     case SIGNATURE:		return "signature";
2028     case NAMESPACE:		return "namespace";
2029     case EXPLICIT:		return "explicit";
2030     case TYPENAME:		return "typename";
2031     case CONST_CAST:		return "const_cast";
2032     case DYNAMIC_CAST:		return "dynamic_cast";
2033     case REINTERPRET_CAST:	return "reinterpret_cast";
2034     case STATIC_CAST:		return "static_cast";
2035     case TYPEID:		return "typeid";
2036     case USING:			return "using";
2037     case WCHAR:			return "wchar_t";
2038     case YYEOF:                 return "EOF";
2039     case FINAL:                 return "final";
2040 
2041     default:
2042       if (t < 255)
2043 	{
2044 	  b[0] = t;
2045 	  b[1] = '\0';
2046 	  return b;
2047 	}
2048       else
2049 	return "???";
2050     }
2051 }
2052 
2053 
2054 /* Reinitialize the scanner for a new input file.  */
2055 
2056 static void
re_init_scanner(void)2057 re_init_scanner (void)
2058 {
2059   in = inbuffer;
2060   yyline = 1;
2061 
2062   if (yytext == NULL)
2063     {
2064       int size = 256;
2065       yytext = (char *) xmalloc (size * sizeof *yytext);
2066       yytext_end = yytext + size;
2067     }
2068 }
2069 
2070 
2071 /* Insert a keyword NAME with token value TKV into the keyword hash
2072    table.  */
2073 
2074 static void
insert_keyword(const char * name,int tkv)2075 insert_keyword (const char *name, int tkv)
2076 {
2077   const char *s;
2078   unsigned h = 0;
2079   struct kw *k = (struct kw *) xmalloc (sizeof *k);
2080 
2081   for (s = name; *s; ++s)
2082     h = (h << 1) ^ *s;
2083 
2084   h %= KEYWORD_TABLE_SIZE;
2085   k->name = name;
2086   k->tk = tkv;
2087   k->next = keyword_table[h];
2088   keyword_table[h] = k;
2089 }
2090 
2091 
2092 /* Initialize the scanner for the first file.  This sets up the
2093    character class vectors and fills the keyword hash table.  */
2094 
2095 static void
init_scanner(void)2096 init_scanner (void)
2097 {
2098   int i;
2099 
2100   /* Allocate the input buffer */
2101   inbuffer_size = READ_CHUNK_SIZE + 1;
2102   inbuffer = in = (char *) xmalloc (inbuffer_size);
2103   yyline = 1;
2104 
2105   /* Set up character class vectors.  */
2106   for (i = 0; i < sizeof is_ident; ++i)
2107     {
2108       if (i == '_' || isalnum (i))
2109         is_ident[i] = 1;
2110 
2111       if (i >= '0' && i <= '9')
2112         is_digit[i] = 1;
2113 
2114       if (i == ' ' || i == '\t' || i == '\f' || i == '\v')
2115         is_white[i] = 1;
2116     }
2117 
2118   /* Fill keyword hash table.  */
2119   insert_keyword ("and", LAND);
2120   insert_keyword ("and_eq", ANDASGN);
2121   insert_keyword ("asm", ASM);
2122   insert_keyword ("auto", AUTO);
2123   insert_keyword ("bitand", '&');
2124   insert_keyword ("bitor", '|');
2125   insert_keyword ("bool", BOOL);
2126   insert_keyword ("break", BREAK);
2127   insert_keyword ("case", CASE);
2128   insert_keyword ("catch", CATCH);
2129   insert_keyword ("char", CHAR);
2130   insert_keyword ("class", CLASS);
2131   insert_keyword ("compl", '~');
2132   insert_keyword ("const", CONST);
2133   insert_keyword ("const_cast", CONST_CAST);
2134   insert_keyword ("continue", CONTINUE);
2135   insert_keyword ("default", DEFAULT);
2136   insert_keyword ("delete", DELETE);
2137   insert_keyword ("do", DO);
2138   insert_keyword ("double", DOUBLE);
2139   insert_keyword ("dynamic_cast", DYNAMIC_CAST);
2140   insert_keyword ("else", ELSE);
2141   insert_keyword ("enum", ENUM);
2142   insert_keyword ("explicit", EXPLICIT);
2143   insert_keyword ("extern", EXTERN);
2144   insert_keyword ("false", FALSE);
2145   insert_keyword ("final", FINAL);
2146   insert_keyword ("float", FLOAT);
2147   insert_keyword ("for", FOR);
2148   insert_keyword ("friend", FRIEND);
2149   insert_keyword ("goto", GOTO);
2150   insert_keyword ("if", IF);
2151   insert_keyword ("inline", T_INLINE);
2152   insert_keyword ("int", INT);
2153   insert_keyword ("long", LONG);
2154   insert_keyword ("mutable", MUTABLE);
2155   insert_keyword ("namespace", NAMESPACE);
2156   insert_keyword ("new", NEW);
2157   insert_keyword ("not", '!');
2158   insert_keyword ("not_eq", NE);
2159   insert_keyword ("operator", OPERATOR);
2160   insert_keyword ("or", LOR);
2161   insert_keyword ("or_eq", ORASGN);
2162   insert_keyword ("private", PRIVATE);
2163   insert_keyword ("protected", PROTECTED);
2164   insert_keyword ("public", PUBLIC);
2165   insert_keyword ("register", REGISTER);
2166   insert_keyword ("reinterpret_cast", REINTERPRET_CAST);
2167   insert_keyword ("return", RETURN);
2168   insert_keyword ("short", SHORT);
2169   insert_keyword ("signed", SIGNED);
2170   insert_keyword ("sizeof", SIZEOF);
2171   insert_keyword ("static", STATIC);
2172   insert_keyword ("static_cast", STATIC_CAST);
2173   insert_keyword ("struct", STRUCT);
2174   insert_keyword ("switch", SWITCH);
2175   insert_keyword ("template", TEMPLATE);
2176   insert_keyword ("this", THIS);
2177   insert_keyword ("throw", THROW);
2178   insert_keyword ("true", TRUE);
2179   insert_keyword ("try", TRY);
2180   insert_keyword ("typedef", TYPEDEF);
2181   insert_keyword ("typeid", TYPEID);
2182   insert_keyword ("typename", TYPENAME);
2183   insert_keyword ("union", UNION);
2184   insert_keyword ("unsigned", UNSIGNED);
2185   insert_keyword ("using", USING);
2186   insert_keyword ("virtual", VIRTUAL);
2187   insert_keyword ("void", VOID);
2188   insert_keyword ("volatile", VOLATILE);
2189   insert_keyword ("wchar_t", WCHAR);
2190   insert_keyword ("while", WHILE);
2191   insert_keyword ("xor", '^');
2192   insert_keyword ("xor_eq", XORASGN);
2193 }
2194 
2195 
2196 
2197 /***********************************************************************
2198 				Parser
2199  ***********************************************************************/
2200 
2201 /* Match the current lookahead token and set it to the next token.  */
2202 
2203 #define MATCH() (tk = yylex ())
2204 
2205 /* Return the lookahead token.  If current lookahead token is cleared,
2206    read a new token.  */
2207 
2208 #define LA1 (tk == -1 ? (tk = yylex ()) : tk)
2209 
2210 /* Is the current lookahead equal to the token T? */
2211 
2212 #define LOOKING_AT(T) (tk == (T))
2213 
2214 /* Is the current lookahead one of T1 or T2?  */
2215 
2216 #define LOOKING_AT2(T1, T2)	(tk == (T1) || tk == (T2))
2217 
2218 /* Is the current lookahead one of T1, T2 or T3?  */
2219 
2220 #define LOOKING_AT3(T1, T2, T3)	(tk == (T1) || tk == (T2) || tk == (T3))
2221 
2222 /* Is the current lookahead one of T1...T4?  */
2223 
2224 #define LOOKING_AT4(T1, T2, T3, T4) \
2225      (tk == (T1) || tk == (T2) || tk == (T3) || tk == (T4))
2226 
2227 /* Match token T if current lookahead is T.  */
2228 
2229 #define MATCH_IF(T) if (LOOKING_AT (T)) MATCH (); else ((void) 0)
2230 
2231 /* Skip to matching token if current token is T.  */
2232 
2233 #define SKIP_MATCHING_IF(T) \
2234   if (LOOKING_AT (T)) skip_matching (); else ((void) 0)
2235 
2236 
2237 /* Skip forward until a given token TOKEN or YYEOF is seen and return
2238    the current lookahead token after skipping.  */
2239 
2240 static int
skip_to(int token)2241 skip_to (int token)
2242 {
2243   while (!LOOKING_AT2 (YYEOF, token))
2244     MATCH ();
2245   return tk;
2246 }
2247 
2248 /* Skip over pairs of tokens (parentheses, square brackets,
2249    angle brackets, curly brackets) matching the current lookahead.  */
2250 
2251 static void
skip_matching(void)2252 skip_matching (void)
2253 {
2254   int open, close, n;
2255 
2256   switch (open = LA1)
2257     {
2258     case '{':
2259       close = '}';
2260       break;
2261 
2262     case '(':
2263       close = ')';
2264       break;
2265 
2266     case '<':
2267       close = '>';
2268       break;
2269 
2270     case '[':
2271       close = ']';
2272       break;
2273 
2274     default:
2275       abort ();
2276     }
2277 
2278   for (n = 0;;)
2279     {
2280       if (LOOKING_AT (open))
2281         ++n;
2282       else if (LOOKING_AT (close))
2283         --n;
2284       else if (LOOKING_AT (YYEOF))
2285         break;
2286 
2287       MATCH ();
2288 
2289       if (n == 0)
2290         break;
2291     }
2292 }
2293 
2294 static void
skip_initializer(void)2295 skip_initializer (void)
2296 {
2297   for (;;)
2298     {
2299       switch (LA1)
2300 	{
2301 	case ';':
2302 	case ',':
2303 	case YYEOF:
2304 	  return;
2305 
2306 	case '{':
2307 	case '[':
2308 	case '(':
2309 	  skip_matching ();
2310 	  break;
2311 
2312 	default:
2313 	  MATCH ();
2314 	  break;
2315 	}
2316     }
2317 }
2318 
2319 /* Build qualified namespace alias (A::B::c) and return it. */
2320 
2321 static struct link *
match_qualified_namespace_alias(void)2322 match_qualified_namespace_alias (void)
2323 {
2324   struct link *head = NULL;
2325   struct link *cur = NULL;
2326   struct link *tmp = NULL;
2327 
2328   for (;;)
2329     {
2330       MATCH ();
2331       switch (LA1)
2332         {
2333         case IDENT:
2334           tmp = (struct link *) xmalloc (sizeof *cur);
2335           tmp->sym = find_namespace (yytext, cur ? cur->sym : NULL);
2336           tmp->next = NULL;
2337           if (head)
2338             {
2339               cur = cur->next = tmp;
2340             }
2341           else
2342             {
2343               head = cur = tmp;
2344             }
2345           break;
2346         case DCOLON:
2347           /* Just skip */
2348           break;
2349         default:
2350           return head;
2351           break;
2352         }
2353     }
2354 }
2355 
2356 /* Re-initialize the parser by resetting the lookahead token.  */
2357 
2358 static void
re_init_parser(void)2359 re_init_parser (void)
2360 {
2361   tk = -1;
2362 }
2363 
2364 
2365 /* Parse a parameter list, including the const-specifier,
2366    pure-specifier, and throw-list that may follow a parameter list.
2367    Return in FLAGS what was seen following the parameter list.
2368    Returns a hash code for the parameter types.  This value is used to
2369    distinguish between overloaded functions.  */
2370 
2371 static unsigned
parm_list(int * flags)2372 parm_list (int *flags)
2373 {
2374   unsigned hash = 0;
2375   int type_seen = 0;
2376 
2377   while (!LOOKING_AT2 (YYEOF, ')'))
2378     {
2379       switch (LA1)
2380         {
2381 	  /* Skip over grouping parens or parameter lists in parameter
2382 	     declarations.  */
2383         case '(':
2384           skip_matching ();
2385           break;
2386 
2387 	  /* Next parameter.  */
2388         case ',':
2389           MATCH ();
2390           type_seen = 0;
2391           break;
2392 
2393           /* Ignore the scope part of types, if any.  This is because
2394              some types need scopes when defined outside of a class body,
2395              and don't need them inside the class body.  This means that
2396              we have to look for the last IDENT in a sequence of
2397              IDENT::IDENT::...  */
2398         case IDENT:
2399           if (!type_seen)
2400             {
2401 	      char *last_id;
2402 	      unsigned ident_type_hash = 0;
2403 
2404 	      parse_qualified_param_ident_or_type (&last_id);
2405 	      if (last_id)
2406 		{
2407 		  /* LAST_ID null means something like `X::*'.  */
2408 		  for (; *last_id; ++last_id)
2409 		    ident_type_hash = (ident_type_hash << 1) ^ *last_id;
2410 		  hash = (hash << 1) ^ ident_type_hash;
2411 		  type_seen = 1;
2412 		}
2413             }
2414 	  else
2415 	    MATCH ();
2416           break;
2417 
2418         case VOID:
2419           /* This distinction is made to make `func (void)' equivalent
2420              to `func ()'.  */
2421           type_seen = 1;
2422           MATCH ();
2423           if (!LOOKING_AT (')'))
2424             hash = (hash << 1) ^ VOID;
2425           break;
2426 
2427         case BOOL:      case CHAR:      case CLASS:     case CONST:
2428         case DOUBLE:    case ENUM:      case FLOAT:     case INT:
2429         case LONG:      case SHORT:     case SIGNED:    case STRUCT:
2430         case UNION:     case UNSIGNED:  case VOLATILE:  case WCHAR:
2431         case ELLIPSIS:
2432           type_seen = 1;
2433           hash = (hash << 1) ^ LA1;
2434           MATCH ();
2435           break;
2436 
2437         case '*':       case '&':       case '[':       case ']':
2438           hash = (hash << 1) ^ LA1;
2439           MATCH ();
2440           break;
2441 
2442         default:
2443           MATCH ();
2444           break;
2445         }
2446     }
2447 
2448   if (LOOKING_AT (')'))
2449     {
2450       MATCH ();
2451 
2452       if (LOOKING_AT (CONST))
2453         {
2454           /* We can overload the same function on `const' */
2455           hash = (hash << 1) ^ CONST;
2456           set_flag (flags, F_CONST);
2457           MATCH ();
2458         }
2459 
2460       if (LOOKING_AT (THROW))
2461         {
2462           MATCH ();
2463           SKIP_MATCHING_IF ('(');
2464           set_flag (flags, F_THROW);
2465         }
2466 
2467       if (LOOKING_AT ('='))
2468         {
2469           MATCH ();
2470           if (LOOKING_AT (CINT) && yyival == 0)
2471             {
2472               MATCH ();
2473               set_flag (flags, F_PURE);
2474             }
2475         }
2476     }
2477 
2478   return hash;
2479 }
2480 
2481 
2482 /* Print position info to stdout.  */
2483 
2484 static void
print_info(void)2485 print_info (void)
2486 {
2487   if (info_position >= 0 && BUFFER_POS () <= info_position)
2488     if (info_cls)
2489       printf ("(\"%s\" \"%s\" \"%s\" %d)\n",
2490 	      info_cls->name, sym_scope (info_cls),
2491 	      info_member->name, info_where);
2492 }
2493 
2494 
2495 /* Parse a member declaration within the class body of CLS.  VIS is
2496    the access specifier for the member (private, protected,
2497    public).  */
2498 
2499 static void
member(struct sym * cls,int vis)2500 member (struct sym *cls, int vis)
2501 {
2502   char *id = NULL;
2503   int sc = SC_MEMBER;
2504   char *regexp = NULL;
2505   int pos;
2506   int is_constructor;
2507   int flags = 0;
2508   int class_tag;
2509   char *class_name;
2510   int type_seen = 0;
2511   int paren_seen = 0;
2512   unsigned hash = 0;
2513   int tilde = 0;
2514 
2515   while (!LOOKING_AT4 (';', '{', '}', YYEOF))
2516     {
2517       switch (LA1)
2518         {
2519         default:
2520           MATCH ();
2521           break;
2522 
2523           /* A function or class may follow.  */
2524         case TEMPLATE:
2525           MATCH ();
2526           set_flag (&flags, F_TEMPLATE);
2527           /* Skip over template argument list */
2528           SKIP_MATCHING_IF ('<');
2529           break;
2530 
2531         case EXPLICIT:
2532           set_flag (&flags, F_EXPLICIT);
2533           goto typeseen;
2534 
2535         case MUTABLE:
2536           set_flag (&flags, F_MUTABLE);
2537           goto typeseen;
2538 
2539         case T_INLINE:
2540           set_flag (&flags, F_INLINE);
2541           goto typeseen;
2542 
2543         case VIRTUAL:
2544           set_flag (&flags, F_VIRTUAL);
2545           goto typeseen;
2546 
2547         case '[':
2548           skip_matching ();
2549           break;
2550 
2551         case ENUM:
2552           sc = SC_TYPE;
2553           goto typeseen;
2554 
2555         case TYPEDEF:
2556           sc = SC_TYPE;
2557           goto typeseen;
2558 
2559         case FRIEND:
2560           sc = SC_FRIEND;
2561           goto typeseen;
2562 
2563         case STATIC:
2564           sc = SC_STATIC;
2565           goto typeseen;
2566 
2567         case '~':
2568 	  tilde = 1;
2569           MATCH ();
2570           break;
2571 
2572         case IDENT:
2573 	  /* Remember IDENTS seen so far.  Among these will be the member
2574 	     name.  */
2575 	  id = (char *) xrealloc (id, strlen (yytext) + 2);
2576 	  if (tilde)
2577 	    {
2578 	      *id = '~';
2579 	      strcpy (id + 1, yytext);
2580 	    }
2581 	  else
2582 	    strcpy (id, yytext);
2583 	  MATCH ();
2584 	  break;
2585 
2586         case OPERATOR:
2587 	  {
2588 	    char *s = operator_name (&sc);
2589 	    id = (char *) xrealloc (id, strlen (s) + 1);
2590 	    strcpy (id, s);
2591 	  }
2592           break;
2593 
2594         case '(':
2595           /* Most probably the beginning of a parameter list.  */
2596           MATCH ();
2597           paren_seen = 1;
2598 
2599           if (id && cls)
2600             {
2601               if (!(is_constructor = streq (id, cls->name)))
2602                 regexp = matching_regexp ();
2603             }
2604           else
2605             is_constructor = 0;
2606 
2607           pos = BUFFER_POS ();
2608           hash = parm_list (&flags);
2609 
2610           if (is_constructor)
2611             regexp = matching_regexp ();
2612 
2613           if (id && cls != NULL)
2614 	    add_member_decl (cls, id, regexp, pos, hash, 0, sc, vis, flags);
2615 
2616           while (!LOOKING_AT3 (';', '{', YYEOF))
2617             MATCH ();
2618 
2619           if (LOOKING_AT ('{') && id && cls)
2620 	    add_member_defn (cls, id, regexp, pos, hash, 0, sc, flags);
2621 
2622 	  free (id);
2623           id = NULL;
2624           sc = SC_MEMBER;
2625           break;
2626 
2627         case STRUCT: case UNION: case CLASS:
2628           /* Nested class */
2629           class_tag = LA1;
2630           type_seen = 1;
2631           MATCH ();
2632           class_name = NULL;
2633 
2634           /* More than one ident here to allow for MS-DOS specialties
2635              like `_export class' etc.  The last IDENT seen counts
2636              as the class name.  */
2637 	  while (!LOOKING_AT4 (YYEOF, ';', ':', '{'))
2638 	    {
2639 	      if (LOOKING_AT (IDENT))
2640                 {
2641                   if (class_name)
2642                     {
2643                       int size = strlen (yytext);
2644 
2645                       if(strlen (class_name) < size)
2646                         {
2647                           class_name = (char *) xrealloc(class_name, size + 1);
2648                         }
2649 
2650                       memcpy(class_name, yytext, size + 1);
2651                     }
2652                   else
2653                     {
2654                       class_name = xstrdup(yytext);
2655                     }
2656                 }
2657 
2658               MATCH ();
2659 	    }
2660 
2661           if (LOOKING_AT2 (':', '{'))
2662 	    class_definition (class_name ? cls : NULL, class_name ? class_name : yytext, class_tag, flags, 1);
2663           else
2664             skip_to (';');
2665 
2666           free(class_name);
2667           break;
2668 
2669         case INT:       case CHAR:      case LONG:      case UNSIGNED:
2670         case SIGNED:    case CONST:     case DOUBLE:    case VOID:
2671         case SHORT:     case VOLATILE:  case BOOL:      case WCHAR:
2672         case TYPENAME:
2673         typeseen:
2674           type_seen = 1;
2675           MATCH ();
2676           break;
2677         }
2678     }
2679 
2680   if (LOOKING_AT (';'))
2681     {
2682       /* The end of a member variable, a friend declaration or an access
2683          declaration.  We don't want to add friend classes as members.  */
2684       if (id && sc != SC_FRIEND && cls)
2685         {
2686           regexp = matching_regexp ();
2687           pos = BUFFER_POS ();
2688 
2689           if (cls != NULL)
2690             {
2691               if (type_seen || !paren_seen)
2692 		add_member_decl (cls, id, regexp, pos, 0, 1, sc, vis, 0);
2693               else
2694 		add_member_decl (cls, id, regexp, pos, hash, 0, sc, vis, 0);
2695             }
2696         }
2697 
2698       MATCH ();
2699       print_info ();
2700     }
2701   else if (LOOKING_AT ('{'))
2702     {
2703       /* A named enum.  */
2704       if (sc == SC_TYPE && id && cls)
2705         {
2706           regexp = matching_regexp ();
2707           pos = BUFFER_POS ();
2708 
2709           if (cls != NULL)
2710             {
2711               add_member_decl (cls, id, regexp, pos, 0, 1, sc, vis, 0);
2712               add_member_defn (cls, id, regexp, pos, 0, 1, sc, 0);
2713             }
2714         }
2715 
2716       skip_matching ();
2717       print_info ();
2718     }
2719 
2720   free (id);
2721 }
2722 
2723 
2724 /* Parse the body of class CLS.  TAG is the tag of the class (struct,
2725    union, class).  */
2726 
2727 static void
class_body(struct sym * cls,int tag)2728 class_body (struct sym *cls, int tag)
2729 {
2730   int vis = tag == CLASS ? PRIVATE : PUBLIC;
2731   int temp;
2732 
2733   while (!LOOKING_AT2 (YYEOF, '}'))
2734     {
2735       switch (LA1)
2736         {
2737         case PRIVATE: case PROTECTED: case PUBLIC:
2738           temp = LA1;
2739           MATCH ();
2740 
2741           if (LOOKING_AT (':'))
2742             {
2743               vis = temp;
2744               MATCH ();
2745             }
2746           else
2747             {
2748               /* Probably conditional compilation for inheritance list.
2749                  We don't known whether there comes more of this.
2750                  This is only a crude fix that works most of the time.  */
2751               do
2752                 {
2753                   MATCH ();
2754                 }
2755               while (LOOKING_AT2 (IDENT, ',')
2756                      || LOOKING_AT3 (PUBLIC, PROTECTED, PRIVATE));
2757             }
2758           break;
2759 
2760         case TYPENAME:
2761         case USING:
2762           skip_to (';');
2763           break;
2764 
2765           /* Try to synchronize */
2766         case CHAR:      case CLASS:     case CONST:
2767         case DOUBLE:    case ENUM:      case FLOAT:     case INT:
2768         case LONG:      case SHORT:     case SIGNED:    case STRUCT:
2769         case UNION:     case UNSIGNED:  case VOID:      case VOLATILE:
2770         case TYPEDEF:   case STATIC:    case T_INLINE:  case FRIEND:
2771         case VIRTUAL:   case TEMPLATE:  case IDENT:     case '~':
2772         case BOOL:      case WCHAR:     case EXPLICIT:  case MUTABLE:
2773           member (cls, vis);
2774           break;
2775 
2776         default:
2777           MATCH ();
2778           break;
2779         }
2780     }
2781 }
2782 
2783 
2784 /* Parse a qualified identifier.  Current lookahead is IDENT.  A
2785    qualified ident has the form `X<..>::Y<...>::T<...>.  Returns a
2786    symbol for that class.  */
2787 
2788 static struct sym *
parse_classname(void)2789 parse_classname (void)
2790 {
2791   struct sym *last_class = NULL;
2792 
2793   while (LOOKING_AT (IDENT))
2794     {
2795       last_class = add_sym (yytext, last_class);
2796       MATCH ();
2797 
2798       if (LOOKING_AT ('<'))
2799         {
2800           skip_matching ();
2801           set_flag (&last_class->flags, F_TEMPLATE);
2802         }
2803 
2804       if (!LOOKING_AT (DCOLON))
2805         break;
2806 
2807       MATCH ();
2808     }
2809 
2810   return last_class;
2811 }
2812 
2813 
2814 /* Parse an operator name.  Add the `static' flag to *SC if an
2815    implicitly static operator has been parsed.  Value is a pointer to
2816    a static buffer holding the constructed operator name string.  */
2817 
2818 static char *
operator_name(int * sc)2819 operator_name (int *sc)
2820 {
2821   static size_t id_size = 0;
2822   static char *id = NULL;
2823   const char *s;
2824   size_t len;
2825 
2826   MATCH ();
2827 
2828   if (LOOKING_AT2 (NEW, DELETE))
2829     {
2830       /* `new' and `delete' are implicitly static.  */
2831       if (*sc != SC_FRIEND)
2832         *sc = SC_STATIC;
2833 
2834       s = token_string (LA1);
2835       MATCH ();
2836 
2837       ptrdiff_t slen = strlen (s);
2838       len = slen + 10;
2839       if (len > id_size)
2840 	{
2841 	  size_t new_size = max (len, 2 * id_size);
2842 	  id = (char *) xrealloc (id, new_size);
2843 	  id_size = new_size;
2844 	}
2845       char *z = stpcpy (id, s);
2846 
2847       /* Vector new or delete?  */
2848       if (LOOKING_AT ('['))
2849 	{
2850 	  z = stpcpy (z, "[");
2851 	  MATCH ();
2852 
2853 	  if (LOOKING_AT (']'))
2854 	    {
2855 	      strcpy (z, "]");
2856 	      MATCH ();
2857 	    }
2858 	}
2859     }
2860   else
2861     {
2862       size_t tokens_matched = 0;
2863 
2864       len = 20;
2865       if (len > id_size)
2866 	{
2867 	  int new_size = max (len, 2 * id_size);
2868 	  id = (char *) xrealloc (id, new_size);
2869 	  id_size = new_size;
2870 	}
2871       char *z = stpcpy (id, "operator");
2872 
2873       /* Beware access declarations of the form "X::f;" Beware of
2874 	 `operator () ()'.  Yet another difficulty is found in
2875 	 GCC 2.95's STL: `operator == __STL_NULL_TMPL_ARGS (...'.  */
2876       while (!(LOOKING_AT ('(') && tokens_matched)
2877 	     && !LOOKING_AT2 (';', YYEOF))
2878         {
2879 	  s = token_string (LA1);
2880 	  len += strlen (s) + 2;
2881 	  if (len > id_size)
2882 	    {
2883 	      ptrdiff_t idlen = z - id;
2884 	      size_t new_size = max (len, 2 * id_size);
2885 	      id = (char *) xrealloc (id, new_size);
2886 	      id_size = new_size;
2887 	      z = id + idlen;
2888 	    }
2889 
2890 	  if (*s != ')' && *s != ']')
2891 	    *z++ = ' ';
2892           z = stpcpy (z, s);
2893           MATCH ();
2894 
2895 	  /* If this is a simple operator like `+', stop now.  */
2896 	  if (!isalpha ((unsigned char) *s) && *s != '(' && *s != '[')
2897 	    break;
2898 
2899 	  ++tokens_matched;
2900         }
2901     }
2902 
2903   return id;
2904 }
2905 
2906 
2907 /* This one consumes the last IDENT of a qualified member name like
2908    `X::Y::z'.  This IDENT is returned in LAST_ID.  Value is the
2909    symbol structure for the ident.  */
2910 
2911 static struct sym *
parse_qualified_ident_or_type(char ** last_id)2912 parse_qualified_ident_or_type (char **last_id)
2913 {
2914   struct sym *cls = NULL;
2915   char *id = NULL;
2916   size_t id_size = 0;
2917   int enter = 0;
2918 
2919   while (LOOKING_AT (IDENT))
2920     {
2921       int len = strlen (yytext) + 1;
2922       if (len > id_size)
2923 	{
2924 	  id = (char *) xrealloc (id, len);
2925 	  id_size = len;
2926 	}
2927       strcpy (id, yytext);
2928       *last_id = id;
2929       MATCH ();
2930 
2931       SKIP_MATCHING_IF ('<');
2932 
2933       if (LOOKING_AT (DCOLON))
2934 	{
2935 	  struct sym *pcn = NULL;
2936 	  struct link *pna = check_namespace_alias (id);
2937 	  if (pna)
2938 	    {
2939 	      do
2940 		{
2941 		  enter_namespace (pna->sym->name);
2942 		  enter++;
2943 		  pna = pna->next;
2944 		}
2945 	      while (pna);
2946 	    }
2947 	  else if ((pcn = check_namespace (id, current_namespace)))
2948 	    {
2949 	      enter_namespace (pcn->name);
2950 	      enter++;
2951 	    }
2952 	  else
2953 	    cls = add_sym (id, cls);
2954 
2955 	  *last_id = NULL;
2956 	  free (id);
2957 	  id = NULL;
2958 	  id_size = 0;
2959 	  MATCH ();
2960 	}
2961       else
2962 	break;
2963     }
2964 
2965   while (enter--)
2966     leave_namespace ();
2967 
2968   return cls;
2969 }
2970 
2971 
2972 /* This one consumes the last IDENT of a qualified member name like
2973    `X::Y::z'.  This IDENT is returned in LAST_ID.  Value is the
2974    symbol structure for the ident.  */
2975 
2976 static void
parse_qualified_param_ident_or_type(char ** last_id)2977 parse_qualified_param_ident_or_type (char **last_id)
2978 {
2979   struct sym *cls = NULL;
2980   static char *id = NULL;
2981   static int id_size = 0;
2982 
2983   assert (LOOKING_AT (IDENT));
2984 
2985   do
2986     {
2987       int len = strlen (yytext) + 1;
2988       if (len > id_size)
2989 	{
2990 	  id = (char *) xrealloc (id, len);
2991 	  id_size = len;
2992 	}
2993       strcpy (id, yytext);
2994       *last_id = id;
2995       MATCH ();
2996 
2997       SKIP_MATCHING_IF ('<');
2998 
2999       if (LOOKING_AT (DCOLON))
3000 	{
3001 	  cls = add_sym (id, cls);
3002 	  *last_id = NULL;
3003 	  MATCH ();
3004 	}
3005       else
3006 	break;
3007     }
3008   while (LOOKING_AT (IDENT));
3009 }
3010 
3011 
3012 /* Parse a class definition.
3013 
3014    CONTAINING is the class containing the class being parsed or null.
3015    This may also be null if NESTED != 0 if the containing class is
3016    anonymous.  TAG is the tag of the class (struct, union, class).
3017    NESTED is non-zero if we are parsing a nested class.
3018 
3019    Current lookahead is the class name.  */
3020 
3021 static void
class_definition(struct sym * containing,const char * class_name,int tag,int flags,int nested)3022 class_definition (struct sym *containing, const char *class_name, int tag, int flags, int nested)
3023 {
3024   struct sym *current;
3025   struct sym *base_class;
3026 
3027   /* Set CURRENT to null if no entry has to be made for the class
3028      parsed.  This is the case for certain command line flag
3029      settings.  */
3030   if ((tag != CLASS && !f_structs) || (nested && !f_nested_classes))
3031     current = NULL;
3032   else
3033     {
3034       current = add_sym (class_name, containing);
3035       current->pos = BUFFER_POS ();
3036       current->regexp = matching_regexp ();
3037       current->filename = filename;
3038       current->flags = flags;
3039     }
3040 
3041   /* If at ':', base class list follows.  */
3042   if (LOOKING_AT (':'))
3043     {
3044       int done = 0;
3045       MATCH ();
3046 
3047       while (!done)
3048         {
3049           switch (LA1)
3050             {
3051             case VIRTUAL: case PUBLIC: case PROTECTED: case PRIVATE:
3052               MATCH ();
3053               break;
3054 
3055             case IDENT:
3056               base_class = parse_classname ();
3057               if (base_class && current && base_class != current)
3058                 add_link (base_class, current);
3059               break;
3060 
3061               /* The `,' between base classes or the end of the base
3062                  class list.  Add the previously found base class.
3063                  It's done this way to skip over sequences of
3064                  `A::B::C' until we reach the end.
3065 
3066                  FIXME: it is now possible to handle `class X : public B::X'
3067                  because we have enough information.  */
3068             case ',':
3069               MATCH ();
3070               break;
3071 
3072             default:
3073               /* A syntax error, possibly due to preprocessor constructs
3074                  like
3075 
3076                  #ifdef SOMETHING
3077                  class A : public B
3078                  #else
3079                  class A : private B.
3080 
3081                  MATCH until we see something like `;' or `{'.  */
3082               while (!LOOKING_AT3 (';', YYEOF, '{'))
3083                 MATCH ();
3084 	      FALLTHROUGH;
3085             case '{':
3086               done = 1;
3087 	      break;
3088             }
3089         }
3090     }
3091 
3092   /* Parse the class body if there is one.  */
3093   if (LOOKING_AT ('{'))
3094     {
3095       if (tag != CLASS && !f_structs)
3096         skip_matching ();
3097       else
3098         {
3099           MATCH ();
3100           class_body (current, tag);
3101 
3102           if (LOOKING_AT ('}'))
3103             {
3104               MATCH ();
3105               if (LOOKING_AT (';') && !nested)
3106                 MATCH ();
3107             }
3108         }
3109     }
3110 }
3111 
3112 /* Add to class *CLS information for the declaration of variable or
3113    type *ID.  If *CLS is null, this means a global declaration.  SC is
3114    the storage class of *ID.  FLAGS is a bit set giving additional
3115    information about the member (see the F_* defines).  */
3116 
3117 static void
add_declarator(struct sym ** cls,char ** id,int flags,int sc)3118 add_declarator (struct sym **cls, char **id, int flags, int sc)
3119 {
3120   if (LOOKING_AT2 (';', ','))
3121     {
3122       /* The end of a member variable or of an access declaration
3123          `X::f'.  To distinguish between them we have to know whether
3124          type information has been seen.  */
3125       if (*id)
3126         {
3127           char *regexp = matching_regexp ();
3128           int pos = BUFFER_POS ();
3129 
3130           if (*cls)
3131 	    add_member_defn (*cls, *id, regexp, pos, 0, 1, SC_UNKNOWN, flags);
3132           else
3133             add_global_defn (*id, regexp, pos, 0, 1, sc, flags);
3134         }
3135 
3136       MATCH ();
3137       print_info ();
3138     }
3139   else if (LOOKING_AT ('{'))
3140     {
3141       if (sc == SC_TYPE && *id)
3142         {
3143           /* A named enumeration.  */
3144           char *regexp = matching_regexp ();
3145           int pos = BUFFER_POS ();
3146           add_global_defn (*id, regexp, pos, 0, 1, sc, flags);
3147         }
3148 
3149       skip_matching ();
3150       print_info ();
3151     }
3152 
3153   free (*id);
3154   *id = NULL;
3155   *cls = NULL;
3156 }
3157 
3158 /* Parse a declaration.  */
3159 
3160 static void
declaration(int flags)3161 declaration (int flags)
3162 {
3163   char *id = NULL;
3164   struct sym *cls = NULL;
3165   char *regexp = NULL;
3166   int pos = 0;
3167   unsigned hash = 0;
3168   int is_constructor;
3169   int sc = 0;
3170 
3171   while (!LOOKING_AT3 (';', '{', YYEOF))
3172     {
3173       switch (LA1)
3174         {
3175         default:
3176           MATCH ();
3177           break;
3178 
3179         case '[':
3180           skip_matching ();
3181           break;
3182 
3183         case ENUM:
3184         case TYPEDEF:
3185           sc = SC_TYPE;
3186           MATCH ();
3187           break;
3188 
3189         case STATIC:
3190           sc = SC_STATIC;
3191           MATCH ();
3192           break;
3193 
3194         case INT:       case CHAR:      case LONG:      case UNSIGNED:
3195         case SIGNED:    case CONST:     case DOUBLE:    case VOID:
3196         case SHORT:     case VOLATILE:  case BOOL:      case WCHAR:
3197           MATCH ();
3198           break;
3199 
3200         case CLASS: case STRUCT: case UNION:
3201           /* This is for the case `STARTWRAP class X : ...' or
3202              `declare (X, Y)\n class A : ...'.  */
3203           if (id)
3204 	    {
3205 	      free (id);
3206 	      return;
3207 	    }
3208 	  FALLTHROUGH;
3209         case '=':
3210           /* Assumed to be the start of an initialization in this
3211 	     context.  */
3212 	  skip_initializer ();
3213           break;
3214 
3215 	case ',':
3216 	  add_declarator (&cls, &id, flags, sc);
3217 	  break;
3218 
3219         case OPERATOR:
3220 	  {
3221 	    char *s = operator_name (&sc);
3222 	    id = (char *) xrealloc (id, strlen (s) + 1);
3223 	    strcpy (id, s);
3224 	  }
3225           break;
3226 
3227         case T_INLINE:
3228           set_flag (&flags, F_INLINE);
3229           MATCH ();
3230           break;
3231 
3232         case '~':
3233 	  MATCH ();
3234 	  if (LOOKING_AT (IDENT))
3235 	    {
3236 	      id = (char *) xrealloc (id, strlen (yytext) + 2);
3237 	      *id = '~';
3238 	      strcpy (id + 1, yytext);
3239 	      MATCH ();
3240 	    }
3241           break;
3242 
3243         case IDENT:
3244 	  cls = parse_qualified_ident_or_type (&id);
3245           break;
3246 
3247         case '(':
3248           /* Most probably the beginning of a parameter list.  */
3249           if (cls)
3250             {
3251               MATCH ();
3252 
3253               if (id && cls)
3254                 {
3255                   if (!(is_constructor = streq (id, cls->name)))
3256                     regexp = matching_regexp ();
3257                 }
3258               else
3259                 is_constructor = 0;
3260 
3261               pos = BUFFER_POS ();
3262               hash = parm_list (&flags);
3263 
3264               if (is_constructor)
3265                 regexp = matching_regexp ();
3266 
3267               if (id && cls)
3268 		add_member_defn (cls, id, regexp, pos, hash, 0,
3269 				 SC_UNKNOWN, flags);
3270             }
3271           else
3272             {
3273               /* This may be a C functions, but also a macro
3274                  call of the form `declare (A, B)' --- such macros
3275                  can be found in some class libraries.  */
3276               MATCH ();
3277 
3278               if (id)
3279                 {
3280                   regexp = matching_regexp ();
3281                   pos = BUFFER_POS ();
3282                   hash = parm_list (&flags);
3283                   add_global_decl (id, regexp, pos, hash, 0, sc, flags);
3284                 }
3285 
3286               /* This is for the case that the function really is
3287                  a macro with no `;' following it.  If a CLASS directly
3288                  follows, we would miss it otherwise.  */
3289               if (LOOKING_AT3 (CLASS, STRUCT, UNION))
3290                 return;
3291             }
3292 
3293           while (!LOOKING_AT3 (';', '{', YYEOF))
3294             MATCH ();
3295 
3296           if (!cls && id && LOOKING_AT ('{'))
3297 	    add_global_defn (id, regexp, pos, hash, 0, sc, flags);
3298 
3299 	  free (id);
3300           id = NULL;
3301           break;
3302         }
3303     }
3304 
3305   add_declarator (&cls, &id, flags, sc);
3306 }
3307 
3308 
3309 /* Parse a list of top-level declarations/definitions.  START_FLAGS
3310    says in which context we are parsing.  If it is F_EXTERNC, we are
3311    parsing in an `extern "C"' block.  Value is 1 if EOF is reached, 0
3312    otherwise.  */
3313 
3314 static int
globals(int start_flags)3315 globals (int start_flags)
3316 {
3317   int class_tk;
3318   char *class_name;
3319   int flags = start_flags;
3320 
3321   for (;;)
3322     {
3323       char *prev_in = in;
3324 
3325       switch (LA1)
3326         {
3327         case NAMESPACE:
3328           {
3329             MATCH ();
3330 
3331             if (LOOKING_AT (IDENT))
3332               {
3333                 char *namespace_name = xstrdup (yytext);
3334                 MATCH ();
3335 
3336                 if (LOOKING_AT ('='))
3337                   {
3338 		    struct link *qna = match_qualified_namespace_alias ();
3339 		    if (qna)
3340                       register_namespace_alias (namespace_name, qna);
3341 
3342                     if (skip_to (';') == ';')
3343                       MATCH ();
3344                   }
3345                 else if (LOOKING_AT ('{'))
3346                   {
3347                     MATCH ();
3348                     enter_namespace (namespace_name);
3349                     globals (0);
3350                     leave_namespace ();
3351                     MATCH_IF ('}');
3352                   }
3353 
3354 		free (namespace_name);
3355               }
3356           }
3357           break;
3358 
3359         case EXTERN:
3360           MATCH ();
3361           if (LOOKING_AT (CSTRING) && *string_start == 'C'
3362               && *(string_start + 1) == '"')
3363             {
3364               /* This is `extern "C"'.  */
3365               MATCH ();
3366 
3367               if (LOOKING_AT ('{'))
3368                 {
3369                   MATCH ();
3370                   globals (F_EXTERNC);
3371                   MATCH_IF ('}');
3372                 }
3373               else
3374                 set_flag (&flags, F_EXTERNC);
3375             }
3376           break;
3377 
3378         case TEMPLATE:
3379           MATCH ();
3380           SKIP_MATCHING_IF ('<');
3381           set_flag (&flags, F_TEMPLATE);
3382           break;
3383 
3384         case CLASS: case STRUCT: case UNION:
3385           class_tk = LA1;
3386           MATCH ();
3387           class_name = NULL;
3388 
3389           /* More than one ident here to allow for MS-DOS and OS/2
3390              specialties like `far', `_Export' etc.  Some C++ libs
3391              have constructs like `_OS_DLLIMPORT(_OS_CLIENT)' in front
3392              of the class name.  */
3393 	  while (!LOOKING_AT4 (YYEOF, ';', ':', '{'))
3394 	    {
3395 	      if (LOOKING_AT (IDENT))
3396                 {
3397                   if (class_name)
3398                     {
3399                       int size = strlen (yytext);
3400 
3401                       if(strlen (class_name) < size)
3402                         {
3403                           class_name = (char *) xrealloc(class_name, size + 1);
3404                         }
3405 
3406                       memcpy(class_name, yytext, size + 1);
3407                     }
3408                   else
3409                     {
3410                       class_name = xstrdup(yytext);
3411                     }
3412                 }
3413 
3414 	      MATCH ();
3415 	    }
3416 
3417           /* Don't add anonymous unions.  */
3418           if (LOOKING_AT2 (':', '{') && class_name)
3419             class_definition (NULL, class_name, class_tk, flags, 0);
3420           else
3421             {
3422               if (skip_to (';') == ';')
3423                 MATCH ();
3424             }
3425 
3426           free(class_name);
3427           flags = start_flags;
3428           break;
3429 
3430         case YYEOF:
3431           return 1;
3432 
3433         case '}':
3434           return 0;
3435 
3436         default:
3437           declaration (flags);
3438           flags = start_flags;
3439           break;
3440         }
3441 
3442       if (prev_in == in)
3443         yyerror ("parse error", NULL);
3444     }
3445 }
3446 
3447 
3448 /* Parse the current input file.  */
3449 
3450 static void
yyparse(void)3451 yyparse (void)
3452 {
3453   while (globals (0) == 0)
3454     MATCH_IF ('}');
3455 }
3456 
3457 
3458 
3459 /***********************************************************************
3460 			     Main Program
3461  ***********************************************************************/
3462 
3463 /* Add the list of paths PATH_LIST to the current search path for
3464    input files.  */
3465 
3466 static void
add_search_path(char * path_list)3467 add_search_path (char *path_list)
3468 {
3469   while (*path_list)
3470     {
3471       char *start = path_list;
3472       struct search_path *p;
3473 
3474       while (*path_list && *path_list != SEPCHAR)
3475         ++path_list;
3476 
3477       p = (struct search_path *) xmalloc (sizeof *p);
3478       p->path = (char *) xmalloc (path_list - start + 1);
3479       memcpy (p->path, start, path_list - start);
3480       p->path[path_list - start] = '\0';
3481       p->next = NULL;
3482 
3483       if (search_path_tail)
3484         {
3485           search_path_tail->next = p;
3486           search_path_tail = p;
3487         }
3488       else
3489         search_path = search_path_tail = p;
3490 
3491       while (*path_list == SEPCHAR)
3492         ++path_list;
3493     }
3494 }
3495 
3496 
3497 /* Open FILE and return a file handle for it, or -1 if FILE cannot be
3498    opened.  Try to find FILE in search_path first, then try the
3499    unchanged file name.  */
3500 
3501 static FILE *
open_file(char * file)3502 open_file (char *file)
3503 {
3504   FILE *fp = NULL;
3505   static char *buffer;
3506   static int buffer_size;
3507   struct search_path *path;
3508   int flen = strlen (file) + 1;	/* +1 for the slash */
3509 
3510   filename = xstrdup (file);
3511 
3512   for (path = search_path; path && fp == NULL; path = path->next)
3513     {
3514       int len = strlen (path->path) + flen;
3515 
3516       if (len + 1 >= buffer_size)
3517 	{
3518 	  buffer_size = max (len + 1, 2 * buffer_size);
3519 	  buffer = (char *) xrealloc (buffer, buffer_size);
3520 	}
3521 
3522       char *z = stpcpy (buffer, path->path);
3523       *z++ = '/';
3524       strcpy (z, file);
3525       fp = fopen (buffer, "r");
3526     }
3527 
3528   /* Try the original file name.  */
3529   if (fp == NULL)
3530      fp = fopen (file, "r");
3531 
3532   if (fp == NULL)
3533     yyerror ("cannot open", NULL);
3534 
3535   return fp;
3536 }
3537 
3538 
3539 /* Display usage information and exit program.  */
3540 
3541 static char const *const usage_message[] =
3542   {
3543     "\
3544 Usage: ebrowse [options] {files}\n\
3545 \n\
3546   -a, --append                  append output to existing file\n\
3547   -f, --files=FILES             read input file names from FILE\n\
3548   -I, --search-path=LIST        set search path for input files\n\
3549   -m, --min-regexp-length=N     set minimum regexp length to N\n\
3550   -M, --max-regexp-length=N     set maximum regexp length to N\n\
3551 ",
3552     "\
3553   -n, --no-nested-classes       exclude nested classes\n\
3554   -o, --output-file=FILE        set output file name to FILE\n\
3555   -p, --position-info           print info about position in file\n\
3556   -s, --no-structs-or-unions    don't record structs or unions\n\
3557   -v, --verbose                 be verbose\n\
3558   -V, --very-verbose            be very verbose\n\
3559   -x, --no-regexps		don't record regular expressions\n\
3560       --help                    display this help\n\
3561       --version			display version info\n\
3562 \n\
3563 "
3564   };
3565 
3566 static _Noreturn void
usage(int error)3567 usage (int error)
3568 {
3569   int i;
3570   for (i = 0; i < sizeof usage_message / sizeof *usage_message; i++)
3571     fputs (usage_message[i], stdout);
3572   exit (error ? EXIT_FAILURE : EXIT_SUCCESS);
3573 }
3574 
3575 
3576 /* Display version and copyright info.  */
3577 
3578 static _Noreturn void
version(void)3579 version (void)
3580 {
3581   fputs (("ebrowse " PACKAGE_VERSION "\n"
3582 	  COPYRIGHT "\n"
3583 	  "This program is distributed under the same terms as Emacs.\n"),
3584 	 stdout);
3585   exit (EXIT_SUCCESS);
3586 }
3587 
3588 
3589 /* Parse one input file FILE, adding classes and members to the symbol
3590    table.  */
3591 
3592 static void
process_file(char * file)3593 process_file (char *file)
3594 {
3595   FILE *fp;
3596 
3597   fp = open_file (file);
3598   if (fp)
3599     {
3600       size_t nread, nbytes;
3601 
3602       /* Give a progress indication if needed.  */
3603       if (f_very_verbose)
3604         {
3605           puts (filename);
3606           fflush (stdout);
3607         }
3608       else if (f_verbose)
3609         {
3610           putchar ('.');
3611           fflush (stdout);
3612         }
3613 
3614       /* Read file to inbuffer.  */
3615       for (nread = 0;;)
3616 	{
3617 	  if (nread + READ_CHUNK_SIZE >= inbuffer_size)
3618 	    {
3619 	      inbuffer_size = nread + READ_CHUNK_SIZE + 1;
3620 	      inbuffer = (char *) xrealloc (inbuffer, inbuffer_size);
3621 	    }
3622 
3623 	  nbytes = fread (inbuffer + nread, 1, READ_CHUNK_SIZE, fp);
3624 	  if (nbytes == 0)
3625 	    break;
3626 	  nread += nbytes;
3627 	}
3628       inbuffer[nread] = '\0';
3629 
3630       /* Reinitialize scanner and parser for the new input file.  */
3631       re_init_scanner ();
3632       re_init_parser ();
3633 
3634       /* Parse it and close the file.  */
3635       yyparse ();
3636       fclose (fp);
3637     }
3638 }
3639 
3640 
3641 /* Read a line from stream FP and return a pointer to a static buffer
3642    containing its contents without the terminating newline.  Value
3643    is null when EOF is reached.  */
3644 
3645 static char *
read_line(FILE * fp)3646 read_line (FILE *fp)
3647 {
3648   static char *buffer;
3649   static int buffer_size;
3650   int i = 0, c;
3651 
3652   while ((c = getc (fp)) != EOF && c != '\n')
3653     {
3654       if (i >= buffer_size)
3655 	{
3656 	  buffer_size = max (100, buffer_size * 2);
3657 	  buffer = (char *) xrealloc (buffer, buffer_size);
3658 	}
3659 
3660       buffer[i++] = c;
3661     }
3662 
3663   if (c == EOF && i == 0)
3664     return NULL;
3665 
3666   if (i == buffer_size)
3667     {
3668       buffer_size = max (100, buffer_size * 2);
3669       buffer = (char *) xrealloc (buffer, buffer_size);
3670     }
3671 
3672   buffer[i] = '\0';
3673   if (i > 0 && buffer[i - 1] == '\r')
3674     buffer[i - 1] = '\0';
3675   return buffer;
3676 }
3677 
3678 
3679 /* Main entry point.  */
3680 
3681 int
main(int argc,char ** argv)3682 main (int argc, char **argv)
3683 {
3684   int i;
3685   int any_inputfiles = 0;
3686   static const char *out_filename = DEFAULT_OUTFILE;
3687   static char **input_filenames = NULL;
3688   static int input_filenames_size = 0;
3689   static int n_input_files;
3690 
3691   filename = "command line";
3692   yyout = stdout;
3693 
3694   while ((i = getopt_long (argc, argv, "af:I:m:M:no:p:svVx",
3695                            options, NULL)) != EOF)
3696     {
3697       switch (i)
3698         {
3699 	  /* Experimental.  */
3700 	case 'p':
3701 	  info_position = atoi (optarg);
3702 	  break;
3703 
3704         case 'n':
3705           f_nested_classes = 0;
3706           break;
3707 
3708         case 'x':
3709           f_regexps = 0;
3710           break;
3711 
3712           /* Add the name of a file containing more input files.  */
3713         case 'f':
3714 	  if (n_input_files == input_filenames_size)
3715 	    {
3716 	      input_filenames_size = max (10, 2 * input_filenames_size);
3717 	      input_filenames = (char **) xrealloc ((void *)input_filenames,
3718 						    input_filenames_size);
3719 	    }
3720           input_filenames[n_input_files++] = xstrdup (optarg);
3721           break;
3722 
3723           /* Append new output to output file instead of truncating it.  */
3724         case 'a':
3725           f_append = 1;
3726           break;
3727 
3728           /* Include structs in the output */
3729         case 's':
3730           f_structs = 0;
3731           break;
3732 
3733           /* Be verbose (give a progress indication).  */
3734         case 'v':
3735           f_verbose = 1;
3736           break;
3737 
3738           /* Be very verbose (print file names as they are processed).  */
3739         case 'V':
3740           f_verbose = 1;
3741           f_very_verbose = 1;
3742           break;
3743 
3744           /* Change the name of the output file.  */
3745         case 'o':
3746 	  out_filename = optarg;
3747           break;
3748 
3749           /* Set minimum length for regular expression strings
3750              when recorded in the output file.  */
3751         case 'm':
3752           min_regexp = atoi (optarg);
3753           break;
3754 
3755           /* Set maximum length for regular expression strings
3756              when recorded in the output file.  */
3757         case 'M':
3758           max_regexp = atoi (optarg);
3759           break;
3760 
3761           /* Add to search path.  */
3762         case 'I':
3763           add_search_path (optarg);
3764           break;
3765 
3766           /* Display help */
3767         case -2:
3768           usage (0);
3769           break;
3770 
3771 	case -3:
3772 	  version ();
3773 	  break;
3774         }
3775     }
3776 
3777   /* Call init_scanner after command line flags have been processed to be
3778      able to add keywords depending on command line (not yet
3779      implemented).  */
3780   init_scanner ();
3781   init_sym ();
3782 
3783   /* Open output file */
3784   if (*out_filename)
3785     {
3786       if (f_append)
3787 	{
3788 	  /* Check that the file to append to exists, and is not
3789 	     empty.  More specifically, it should be a valid file
3790 	     produced by a previous run of ebrowse, but that's too
3791 	     difficult to check.  */
3792 	  FILE *fp;
3793 	  int rc;
3794 
3795 	  fp = fopen (out_filename, "r");
3796 	  if (fp == NULL)
3797 	    {
3798 	      yyerror ("file '%s' must exist for --append", out_filename);
3799 	      exit (EXIT_FAILURE);
3800 	    }
3801 
3802 	  rc = fseek (fp, 0, SEEK_END);
3803 	  if (rc == -1)
3804 	    {
3805 	      yyerror ("error seeking in file '%s'", out_filename);
3806 	      exit (EXIT_FAILURE);
3807 	    }
3808 
3809 	  rc = ftell (fp);
3810 	  if (rc == -1)
3811 	    {
3812 	      yyerror ("error getting size of file '%s'", out_filename);
3813 	      exit (EXIT_FAILURE);
3814 	    }
3815 
3816 	  else if (rc == 0)
3817 	    {
3818 	      yyerror ("file '%s' is empty", out_filename);
3819 	      /* It may be ok to use an empty file for appending.
3820 		 exit (EXIT_FAILURE); */
3821 	    }
3822 
3823 	  fclose (fp);
3824 	}
3825 
3826       yyout = fopen (out_filename, f_append ? "a" : "w");
3827       if (yyout == NULL)
3828 	{
3829 	  yyerror ("cannot open output file '%s'", out_filename);
3830 	  exit (EXIT_FAILURE);
3831 	}
3832     }
3833 
3834   /* Process input files specified on the command line.  */
3835   while (optind < argc)
3836     {
3837       process_file (argv[optind++]);
3838       any_inputfiles = 1;
3839     }
3840 
3841   /* Process files given on stdin if no files specified.  */
3842   if (!any_inputfiles && n_input_files == 0)
3843     {
3844       char *file;
3845       while ((file = read_line (stdin)) != NULL)
3846 	process_file (file);
3847     }
3848   else
3849     {
3850       /* Process files from `--files=FILE'.  Every line in FILE names
3851 	 one input file to process.  */
3852       for (i = 0; i < n_input_files; ++i)
3853         {
3854           FILE *fp = fopen (input_filenames[i], "r");
3855 
3856           if (fp == NULL)
3857             yyerror ("cannot open input file '%s'", input_filenames[i]);
3858           else
3859             {
3860 	      char *file;
3861 	      while ((file = read_line (fp)) != NULL)
3862 		process_file (file);
3863               fclose (fp);
3864             }
3865         }
3866     }
3867 
3868   /* Write output file.  */
3869   dump_roots (yyout);
3870 
3871   /* Close output file.  */
3872   if (yyout != stdout)
3873     fclose (yyout);
3874 
3875   return EXIT_SUCCESS;
3876 }
3877 
3878 /* ebrowse.c ends here */
3879