home *** CD-ROM | disk | FTP | other *** search
- /* EMACS CLASS BROWSER FOR C++.
- Copyright (C) 1993 Gerd Moellmann. All rights reserved.
- Altenbergstr. 6, D-40235 Duesseldorf 1, Germany.
- 100025.3303@COMPUSERVE.COM
-
- $Id: sym.c,v 3.1 1995/02/17 18:20:24 mmann Exp $
-
- This file may be made part of GNU Emacs at the option of the FSF.
-
- This code is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY. No author or distributor
- accepts responsibility to anyone for the consequences of using it
- or for whether it serves any particular purpose or works at all,
- unless he says so in writing. Refer to the GNU Emacs General Public
- License for full details.
-
- Everyone is granted permission to copy, modify and redistribute
- this code, but only under the conditions described in the
- GNU Emacs General Public License. A copy of this license is
- supposed to have been given to you along with GNU Emacs so you
- can know your rights and responsibilities. It should be in a
- file named COPYING. Among other things, the copyright notice
- and this notice must be preserved on all copies. */
-
- #ifdef __IBMC__
- #include <io.h>
- #endif
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <assert.h>
- #ifdef __BORLANDC__
- #include <alloc.h>
- #endif
- #include "lex.h"
-
- /* The hash table for class symbols. */
- sym_t* sym_hash_table[SYM_HASH_SIZE];
-
- /* The special class symbol used to hold global functions,
- variables etc. */
- sym_t* global_symbols;
-
- /* Amount of memory allocated (used for debugging/ optimization).
- This is output when `ebrowse' is run in verbose mode (`-v'). */
- long total_allocated;
-
- /* File position in regular expression file. This is used when
- regular expressions are extracted from source files (option
- `-r<file>'). In this case the BROWSE output file doesn't
- contain buffer positions and regular expressions but buffer
- positions and positions of regular expressions in the
- regexp file. */
- long regexp_pos = 1;
-
- #ifdef PROTOTYPES
- static unsigned dump_members (FILE* fp, member_t* m);
- static void dump_sym (FILE* fp, sym_t* root);
- static unsigned dump_tree (FILE* fp, sym_t* root);
- static member_t* find_member (sym_t* cls, char* name, int var, int sc,
- long hash);
- static member_t* add_member (sym_t* cls, char* name, int var, int sc,
- long hash);
- static void mark_virtual (sym_t* cls);
- static void mark_virtual (sym_t* r);
- #ifdef MSDOS
- static void write_regexp (int handle, char* s);
- #endif
- #endif
-
- #define get_list(cls, var, sc) \
- (sc == SC_FRIEND ? &cls->friends : \
- (sc == SC_TYPE ? &cls->types : \
- (sc == SC_STATIC ? (var ? &cls->static_vars : &cls->static_fns) \
- : (var ? &cls->vars : &cls->fns))))
-
- #ifdef MSDOS
- void
- write_regexp (handle, s)
- char* s;
- int handle;
- {
- char* p;
- unsigned len = 0;
- unsigned delta = 0;
-
- for (p = s; *p; ++p, ++len)
- if (*p == '\r')
- ++delta;
-
- write (handle, s, len);
- regexp_pos += len - delta;
- }
- #else
- #define write_regexp(handle, s) \
- do \
- { \
- int len = strlen (s); \
- write (handle, s, len); \
- regexp_pos += len; \
- } \
- while (0)
- #endif
-
- /* Utility: allocate SZ bytes of memory and print
- an error/exit when not enough memory is available. */
-
- void*
- xmalloc (unsigned sz)
- {
- void* p = malloc (sz);
-
- if (!p)
- {
- yyerror ("out of memory");
- exit (1);
- }
-
- total_allocated += sz;
- return p;
- }
-
- /* Make a copy of a NUL terninated string on the heap.
- Print an error if not enough memory is available and
- quit the program. */
-
- char*
- dupstr (s)
- char* s;
- {
- return s ? strcpy (xmalloc (strlen (s)+1), s) : NULL;
- }
-
- /* Intialize the symbol table management module.
- This currently only sets up the special symbol for
- globals (`*Globals*'). */
-
- void
- init_sym ()
- {
- global_symbols = add_sym (GLOBALS_NAME);
- }
-
- /* Lookup NAME in the class symbol table and return a
- pointer to the symbol found or NULL if not found. */
-
- sym_t*
- find_sym (name)
- char* name;
- {
- char* s;
- unsigned h;
- sym_t* sym;
-
- for (s = name, h = 0; *s; ++s)
- h = (h << 1) ^ *s;
-
- h %= SYM_HASH_SIZE;
-
- for (sym = sym_hash_table[h]; sym; sym = sym->next)
- if (!strcmp (name, sym->name))
- break;
-
- return sym;
- }
-
- /* Add a symbol for class NAME to the symbol table.
- If a symbol entry for NAME already exists, return that.
- Otherwise create a new symbol and set it to default
- values. */
-
- sym_t*
- add_sym (name)
- char* name;
- {
- sym_t* s;
- unsigned h;
-
- if (0 == (s = find_sym (name)))
- {
- if (f_very_verbose)
- {
- putchar ('\t');
- puts (name);
- }
-
- s = (sym_t*) xmalloc (sizeof *s + strlen (name));
- strcpy (s->name, name);
- s->subs = s->supers = NULL;
- s->vars = s->fns = NULL;
- s->friends = NULL;
- s->types = NULL;
- s->static_vars = s->static_fns = NULL;
- s->regexp = s->filename = NULL;
- s->pos = 0;
- s->sfilename = 0;
- s->is_template = 0;
-
- for (h = 0; *name; ++name)
- h = (h << 1) ^ *name;
-
- h %= SYM_HASH_SIZE;
-
- s->next = sym_hash_table[h];
- return sym_hash_table[h] = s;
- }
-
- return s;
- }
-
- /* Add a link from a superclass SUPER to a subclass SUB.
- This is done by
-
- (a) Adding a `link_t' structure to the `subs' list
- of subclasses of SUPER which points to the new subclass.
- Subclasses are kept sorted lexically.
-
- (b) Adding a `link_t' structure to the `super' list
- of SUB. */
-
- void
- add_link (super, sub)
- sym_t* super;
- sym_t* sub;
- {
- link_t* lnk = (link_t*) xmalloc (sizeof *lnk);
- link_t* lnk2 = (link_t*) xmalloc (sizeof *lnk);
- link_t* p;
- link_t* prev;
-
- assert (super != NULL && sub != NULL);
-
- for (p = super->subs, prev = 0; p && strcmp (sub->name, p->sym->name) > 0;
- prev = p, p = p->next)
- ;
-
- /* Avoid duplicates */
- if (p && p->sym == sub)
- return;
-
- 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;
- }
-
- void
- add_member_declaration (cls, name, regexp, pos, hash, var, sc, vis,
- is_virtual, is_inline, is_const, is_pure)
- sym_t* cls;
- char* name;
- char* regexp;
- unsigned pos;
- long hash;
- int var;
- int sc;
- unsigned vis;
- int is_virtual;
- int is_inline;
- int is_const;
- int is_pure;
- {
- member_t* m;
-
- assert (cls != NULL);
-
- if (0 == (m = find_member (cls, name, var, sc, hash)))
- m = add_member (cls, name, var, sc, hash);
-
- if (!cls->filename || strcmp (cls->filename, filename))
- m->filename = filename;
-
- m->regexp = regexp;
- m->pos = pos;
-
- if (vis)
- m->vis = vis == PRIVATE ? V_PRIVATE
- : (vis == PROTECTED ? V_PROTECTED : V_PUBLIC);
-
- m->is_virtual = is_virtual;
- m->is_inline = is_inline;
- m->is_const = is_const;
- m->is_pure = is_pure;
- }
-
- void
- add_member_definition (cls, name, regexp, pos, hash, var, sc, is_inline,
- is_const)
- sym_t* cls;
- char* name;
- char* regexp;
- unsigned pos;
- long hash;
- int var;
- int sc;
- int is_inline;
- int is_const;
- {
- member_t* m;
-
- assert (cls != NULL);
-
- if (sc == SC_UNKNOWN)
- {
- if (0 == (m = find_member (cls, name, var, SC_MEMBER, hash)))
- if (0 == (m = find_member (cls, name, var, SC_STATIC, hash)))
- m = add_member (cls, name, var, sc, hash);
- }
- else
- {
- if (0 == (m = find_member (cls, name, var, sc, hash)))
- m = add_member (cls, name, var, sc, hash);
- }
-
- if (!cls->sfilename)
- cls->sfilename = filename;
-
- if (strcmp (cls->sfilename, filename))
- m->def_filename = filename;
-
- m->def_regexp = regexp;
- m->def_pos = pos;
- m->is_inline |= is_inline;
- m->is_const |= is_const;
- }
-
- void
- add_global_definition (name, regexp, pos, hash, var, sc, is_inline, is_const)
- char* name;
- char* regexp;
- unsigned pos;
- long hash;
- int is_const;
- {
- int i;
- sym_t* sym;
-
- /* Try to find out for which class this symbol is a friend. */
-
- if (!var)
- for (i = 0; i < SYM_HASH_SIZE; ++i)
- for (sym = sym_hash_table[i]; sym; sym = sym->next)
- if (sym != global_symbols)
- if (find_member (sym, name, 0, SC_FRIEND, hash))
- add_member_definition (sym, name, regexp, pos, hash, 0,
- SC_FRIEND, 0, is_const);
-
- /* Add to global symbols. */
-
- add_member_definition (global_symbols, name, regexp, pos, hash, var,
- sc, is_inline, is_const);
- }
-
- void
- add_global_declaration (name, regexp, pos, hash, var, sc, is_inline, is_const)
- char* name;
- char* regexp;
- unsigned pos;
- long hash;
- int is_const;
- {
- /* 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. */
-
- member_t* m;
- member_t* found;
-
- if (0 == (m = found = find_member (global_symbols, name, var, sc, hash)))
- m = add_member (global_symbols, name, var, sc, hash);
-
- /* Definition already seen => probably last declaration implicit.
- Override. This means that declarations must always added to
- the symbol table before definitions (parse.c). */
-
- if (!found)
- {
- if (!global_symbols->filename
- || strcmp (global_symbols->filename, filename))
- m->filename = filename;
-
- m->regexp = regexp;
- m->pos = pos;
- m->vis = V_PUBLIC;
- m->is_inline = is_inline;
- m->is_const = is_const;
- m->is_virtual = m->is_pure = 0;
- }
- }
-
- static member_t*
- find_member (cls, name, var, sc, hash)
- sym_t* cls;
- char* name;
- int var;
- int sc;
- long hash;
- {
- member_t** list;
- member_t* p;
-
- assert (cls != NULL);
-
- list = get_list (cls, var, sc);
-
- for (p = *list; p; p = p->next)
- {
- if (!strcmp (name, p->name) && p->params == hash)
- return p;
- }
-
- return 0;
- }
-
- static member_t*
- add_member (cls, name, var, sc, hash)
- sym_t* cls;
- char* name;
- int var;
- int sc;
- long hash;
- {
- member_t* m = (member_t*) xmalloc (sizeof *m + strlen (name));
- member_t** list;
- member_t* p;
- member_t* prev;
-
- strcpy (m->name, name);
- m->params = hash;
-
- m->vis = 0;
- m->is_virtual = 0;
- m->is_inline = 0;
- m->is_const = 0;
- m->is_pure = 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);
-
- list = get_list (cls, var, sc);
-
- for (p = *list, prev = 0; p && strcmp (name, p->name) > 0;
- prev = p, p = p->next)
- ;
-
- m->next = p;
- return prev ? (prev->next = m) : (*list = m);
- }
-
- #define putstr(s, fp) \
- if (!s) \
- { \
- putc ('(', fp); \
- putc (')', fp); \
- putc (' ', fp); \
- } \
- else \
- { \
- putc ('"', fp); \
- fputs (s, fp); \
- putc ('"', fp); \
- putc (' ', fp); \
- }
-
- static unsigned
- dump_members (fp, m)
- FILE* fp;
- member_t* m;
- {
- char b[35];
- unsigned n = 0;
- unsigned temp;
-
- putc ('(', fp);
-
- for (; m; m = m->next, ++n)
- {
- #if USE_STRUCTS
- fputs (MEMBER_STRUCT, fp);
- #elif USE_ARRAYS
- putc ('\[', fp);
- #else
- putc ('\(', fp);
- #endif
-
- putstr (m->name, fp);
- putstr (m->filename, fp);
-
- if (regexp_file)
- {
- fprintf (fp, "%lu ", regexp_pos);
-
- if (m->regexp)
- {
- write (regexp_file, "\"", 1);
- write_regexp (regexp_file, m->regexp);
- write (regexp_file, "\" ", 2);
- regexp_pos += 3;
- }
- else
- {
- write (regexp_file, "() ", 3);
- regexp_pos += 3;
- }
- }
- else
- putstr (m->regexp, fp);
-
- fprintf (fp, "%lu ", (long) m->pos);
-
- /* Bitfields merged */
- temp = (m->is_pure << 7)
- | (m->is_const << 6)
- | (m->is_virtual << 5)
- | (m->is_inline << 4)
- | m->vis;
-
- fprintf (fp, "%lu", (long) temp);
-
- #if !USE_ARRAYS && !USE_STRUCTS
- if (m->def_regexp)
- #endif
- {
- putc (' ', fp);
- putstr (m->def_filename, fp);
-
- if (regexp_file)
- {
- fprintf (fp, "%lu ", regexp_pos);
-
- if (m->def_regexp)
- {
- write (regexp_file, "\"", 1);
- write_regexp (regexp_file, m->def_regexp);
- write (regexp_file, "\" ", 2);
- regexp_pos += 3;
- }
- else
- {
- write (regexp_file, "() ", 3);
- regexp_pos += 3;
- }
- }
- else
- putstr (m->def_regexp, fp);
-
- fprintf (fp, "%lu", (long) m->def_pos);
- }
-
- putc (' ', fp);
- fprintf (fp, "%lu", m->params);
-
- #if USE_ARRAYS || USE_STRUCTS
- putc (']', fp);
- #else
- putc (')', fp);
- #endif
- putc ('\n', fp);
- }
-
- putc (')', fp);
- putc ('\n', fp);
- return n;
- }
-
- static void
- dump_sym (fp, root)
- FILE* fp;
- sym_t* root;
- {
- char b[35];
-
- #if USE_STRUCTS
- fputs (CLASS_STRUCT, fp);
- #else
- putc ('\[', fp);
- #endif
- putstr (root->name, fp);
- putstr (root->filename, fp);
- putstr (root->regexp, fp);
- fprintf (fp, "%lu", (long) root->pos);
- putstr (root->sfilename, fp);
- putc (']', fp);
- putc ('\n', fp);
- }
-
- static unsigned
- dump_tree (fp, root)
- FILE* fp;
- sym_t* root;
- {
- link_t* lk;
- unsigned n;
-
- dump_sym (fp, root);
-
- if (f_verbose)
- {
- putchar ('+');
- fflush (stdout);
- }
-
- putc ('(', fp);
-
- for (lk = root->subs; lk; lk = lk->next)
- {
- #ifdef USE_STRUCTS
- fputs (TREE_STRUCT, fp);
- #else
- putc ('\(', fp);
- #endif
- n += dump_tree (fp, lk->sym);
- #ifdef USE_STRUCTS
- putc (']', fp);
- #else
- putc (')', fp);
- #endif
- }
-
- putc (')', fp);
-
- dump_members (fp, root->vars);
- n += dump_members (fp, root->fns);
- dump_members (fp, root->static_vars);
- n += dump_members (fp, root->static_fns);
- n += dump_members (fp, root->friends);
- dump_members (fp, root->types);
-
- /* Superclasses. */
-
- putc ('(', fp);
- putc (')', fp);
-
- /* Mark slot */
-
- putc ('(', fp);
- putc (')', fp);
-
- putc ('\n', fp);
-
- return n;
- }
-
- /* Dump an entire class tree to a file. */
-
- void
- dump_roots (fp)
- FILE* fp;
- {
- unsigned i, n = 0;
- sym_t* r;
-
- /* Output file header containing version string, command line
- options, file name of regular expression file (if any), and
- a free slot used by the Lisp package. */
-
- if (!f_append)
- {
- fputs (TREE_HEADER_STRUCT, fp);
- putstr (VERSION, fp);
-
- putc ('\"', fp);
- if (!f_costly_friends) fputs (" -f", fp);
- if (!f_structs) fputs (" -s", fp);
- if (f_regexps) fputs (" -x", fp);
- putc ('\"', fp);
-
- putstr (regexp_filename, fp);
- fputs (" ()", fp);
- putc (']', fp);
- }
-
- mark_inherited_virtual ();
-
- for (i = 0; i < SYM_HASH_SIZE; ++i)
- for (r = sym_hash_table[i]; r; r = r->next)
- if (!r->supers)
- {
- fputs (TREE_STRUCT, fp);
- n += dump_tree (fp, r);
- putc (']', fp);
- }
- }
-
- /* Given the root R of a class tree, step through all subclasses,
- marking functions as virtual that are declared virtual in
- base classes. */
-
- static void
- mark_virtual (r)
- sym_t* r;
- {
- link_t* p;
- member_t* m;
- member_t* m2;
-
- for (p = r->subs; p; p = p->next)
- {
- for (m = r->fns; m; m = m->next)
- if (m->is_virtual)
- {
- for (m2 = p->sym->fns; m2; m2 = m2->next)
- if (m->params == m2->params && !strcmp (m->name, m2->name))
- m2->is_virtual = 1;
- }
-
- 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. */
-
- void
- mark_inherited_virtual ()
- {
- int i;
- sym_t* r;
-
- for (i = 0; i < SYM_HASH_SIZE; ++i)
- for (r = sym_hash_table[i]; r; r = r->next)
- if (!r->supers)
- mark_virtual (r);
- }
-