home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 5 Edit
/
05-Edit.zip
/
browser2.zip
/
sym.c
< prev
Wrap
C/C++ Source or Header
|
1995-02-17
|
17KB
|
737 lines
/* 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);
}