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

  1. /* EMACS CLASS BROWSER FOR C++.
  2.    Copyright (C) 1993 Gerd Moellmann. All rights reserved.
  3.    Altenbergstr. 6, D-40235 Duesseldorf 1, Germany.
  4.    100025.3303@COMPUSERVE.COM
  5.  
  6.    $Id: sym.c,v 3.1 1995/02/17 18:20:24 mmann Exp $
  7.  
  8.    This file may be made part of GNU Emacs at the option of the FSF.
  9.  
  10.    This code is distributed in the hope that it will be useful,
  11.    but WITHOUT ANY WARRANTY.  No author or distributor
  12.    accepts responsibility to anyone for the consequences of using it
  13.    or for whether it serves any particular purpose or works at all,
  14.    unless he says so in writing.  Refer to the GNU Emacs General Public
  15.    License for full details.
  16.  
  17.    Everyone is granted permission to copy, modify and redistribute
  18.    this code, but only under the conditions described in the
  19.    GNU Emacs General Public License.   A copy of this license is
  20.    supposed to have been given to you along with GNU Emacs so you
  21.    can know your rights and responsibilities.  It should be in a
  22.    file named COPYING.  Among other things, the copyright notice
  23.    and this notice must be preserved on all copies. */
  24.  
  25. #ifdef __IBMC__
  26. #include <io.h>
  27. #endif
  28. #include <stdio.h>
  29. #include <stdlib.h>
  30. #include <string.h>
  31. #include <assert.h>
  32. #ifdef __BORLANDC__
  33. #include <alloc.h>
  34. #endif
  35. #include "lex.h"
  36.  
  37. /* The hash table for class symbols. */
  38. sym_t* sym_hash_table[SYM_HASH_SIZE];
  39.  
  40. /* The special class symbol used to hold global functions,
  41.    variables etc. */
  42. sym_t* global_symbols;
  43.  
  44. /* Amount of memory allocated (used for debugging/ optimization).
  45.    This is output when `ebrowse' is run in verbose mode (`-v'). */
  46. long total_allocated;
  47.  
  48. /* File position in regular expression file. This is used when
  49.    regular expressions are extracted from source files (option
  50.    `-r<file>'). In this case the BROWSE output file doesn't
  51.    contain buffer positions and regular expressions but buffer
  52.    positions and positions of regular expressions in the
  53.    regexp file. */
  54. long regexp_pos = 1;
  55.  
  56. #ifdef PROTOTYPES
  57. static unsigned dump_members (FILE* fp, member_t* m);
  58. static void dump_sym (FILE* fp, sym_t* root);
  59. static unsigned dump_tree (FILE* fp, sym_t* root);
  60. static member_t* find_member (sym_t* cls, char* name, int var, int sc,
  61.                               long hash);
  62. static member_t* add_member (sym_t* cls, char* name, int var, int sc,
  63.                              long hash);
  64. static void mark_virtual (sym_t* cls);
  65. static void mark_virtual (sym_t* r);
  66. #ifdef MSDOS
  67. static void write_regexp (int handle, char* s);
  68. #endif
  69. #endif
  70.  
  71. #define get_list(cls, var, sc) \
  72.   (sc == SC_FRIEND ? &cls->friends : \
  73.    (sc == SC_TYPE ? &cls->types : \
  74.      (sc == SC_STATIC ? (var ? &cls->static_vars : &cls->static_fns) \
  75.                         : (var ? &cls->vars : &cls->fns))))
  76.  
  77. #ifdef MSDOS
  78. void
  79. write_regexp (handle, s)
  80.      char* s;
  81.      int handle;
  82. {
  83.   char* p;
  84.   unsigned len = 0;
  85.   unsigned delta = 0;
  86.  
  87.   for (p = s; *p; ++p, ++len)
  88.     if (*p == '\r')
  89.       ++delta;
  90.  
  91.   write (handle, s, len);
  92.   regexp_pos += len - delta;
  93. }
  94. #else
  95. #define write_regexp(handle, s)        \
  96.   do                     \
  97.     {                     \
  98.       int len = strlen (s);         \
  99.       write (handle, s, len);         \
  100.       regexp_pos += len;          \
  101.     }                     \
  102.   while (0)
  103. #endif
  104.  
  105. /* Utility: allocate SZ bytes of memory and print
  106.    an error/exit when not enough memory is available. */
  107.  
  108. void*
  109. xmalloc (unsigned sz)
  110. {
  111.   void* p = malloc (sz);
  112.  
  113.   if (!p)
  114.     {
  115.       yyerror ("out of memory");
  116.       exit (1);
  117.     }
  118.  
  119.   total_allocated += sz;
  120.   return p;
  121. }
  122.  
  123. /* Make a copy of a NUL terninated string on the heap.
  124.    Print an error if not enough memory is available and
  125.    quit the program. */
  126.  
  127. char*
  128. dupstr (s)
  129.      char* s;
  130. {
  131.   return s ? strcpy (xmalloc (strlen (s)+1), s) : NULL;
  132. }
  133.  
  134. /* Intialize the symbol table management module.
  135.    This currently only sets up the special symbol for
  136.    globals (`*Globals*'). */
  137.  
  138. void
  139. init_sym ()
  140. {
  141.   global_symbols = add_sym (GLOBALS_NAME);
  142. }
  143.  
  144. /* Lookup NAME in the class symbol table and return a
  145.    pointer to the symbol found or NULL if not found. */
  146.  
  147. sym_t*
  148. find_sym (name)
  149.      char* name;
  150. {
  151.   char* s;
  152.   unsigned h;
  153.   sym_t* sym;
  154.  
  155.   for (s = name, h = 0; *s; ++s)
  156.     h = (h << 1) ^ *s;
  157.  
  158.   h %= SYM_HASH_SIZE;
  159.  
  160.   for (sym = sym_hash_table[h]; sym; sym = sym->next)
  161.     if (!strcmp (name, sym->name))
  162.       break;
  163.  
  164.   return sym;
  165. }
  166.  
  167. /* Add a symbol for class NAME to the symbol table.
  168.    If a symbol entry for NAME already exists, return that.
  169.    Otherwise create a new symbol and set it to default
  170.    values. */
  171.  
  172. sym_t*
  173. add_sym (name)
  174.      char* name;
  175. {
  176.   sym_t* s;
  177.   unsigned h;
  178.  
  179.   if (0 == (s = find_sym (name)))
  180.     {
  181.       if (f_very_verbose)
  182.     {
  183.       putchar ('\t');
  184.       puts (name);
  185.     }
  186.  
  187.       s = (sym_t*) xmalloc (sizeof *s + strlen (name));
  188.       strcpy (s->name, name);
  189.       s->subs = s->supers = NULL;
  190.       s->vars = s->fns = NULL;
  191.       s->friends = NULL;
  192.       s->types = NULL;
  193.       s->static_vars = s->static_fns = NULL;
  194.       s->regexp = s->filename = NULL;
  195.       s->pos = 0;
  196.       s->sfilename = 0;
  197.       s->is_template = 0;
  198.  
  199.       for (h = 0; *name; ++name)
  200.         h = (h << 1) ^ *name;
  201.  
  202.       h %= SYM_HASH_SIZE;
  203.  
  204.       s->next = sym_hash_table[h];
  205.       return sym_hash_table[h] = s;
  206.     }
  207.  
  208.   return s;
  209. }
  210.  
  211. /* Add a link from a superclass SUPER to a subclass SUB.
  212.    This is done by
  213.  
  214.    (a) Adding a `link_t' structure to the `subs' list
  215.    of subclasses of SUPER which points to the new subclass.
  216.    Subclasses are kept sorted lexically.
  217.  
  218.    (b) Adding a `link_t' structure to the `super' list
  219.    of SUB. */
  220.  
  221. void
  222. add_link (super, sub)
  223.      sym_t* super;
  224.      sym_t* sub;
  225. {
  226.   link_t* lnk = (link_t*) xmalloc (sizeof *lnk);
  227.   link_t* lnk2 = (link_t*) xmalloc (sizeof *lnk);
  228.   link_t* p;
  229.   link_t* prev;
  230.  
  231.   assert (super != NULL && sub != NULL);
  232.  
  233.   for (p = super->subs, prev = 0; p && strcmp (sub->name, p->sym->name) > 0;
  234.        prev = p, p = p->next)
  235.     ;
  236.  
  237.   /* Avoid duplicates */
  238.   if (p && p->sym == sub)
  239.     return;
  240.  
  241.   lnk->sym = sub;
  242.   lnk->next = p;
  243.  
  244.   if (prev)
  245.     prev->next = lnk;
  246.   else
  247.     super->subs = lnk;
  248.  
  249.   lnk2->sym = super;
  250.   lnk2->next = sub->supers;
  251.   sub->supers = lnk2;
  252. }
  253.  
  254. void
  255. add_member_declaration (cls, name, regexp, pos, hash, var, sc, vis,
  256.                         is_virtual, is_inline, is_const, is_pure)
  257.      sym_t* cls;
  258.      char* name;
  259.      char* regexp;
  260.      unsigned pos;
  261.      long hash;
  262.      int var;
  263.      int sc;
  264.      unsigned vis;
  265.      int is_virtual;
  266.      int is_inline;
  267.      int is_const;
  268.      int is_pure;
  269. {
  270.   member_t* m;
  271.  
  272.   assert (cls != NULL);
  273.  
  274.   if (0 == (m = find_member (cls, name, var, sc, hash)))
  275.     m = add_member (cls, name, var, sc, hash);
  276.  
  277.   if (!cls->filename || strcmp (cls->filename, filename))
  278.     m->filename = filename;
  279.  
  280.   m->regexp = regexp;
  281.   m->pos = pos;
  282.  
  283.   if (vis)
  284.     m->vis = vis == PRIVATE ? V_PRIVATE
  285.       : (vis == PROTECTED ? V_PROTECTED : V_PUBLIC);
  286.  
  287.   m->is_virtual = is_virtual;
  288.   m->is_inline = is_inline;
  289.   m->is_const = is_const;
  290.   m->is_pure = is_pure;
  291. }
  292.  
  293. void
  294. add_member_definition (cls, name, regexp, pos, hash, var, sc, is_inline,
  295.                        is_const)
  296.      sym_t* cls;
  297.      char* name;
  298.      char* regexp;
  299.      unsigned pos;
  300.      long hash;
  301.      int var;
  302.      int sc;
  303.      int is_inline;
  304.      int is_const;
  305. {
  306.   member_t* m;
  307.  
  308.   assert (cls != NULL);
  309.  
  310.   if (sc == SC_UNKNOWN)
  311.     {
  312.       if (0 == (m = find_member (cls, name, var, SC_MEMBER, hash)))
  313.         if (0 == (m = find_member (cls, name, var, SC_STATIC, hash)))
  314.           m = add_member (cls, name, var, sc, hash);
  315.     }
  316.   else
  317.     {
  318.       if (0 == (m = find_member (cls, name, var, sc, hash)))
  319.         m = add_member (cls, name, var, sc, hash);
  320.     }
  321.  
  322.   if (!cls->sfilename)
  323.     cls->sfilename = filename;
  324.  
  325.   if (strcmp (cls->sfilename, filename))
  326.     m->def_filename = filename;
  327.  
  328.   m->def_regexp = regexp;
  329.   m->def_pos = pos;
  330.   m->is_inline |= is_inline;
  331.   m->is_const |= is_const;
  332. }
  333.  
  334. void
  335. add_global_definition (name, regexp, pos, hash, var, sc, is_inline, is_const)
  336.      char* name;
  337.      char* regexp;
  338.      unsigned pos;
  339.      long hash;
  340.      int is_const;
  341. {
  342.   int i;
  343.   sym_t* sym;
  344.  
  345.   /* Try to find out for which class this symbol is a friend. */
  346.  
  347.   if (!var)
  348.     for (i = 0; i < SYM_HASH_SIZE; ++i)
  349.       for (sym = sym_hash_table[i]; sym; sym = sym->next)
  350.     if (sym != global_symbols)
  351.       if (find_member (sym, name, 0, SC_FRIEND, hash))
  352.         add_member_definition (sym, name, regexp, pos, hash, 0,
  353.                    SC_FRIEND, 0, is_const);
  354.  
  355.   /* Add to global symbols. */
  356.  
  357.   add_member_definition (global_symbols, name, regexp, pos, hash, var,
  358.              sc, is_inline, is_const);
  359. }
  360.  
  361. void 
  362. add_global_declaration (name, regexp, pos, hash, var, sc, is_inline, is_const)
  363.      char* name;
  364.      char* regexp;
  365.      unsigned pos;
  366.      long hash;
  367.      int is_const;
  368. {
  369.   /* Add declaration only if not already declared.  Header files must
  370.      be processed before source files for this to have the right effect.
  371.      I do not want to handle implicit declarations at the moment. */
  372.  
  373.   member_t* m;
  374.   member_t* found;
  375.  
  376.   if (0 == (m = found = find_member (global_symbols, name, var, sc, hash)))
  377.     m = add_member (global_symbols, name, var, sc, hash);
  378.  
  379.   /* Definition already seen => probably last declaration implicit.
  380.      Override. This means that declarations must always added to
  381.      the symbol table before definitions (parse.c). */
  382.  
  383.   if (!found)
  384.     {
  385.       if (!global_symbols->filename
  386.       || strcmp (global_symbols->filename, filename))
  387.     m->filename = filename;
  388.  
  389.       m->regexp = regexp;
  390.       m->pos = pos;
  391.       m->vis = V_PUBLIC;
  392.       m->is_inline = is_inline;
  393.       m->is_const = is_const;
  394.       m->is_virtual = m->is_pure = 0;
  395.     }
  396. }
  397.  
  398. static member_t*
  399. find_member (cls, name, var, sc, hash)
  400.      sym_t* cls;
  401.      char* name;
  402.      int var;
  403.      int sc;
  404.      long hash;
  405. {
  406.   member_t** list;
  407.   member_t* p;
  408.  
  409.   assert (cls != NULL);
  410.  
  411.   list = get_list (cls, var, sc);
  412.  
  413.   for (p = *list; p; p = p->next)
  414.     {
  415.       if (!strcmp (name, p->name) && p->params == hash)
  416.         return p;
  417.     }
  418.  
  419.   return 0;
  420. }
  421.  
  422. static member_t*
  423. add_member (cls, name, var, sc, hash)
  424.      sym_t* cls;
  425.      char* name;
  426.      int var;
  427.      int sc;
  428.      long hash;
  429. {
  430.   member_t* m = (member_t*) xmalloc (sizeof *m + strlen (name));
  431.   member_t** list;
  432.   member_t* p;
  433.   member_t* prev;
  434.  
  435.   strcpy (m->name, name);
  436.   m->params = hash;
  437.  
  438.   m->vis = 0;
  439.   m->is_virtual = 0;
  440.   m->is_inline = 0;
  441.   m->is_const = 0;
  442.   m->is_pure = 0;
  443.   m->regexp = NULL;
  444.   m->filename = NULL;
  445.   m->pos = 0;
  446.   m->def_regexp = NULL;
  447.   m->def_filename = NULL;
  448.   m->def_pos = 0;
  449.  
  450.   assert (cls != NULL);
  451.  
  452.   list = get_list (cls, var, sc);
  453.  
  454.   for (p = *list, prev = 0; p && strcmp (name, p->name) > 0;
  455.        prev = p, p = p->next)
  456.     ;
  457.  
  458.   m->next = p;
  459.   return prev ? (prev->next = m) : (*list = m);
  460. }
  461.  
  462. #define putstr(s, fp)           \
  463.         if (!s)                 \
  464.           {                     \
  465.             putc ('(', fp);     \
  466.             putc (')', fp);     \
  467.             putc (' ', fp);     \
  468.           }                     \
  469.         else                    \
  470.           {                     \
  471.             putc ('"', fp);     \
  472.             fputs (s, fp);      \
  473.             putc ('"', fp);     \
  474.             putc (' ', fp);     \
  475.           }
  476.  
  477. static unsigned
  478. dump_members (fp, m)
  479.      FILE* fp;
  480.      member_t* m;
  481. {
  482.   char b[35];
  483.   unsigned n = 0;
  484.   unsigned temp;
  485.  
  486.   putc ('(', fp);
  487.  
  488.   for (; m; m = m->next, ++n)
  489.     {
  490. #if USE_STRUCTS
  491.       fputs (MEMBER_STRUCT, fp);
  492. #elif USE_ARRAYS
  493.       putc ('\[', fp);
  494. #else
  495.       putc ('\(', fp);
  496. #endif
  497.  
  498.       putstr (m->name, fp);
  499.       putstr (m->filename, fp);
  500.  
  501.       if (regexp_file)
  502.     {
  503.       fprintf (fp, "%lu ", regexp_pos);
  504.  
  505.       if (m->regexp)
  506.         {
  507.           write (regexp_file, "\"", 1);
  508.           write_regexp (regexp_file, m->regexp);
  509.           write (regexp_file, "\" ", 2);
  510.           regexp_pos += 3;
  511.         }
  512.       else
  513.         {
  514.           write (regexp_file, "() ", 3);
  515.           regexp_pos += 3;
  516.         }
  517.     }
  518.       else
  519.     putstr (m->regexp, fp);
  520.  
  521.       fprintf (fp, "%lu ", (long) m->pos);
  522.  
  523.       /* Bitfields merged */
  524.       temp = (m->is_pure << 7)
  525.            | (m->is_const << 6)
  526.            | (m->is_virtual << 5)
  527.            | (m->is_inline << 4)
  528.            | m->vis;
  529.  
  530.       fprintf (fp, "%lu", (long) temp);
  531.  
  532. #if !USE_ARRAYS && !USE_STRUCTS
  533.       if (m->def_regexp)
  534. #endif
  535.         {
  536.           putc (' ', fp);
  537.           putstr (m->def_filename, fp);
  538.  
  539.       if (regexp_file)
  540.         {
  541.           fprintf (fp, "%lu ", regexp_pos);
  542.  
  543.           if (m->def_regexp)
  544.         {
  545.           write (regexp_file, "\"", 1);
  546.           write_regexp (regexp_file, m->def_regexp);
  547.           write (regexp_file, "\" ", 2);
  548.           regexp_pos += 3;
  549.         }
  550.           else
  551.         {
  552.           write (regexp_file, "() ", 3);
  553.           regexp_pos += 3;
  554.         }
  555.         }
  556.       else
  557.         putstr (m->def_regexp, fp);
  558.  
  559.       fprintf (fp, "%lu", (long) m->def_pos);
  560.         }
  561.  
  562.       putc (' ', fp);
  563.       fprintf (fp, "%lu", m->params);
  564.  
  565. #if USE_ARRAYS || USE_STRUCTS
  566.       putc (']', fp);
  567. #else
  568.       putc (')', fp);
  569. #endif
  570.       putc ('\n', fp);
  571.     }
  572.  
  573.   putc (')', fp);
  574.   putc ('\n', fp);
  575.   return n;
  576. }
  577.  
  578. static void
  579. dump_sym (fp, root)
  580.      FILE* fp;
  581.      sym_t* root;
  582. {
  583.   char b[35];
  584.  
  585. #if USE_STRUCTS
  586.   fputs (CLASS_STRUCT, fp);
  587. #else
  588.   putc ('\[', fp);
  589. #endif
  590.   putstr (root->name, fp);
  591.   putstr (root->filename, fp);
  592.   putstr (root->regexp, fp);
  593.   fprintf (fp, "%lu", (long) root->pos);
  594.   putstr (root->sfilename, fp);
  595.   putc (']', fp);
  596.   putc ('\n', fp);
  597. }
  598.  
  599. static unsigned
  600. dump_tree (fp, root)
  601.      FILE* fp;
  602.      sym_t* root;
  603. {
  604.   link_t* lk;
  605.   unsigned n;
  606.  
  607.   dump_sym (fp, root);
  608.  
  609.   if (f_verbose)
  610.     {
  611.       putchar ('+');
  612.       fflush (stdout);
  613.     }
  614.  
  615.   putc ('(', fp);
  616.  
  617.   for (lk = root->subs; lk; lk = lk->next)
  618.     {
  619. #ifdef USE_STRUCTS
  620.       fputs (TREE_STRUCT, fp);
  621. #else
  622.       putc ('\(', fp);
  623. #endif
  624.       n += dump_tree (fp, lk->sym);
  625. #ifdef USE_STRUCTS
  626.       putc (']', fp);
  627. #else
  628.       putc (')', fp);
  629. #endif
  630.     }
  631.  
  632.   putc (')', fp);
  633.  
  634.   dump_members (fp, root->vars);
  635.   n += dump_members (fp, root->fns);
  636.   dump_members (fp, root->static_vars);
  637.   n += dump_members (fp, root->static_fns);
  638.   n += dump_members (fp, root->friends);
  639.   dump_members (fp, root->types);
  640.  
  641.   /* Superclasses. */
  642.  
  643.   putc ('(', fp);
  644.   putc (')', fp);
  645.  
  646.   /* Mark slot */
  647.  
  648.   putc ('(', fp);
  649.   putc (')', fp);
  650.  
  651.   putc ('\n', fp);
  652.  
  653.   return n;
  654. }
  655.  
  656. /* Dump an entire class tree to a file. */
  657.  
  658. void
  659. dump_roots (fp)
  660.      FILE* fp;
  661. {
  662.   unsigned i, n = 0;
  663.   sym_t* r;
  664.  
  665.   /* Output file header containing version string, command line
  666.      options, file name of regular expression file (if any), and
  667.      a free slot used by the Lisp package. */
  668.  
  669.   if (!f_append)
  670.     {
  671.       fputs (TREE_HEADER_STRUCT, fp);
  672.       putstr (VERSION, fp);
  673.  
  674.       putc ('\"', fp);
  675.       if (!f_costly_friends) fputs (" -f", fp);
  676.       if (!f_structs) fputs (" -s", fp);
  677.       if (f_regexps) fputs (" -x", fp);
  678.       putc ('\"', fp);
  679.  
  680.       putstr (regexp_filename, fp);
  681.       fputs (" ()", fp);
  682.       putc (']', fp);
  683.     }
  684.  
  685.   mark_inherited_virtual ();
  686.  
  687.   for (i = 0; i < SYM_HASH_SIZE; ++i)
  688.     for (r = sym_hash_table[i]; r; r = r->next)
  689.       if (!r->supers)
  690.         {
  691.       fputs (TREE_STRUCT, fp);
  692.           n += dump_tree (fp, r);
  693.       putc (']', fp);
  694.         }
  695. }
  696.  
  697. /* Given the root R of a class tree, step through all subclasses,
  698.    marking functions as virtual that are declared virtual in
  699.    base classes. */
  700.  
  701. static void
  702. mark_virtual (r)
  703.      sym_t* r;
  704. {
  705.   link_t* p;
  706.   member_t* m;
  707.   member_t* m2;
  708.  
  709.   for (p = r->subs; p; p = p->next)
  710.     {
  711.       for (m = r->fns; m; m = m->next)
  712.         if (m->is_virtual)
  713.           {
  714.             for (m2 = p->sym->fns; m2; m2 = m2->next)
  715.               if (m->params == m2->params && !strcmp (m->name, m2->name))
  716.                 m2->is_virtual = 1;
  717.           }
  718.  
  719.       mark_virtual (p->sym);
  720.     }
  721. }
  722.  
  723. /* For all roots of the class tree, mark functions as virtual that
  724.    are virtual because of a virtual declaration in a base class. */
  725.  
  726. void
  727. mark_inherited_virtual ()
  728. {
  729.   int i;
  730.   sym_t* r;
  731.  
  732.   for (i = 0; i < SYM_HASH_SIZE; ++i)
  733.     for (r = sym_hash_table[i]; r; r = r->next)
  734.       if (!r->supers)
  735.         mark_virtual (r);
  736. }
  737.