mirrored from git://git.sv.gnu.org/emacs.git
-
Notifications
You must be signed in to change notification settings - Fork 1.3k
/
Copy pathebrowse.c
3932 lines (3243 loc) · 94.2 KB
/
ebrowse.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/* ebrowse.c --- parsing files for the ebrowse C++ browser
Copyright (C) 1992-2025 Free Software Foundation, Inc.
This file is part of GNU Emacs.
GNU Emacs is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or (at
your option) any later version.
GNU Emacs is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
#include <config.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <getopt.h>
#include <attribute.h>
#include <c-ctype.h>
#include <flexmember.h>
#include <min-max.h>
#include <unlocked-io.h>
/* Files are read in chunks of this number of bytes. */
enum { READ_CHUNK_SIZE = 100 * 1024 };
/* Value is true if strings X and Y compare equal. */
static bool
streq (char const *x, char const *y)
{
return strcmp (x, y) == 0;
}
static bool
filename_eq (char const *x, char const *y)
{
#ifdef __MSDOS__
return strcasecmp (x, y) == 0;
#elif defined WINDOWSNT
return stricmp (x, y) == 0;
#else
return streq (x, y);
#endif
}
/* The default output file name. */
#define DEFAULT_OUTFILE "BROWSE"
/* A version string written to the output file. Change this whenever
the structure of the output file changes. */
#define EBROWSE_FILE_VERSION "ebrowse 5.0"
/* The output file consists of a tree of Lisp objects, with major
nodes built out of Lisp structures. These are the heads of the
Lisp structs with symbols identifying their type. */
#define TREE_HEADER_STRUCT "[ebrowse-hs "
#define TREE_STRUCT "[ebrowse-ts "
#define MEMBER_STRUCT "[ebrowse-ms "
#define CLASS_STRUCT "[ebrowse-cs "
/* The name of the symbol table entry for global functions, variables,
defines etc. This name also appears in the browser display. */
#define GLOBALS_NAME "*Globals*"
/* Token definitions. */
enum token
{
YYEOF = 0, /* end of file */
CSTRING = 256, /* string constant */
CCHAR, /* character constant */
CINT, /* integral constant */
CFLOAT, /* real constant */
ELLIPSIS, /* ... */
LSHIFTASGN, /* <<= */
RSHIFTASGN, /* >>= */
ARROWSTAR, /* ->* */
IDENT, /* identifier */
DIVASGN, /* /= */
INC, /* ++ */
ADDASGN, /* += */
DEC, /* -- */
ARROW, /* -> */
SUBASGN, /* -= */
MULASGN, /* *= */
MODASGN, /* %= */
LOR, /* || */
ORASGN, /* |= */
LAND, /* && */
ANDASGN, /* &= */
XORASGN, /* ^= */
POINTSTAR, /* .* */
DCOLON, /* :: */
EQ, /* == */
NE, /* != */
LE, /* <= */
LSHIFT, /* << */
GE, /* >= */
RSHIFT, /* >> */
/* Keywords. The undef's are there because these
three symbols are very likely to be defined somewhere. */
#undef BOOL
#undef TRUE
#undef FALSE
ASM, /* asm */
AUTO, /* auto */
BREAK, /* break */
CASE, /* case */
CATCH, /* catch */
CHAR, /* char */
CLASS, /* class */
CONST, /* const */
CONTINUE, /* continue */
DEFAULT, /* default */
DELETE, /* delete */
DO, /* do */
DOUBLE, /* double */
ELSE, /* else */
ENUM, /* enum */
EXTERN, /* extern */
FLOAT, /* float */
FOR, /* for */
FRIEND, /* friend */
GOTO, /* goto */
IF, /* if */
T_INLINE, /* inline */
INT, /* int */
LONG, /* long */
NEW, /* new */
OPERATOR, /* operator */
PRIVATE, /* private */
PROTECTED, /* protected */
PUBLIC, /* public */
REGISTER, /* register */
RETURN, /* return */
SHORT, /* short */
SIGNED, /* signed */
SIZEOF, /* sizeof */
STATIC, /* static */
STRUCT, /* struct */
SWITCH, /* switch */
TEMPLATE, /* template */
THIS, /* this */
THROW, /* throw */
TRY, /* try */
TYPEDEF, /* typedef */
UNION, /* union */
UNSIGNED, /* unsigned */
VIRTUAL, /* virtual */
VOID, /* void */
VOLATILE, /* volatile */
WHILE, /* while */
MUTABLE, /* mutable */
BOOL, /* bool */
TRUE, /* true */
FALSE, /* false */
SIGNATURE, /* signature (GNU extension) */
NAMESPACE, /* namespace */
EXPLICIT, /* explicit */
TYPENAME, /* typename */
CONST_CAST, /* const_cast */
DYNAMIC_CAST, /* dynamic_cast */
REINTERPRET_CAST, /* reinterpret_cast */
STATIC_CAST, /* static_cast */
TYPEID, /* typeid */
USING, /* using */
WCHAR, /* wchar_t */
FINAL /* final */
};
/* Storage classes, in a wider sense. */
enum sc
{
SC_UNKNOWN,
SC_MEMBER, /* Is an instance member. */
SC_STATIC, /* Is static member. */
SC_FRIEND, /* Is friend function. */
SC_TYPE /* Is a type definition. */
};
/* Member visibility. */
enum visibility
{
V_PUBLIC,
V_PROTECTED,
V_PRIVATE
};
/* Member flags. */
#define F_VIRTUAL 1 /* Is virtual function. */
#define F_INLINE 2 /* Is inline function. */
#define F_CONST 4 /* Is const. */
#define F_PURE 8 /* Is pure virtual function. */
#define F_MUTABLE 16 /* Is mutable. */
#define F_TEMPLATE 32 /* Is a template. */
#define F_EXPLICIT 64 /* Is explicit constructor. */
#define F_THROW 128 /* Has a throw specification. */
#define F_EXTERNC 256 /* Is declared extern "C". */
#define F_DEFINE 512 /* Is a #define. */
/* Set and test a bit in an int. */
static void
set_flag (int *f, int flag)
{
*f |= flag;
}
static bool
has_flag (int f, int flag)
{
return (f & flag) != 0;
}
/* Structure describing a class member. */
struct member
{
struct member *next; /* Next in list of members. */
struct member *anext; /* Collision chain in member_table. */
struct member **list; /* Pointer to list in class. */
unsigned param_hash; /* Hash value for parameter types. */
int vis; /* Visibility (public, ...). */
int flags; /* See F_* above. */
char *regexp; /* Matching regular expression. */
const char *filename; /* Don't free this shared string. */
int pos; /* Buffer position of occurrence. */
char *def_regexp; /* Regular expression matching definition. */
const char *def_filename; /* File name of definition. */
int def_pos; /* Buffer position of definition. */
char name[FLEXIBLE_ARRAY_MEMBER]; /* Member name. */
};
/* Structures of this type are used to connect class structures with
their super and subclasses. */
struct link
{
struct sym *sym; /* The super or subclass. */
struct link *next; /* Next in list or NULL. */
};
/* Structure used to record namespace aliases. */
struct alias
{
struct alias *next; /* Next in list. */
struct sym *namesp; /* Namespace in which defined. */
struct link *aliasee; /* List of aliased namespaces (A::B::C...). */
char name[FLEXIBLE_ARRAY_MEMBER]; /* Alias name. */
};
/* The structure used to describe a class in the symbol table,
or a namespace in all_namespaces. */
struct sym
{
int flags; /* Is class a template class?. */
unsigned char visited; /* Used to find circles. */
struct sym *next; /* Hash collision list. */
struct link *subs; /* List of subclasses. */
struct link *supers; /* List of superclasses. */
struct member *vars; /* List of instance variables. */
struct member *fns; /* List of instance functions. */
struct member *static_vars; /* List of static variables. */
struct member *static_fns; /* List of static functions. */
struct member *friends; /* List of friend functions. */
struct member *types; /* List of local types. */
char *regexp; /* Matching regular expression. */
int pos; /* Buffer position. */
const char *filename; /* File in which it can be found. */
const char *sfilename; /* File in which members can be found. */
struct sym *namesp; /* Namespace in which defined. . */
char name[FLEXIBLE_ARRAY_MEMBER]; /* Name of the class. */
};
/* Experimental: Print info for `--position-info'. We print
'(CLASS-NAME SCOPE MEMBER-NAME). */
#define P_DEFN 1
#define P_DECL 2
static int info_where;
static struct sym *info_cls = NULL;
static struct member *info_member = NULL;
/* Experimental. For option `--position-info', the buffer position we
are interested in. When this position is reached, print out
information about what we know about that point. */
static int info_position = -1;
/* Command line options structure for getopt_long. */
static struct option const options[] =
{
{"append", no_argument, NULL, 'a'},
{"files", required_argument, NULL, 'f'},
{"help", no_argument, NULL, -2},
{"min-regexp-length", required_argument, NULL, 'm'},
{"max-regexp-length", required_argument, NULL, 'M'},
{"no-nested-classes", no_argument, NULL, 'n'},
{"no-regexps", no_argument, NULL, 'x'},
{"no-structs-or-unions", no_argument, NULL, 's'},
{"output-file", required_argument, NULL, 'o'},
{"position-info", required_argument, NULL, 'p'},
{"search-path", required_argument, NULL, 'I'},
{"verbose", no_argument, NULL, 'v'},
{"version", no_argument, NULL, -3},
{"very-verbose", no_argument, NULL, 'V'},
{NULL, 0, NULL, 0}
};
/* Semantic values of tokens. Set by yylex.. */
static unsigned yyival; /* Set for token CINT. */
static char *yytext; /* Set for token IDENT. */
static char *yytext_end;
/* Output file. */
static FILE *yyout;
/* Current line number. */
static int yyline;
/* The name of the current input file. */
static const char *filename;
/* Three character class vectors, and macros to test membership
of characters. */
static char is_ident[255];
static char is_digit[255];
static char is_white[255];
#define IDENTP(C) is_ident[(unsigned char) (C)]
#define DIGITP(C) is_digit[(unsigned char) (C)]
#define WHITEP(C) is_white[(unsigned char) (C)]
/* Command line flags. */
static int f_append;
static int f_verbose;
static int f_very_verbose;
static int f_structs = 1;
static int f_regexps = 1;
static int f_nested_classes = 1;
/* Maximum and minimum lengths of regular expressions matching a
member, class etc., for writing them to the output file. These are
overridable from the command line. */
static int min_regexp = 5;
static int max_regexp = 50;
/* Input buffer. */
static char *inbuffer;
static char *in;
static size_t inbuffer_size;
/* Return the current buffer position in the input file. */
#define BUFFER_POS() (in - inbuffer)
/* If current lookahead is CSTRING, the following points to the
first character in the string constant. Used for recognizing
extern "C". */
static char *string_start;
/* The size of the hash tables for classes.and members. Should be
prime. */
#define TABLE_SIZE 1001
/* The hash table for class symbols. */
static struct sym *class_table[TABLE_SIZE];
/* Hash table containing all member structures. This is generally
faster for member lookup than traversing the member lists of a
`struct sym'. */
static struct member *member_table[TABLE_SIZE];
/* Hash table for namespace aliases */
static struct alias *namespace_alias_table[TABLE_SIZE];
/* The special class symbol used to hold global functions,
variables etc. */
static struct sym *global_symbols;
/* The current namespace. */
static struct sym *current_namespace;
/* The list of all known namespaces. */
static struct sym *all_namespaces;
/* Stack of namespaces we're currently nested in, during the parse. */
static struct sym **namespace_stack;
static int namespace_stack_size;
static int namespace_sp;
/* The current lookahead token. */
static int tk = -1;
/* Structure describing a keyword. */
struct kw
{
const char *name; /* Spelling. */
int tk; /* Token value. */
struct kw *next; /* Next in collision chain. */
};
/* Keywords are lookup up in a hash table of their own. */
#define KEYWORD_TABLE_SIZE 1001
static struct kw *keyword_table[KEYWORD_TABLE_SIZE];
/* Search path. */
struct search_path
{
char *path;
struct search_path *next;
};
static struct search_path *search_path;
static struct search_path *search_path_tail;
/* Function prototypes. */
static char *matching_regexp (void);
static struct sym *add_sym (const char *, struct sym *);
static void add_global_defn (char *, char *, int, unsigned, int, int, int);
static void add_global_decl (char *, char *, int, unsigned, int, int, int);
static struct member *add_member (struct sym *, char *, int, int, unsigned);
static void class_definition (struct sym *, const char *, int, int, int);
static char *operator_name (int *);
static void parse_qualified_param_ident_or_type (char **);
/***********************************************************************
Utilities
***********************************************************************/
/* Print an error in a printf-like style with the current input file
name and line number. */
static void
yyerror (const char *format, const char *s)
{
fprintf (stderr, "%s:%d: ", filename, yyline);
fprintf (stderr, format, s);
putc ('\n', stderr);
}
/* Like malloc but print an error and exit if not enough memory is
available. */
static void * ATTRIBUTE_MALLOC
xmalloc (size_t nbytes)
{
void *p = malloc (nbytes);
if (p == NULL)
{
yyerror ("out of memory", NULL);
exit (EXIT_FAILURE);
}
return p;
}
/* Like realloc but print an error and exit if out of memory. */
static void *
xrealloc (void *p, size_t sz)
{
p = realloc (p, sz);
if (p == NULL)
{
yyerror ("out of memory", NULL);
exit (EXIT_FAILURE);
}
return p;
}
/* Like strdup, but print an error and exit if not enough memory is
available.. If S is null, return null. */
static char *
xstrdup (char *s)
{
if (s)
return strcpy (xmalloc (strlen (s) + 1), s);
return s;
}
/***********************************************************************
Symbols
***********************************************************************/
/* Initialize the symbol table. This currently only sets up the
special symbol for globals (`*Globals*'). */
static void
init_sym (void)
{
global_symbols = add_sym (GLOBALS_NAME, NULL);
}
/* Add a symbol for class NAME to the symbol table. NESTED_IN_CLASS
is the class in which class NAME was found. If it is null,
this means the scope of NAME is the current namespace.
If a symbol for NAME already exists, return that. Otherwise
create a new symbol and set it to default values. */
static struct sym *
add_sym (const char *name, struct sym *nested_in_class)
{
struct sym *sym;
unsigned h;
const char *s;
struct sym *scope = nested_in_class ? nested_in_class : current_namespace;
for (s = name, h = 0; *s; ++s)
h = (h << 1) ^ *s;
h %= TABLE_SIZE;
for (sym = class_table[h]; sym; sym = sym->next)
if (streq (name, sym->name)
&& ((!sym->namesp && !scope)
|| (sym->namesp && scope
&& streq (sym->namesp->name, scope->name))))
break;
if (sym == NULL)
{
if (f_very_verbose)
{
putchar ('\t');
puts (name);
}
sym = xmalloc (FLEXSIZEOF (struct sym, name, strlen (name) + 1));
memset (sym, 0, offsetof (struct sym, name));
strcpy (sym->name, name);
sym->namesp = scope;
sym->next = class_table[h];
class_table[h] = sym;
}
return sym;
}
/* Add links between superclass SUPER and subclass SUB. */
static void
add_link (struct sym *super, struct sym *sub)
{
struct link *lnk, *lnk2, *p, *prev;
/* See if a link already exists. */
for (p = super->subs, prev = NULL;
p && strcmp (sub->name, p->sym->name) > 0;
prev = p, p = p->next)
;
/* Avoid duplicates. */
if (p == NULL || p->sym != sub)
{
lnk = (struct link *) xmalloc (sizeof *lnk);
lnk2 = (struct link *) xmalloc (sizeof *lnk2);
lnk->sym = sub;
lnk->next = p;
if (prev)
prev->next = lnk;
else
super->subs = lnk;
lnk2->sym = super;
lnk2->next = sub->supers;
sub->supers = lnk2;
}
}
/* Find in class CLS member NAME.
VAR non-zero means look for a member variable; otherwise a function
is searched. SC specifies what kind of member is searched---a
static, or per-instance member etc. HASH is a hash code for the
parameter types of functions. Value is a pointer to the member
found or null if not found. */
static struct member *
find_member (struct sym *cls, char *name, int var, int sc, unsigned int hash)
{
struct member **list;
struct member *p;
unsigned name_hash = 0;
char *s;
int i;
switch (sc)
{
case SC_FRIEND:
list = &cls->friends;
break;
case SC_TYPE:
list = &cls->types;
break;
case SC_STATIC:
list = var ? &cls->static_vars : &cls->static_fns;
break;
default:
list = var ? &cls->vars : &cls->fns;
break;
}
for (s = name; *s; ++s)
name_hash = (name_hash << 1) ^ *s;
i = name_hash % TABLE_SIZE;
for (p = member_table[i]; p; p = p->anext)
if (p->list == list && p->param_hash == hash && streq (name, p->name))
break;
return p;
}
/* Add to class CLS information for the declaration of member NAME.
REGEXP is a regexp matching the declaration, if non-null. POS is
the position in the source where the declaration is found. HASH is
a hash code for the parameter list of the member, if it's a
function. VAR non-zero means member is a variable or type. SC
specifies the type of member (instance member, static, ...). VIS
is the member's visibility (public, protected, private). FLAGS is
a bit set giving additional information about the member (see the
F_* defines). */
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)
{
struct member *m;
m = find_member (cls, name, var, sc, hash);
if (m == NULL)
m = add_member (cls, name, var, sc, hash);
/* Have we seen a new filename? If so record that. */
if (!cls->filename || !filename_eq (cls->filename, filename))
m->filename = filename;
m->regexp = regexp;
m->pos = pos;
m->flags = flags;
switch (vis)
{
case PRIVATE:
m->vis = V_PRIVATE;
break;
case PROTECTED:
m->vis = V_PROTECTED;
break;
case PUBLIC:
m->vis = V_PUBLIC;
break;
}
info_where = P_DECL;
info_cls = cls;
info_member = m;
}
/* Add to class CLS information for the definition of member NAME.
REGEXP is a regexp matching the declaration, if non-null. POS is
the position in the source where the declaration is found. HASH is
a hash code for the parameter list of the member, if it's a
function. VAR non-zero means member is a variable or type. SC
specifies the type of member (instance member, static, ...). VIS
is the member's visibility (public, protected, private). FLAGS is
a bit set giving additional information about the member (see the
F_* defines). */
static void
add_member_defn (struct sym *cls, char *name, char *regexp, int pos, unsigned int hash, int var, int sc, int flags)
{
struct member *m;
if (sc == SC_UNKNOWN)
{
m = find_member (cls, name, var, SC_MEMBER, hash);
if (m == NULL)
{
m = find_member (cls, name, var, SC_STATIC, hash);
if (m == NULL)
m = add_member (cls, name, var, sc, hash);
}
}
else
{
m = find_member (cls, name, var, sc, hash);
if (m == NULL)
m = add_member (cls, name, var, sc, hash);
}
if (!cls->sfilename)
cls->sfilename = filename;
if (!filename_eq (cls->sfilename, filename))
m->def_filename = filename;
m->def_regexp = regexp;
m->def_pos = pos;
m->flags |= flags;
info_where = P_DEFN;
info_cls = cls;
info_member = m;
}
/* Add a symbol for a define named NAME to the symbol table.
REGEXP is a regular expression matching the define in the source,
if it is non-null. POS is the position in the file. */
static void
add_define (char *name, char *regexp, int pos)
{
add_global_defn (name, regexp, pos, 0, 1, SC_FRIEND, F_DEFINE);
add_global_decl (name, regexp, pos, 0, 1, SC_FRIEND, F_DEFINE);
}
/* Add information for the global definition of NAME.
REGEXP is a regexp matching the declaration, if non-null. POS is
the position in the source where the declaration is found. HASH is
a hash code for the parameter list of the member, if it's a
function. VAR non-zero means member is a variable or type. SC
specifies the type of member (instance member, static, ...). VIS
is the member's visibility (public, protected, private). FLAGS is
a bit set giving additional information about the member (see the
F_* defines). */
static void
add_global_defn (char *name, char *regexp, int pos, unsigned int hash, int var, int sc, int flags)
{
int i;
struct sym *sym;
/* Try to find out for which classes a function is a friend, and add
what we know about it to them. */
if (!var)
for (i = 0; i < TABLE_SIZE; ++i)
for (sym = class_table[i]; sym; sym = sym->next)
if (sym != global_symbols && sym->friends)
if (find_member (sym, name, 0, SC_FRIEND, hash))
add_member_defn (sym, name, regexp, pos, hash, 0,
SC_FRIEND, flags);
/* Add to global symbols. */
add_member_defn (global_symbols, name, regexp, pos, hash, var, sc, flags);
}
/* Add information for the global declaration of NAME.
REGEXP is a regexp matching the declaration, if non-null. POS is
the position in the source where the declaration is found. HASH is
a hash code for the parameter list of the member, if it's a
function. VAR non-zero means member is a variable or type. SC
specifies the type of member (instance member, static, ...). VIS
is the member's visibility (public, protected, private). FLAGS is
a bit set giving additional information about the member (see the
F_* defines). */
static void
add_global_decl (char *name, char *regexp, int pos, unsigned int hash, int var, int sc, int flags)
{
/* Add declaration only if not already declared. Header files must
be processed before source files for this to have the right effect.
I do not want to handle implicit declarations at the moment. */
struct member *m;
struct member *found;
m = found = find_member (global_symbols, name, var, sc, hash);
if (m == NULL)
m = add_member (global_symbols, name, var, sc, hash);
/* Definition already seen => probably last declaration implicit.
Override. This means that declarations must always be added to
the symbol table before definitions. */
if (!found)
{
if (!global_symbols->filename
|| !filename_eq (global_symbols->filename, filename))
m->filename = filename;
m->regexp = regexp;
m->pos = pos;
m->vis = V_PUBLIC;
m->flags = flags;
info_where = P_DECL;
info_cls = global_symbols;
info_member = m;
}
}
/* Add a symbol for member NAME to class CLS.
VAR non-zero means it's a variable. SC specifies the kind of
member. HASH is a hash code for the parameter types of a function.
Value is a pointer to the member's structure. */
static struct member *
add_member (struct sym *cls, char *name, int var, int sc, unsigned int hash)
{
struct member *m = xmalloc (FLEXSIZEOF (struct member, name,
strlen (name) + 1));
struct member **list;
struct member *p;
struct member *prev;
unsigned name_hash = 0;
int i;
char *s;
strcpy (m->name, name);
m->param_hash = hash;
m->vis = 0;
m->flags = 0;
m->regexp = NULL;
m->filename = NULL;
m->pos = 0;
m->def_regexp = NULL;
m->def_filename = NULL;
m->def_pos = 0;
assert (cls != NULL);
switch (sc)
{
case SC_FRIEND:
list = &cls->friends;
break;
case SC_TYPE:
list = &cls->types;
break;
case SC_STATIC:
list = var ? &cls->static_vars : &cls->static_fns;
break;
default:
list = var ? &cls->vars : &cls->fns;
break;
}
for (s = name; *s; ++s)
name_hash = (name_hash << 1) ^ *s;
i = name_hash % TABLE_SIZE;
m->anext = member_table[i];
member_table[i] = m;
m->list = list;
/* Keep the member list sorted. It's cheaper to do it here than to
sort them in Lisp. */
for (prev = NULL, p = *list;
p && strcmp (name, p->name) > 0;
prev = p, p = p->next)
;
m->next = p;
if (prev)
prev->next = m;
else
*list = m;
return m;
}
/* Given the root R of a class tree, step through all subclasses
recursively, marking functions as virtual that are declared virtual
in base classes. */
static void
mark_virtual (struct sym *r)
{
struct link *p;
struct member *m, *m2;
for (p = r->subs; p; p = p->next)
{
for (m = r->fns; m; m = m->next)
if (has_flag (m->flags, F_VIRTUAL))
{
for (m2 = p->sym->fns; m2; m2 = m2->next)
if (m->param_hash == m2->param_hash && streq (m->name, m2->name))
set_flag (&m2->flags, F_VIRTUAL);
}
mark_virtual (p->sym);
}
}
/* For all roots of the class tree, mark functions as virtual that
are virtual because of a virtual declaration in a base class. */
static void
mark_inherited_virtual (void)
{
struct sym *r;
int i;
for (i = 0; i < TABLE_SIZE; ++i)
for (r = class_table[i]; r; r = r->next)
if (r->supers == NULL)
mark_virtual (r);
}
/* Create and return a symbol for a namespace with name NAME. */
static struct sym *
make_namespace (char *name, struct sym *context)
{
struct sym *s = xmalloc (FLEXSIZEOF (struct sym, name, strlen (name) + 1));
memset (s, 0, offsetof (struct sym, name));
strcpy (s->name, name);
s->next = all_namespaces;
s->namesp = context;
all_namespaces = s;
return s;
}
/* Find the symbol for namespace NAME. If not found, return NULL */
static struct sym *
check_namespace (char *name, struct sym *context)
{
struct sym *p = NULL;
for (p = all_namespaces; p; p = p->next)
{
if (streq (p->name, name) && (p->namesp == context))
break;
}