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