diff src/symtab.cc @ 3013:66a1cede95e7

[project @ 1997-06-02 19:35:05 by jwe]
author jwe
date Mon, 02 Jun 1997 19:41:17 +0000
parents a3556d2adec9
children dcc6c985d72d
line wrap: on
line diff
--- a/src/symtab.cc	Mon Jun 02 18:58:13 1997 +0000
+++ b/src/symtab.cc	Mon Jun 02 19:41:17 1997 +0000
@@ -28,7 +28,11 @@
 #include <config.h>
 #endif
 
+#include <cassert>
 #include <cctype>
+#include <climits>
+
+#include <iomanip.h>
 
 #include "glob-match.h"
 #include "str-vec.h"
@@ -36,196 +40,18 @@
 #include "error.h"
 #include "oct-lvalue.h"
 #include "ov.h"
+#include "pager.h"
 #include "symtab.h"
 #include "utils.h"
 #include "variables.h"
 
-// Variables and functions.
-
-symbol_def::symbol_def (void)
-{
-  init_state ();
-}
-
-symbol_def::symbol_def (const octave_value& val, unsigned int sym_type)
-{
-  init_state ();
-  definition = val;
-  type = sym_type;
-}
-
-void
-symbol_def::init_state (void)
-{
-  type = UNKNOWN;
-  eternal = 0;
-  read_only = 0;
-
-  next_elem = 0;
-  count = 0;
-}
-
-bool
-symbol_def::is_variable (void) const
-{
-  return (type & USER_VARIABLE || type & BUILTIN_VARIABLE);
-}
-
-bool
-symbol_def::is_function (void) const
-{
-  return (type & USER_FUNCTION || type & BUILTIN_FUNCTION);
-}
-
-bool
-symbol_def::is_user_variable (void) const
-{
-  return (type & USER_VARIABLE);
-}
-
-bool
-symbol_def::is_text_function (void) const
-{
-  return (type & TEXT_FUNCTION);
-}
-
-bool
-symbol_def::is_mapper_function (void) const
-{
-  return (type & MAPPER_FUNCTION);
-}
-
-bool
-symbol_def::is_user_function (void) const
-{
-  return (type & USER_FUNCTION);
-}
-
-bool
-symbol_def::is_builtin_variable (void) const
-{
-  return (type & BUILTIN_VARIABLE);
-}
-
-bool
-symbol_def::is_builtin_function (void) const
-{
-  return (type & BUILTIN_FUNCTION);
-}
-
-// XXX FIXME XXX
-bool
-symbol_def::is_map_element (const string& /* elts */) const
-{
-  return false;
-}
-
-void
-symbol_def::define (const octave_value& val, unsigned int sym_type)
-{
-  definition = val;
-
-  type = sym_type;
-}
-
-void
-symbol_def::protect (void)
-{
-  read_only = 1;
-}
-
-void
-symbol_def::unprotect (void)
-{
-  read_only = 0;
-
-}
-
-void
-symbol_def::make_eternal (void)
-{
-  eternal = 1;
-}
-
-octave_value&
-symbol_def::def (void)
-{
-  return definition;
-}
-
-string
-symbol_def::help (void) const
-{
-  return help_string;
-}
-
-void
-symbol_def::document (const string& h)
-{
-  help_string = h;
-}
-
-int
-maybe_delete (symbol_def *def)
-{
-  int count = 0;
-  if (def && def->count > 0)
-    {
-      def->count--;
-      count = def->count;
-      if (def->count == 0)
-	delete def;
-    }
-  return count;
-}
+octave_allocator
+symbol_record::symbol_def::allocator (sizeof (symbol_record::symbol_def));
 
 // Individual records in a symbol table.
 
-symbol_record::symbol_record (void)
-{
-  init_state ();
-}
-
-symbol_record::symbol_record (const string& n, symbol_record *nxt)
-{
-  init_state ();
-  nm = n;
-  next_elem = nxt;
-}
-
-void
-symbol_record::init_state (void)
-{
-  formal_param = 0;
-  linked_to_global = 0;
-  tagged_static = 0;
-  sv_fcn = 0;
-  definition = 0;
-  next_elem = 0;
-}
-
-string
-symbol_record::name (void) const
-{
-  return nm;
-}
-
-string
-symbol_record::help (void) const
-{
-  string retval;
-  if (definition)
-    retval = definition->help ();
-  return retval;
-}
-
-octave_value&
-symbol_record::def (void)
-{
-  static octave_value foo;
-
-  return definition ? definition->def () : foo;
-}
+// XXX FIXME XXX -- there are lots of places below where we should
+// probably be temporarily ignoring interrupts.
 
 void
 symbol_record::rename (const string& new_name)
@@ -234,270 +60,104 @@
     nm = new_name;
 }
 
-bool
-symbol_record::is_function (void) const
-{
-  return definition ? definition->is_function () : false;
-}
-
-bool
-symbol_record::is_text_function (void) const
-{
-  return definition ? definition->is_text_function () : false;
-}
-
-bool
-symbol_record::is_mapper_function (void) const
-{
-  return definition ? definition->is_mapper_function () : false;
-}
-
-bool
-symbol_record::is_user_function (void) const
+void
+symbol_record::define (const octave_value& v, unsigned int sym_type)
 {
-  return definition ? definition->is_user_function () : false;
-}
-
-bool
-symbol_record::is_builtin_function (void) const
-{
-  return definition ? definition->is_builtin_function () : false;
-}
-
-bool
-symbol_record::is_variable (void) const
-{
-  return definition ? definition->is_variable () : false;
-}
-
-bool
-symbol_record::is_user_variable (void) const
-{
-  return definition ? definition->is_user_variable () : false;
-}
+  if (! (is_variable () && read_only_error ("redefine")))
+    {
+      if (is_function ())
+	push_def (new symbol_def ());
 
-bool
-symbol_record::is_builtin_variable (void) const
-{
-  return definition ? definition->is_builtin_variable () : false;
-}
-
-bool
-symbol_record::is_map_element (const string& elts) const
-{
-  return definition ? definition->is_map_element (elts) : false;
-}
-
-unsigned int
-symbol_record::type (void) const
-{
-  return definition ? definition->type : false;
-}
+      if (definition->type () == symbol_record::BUILTIN_VARIABLE)
+	sym_type = symbol_record::BUILTIN_VARIABLE;
 
-bool
-symbol_record::is_defined (void) const
-{
-  return (definition != 0);
-}
-
-bool
-symbol_record::is_read_only (void) const
-{
-  return definition ? definition->read_only : false;
-}
-
-bool
-symbol_record::is_eternal (void) const
-{
-  return definition ? definition->eternal : false;
-}
-
-void
-symbol_record::protect (void)
-{
-  if (definition)
-    {
-      definition->protect ();
-
-      if (! is_defined ())
-	warning ("protecting undefined variable `%s'", nm.c_str ());
+      definition->define (v, sym_type);
     }
 }
 
 void
-symbol_record::unprotect (void)
-{
-  if (definition)
-    definition->unprotect ();
-}
-
-void
-symbol_record::make_eternal (void)
+symbol_record::define_builtin_var (const octave_value& v)
 {
-  if (definition)
-    {
-      definition->make_eternal ();
+  define (v, symbol_record::BUILTIN_VARIABLE);
 
-      if (! is_defined ())
-	warning ("giving eternal life to undefined variable `%s'",
-		 nm.c_str ());
-    }
+  if (chg_fcn)
+    chg_fcn ();
 }
 
-void
-symbol_record::set_sv_function (sv_function f)
+bool
+symbol_record::define_as_fcn (const octave_value& v)
 {
-  sv_fcn = f;
-}
+  bool retval = false;
 
-int
-symbol_record::define (const octave_value& v, unsigned int sym_type)
-{
-  int retval = 0;
-
-  if (! (is_variable () && read_only_error ("redefine")))
+  if (! (is_variable () || read_only_error ("redefine")))
     {
-      if (! definition)
-	{
-	  definition = new symbol_def ();
-	  definition->count = 1;
-	}
-      else if (is_function ())
-	{
-	  push_def (new symbol_def ());
-	  definition->count = 1;
-	}
+      replace_all_defs (new symbol_def (v, symbol_record::BUILTIN_FUNCTION));
 
-      if (definition->symbol_type () == symbol_def::BUILTIN_VARIABLE)
-	sym_type = symbol_def::BUILTIN_VARIABLE;
-
-      definition->define (v, sym_type);
+      retval = true;
     }
 
   return retval;
 }
 
-int
-symbol_record::define_builtin_var (const octave_value& v)
+bool
+symbol_record::define (octave_function *f, unsigned int sym_type)
 {
-  int retval = define (v, symbol_def::BUILTIN_VARIABLE);
+  bool retval = false;
 
-  if (sv_fcn)
-    sv_fcn ();
+  if (! read_only_error ("redefine"))
+    {
+      octave_value tmp (f);
+
+      replace_all_defs (new symbol_def (tmp, sym_type));
+
+      retval = true;
+    }
 
   return retval;
 }
 
-int
-symbol_record::define_as_fcn (const octave_value& v)
-{
-  if (is_variable () && read_only_error ("redefine"))
-    return 0;
-
-  if (is_variable ())
-    {
-      symbol_def *old_def = pop_def ();
-      maybe_delete (old_def);
-    }
-
-  if (is_function ())
-    {
-      symbol_def *old_def = pop_def ();
-      maybe_delete (old_def);
-    }
-
-  push_def (new symbol_def (v, symbol_def::BUILTIN_FUNCTION));
-
-  definition->count = 1;
-
-  return 1;
-}
-
-int
-symbol_record::define (octave_function *f, unsigned int sym_type)
-{
-  if (read_only_error ("redefine"))
-    return 0;
-
-  if (is_variable ())
-    {
-      symbol_def *old_def = pop_def ();
-      maybe_delete (old_def);
-    }
-
-  if (is_function ())
-    {
-      symbol_def *old_def = pop_def ();
-      maybe_delete (old_def);
-    }
-
-  octave_value tmp (f);
-
-  push_def (new symbol_def (tmp, sym_type));
-
-  definition->count = 1;
-
-  return 1;
-}
-
 void
-symbol_record::document (const string& h)
-{
-  if (definition)
-    {
-      definition->document (h);
-
-      if (! is_defined ())
-	warning ("documenting undefined variable `%s'", nm.c_str ());
-    }
-}
-
-int
 symbol_record::clear (void)
 {
-  int count = 0;
   if (linked_to_global)
     {
-      count = maybe_delete (definition);
-      definition = 0;
+      if (--definition->count <= 0)
+	delete definition;
+
+      definition = new symbol_def ();
+
       linked_to_global = 0;
     }
   else if (! tagged_static)
     {
-      symbol_def *old_def = pop_def ();
-      count = maybe_delete (old_def);
+      remove_top_def ();
+
+      if (! definition)
+	definition = new symbol_def ();
     }
-  return count;
 }
 
 void
-symbol_record::alias (symbol_record *s, bool force)
+symbol_record::alias (symbol_record *s, bool /* force */)
 {
-  sv_fcn = s->sv_fcn;
+  chg_fcn = s->chg_fcn;
 
-  if (force && ! s->definition)
-    {
-      s->definition = new symbol_def ();
-      definition = s->definition;
-      definition->count = 2; // Yes, this is correct.
-    }
-  else if (s->definition)
-    {
-      definition = s->definition;
-      definition->count++;
-    }
+  replace_all_defs (s->definition);
+
+  definition->count++;
 }
 
 void
 symbol_record::mark_as_formal_parameter (void)
 {
-  formal_param = 1;
-}
-
-bool
-symbol_record::is_formal_parameter (void) const
-{
-  return formal_param;
+  if (is_linked_to_global ())
+    error ("can't mark global variable `%s' as function parameter",
+	   nm.c_str ());
+  else if (is_static ())
+    error ("can't mark static variable `%s' as function paraemter",
+	   nm.c_str ());
+  else
+    formal_param = 1;
 }
 
 void
@@ -511,12 +171,6 @@
     linked_to_global = 1;
 }
 
-bool
-symbol_record::is_linked_to_global (void) const
-{
-  return linked_to_global;
-}
-
 void
 symbol_record::mark_as_static (void)
 {
@@ -529,9 +183,35 @@
 }
 
 bool
-symbol_record::is_static (void) const
+symbol_record::hides_fcn (void) const
 {
-  return tagged_static;
+  bool retval = false;
+
+  if (is_variable () && is_defined ())
+    {
+      symbol_def *hidden_def = definition->next_elem;
+
+      if (hidden_def && hidden_def->is_builtin_function ())
+	retval = true;
+    }
+
+  return retval;
+}
+
+bool
+symbol_record::hides_builtin (void) const
+{
+  bool retval = false;
+
+  if (is_variable () && is_defined ())
+    {
+      symbol_def *hidden_def = definition->next_elem;
+
+      if (hidden_def && hidden_def->is_user_function ())
+	retval = true;
+    }
+
+  return retval;
 }
 
 octave_value&
@@ -560,19 +240,7 @@
 	}
     }
 
-  return octave_lvalue (&(def ()), sv_fcn);
-}
-
-symbol_record *
-symbol_record::next (void) const
-{
-  return next_elem;
-}
-
-void
-symbol_record::chain (symbol_record *s)
-{
-  next_elem = s;
+  return octave_lvalue (&(def ()), chg_fcn);
 }
 
 void
@@ -581,9 +249,11 @@
   if (! is_static ())
     {
       context.push (definition);
-      definition = 0;
+
+      definition = new symbol_def ();
 
       global_link_context.push (static_cast<unsigned int> (linked_to_global));
+
       linked_to_global = 0;
     }
 }
@@ -597,45 +267,59 @@
 
   if (! context.empty ())
     {
-      if (is_variable ())
-	{
-	  symbol_def *old_def = pop_def ();
-	  maybe_delete (old_def);
-	}
+      replace_all_defs (context.pop ());
 
-      if (is_function ())
-	{
-	  symbol_def *old_def = pop_def ();
-	  maybe_delete (old_def);
-	}
-
-      definition = context.pop ();
       linked_to_global = global_link_context.pop ();
     }
 }
 
-int
+void
+symbol_record::print_symbol_info_line (ostream& os)
+{
+  os << (is_read_only () ? " r-" : " rw")
+     << (is_eternal () ? "-" : "d")
+#if 0
+     << (hides_fcn () ? "f" : (hides_builtin () ? "F" : "-"))
+#endif
+     << "  "
+     << setiosflags (ios::left) << setw (24) << type_name () . c_str ();
+
+  os << resetiosflags (ios::left);
+
+  int nr = rows ();
+  int nc = columns ();
+
+  if (nr < 0)
+    os << "      -";
+  else
+    os << setiosflags (ios::right) << setw (7) << nr;
+
+  if (nc < 0)
+    os << "      -";
+  else
+    os << setiosflags (ios::right) << setw (7) << nc;
+
+  os << resetiosflags (ios::right);
+
+  os << "  " << name () << "\n";
+}
+
+bool
 symbol_record::read_only_error (const char *action)
 {
   if (is_read_only ())
     {
       if (is_variable ())
-	{
-	  ::error ("can't %s read-only constant `%s'", action, nm.c_str ());
-	}
+	::error ("can't %s read-only constant `%s'", action, nm.c_str ());
       else if (is_function ())
-	{
-	  ::error ("can't %s read-only function `%s'", action, nm.c_str ());
-	}
+	::error ("can't %s read-only function `%s'", action, nm.c_str ());
       else
-	{
-	  ::error ("can't %s read-only symbol `%s'", action, nm.c_str ());
-	}
+	::error ("can't %s read-only symbol `%s'", action, nm.c_str ());
 
-      return 1;
+      return true;
     }
   else
-    return 0;
+    return false;
 }
 
 void
@@ -644,172 +328,39 @@
   if (! sd)
     return;
 
+  assert (definition == 0 || definition->next_elem == 0);
+
   sd->next_elem = definition;
+
   definition = sd;
 }
 
-symbol_def *
-symbol_record::pop_def (void)
+void
+symbol_record::remove_top_def (void)
 {
   symbol_def *top = definition;
-  if (definition)
-    definition = definition->next_elem;
-  return top;
-}
 
-// A structure for handling verbose information about a symbol_record.
-
-symbol_record_info::symbol_record_info (void)
-  : initialized (0), nr (-1), nc (-1), type (symbol_def::UNKNOWN),
-    hides (SR_INFO_NONE), eternal (0), read_only (0), nm (),
-    const_type () { }
-
-symbol_record_info::symbol_record_info (symbol_record& sr)
-  : initialized (0), nr (-1), nc (-1), type (sr.type ()),
-    hides (SR_INFO_NONE), eternal (0), read_only (0), nm (),
-    const_type ()
-{
-  if (sr.is_variable () && sr.is_defined ())
-    {
-      octave_value tmp = sr.def ();
-
-      const_type = tmp.type_name ();
-
-      nr = tmp.rows ();
-      nc = tmp.columns ();
-
-      symbol_def *sr_def = sr.definition;
-      symbol_def *hidden_def = sr_def->next_elem;
+  definition = definition->next_elem;
 
-      if (hidden_def)
-	{
-	  if (hidden_def->is_user_function ())
-	    hides = SR_INFO_USER_FUNCTION;
-	  else if (hidden_def->is_builtin_function ())
-	    hides = SR_INFO_BUILTIN_FUNCTION;
-	}
-    }
-
-  eternal = sr.is_eternal ();
-  read_only = sr.is_read_only ();
-
-  nm = sr.name ();
-
-  initialized = 1;
-}
-
-symbol_record_info::symbol_record_info (const symbol_record_info& s)
-  : initialized (s.initialized), nr (s.nr), nc (s.nc), type (s.type),
-    hides (s.hides), eternal (s.eternal), read_only (s.read_only),
-    nm (s.nm), const_type (s.const_type) { }
-
-symbol_record_info&
-symbol_record_info::operator = (const symbol_record_info& s)
-{
-  if (this != &s)
-    {
-      initialized = s.initialized;
-      nr = s.nr;
-      nc = s.nc;
-      type = s.type;
-      hides = s.hides;
-      eternal = s.eternal;
-      read_only = s.read_only;
-      nm = s.nm;
-      const_type = s.const_type;
-    }
-  return *this;
+  if (--top->count <= 0)
+    delete top;
 }
 
-bool
-symbol_record_info::is_defined (void) const
-{
-  return initialized;
-}
-
-bool
-symbol_record_info::is_read_only (void) const
-{
-  return read_only;
-}
-
-bool
-symbol_record_info::is_eternal (void) const
+void
+symbol_record::replace_all_defs (symbol_def *sd)
 {
-  return eternal;
-}
-
-bool
-symbol_record_info::hides_fcn (void) const
-{
-  return (hides & SR_INFO_USER_FUNCTION);
-}
-
-bool
-symbol_record_info::hides_builtin (void) const
-{
-  return (hides & SR_INFO_BUILTIN_FUNCTION);
-}
-
-string
-symbol_record_info::type_name (void) const
-{
-  string retval;
+  while (definition)
+    remove_top_def ();
 
-  if (type == symbol_def::USER_FUNCTION)
-    retval = "user function";
-  else if (type & symbol_def::BUILTIN_FUNCTION)
-    {
-      if (type & symbol_def::TEXT_FUNCTION)
-	retval = "text function";
-      else if (type & symbol_def::MAPPER_FUNCTION)
-	retval = "mapper function";
-      else
-	retval = "builtin function";
-    }
-  else
-    retval = const_type;
-
-  return retval;
-}
-
-bool
-symbol_record_info::is_function (void) const
-{
-  return (type == symbol_def::USER_FUNCTION
-	  || type == symbol_def::BUILTIN_FUNCTION
-	  || symbol_def::TEXT_FUNCTION
-	  || symbol_def::MAPPER_FUNCTION);
-}
-
-int
-symbol_record_info::rows (void) const
-{
-  return nr;
-}
-
-int
-symbol_record_info::columns (void) const
-{
-  return nc;
-}
-
-string
-symbol_record_info::name (void) const
-{
-  return nm;
+  push_def (sd);
 }
 
 // A symbol table.
 
-symbol_table::symbol_table (void)
-{
-}
-
 symbol_record *
 symbol_table::lookup (const string& nm, bool insert, bool warn)
 {
-  int index = hash (nm) & HASH_MASK;
+  unsigned int index = hash (nm);
 
   symbol_record *ptr = table[index].next ();
 
@@ -817,15 +368,17 @@
     {
       if (ptr->name () == nm)
 	return ptr;
+
       ptr = ptr->next ();
     }
 
   if (insert)
     {
-      symbol_record *new_sym;
-      new_sym = new symbol_record (nm, table[index].next ());
-      table[index].chain (new_sym);
-      return new_sym;
+      symbol_record *sr = new symbol_record (nm, table[index].next ());
+
+      table[index].chain (sr);
+
+      return sr;
     }
   else if (warn)
     warning ("lookup: symbol`%s' not found", nm.c_str ());
@@ -836,7 +389,7 @@
 void
 symbol_table::rename (const string& old_name, const string& new_name)
 {
-  int index = hash (old_name) & HASH_MASK;
+  unsigned int index = hash (old_name);
 
   symbol_record *prev = &table[index];
   symbol_record *ptr = prev->next ();
@@ -851,7 +404,7 @@
 	    {
 	      prev->chain (ptr->next ());
 
-	      index = hash (new_name) & HASH_MASK;
+	      index = hash (new_name);
 	      table[index].chain (ptr);
 
 	      return;
@@ -871,7 +424,7 @@
 void
 symbol_table::clear (bool clear_user_functions)
 {
-  for (int i = 0; i < HASH_TABLE_SIZE; i++)
+  for (unsigned int i = 0; i < table_size; i++)
     {
       symbol_record *ptr = table[i].next ();
 
@@ -888,10 +441,10 @@
     }
 }
 
-int
+bool
 symbol_table::clear (const string& nm, bool clear_user_functions)
 {
-  int index = hash (nm) & HASH_MASK;
+  unsigned int index = hash (nm);
 
   symbol_record *ptr = table[index].next ();
 
@@ -902,72 +455,63 @@
 	      || (clear_user_functions && ptr->is_user_function ())))
 	{
 	  ptr->clear ();
-	  return 1;
+	  return true;
 	}
       ptr = ptr->next ();
     }
 
-  return 0;
+  return false;
 }
 
 int
 symbol_table::size (void) const
 {
   int count = 0;
-  for (int i = 0; i < HASH_TABLE_SIZE; i++)
+
+  for (unsigned int i = 0; i < table_size; i++)
     {
       symbol_record *ptr = table[i].next ();
+
       while (ptr)
 	{
 	  count++;
 	  ptr = ptr->next ();
 	}
     }
+
   return count;
 }
 
-static inline int
-pstrcmp (char **a, char **b)
+static bool
+matches_patterns (const string& name, const string_vector& pats)
 {
-  return strcmp (*a, *b);
-}
+  int npats = pats.length ();
 
-static inline int
-symbol_record_info_cmp (symbol_record_info *a, symbol_record_info *b)
-{
-  return (a->name () == b->name ());
+  if (npats == 0)
+    return true;
+
+  glob_match pattern (pats);
+
+  return pattern.match (name);
 }
 
-static int
-matches_patterns (const string& name, const string_vector& pats, int npats)
-{
-  for (int i = 0; i < npats; i++)
-    {
-      glob_match pattern (pats[i]);
-      if (pattern.match (name))
-	return 1;
-    }
-
-  return 0;
-}
-
-// This function should probably share code with symbol_table::list.
-// XXX FIXME XXX
-
-symbol_record_info *
-symbol_table::long_list (int& count, const string_vector& pats,
-			 int npats, bool sort, unsigned int type,
-			 unsigned int scope) const 
+Array<symbol_record *>
+symbol_table::symbol_list (int& count, const string_vector& pats,
+			   unsigned int type, unsigned int scope) const
 {
   count = 0;
+
   int n = size ();
+
   if (n == 0)
     return 0;
 
-  symbol_record_info *symbols = new symbol_record_info [n+1];
-  for (int i = 0; i < HASH_TABLE_SIZE; i++)
+  Array<symbol_record *> symbols (n);
+
+  for (unsigned int i = 0; i < table_size; i++)
     {
       symbol_record *ptr = table[i].next ();
+
       while (ptr)
 	{
 	  assert (count < n);
@@ -979,48 +523,8 @@
 	  string my_name = ptr->name ();
 
 	  if ((type & my_type) && (scope & my_scope)
-	      && (npats == 0 || matches_patterns (my_name, pats, npats)))
-	    symbols[count++] = symbol_record_info (*ptr);
-
-	  ptr = ptr->next ();
-	}
-    }
-  symbols[count] = symbol_record_info ();
-
-  if (sort && symbols)
-    qsort (symbols, count, sizeof (symbol_record_info),
-	   symbol_record_info_cmp);
-
-  return symbols;
-}
-
-string_vector
-symbol_table::list (int& count, const string_vector& pats, int npats,
-		    bool sort, unsigned int type, unsigned int scope) const
-{
-  count = 0;
-  int n = size ();
-  if (n == 0)
-    return 0;
-
-  string_vector symbols (n);
-
-  for (int i = 0; i < HASH_TABLE_SIZE; i++)
-    {
-      symbol_record *ptr = table[i].next ();
-      while (ptr)
-	{
-	  assert (count < n);
-
-	  unsigned int my_scope = ptr->is_linked_to_global () + 1; // Tricky...
-
-	  unsigned int my_type = ptr->type ();
-
-	  string my_name = ptr->name ();
-
-	  if ((type & my_type) && (scope & my_scope)
-	      && (npats == 0 || matches_patterns (my_name, pats, npats)))
-	    symbols[count++] = ptr->name ();
+	      && matches_patterns (my_name, pats))
+	    symbols(count++) = ptr;
 
 	  ptr = ptr->next ();
 	}
@@ -1028,10 +532,87 @@
 
   symbols.resize (count);
 
-  if (sort && ! symbols.empty ())
-    symbols.qsort ();
+  return symbols;
+}
+
+string_vector
+symbol_table::name_list (int& count, const string_vector& pats, bool sort,
+			 unsigned int type, unsigned int scope) const
+{
+  Array<symbol_record *> symbols
+    = symbol_list (count, pats, type, scope);
+
+  string_vector names;
+
+  int n = symbols.length ();
+
+  if (n > 0)
+    {
+      names.resize (n);
+
+      for (int i = 0; i < n; i++)
+	names[i] = symbols(i)->name ();
+    }
+
+  if (sort)
+    names.qsort ();
+
+  return names;
+}
+
+static int
+maybe_list_cmp_fcn (symbol_record **a_arg, symbol_record **b_arg)
+{
+  string a = (*a_arg)->name ();
+  string b = (*b_arg)->name ();
+
+  return a.compare (b);
+}
 
-  return symbols;
+int
+symbol_table::maybe_list (const char *header, const string_vector& argv,
+			  ostream& os, bool show_verbose,
+			  unsigned type, unsigned scope)
+{
+  int count;
+
+  int status = 0;
+
+  if (show_verbose)
+    {
+      Array<symbol_record *> symbols = symbol_list (count, argv, type, scope);
+
+      int len = symbols.length ();
+
+      if (len > 0 && count > 0)
+	{
+	  os << "\n" << header << "\n\n"
+		     << "prot  type                       rows   cols  name\n"
+		     << "====  ====                       ====   ====  ====\n";
+
+	  symbols.qsort (maybe_list_cmp_fcn);
+
+	  for (int i = 0; i < len; i++)
+	    symbols(i)->print_symbol_info_line (os);
+
+	  status = 1;
+	}
+    }
+  else
+    {
+      string_vector symbols = name_list (count, argv, 1, type, scope);
+
+      if (symbols.length () > 0 && count > 0)
+	{
+	  os << "\n" << header << "\n\n";
+
+	  symbols.list_in_columns (os);
+
+	  status = 1;
+	}
+    }
+
+  return status;
 }
 
 symbol_record **
@@ -1044,9 +625,11 @@
     return 0;
 
   symbol_record **symbols = new symbol_record * [n+1];
-  for (int i = 0; i < HASH_TABLE_SIZE; i++)
+
+  for (unsigned int i = 0; i < table_size; i++)
     {
       symbol_record *ptr = table[i].next ();
+
       while (ptr)
 	{
 	  assert (count < n);
@@ -1074,7 +657,7 @@
 void
 symbol_table::push_context (void)
 {
-  for (int i = 0; i < HASH_TABLE_SIZE; i++)
+  for (unsigned int i = 0; i < table_size; i++)
     {
       symbol_record *ptr = table[i].next ();
 
@@ -1089,7 +672,7 @@
 void
 symbol_table::pop_context (void)
 {
-  for (int i = 0; i < HASH_TABLE_SIZE; i++)
+  for (unsigned int i = 0; i < table_size; i++)
     {
       symbol_record *ptr = table[i].next ();
 
@@ -1101,36 +684,67 @@
     }
 }
 
+void
+symbol_table::print_stats (void)
+{
+  int count = 0;
+  int empty_chains = 0;
+  int max_chain_length = 0;
+  int min_chain_length = INT_MAX;
+
+  for (unsigned int i = 0; i < table_size; i++)
+    {
+      int num_this_chain = 0;
+
+      symbol_record *ptr = table[i].next ();
+
+      if (ptr)
+	octave_stdout << "chain number " << i << ":\n";
+      else
+	{
+	  empty_chains++;
+	  min_chain_length = 0;
+	}
+
+      while (ptr)
+	{
+	  num_this_chain++;
+
+	  octave_stdout << "  " << ptr->name () << "\n";
+
+	  ptr = ptr->next ();
+	}
+
+      count += num_this_chain;
+
+      if (num_this_chain > max_chain_length)
+	max_chain_length = num_this_chain;
+
+      if (num_this_chain < min_chain_length)
+	min_chain_length = num_this_chain;
+
+      if (num_this_chain > 0)
+	octave_stdout << "\n";
+    }
+
+  octave_stdout << "max chain length: " << max_chain_length << "\n";
+  octave_stdout << "min chain length: " << min_chain_length << "\n";
+  octave_stdout << "empty chains:     " << empty_chains << "\n";
+  octave_stdout << "total chains:     " << table_size << "\n";
+  octave_stdout << "total symbols:    " << count << "\n";
+}
+
 // Chris Torek's fave hash function.
 
 unsigned int
 symbol_table::hash (const string& str)
 {
   unsigned int h = 0;
+
   for (unsigned int i = 0; i < str.length (); i++)
     h = h * 33 + str[i];
-  return h;
-}
 
-// Return nonzero if S is a valid identifier.
-
-bool
-valid_identifier (const char *s)
-{
-  if (! s || ! (isalnum (*s) || *s == '_'))
-     return false;
-
-  while (*++s != '\0')
-    if (! (isalnum (*s) || *s == '_'))
-      return false;
-
-  return true;
-}
-
-bool
-valid_identifier (const string& s)
-{
-  return valid_identifier (s.c_str ());
+  return h & (table_size - 1);
 }
 
 /*