diff src/symtab.h @ 7336:745a8299c2b5

[project @ 2007-12-28 20:56:55 by jwe]
author jwe
date Fri, 28 Dec 2007 20:56:58 +0000
parents 88417316c1b0
children 40252ccfcb67
line wrap: on
line diff
--- a/src/symtab.h	Fri Feb 01 23:56:51 2008 -0500
+++ b/src/symtab.h	Fri Dec 28 20:56:58 2007 +0000
@@ -2,7 +2,7 @@
 
 Copyright (C) 1993, 1994, 1995, 1996, 1997, 1999, 2000, 2002, 2003,
               2004, 2005, 2006, 2007 John W. Eaton
-
+  
 This file is part of Octave.
 
 Octave is free software; you can redistribute it and/or modify it
@@ -24,474 +24,19 @@
 #if !defined (octave_symtab_h)
 #define octave_symtab_h 1
 
-#include <cassert>
-
-#include <string>
+#include <deque>
+#include <list>
+#include <map>
+#include <set>
 #include <stack>
-#include <sstream>
-
-#include "oct-alloc.h"
-#include "str-vec.h"
-
-#include "ov.h"
-
-class octave_lvalue;
-
-class string_vector;
-
-class symbol_record;
-class symbol_table;
-
-struct
-whos_parameter
-{
-  char command;
-  char modifier;
-  int parameter_length;
-  int first_parameter_length;
-  int dimensions;
-  int balance;
-  std::string text;
-  std::string line;
-};
-
-// Individual records in a symbol table.
-
-class
-OCTINTERP_API
-symbol_record
-{
-public:
-
-  // If you add or delete an entry here, you'll also need to change
-  // the width parameter in the declaration for symbol_type below...
-
-  enum TYPE
-    {
-      UNKNOWN = 0,
-      USER_FUNCTION = 1,
-      USER_VARIABLE = 2,
-      DLD_FUNCTION = 4,
-      BUILTIN_FUNCTION = 8,
-      COMMAND = 16,
-      RAWCOMMAND = 32,
-      MAPPER_FUNCTION = 64,
-      MEX_FUNCTION = 128
-    };
-
-private:
-
-  // Variables or functions.
-
-  class symbol_def
-  {
-  public:
-
-    symbol_def (const octave_value& val = octave_value (),
-		unsigned int sym_type = 0)
-      : symbol_type (sym_type), read_only (0), help_string (),
-	definition (val), count (1) { }
-
-    ~symbol_def (void) { }
-
-    bool is_variable (void) const
-      { return (symbol_type & symbol_record::USER_VARIABLE); }
-
-    // It's not necessary to check for COMMAND and MAPPER_FUNCTION
-    // here.  Those tags are just used as additional qualifiers for
-    // the other types of functions.
-
-    bool is_function (void) const
-      {
-	return (symbol_type & symbol_record::USER_FUNCTION
-		|| symbol_type & symbol_record::DLD_FUNCTION
-		|| symbol_type & symbol_record::MEX_FUNCTION
-		|| symbol_type & symbol_record::BUILTIN_FUNCTION);
-      }
-
-    bool is_user_variable (void) const
-      { return (symbol_type & symbol_record::USER_VARIABLE); }
-
-    // Don't use |= here to avoid error with AIX compiler.
-    void mark_as_command (void)
-      { symbol_type = symbol_type | symbol_record::COMMAND; }
-
-    void unmark_command (void)
-      { symbol_type &= ~symbol_record::COMMAND; }
-
-    bool is_command (void) const
-      { return (symbol_type & symbol_record::COMMAND); }
-
-    void mark_as_rawcommand (void)
-      { symbol_type |= (symbol_record::COMMAND
-			| symbol_record::RAWCOMMAND); }
-
-    void unmark_rawcommand (void)
-      { symbol_type &= ~symbol_record::RAWCOMMAND; }
-
-    bool is_rawcommand (void) const
-      { return (symbol_type & symbol_record::RAWCOMMAND); }      
-
-    bool is_mapper_function (void) const
-      { return (symbol_type & symbol_record::MAPPER_FUNCTION); }
-
-    bool is_user_function (void) const
-      { return (symbol_type & symbol_record::USER_FUNCTION); }
-
-    bool is_builtin_function (void) const
-      { return (symbol_type & symbol_record::BUILTIN_FUNCTION); }
-
-    bool is_dld_function (void) const
-      { return (symbol_type & symbol_record::DLD_FUNCTION); }
-
-    bool is_mex_function (void) const
-      { return (symbol_type & symbol_record::MEX_FUNCTION); }
-
-    // FIXME
-    bool is_map_element (const std::string& /* elts */) const
-      { return false; }
-
-    bool is_defined (void) const
-      { return definition.is_defined (); }
-
-    bool is_read_only (void) const
-      { return read_only; }
-
-    bool is_matrix_type (void) const 
-      { return definition.is_matrix_type (); }
-
-    bool is_sparse_type (void) const
-      { return definition.is_sparse_type (); }
-
-    bool is_complex_type (void) const
-      { return definition.is_complex_type (); }
-
-    std::string class_name (void) const
-      { return definition.class_name (); }
-
-    Matrix size (void) const
-      { return definition.size (); }
-
-    size_t byte_size (void) const
-      { return definition.byte_size (); };
-
-    octave_idx_type numel (void) const
-      { return definition.numel (); };
-
-    octave_idx_type capacity (void) const
-      { return definition.capacity (); };
-
-    dim_vector dims (void) const 
-      { return definition.dims (); }
-
-    octave_idx_type rows (void) const { return definition.rows (); }
-    octave_idx_type columns (void) const { return definition.columns (); }
-
-    std::string type_name (void) const { return definition.type_name (); }
-
-    std::string type_as_string (void) const;
-
-    void type (std::ostream& os, const std::string& name, bool pr_type_info,
-	       bool quiet, bool pr_orig_txt);
-
-    std::string which (const std::string& name);
-
-    void which (std::ostream& os, const std::string& name);
-
-    void define (const octave_value& val, unsigned int sym_type)
-      {
-	definition = val;
-	symbol_type = sym_type;
-      }
-
-    void protect (void) { read_only = 1; }
-
-    void unprotect (void) { read_only = 0; }
-
-    octave_value& def (void) { return definition; }
-
-    std::string help (void) const { return help_string; }
-
-    void document (const std::string& h);
-
-    unsigned int type (void) { return symbol_type; }
-
-    void *operator new (size_t size)
-      { return allocator.alloc (size); }
-
-    void operator delete (void *p, size_t size)
-      { allocator.free (p, size); }
-
-    static octave_allocator allocator;
-
-    // The type of this symbol (see the enum above).
-    unsigned int symbol_type : 9;
-
-    // Nonzero means this variable cannot be given a new value.
-    unsigned int read_only : 1;
-
-    // The doc string associated with this variable.
-    std::string help_string;
-
-    // The value of this definition.  See ov.h and related files.
-    octave_value definition;
-
-    // Reference count.
-    int count;
-
-    void print_info (std::ostream& os,
-		     const std::string& prefix = std::string ()) const;
-
-    // No copying!
-
-    symbol_def (const symbol_def& sd);
-
-    symbol_def& operator = (const symbol_def& sd);
-  };
-
-public:
-
-  typedef int (*change_function) (void);
+#include <string>
 
-  symbol_record (void)
-    : formal_param (false), automatic_variable (false),
-      linked_to_global (false), tagged_static (false),
-      can_hide_function (true), visible (true), eternal (false),
-      nm (), chg_fcn (0), definition (new symbol_def ()), next_elem (0) { }
-
-  // FIXME -- kluge alert!  We obviously need a better way of
-  // handling allow_shadow!
-
-  symbol_record (const std::string& n, symbol_record *nxt)
-    : formal_param (false), automatic_variable (false),
-      linked_to_global (false), tagged_static (false),
-      can_hide_function (n != "__end__"), visible (true),
-      eternal (false), nm (n), chg_fcn (0),
-      definition (new symbol_def ()), next_elem (nxt) { }
-
-  ~symbol_record (void)
-    {
-      if (--definition->count <= 0)
-	delete definition;
-    }
-
-  std::string name (void) const { return nm; }
-
-  std::string help (void) const { return definition->help (); }
-
-  octave_value& def (void) { return definition->def (); }
-
-  void rename (const std::string& new_name);
-
-  bool is_function (void) const
-    { return definition->is_function (); }
-
-  void mark_as_command (void)
-    { definition->mark_as_command (); }
-
-  void unmark_command (void)
-    { definition->unmark_command (); }
-
-  bool is_command (void) const
-    { return definition->is_command (); }
-
-  void mark_as_rawcommand (void)
-    { definition->mark_as_rawcommand (); }
-
-  void unmark_rawcommand (void)
-    { definition->unmark_rawcommand (); }
-
-  bool is_rawcommand (void) const
-    { return definition->is_rawcommand (); }    
-
-  bool is_mapper_function (void) const
-    { return definition->is_mapper_function (); }
-
-  bool is_user_function (void) const
-    { return definition->is_user_function (); }
-
-  bool is_builtin_function (void) const
-    { return definition->is_builtin_function (); }
-
-  bool is_dld_function (void) const
-    { return definition->is_dld_function (); }
-
-  bool is_mex_function (void) const
-    { return definition->is_mex_function (); }
-
-  bool is_variable (void) const
-    { return definition->is_variable (); }
-
-  bool is_user_variable (void) const
-    { return definition->is_user_variable (); }
-
-  bool is_map_element (const std::string& elts) const
-    { return definition->is_map_element (elts); }
-
-  unsigned int type (void) const { return definition->type (); }
-
-  bool is_defined (void) const { return definition->is_defined (); }
-
-  bool is_read_only (void) const { return definition->is_read_only (); }
-
-  bool is_eternal (void) const { return eternal; }
-
-  void protect (void) { definition->protect (); }
-
-  void unprotect (void) { definition->unprotect (); }
-
-  void make_eternal (void) { eternal = 1; }
-
-  void hide (void) { visible = false; }
-  void show (void) { visible = true; }
-  bool is_visible (void) const { return visible; }
-
-  void set_change_function (change_function f) { chg_fcn = f; }
-
-  void define (const octave_value& v, unsigned int sym_type = USER_VARIABLE);
-
-  bool define (octave_function *f, unsigned int sym_type);
-
-  void document (const std::string& h) { definition->document (h); }
-
-  void clear (void);
-
-  void alias (symbol_record *s, bool mark_to_clear = false);
-
-  void mark_as_formal_parameter (void);
-  bool is_formal_parameter (void) const { return formal_param; }
-
-  void mark_as_automatic_variable (void);
-  bool is_automatic_variable (void) const { return automatic_variable; }
-
-  void mark_as_linked_to_global (void);
-  bool is_linked_to_global (void) const { return linked_to_global; }
-
-  void mark_as_static (void);
-  bool is_static (void) const { return tagged_static; }
-  void unmark_static (void) { tagged_static = false; }
+#include "glob-match.h"
 
-  bool is_matrix_type (void) const 
-    { return definition->is_matrix_type (); }
-
-  bool is_sparse_type (void) const
-    { return definition->is_sparse_type (); }
-
-  bool is_complex_type (void) const
-    { return definition->is_complex_type (); }
-
-  std::string class_name (void) const
-    { return definition->class_name (); }
-
-  Matrix size (void) const
-    { return definition->size (); }
-
-  size_t byte_size (void) const
-    { return definition->byte_size (); };
-
-  octave_idx_type numel (void) const
-    { return definition->numel (); };
-
-  octave_idx_type capacity (void) const
-    { return definition->capacity (); };
-
-  dim_vector dims (void) const { return definition->dims (); }
-
-  int dimensions_string_req_first_space (int print_dims) const;
-
-  int dimensions_string_req_total_space (int print_dims) const;
-
-  std::string make_dimensions_string (int print_dims) const;
-
-  octave_idx_type rows (void) const { return definition->rows (); }
-  octave_idx_type columns (void) const { return definition->columns (); }
-
-  std::string type_name (void) const { return definition->type_name (); }
-
-  std::string type_as_string (void) const
-    { return definition->type_as_string (); }
-
-  void type (std::ostream& os, bool pr_type_info, bool quiet, bool pr_orig_txt)
-    { definition->type (os, name (), pr_type_info, quiet, pr_orig_txt); }
-
-  std::string which (void) { return definition->which (name ()); }
-
-  void which (std::ostream& os) { definition->which (os, name ()); }
-
-  octave_value& variable_value (void);
-  octave_lvalue variable_reference (void);
-
-  symbol_record *next (void) const { return next_elem; }
-
-  void chain (symbol_record *s) { next_elem = s; }
-
-  void push_context (void);
-
-  void pop_context (void);
-
-  void print_symbol_info_line (std::ostream& os,
-			       std::list<whos_parameter>& params) const;
+class tree_argument_list;
 
-  void print_info (std::ostream& os,
-		   const std::string& prefix = std::string ()) const;
-
-private:
-
-  unsigned int formal_param : 1;
-  unsigned int automatic_variable : 1;
-  unsigned int linked_to_global : 1;
-  unsigned int tagged_static : 1;
-  unsigned int can_hide_function : 1;
-  unsigned int visible : 1;
-  unsigned int eternal : 1;
-
-  std::string nm;
-  change_function chg_fcn;
-  symbol_def *definition;
-  symbol_record *next_elem;
-
-  // This should maybe be one stack with a structure containing all the
-  // items we need to save for recursive calls...
-  std::stack <symbol_def *> context;
-  std::stack <unsigned int> global_link_context;
-
-  std::stack <symbol_record *> aliases_to_clear;
-
-  void push_alias_to_clear (symbol_record *s)
-    { aliases_to_clear.push (s); }
-
-  bool read_only_error (const char *action);
-
-  void maybe_delete_def (void)
-    {
-      if (--definition->count <= 0)
-        delete definition;
-    }
-
-  // No copying!
-
-  symbol_record (const symbol_record& s);
-
-  symbol_record& operator = (const symbol_record& s);
-};
-
-// A symbol table.
-
-#define SYMTAB_LOCAL_SCOPE 1
-#define SYMTAB_GLOBAL_SCOPE 2
-
-#define SYMTAB_ALL_SCOPES (SYMTAB_LOCAL_SCOPE | SYMTAB_GLOBAL_SCOPE)
-
-#define SYMTAB_ALL_TYPES (symbol_record::USER_FUNCTION \
-			  | symbol_record::USER_VARIABLE \
-			  | symbol_record::DLD_FUNCTION \
-			  | symbol_record::BUILTIN_FUNCTION \
-			  | symbol_record::COMMAND \
-  			  | symbol_record::RAWCOMMAND \
-			  | symbol_record::MAPPER_FUNCTION \
-			  | symbol_record::MEX_FUNCTION)
-
-#define SYMTAB_VARIABLES (symbol_record::USER_VARIABLE)
+#include "oct-obj.h"
+#include "ov.h"
 
 class
 OCTINTERP_API
@@ -499,135 +44,1737 @@
 {
 public:
 
-  symbol_table (unsigned int tab_size = 64,
-		const std::string& nm = std::string ())
-    : table_size (tab_size), table (new symbol_record [table_size]),
-      table_name (nm)
+  typedef int scope_id;
+
+  class
+  symbol_record
+  {
+  public:
+
+    // generic variable
+    static const unsigned int local = 1;
+
+    // varargin, argn, .nargin., .nargout.
+    // (FIXME -- is this really used now?)
+    static const unsigned int automatic = 2;
+
+    // formal parameter
+    static const unsigned int formal = 4;
+
+    // not listed or cleared (.nargin., .nargout.)
+    static const unsigned int hidden = 8;
+
+    // inherited from parent scope; not cleared at function exit
+    static const unsigned int inherited = 16;
+
+    // global (redirects to global scope)
+    static const unsigned int global = 32;
+
+    // not cleared at function exit
+    static const unsigned int persistent = 64;
+
+  private:
+
+    class
+    symbol_record_rep
     {
-      assert ((tab_size % 2) == 0);
+    public:
+
+      symbol_record_rep (const std::string& nm, const octave_value& v,
+			 unsigned int sc)
+	: name (nm), value_stack (), storage_class (sc), count (1)
+      {
+	value_stack.push (v);
+      }
+
+      octave_value& varref (void) { return value_stack.top (); }
+
+      octave_value varval (void) const { return value_stack.top (); }
+
+      void push_context (void) { value_stack.push (octave_value ()); }
+
+      void pop_context (void) { value_stack.pop (); }
+
+      void clear (void)
+      {
+	if (! (is_hidden () || is_inherited ()))
+	  {
+	    if (is_global ())
+	      unmark_global ();
+
+	    if (is_persistent ())
+	      {
+		symbol_table::persistent_varref (name) = varval ();
+		unmark_persistent ();
+	      }
+
+	    varref () = octave_value ();
+	  }
+      }
+
+      bool is_defined (void) const { return varval ().is_defined (); }
+
+      bool is_variable (void) const
+      {
+	return (storage_class != local || is_defined ());
+      }
+
+      bool is_local (void) const { return storage_class & local; }
+      bool is_automatic (void) const { return storage_class & automatic; }
+      bool is_formal (void) const { return storage_class & formal; }
+      bool is_hidden (void) const { return storage_class & hidden; }
+      bool is_inherited (void) const { return storage_class & inherited; }
+      bool is_global (void) const { return storage_class & global; }
+      bool is_persistent (void) const { return storage_class & persistent; }
+
+      void mark_local (void) { storage_class |= local; }
+      void mark_automatic (void) { storage_class |= automatic; }
+      void mark_formal (void) { storage_class |= formal; }
+      void mark_hidden (void) { storage_class |= hidden; }
+      void mark_inherited (void) { storage_class |= inherited; }
+      void mark_global (void)
+      {
+	if (is_persistent ())
+	  error ("can't make persistent variable %s global", name.c_str ());
+	else
+	  storage_class |= global;
+      }
+      void mark_persistent (void)
+      {
+	if (is_global ())
+	  error ("can't make global variable %s persistent", name.c_str ());
+	else
+	  storage_class |= persistent;
+      }
+
+      void unmark_local (void) { storage_class &= ~local; }
+      void unmark_automatic (void) { storage_class &= ~automatic; }
+      void unmark_formal (void) { storage_class &= ~formal; }
+      void unmark_hidden (void) { storage_class &= ~hidden; }
+      void unmark_inherited (void) { storage_class &= ~inherited; }
+      void unmark_global (void) { storage_class &= ~global; }
+      void unmark_persistent (void) { storage_class &= ~persistent; }
+
+      void init_persistent (void)
+      {
+	if (! is_defined ())
+	  {
+	    mark_persistent ();
+
+	    varref () = symbol_table::persistent_varval (name);
+	  }
+	// FIXME -- this causes trouble with recursive calls.
+	// else
+	//   error ("unable to declare existing variable persistent");
+      }
+
+      void erase_persistent (void)
+      {
+	unmark_persistent ();
+	symbol_table::erase_persistent (name);
+      }
+
+      symbol_record_rep *dup (void)
+      {
+	return new symbol_record_rep (name, varval (), storage_class);
+      }
+
+      std::string name;
+
+      std::stack<octave_value> value_stack;
+
+      unsigned int storage_class;
+
+      size_t count;
+
+    private:
+
+      // No copying!
+
+      symbol_record_rep (const symbol_record_rep& ov);
+
+      symbol_record_rep& operator = (const symbol_record_rep&);
+    };
+
+  public:
+
+    symbol_record (const std::string& nm = std::string (),
+		   const octave_value& v = octave_value (),
+		   unsigned int sc = local)
+      : rep (new symbol_record_rep (nm, v, sc)) { }
+
+    symbol_record (const symbol_record& sr)
+      : rep (sr.rep)
+    { 
+      rep->count++;
+    }
+
+    symbol_record& operator = (const symbol_record& sr)
+    {
+      if (this != &sr)
+	{
+	  rep = sr.rep;
+	  rep->count++;
+	}
+
+      return *this;
+    }
+
+    ~symbol_record (void)
+    {
+      if (--rep->count == 0)
+	delete rep;
+    }
+
+    symbol_record dup (void) const { return symbol_record (rep->dup ()); }
+
+    std::string name (void) const { return rep->name; }
+
+    octave_value
+    find (tree_argument_list *args, const string_vector& arg_names,
+	  octave_value_list& evaluated_args, bool& args_evaluated) const;
+
+    octave_value& varref (void)
+    {
+      return is_global ()
+	? symbol_table::varref (name (), symbol_table::global_scope ())
+	: rep->varref ();
+    }
+
+    octave_value varval (void) const
+    {
+      return is_global ()
+	? symbol_table::varval (name (), symbol_table::global_scope ())
+	: rep->varval ();
+    }
+
+    void push_context (void)
+    {
+      if (! (is_persistent () || is_global ()))
+	rep->push_context ();
+    }
+
+    void pop_context (void)
+    {
+      if (! (is_persistent () || is_global ()))
+	rep->pop_context ();
+    }
+
+    void clear (void) { rep->clear (); }
+
+    bool is_defined (void) const { return rep->is_defined (); }
+    bool is_variable (void) const { return rep->is_variable (); }
+
+    bool is_local (void) const { return rep->is_local (); }
+    bool is_automatic (void) const { return rep->is_automatic (); }
+    bool is_formal (void) const { return rep->is_formal (); }
+    bool is_global (void) const { return rep->is_global (); }
+    bool is_hidden (void) const { return rep->is_hidden (); }
+    bool is_inherited (void) const { return rep->is_inherited (); }
+    bool is_persistent (void) const { return rep->is_persistent (); }
+
+    void mark_local (void) { rep->mark_local (); }
+    void mark_automatic (void) { rep->mark_automatic (); }
+    void mark_formal (void) { rep->mark_formal (); }
+    void mark_hidden (void) { rep->mark_hidden (); }
+    void mark_inherited (void) { rep->mark_inherited (); }
+    void mark_global (void) { rep->mark_global (); }
+    void mark_persistent (void) { rep->mark_persistent (); }
+
+    void unmark_local (void) { rep->unmark_local (); }
+    void unmark_automatic (void) { rep->unmark_automatic (); }
+    void unmark_formal (void) { rep->unmark_formal (); }
+    void unmark_hidden (void) { rep->unmark_hidden (); }
+    void unmark_inherited (void) { rep->unmark_inherited (); }
+    void unmark_global (void) { rep->unmark_global (); }
+    void unmark_persistent (void) { rep->unmark_persistent (); }
+
+    void init_persistent (void) { rep->init_persistent (); }
+
+    void erase_persistent (void) { rep->erase_persistent (); }
+
+    unsigned int xstorage_class (void) const { return rep->storage_class; }
+
+  private:
+
+    symbol_record_rep *rep;
+
+    symbol_record (symbol_record_rep *new_rep) : rep (new_rep) { }
+  };
+
+  class
+  fcn_info
+  {
+  public:
+
+    typedef std::map<std::string, std::string> dispatch_map_type;
+
+    typedef std::map<scope_id, octave_value>::const_iterator const_scope_val_iterator;
+    typedef std::map<scope_id, octave_value>::iterator scope_val_iterator;
 
-      if (table_name.empty ())
+    typedef std::map<std::string, octave_value>::const_iterator const_str_val_iterator;
+    typedef std::map<std::string, octave_value>::iterator str_val_iterator;
+
+    typedef dispatch_map_type::const_iterator const_dispatch_map_iterator;
+    typedef dispatch_map_type::iterator dispatch_map_iterator;
+
+  private:
+
+    class
+    fcn_info_rep
+    {
+    public:
+
+      fcn_info_rep (const std::string& nm)
+	: name (nm), subfunctions (), private_functions (),
+	  class_constructors (), class_methods (), cmdline_function (),
+	  autoload_function (), function_on_path (), built_in_function (),
+	  count (1) { }
+
+      octave_value load_private_function (const std::string& dir_name);
+
+      octave_value load_class_constructor (void);
+
+      octave_value load_class_method (const std::string& dispatch_type);
+
+      octave_value
+      find (tree_argument_list *args, const string_vector& arg_names,
+	    octave_value_list& evaluated_args, bool& args_evaluated,
+	    scope_id scope);
+
+      octave_value find_method (const std::string& dispatch_type);
+
+      octave_value find_autoload (void);
+
+      octave_value find_user_function (void);
+
+      bool is_user_function_defined (void) const
+      {
+	return function_on_path.is_defined ();
+      }
+
+      octave_value find_function (scope_id scope)
+      {
+	octave_value_list args;
+
+	return find_function (args, scope);
+      }
+
+      octave_value find_function (const octave_value_list& args,
+				  scope_id scope)
+      {
+	string_vector arg_names;
+	octave_value_list evaluated_args = args;
+	bool args_evaluated;
+
+	return find (0, arg_names, evaluated_args, args_evaluated, scope);
+      }
+
+      void install_cmdline_function (const octave_value& f)
+      {
+	cmdline_function = f;
+      }
+
+      void install_subfunction (const octave_value& f, scope_id scope)
+      {
+	subfunctions[scope] = f;
+      }
+
+      void install_user_function (const octave_value& f)
+      {
+	function_on_path = f;
+      }
+
+      void install_built_in_function (const octave_value& f)
+      {
+	built_in_function = f;
+      }
+
+      void clear (void)
+      {
+	subfunctions.clear ();
+	private_functions.clear ();
+	class_constructors.clear ();
+	class_methods.clear ();
+	cmdline_function = octave_value ();
+	autoload_function = octave_value ();
+	function_on_path = octave_value ();
+      }
+
+      // FIXME -- should this also clear the cmdline and other "user
+      // defined" functions?
+      void clear_user_function (void)
+      {
+	function_on_path = octave_value ();
+      }
+
+      void clear_mex_function (void)
+      {
+	if (function_on_path.is_mex_function ())
+	  function_on_path = octave_value ();
+      }
+
+      void add_dispatch (const std::string& type, const std::string& fname)
+      {
+	dispatch_map[type] = fname;
+      }
+
+      void clear_dispatch (const std::string& type)
+      {
+	dispatch_map_iterator p = dispatch_map.find (type);
+
+	if (p != dispatch_map.end ())
+	  dispatch_map.erase (p);
+      }
+
+      void print_dispatch (std::ostream& os) const;
+
+      std::string help_for_dispatch (void) const;
+
+      dispatch_map_type get_dispatch (void) const { return dispatch_map; }
+
+      std::string name;
+
+      // Scope id to function object.
+      std::map<scope_id, octave_value> subfunctions;
+
+      // Directory name to function object.
+      std::map<std::string, octave_value> private_functions;
+
+      // Class name to function object.
+      std::map<std::string, octave_value> class_constructors;
+
+      // Dispatch type to function object.
+      std::map<std::string, octave_value> class_methods;
+
+      // Legacy dispatch map (dispatch type name to function name).
+      dispatch_map_type dispatch_map;
+
+      octave_value cmdline_function;
+
+      octave_value autoload_function;
+
+      octave_value function_on_path;
+
+      octave_value built_in_function;
+
+      size_t count;
+
+    private:
+
+      // No copying!
+
+      fcn_info_rep (const fcn_info_rep&);
+
+      fcn_info_rep& operator = (const fcn_info_rep&);
+    };
+
+  public:
+
+    fcn_info (const std::string& nm = std::string ())
+      : rep (new fcn_info_rep (nm)) { }
+
+    fcn_info (const fcn_info& ov) : rep (ov.rep)
+    { 
+      rep->count++;
+    }
+
+    fcn_info& operator = (const fcn_info& ov)
+    {
+      if (this != &ov)
 	{
-	  std::ostringstream buf;
-	  buf << symtab_count++;
-	  table_name = buf.str ();
+	  rep = ov.rep;
+	  rep->count++;
 	}
+
+      return *this;
+    }
+
+    ~fcn_info (void)
+    {
+      if (--rep->count == 0)
+	delete rep;
+    }
+
+    octave_value
+    find (tree_argument_list *args, const string_vector& arg_names,
+	  octave_value_list& evaluated_args, bool& args_evaluated,
+	  scope_id scope);
+
+    octave_value find_method (const std::string& dispatch_type) const
+    {
+      return rep->find_method (dispatch_type);
+    }
+
+    octave_value find_built_in_function (void) const
+    {
+      return rep->built_in_function;
+    }
+
+    octave_value find_autoload (void)
+    {
+      return rep->find_autoload ();
+    }
+
+    octave_value find_user_function (void)
+    {
+      return rep->find_user_function ();
+    }
+
+    bool is_user_function_defined (void) const
+    {
+      return rep->is_user_function_defined ();
+    }
+
+    octave_value find_function (scope_id scope)
+    {
+      return rep->find_function (scope);
+    }
+
+    octave_value find_function (const octave_value_list& args,
+				scope_id scope)
+    {
+      return rep->find_function (args, scope);
+    }
+
+    void install_cmdline_function (const octave_value& f)
+    {
+      rep->install_cmdline_function (f);
+    }
+
+    void install_subfunction (const octave_value& f, scope_id scope)
+    {
+      rep->install_subfunction (f, scope);
+    }
+
+    void install_user_function (const octave_value& f)
+    {
+      rep->install_user_function (f);
+    }
+
+    void install_built_in_function (const octave_value& f)
+    {
+      rep->install_built_in_function (f);
+    }
+
+    void clear (void) { rep->clear (); }
+    
+    void clear_user_function (void) { rep->clear_user_function (); }
+    
+    void clear_mex_function (void) { rep->clear_mex_function (); }
+    
+    void add_dispatch (const std::string& type, const std::string& fname)
+    {
+      rep->add_dispatch (type, fname);
+    }
+
+    void clear_dispatch (const std::string& type)
+    {
+      rep->clear_dispatch (type);
+    }
+
+    void print_dispatch (std::ostream& os) const
+    {
+      rep->print_dispatch (os);
+    }
+
+    std::string help_for_dispatch (void) const { return rep->help_for_dispatch (); }
+
+    dispatch_map_type get_dispatch (void) const
+    {
+      return rep->get_dispatch ();
     }
 
-  ~symbol_table (void);
+  private:
+
+    fcn_info_rep *rep;
+  };
+
+  static scope_id global_scope (void) { return xglobal_scope; }
+  static scope_id top_scope (void) { return xtop_scope; }
+
+  static scope_id current_scope (void) { return xcurrent_scope; }
+  static scope_id current_caller_scope (void) { return xcurrent_caller_scope; }
+
+  // We use parent_scope to handle parsing subfunctions.
+  static scope_id parent_scope (void) { return xparent_scope; }
+
+  static scope_id alloc_scope (void)
+  {
+    scope_id retval;
+
+    scope_ids_free_list_iterator p = scope_ids_free_list.begin ();
+
+    if (p != scope_ids_free_list.end ())
+      {
+	retval = *p;
+	scope_ids_free_list.erase (p);
+      }
+    else
+      retval = next_available_scope++;
+
+    scope_ids_in_use.insert (retval);
+
+    return retval;
+  }
+
+  static void set_scope (scope_id scope)
+  {
+    if (scope == xglobal_scope)
+      error ("can't set scope to global");
+    else if (scope != xcurrent_scope)
+      {
+	all_instances_iterator p = all_instances.find (scope);
+
+	if (p == all_instances.end ())
+	  {
+	    instance = new symbol_table ();
 
-  symbol_record *lookup (const std::string& nm, bool insert = false,
-			 bool warn = false);
+	    all_instances[scope] = instance;
+	  }
+	else
+	  instance = p->second;
+
+	xcurrent_scope = scope;
+      }
+  }
+
+  static void push_scope (scope_id scope)
+  {
+    if (scope_stack.empty ())
+      scope_stack.push_front (xtop_scope);
+
+    xcurrent_caller_scope = xcurrent_scope;
+
+    set_scope (scope);
+
+    scope_stack.push_front (scope);
+  }
+
+  static void pop_scope (void)
+  {
+    scope_stack.pop_front ();
 
-  void rename (const std::string& old_name, const std::string& new_name);
+    set_scope (scope_stack[0]);
+
+    xcurrent_caller_scope = scope_stack[1];
+  }
+
+  static void pop_scope (void *) { pop_scope (); }
+
+  static void reset_scope (void)
+  {
+    scope_stack.clear ();
+
+    scope_stack.push_front (xtop_scope);
 
-  void clear (void);
+    set_scope (xtop_scope);
+
+    xcurrent_caller_scope = -1;
+  }
+
+  static void set_parent_scope (scope_id scope)
+  {
+    xparent_scope = scope;
+  }
+
+  static void reset_parent_scope (void)
+  {
+    set_parent_scope (-1);
+  }
 
-  void clear_variables (void);
-  void clear_functions (void);
-  void clear_mex_functions (void);
-  void clear_globals (void);
+  static void erase_scope (scope_id scope = xcurrent_scope)
+  {
+    all_instances_iterator p = all_instances.find (scope);
+
+    if (p != all_instances.end ())
+      all_instances.erase (p);
+
+    // free_scope (scope);
+  }
+
+  static scope_id dup_scope (scope_id scope = xcurrent_scope)
+  {
+    scope_id retval = -1;
+
+    symbol_table *inst = get_instance (scope);
+
+    if (inst)
+      {
+	scope_id new_scope = alloc_scope ();
+
+	symbol_table *new_symbol_table = new symbol_table ();
+
+	if (new_symbol_table)
+	  {
+	    all_instances[new_scope] = new_symbol_table;
+
+	    inst->do_dup_scope (*new_symbol_table);
+
+	    retval = new_scope;
+	  }
+      }
+
+    return retval;
+  }
+
+#if 0
+  static void print_scope (const std::string& tag, scope_id scope)
+  {
+    symbol_table *inst = get_instance (scope);
+
+    if (inst)
+      {
+	std::cerr << "printing " << tag << ", scope: " << scope
+		  << ", inst: " << inst << std::endl;
+
+	inst->do_print_scope (std::cerr);
+      }
+  }
 
-  bool clear (const std::string& nm);
+  void do_print_scope (std::ostream& os) const
+  {
+    for (const_table_iterator p = table.begin (); p != table.end (); p++)
+      {
+	symbol_record sr = p->second;
+
+	octave_value val = sr.varval ();
+
+	if (val.is_defined ())
+	  sr.varval ().print_with_name (os, sr.name ());
+	else
+	  os << sr.name () << " is not defined" << std::endl;
+      }
+  }
+#endif
+
+  static symbol_record find_symbol (const std::string& name,
+				    scope_id scope = xcurrent_scope)
+  {
+    symbol_table *inst = get_instance (scope);
+
+    return inst ? inst->do_find_symbol (name) : symbol_record ();
+  }
 
-  bool clear_variable (const std::string& nm);
-  bool clear_function (const std::string& nm);
-  bool clear_global (const std::string& nm);
+  static void inherit (scope_id scope, scope_id donor_scope)
+  {
+    symbol_table *inst = get_instance (scope);
+
+    if (inst)
+      inst->do_inherit (donor_scope);
+  }
+
+  static bool at_top_level (void) { return xcurrent_scope == xtop_scope; }
+
+  // Find a value corresponding to the given name in the table.
+  static octave_value
+  find (const std::string& name, tree_argument_list *args,
+	const string_vector& arg_names,
+	octave_value_list& evaluated_args, bool& args_evaluated,
+	scope_id scope = xcurrent_scope, bool skip_variables = false);
+
+  // Insert a new name in the table.
+  static symbol_record&
+  insert (const std::string& name, scope_id scope = xcurrent_scope)
+  {
+    static symbol_record foobar;
+
+    symbol_table *inst = get_instance (scope);
 
-  bool clear_variable_pattern (const std::string& pat);
-  bool clear_function_pattern (const std::string& pat);
-  bool clear_global_pattern (const std::string& pat);
+    return inst ? inst->do_insert (name) : foobar;
+  }
+
+  static octave_value&
+  varref (const std::string& name, scope_id scope = xcurrent_scope)
+  {
+    static octave_value foobar;
+
+    symbol_table *inst = get_instance (scope);
+
+    return inst ? inst->do_varref (name) : foobar;
+  }
+
+  static octave_value
+  varval (const std::string& name, scope_id scope = xcurrent_scope)
+  {
+    symbol_table *inst = get_instance (scope);
+
+    return inst ? inst->do_varval (name) : octave_value ();
+  }
+
+  static octave_value&
+  persistent_varref (const std::string& name, scope_id scope = xcurrent_scope)
+  {
+    static octave_value foobar;
+
+    symbol_table *inst = get_instance (scope);
+
+    return inst ? inst->do_persistent_varref (name) : foobar;
+  }
+
+  static octave_value
+  persistent_varval (const std::string& name, scope_id scope = xcurrent_scope)
+  {
+    symbol_table *inst = get_instance (scope);
+
+    return inst ? inst->do_persistent_varval (name) : octave_value ();
+  }
+
+  static void
+  erase_persistent (const std::string& name, scope_id scope = xcurrent_scope)
+  {
+    symbol_table *inst = get_instance (scope);
+
+    if (inst)
+      inst->do_erase_persistent (name);
+  }
 
-  int size (void) const;
+  static bool
+  is_variable (const std::string& name, scope_id scope = xcurrent_scope)
+  {
+    symbol_table *inst = get_instance (scope);
+
+    return inst ? inst->do_is_variable (name) : false;
+  }
+
+  static bool
+  is_built_in_function_name (const std::string& name)
+  {
+    octave_value val = find_built_in_function (name);
+
+    return val.is_defined ();
+  }
+
+  static octave_value
+  find_method (const std::string& name, const std::string& dispatch_type)
+  {
+    const_fcn_table_iterator p = fcn_table.find (name);
 
-  Array<symbol_record *>
-  subsymbol_list (const string_vector& pats = string_vector (),
-		  unsigned int type = SYMTAB_ALL_TYPES,
-		  unsigned int scope = SYMTAB_ALL_SCOPES) const;
+    if (p != fcn_table.end ())
+      return p->second.find_method (dispatch_type);
+    else
+      {
+	fcn_info finfo (name);
+
+	octave_value fcn = finfo.find_method (dispatch_type);
+
+	if (fcn.is_defined ())
+	  fcn_table[name] = finfo;
+
+	return fcn;
+      }
+  }
+
+  static octave_value
+  find_built_in_function (const std::string& name)
+  {
+    const_fcn_table_iterator p = fcn_table.find (name);
+
+    return (p != fcn_table.end ())
+      ? p->second.find_built_in_function () : octave_value ();
+  }
+
+  static octave_value
+  find_autoload (const std::string& name)
+  {
+    fcn_table_iterator p = fcn_table.find (name);
 
-  Array<symbol_record *>
-  symbol_list (const string_vector& pats = string_vector (),
-	       unsigned int type = SYMTAB_ALL_TYPES,
-	       unsigned int scope = SYMTAB_ALL_SCOPES) const;
+    return (p != fcn_table.end ())
+      ? p->second.find_autoload () : octave_value ();
+  }
+
+  static octave_value
+  find_function (const std::string& name, tree_argument_list *args,
+		 const string_vector& arg_names,
+		 octave_value_list& evaluated_args, bool& args_evaluated,
+		 scope_id scope = xcurrent_scope);
+
+  static octave_value
+  find_user_function (const std::string& name)
+  {
+    fcn_table_iterator p = fcn_table.find (name);
+
+    return (p != fcn_table.end ())
+      ? p->second.find_user_function () : octave_value ();
+  }
+
+  static octave_value
+  find_function (const std::string& name, scope_id scope = xcurrent_scope)
+  {
+    octave_value_list evaluated_args;
+
+    return find_function (name, evaluated_args, scope);
+  }
+
+  static octave_value
+  find_function (const std::string& name, const octave_value_list& args,
+		 scope_id scope = xcurrent_scope)
+  {
+    string_vector arg_names;
+    octave_value_list evaluated_args = args;
+    bool args_evaluated = ! args.empty ();
+
+    return find_function (name, 0, arg_names, evaluated_args,
+			  args_evaluated, scope);
+  }
+
+  static void install_cmdline_function (const std::string& name,
+					const octave_value& fcn)
+  {
+    fcn_table_iterator p = fcn_table.find (name);
+
+    if (p != fcn_table.end ())
+      {
+	fcn_info& finfo = p->second;
 
+	finfo.install_cmdline_function (fcn);
+      }
+    else
+      {
+	fcn_info finfo (name);
 
-  string_vector
-  name_list (const string_vector& pats = string_vector (),
-	     bool sort = false, unsigned int type = SYMTAB_ALL_TYPES,
-	     unsigned int scope = SYMTAB_ALL_SCOPES) const;
+	finfo.install_cmdline_function (fcn);
+
+	fcn_table[name] = finfo;
+      }
+  }
+
+  static void install_subfunction (const std::string& name,
+				   const octave_value& fcn,
+				   scope_id scope = xparent_scope)
+  {
+    fcn_table_iterator p = fcn_table.find (name);
+
+    if (p != fcn_table.end ())
+      {
+	fcn_info& finfo = p->second;
+
+	finfo.install_subfunction (fcn, scope);
+      }
+    else
+      {
+	fcn_info finfo (name);
+
+	finfo.install_subfunction (fcn, scope);
+
+	fcn_table[name] = finfo;
+      }
+  }
+
+  static void install_user_function (const std::string& name,
+				     const octave_value& fcn)
+  {
+    fcn_table_iterator p = fcn_table.find (name);
+
+    if (p != fcn_table.end ())
+      {
+	fcn_info& finfo = p->second;
+
+	finfo.install_user_function (fcn);
+      }
+    else
+      {
+	fcn_info finfo (name);
+
+	finfo.install_user_function (fcn);
+
+	fcn_table[name] = finfo;
+      }
+  }
 
-  string_vector
-  user_function_name_list (void) const
-    {
-      return name_list
-	(string_vector (), false,
-	 symbol_record::USER_FUNCTION|symbol_record::DLD_FUNCTION|symbol_record::MEX_FUNCTION,
-	 SYMTAB_ALL_SCOPES);
-    }
+  static void install_built_in_function (const std::string& name,
+					 const octave_value& fcn)
+  {
+    fcn_table_iterator p = fcn_table.find (name);
+
+    if (p != fcn_table.end ())
+      {
+	fcn_info& finfo = p->second;
+
+	finfo.install_built_in_function (fcn);
+      }
+    else
+      {
+	fcn_info finfo (name);
+
+	finfo.install_built_in_function (fcn);
+
+	fcn_table[name] = finfo;
+      }
+  }
+
+  static void clear (const std::string& name, scope_id scope = xcurrent_scope)
+  {
+    clear_variable (name, scope);
+  }
+
+  static void clear_all (void)
+  {
+    clear_variables ();
+
+    clear_functions ();
+  }
+
+  static void clear_variables (scope_id scope = xcurrent_scope)
+  {
+    symbol_table *inst = get_instance (scope);
+
+    if (inst)
+      inst->do_clear_variables ();
+  }
+
+  // For unwind_protect.
+  static void clear_variables (void *) { clear_variables (); }
+
+  static void clear_functions (void)
+  {
+    for (fcn_table_iterator p = fcn_table.begin (); p != fcn_table.end (); p++)
+      p->second.clear ();
+  }
+
+  static void clear_function (const std::string& name)
+  {
+    clear_user_function (name);
+  }
+
+  static void clear_global (const std::string& name,
+			    scope_id scope = xcurrent_scope)
+  {
+    symbol_table *inst = get_instance (scope);
+
+    if (inst)
+      inst->do_clear_global (name);
+  }
+
+  static void clear_variable (const std::string& name,
+			      scope_id scope = xcurrent_scope)
+  {
+    symbol_table *inst = get_instance (scope);
+
+    if (inst)
+      inst->do_clear_variable (name);
+  }
+
+  static void clear_symbol (const std::string& name)
+  {
+    // FIXME -- are we supposed to do both here?
+
+    clear_variable (name);
+    clear_function (name);
+  }
+
+  static void clear_function_pattern (const std::string& pat)
+  {
+    glob_match pattern (pat);
+
+    for (fcn_table_iterator p = fcn_table.begin (); p != fcn_table.end (); p++)
+      {
+	if (pattern.match (p->first))
+	  p->second.clear_user_function ();
+      }
+  }
+
+  static void clear_global_pattern (const std::string& pat,
+				    scope_id scope = xcurrent_scope)
+  {
+    symbol_table *inst = get_instance (scope);
 
-  string_vector
-  global_variable_name_list (void) const
-    {
-      return name_list
-	(string_vector (), false, SYMTAB_VARIABLES, SYMTAB_GLOBAL_SCOPE);
-    }
+    if (inst)
+      inst->do_clear_global_pattern (pat);
+  }
+
+  static void clear_variable_pattern (const std::string& pat,
+				      scope_id scope = xcurrent_scope)
+  {
+    symbol_table *inst = get_instance (scope);
+
+    if (inst)
+      inst->do_clear_variable_pattern (pat);
+  }
+
+  static void clear_symbol_pattern (const std::string& pat)
+  {
+    // FIXME -- are we supposed to do both here?
+
+    clear_variable_pattern (pat);
+    clear_function_pattern (pat);
+  }
+
+  static void clear_user_function (const std::string& name)
+  {
+    fcn_table_iterator p = fcn_table.find (name);
+
+    if (p != fcn_table.end ())
+      {
+	fcn_info& finfo = p->second;
+
+	finfo.clear_user_function ();
+      }
+    // FIXME -- is this necessary, or even useful?
+    // else
+    //   error ("clear: no such function `%s'", name.c_str ());
+  }
+
+  static void clear_mex_functions (void)
+  {
+    for (fcn_table_iterator p = fcn_table.begin (); p != fcn_table.end (); p++)
+      {
+	fcn_info& finfo = p->second;
+
+	finfo.clear_mex_function ();
+      }
+  }
+
+  static void alias_built_in_function (const std::string& alias,
+				       const std::string& name)
+  {
+    octave_value fcn = find_built_in_function (name);
+
+    if (fcn.is_defined ())
+      {
+	fcn_info finfo (alias);
+
+	finfo.install_built_in_function (fcn);
+
+	fcn_table[alias] = finfo;
+      }
+    else
+      panic ("alias: `%s' is undefined", name.c_str ());
+  }
+
+  static void add_dispatch (const std::string& name, const std::string& type,
+			    const std::string& fname)
+  {
+    fcn_table_iterator p = fcn_table.find (name);
+
+    if (p != fcn_table.end ())
+      {
+	fcn_info& finfo = p->second;
+
+	finfo.add_dispatch (type, fname);
+      }
+    else
+      {
+	fcn_info finfo (name);
+
+	finfo.add_dispatch (type, fname);
+
+	fcn_table[name] = finfo;
+      }
+  }
+
+  static void clear_dispatch (const std::string& name, const std::string& type)
+  {
+    fcn_table_iterator p = fcn_table.find (name);
+
+    if (p != fcn_table.end ())
+      {
+	fcn_info& finfo = p->second;
+
+	finfo.clear_dispatch (type);
+      }
+  }
+
+  static void print_dispatch (std::ostream& os, const std::string& name)
+  {
+    fcn_table_iterator p = fcn_table.find (name);
 
-  string_vector
-  variable_name_list (void) const
-    {
-      return name_list
-	(string_vector (), false, SYMTAB_VARIABLES, SYMTAB_LOCAL_SCOPE);
-    }
+    if (p != fcn_table.end ())
+      {
+	fcn_info& finfo = p->second;
+
+	finfo.print_dispatch (os);
+      }
+  }
+
+  static fcn_info::dispatch_map_type get_dispatch (const std::string& name)
+  {
+    fcn_info::dispatch_map_type retval;
+
+    fcn_table_iterator p = fcn_table.find (name);
+
+    if (p != fcn_table.end ())
+      {
+	fcn_info& finfo = p->second;
+
+	retval = finfo.get_dispatch ();
+      }
+
+    return retval;
+  }
+
+  static std::string help_for_dispatch (const std::string& name)
+  {
+    std::string retval;
+
+    fcn_table_iterator p = fcn_table.find (name);
+
+    if (p != fcn_table.end ())
+      {
+	fcn_info& finfo = p->second;
+
+	retval = finfo.help_for_dispatch ();
+      }
+
+    return retval;
+  }
+
+  static void push_context (scope_id scope = xcurrent_scope)
+  {
+    if (scope == xglobal_scope || scope == xtop_scope)
+      error ("invalid call to xymtab::push_context");
+    else
+      {
+	symbol_table *inst = get_instance (scope);
+
+	if (inst)
+	  inst->do_push_context ();
+      }
+  }
+
+  static void pop_context (scope_id scope = xcurrent_scope)
+  {
+    if (scope == xglobal_scope || scope == xtop_scope)
+      error ("invalid call to xymtab::push_context");
+    else
+      {
+	symbol_table *inst = get_instance (scope);
+
+	if (inst)
+	  inst->do_pop_context ();
+      }
+  }
+
+  // For unwind_protect.
+  static void pop_context (void *) { pop_context (); }
+
+  static void mark_hidden (const std::string& name,
+			   scope_id scope = xcurrent_scope)
+  {
+    symbol_table *inst = get_instance (scope);
+
+    if (inst)
+      inst->do_mark_hidden (name);
+  }
+
+  static void mark_global (const std::string& name,
+			   scope_id scope = xcurrent_scope)
+  {
+    symbol_table *inst = get_instance (scope);
+
+    if (inst)
+      inst->do_mark_global (name);
+  }
+
+  static std::list<symbol_record>
+  all_variables (scope_id scope = xcurrent_scope, bool defined_only = true)
+  {
+    symbol_table *inst = get_instance (scope);
+
+    return inst
+      ? inst->do_all_variables (defined_only) : std::list<symbol_record> ();
+  }
 
-  int maybe_list (const char *header, const string_vector& argv,
-		  std::ostream& os, bool show_verbose,
-		  unsigned type, unsigned scope);
-  
-  Array<symbol_record *> glob (const std::string& pat = std::string ("*"),
-			       unsigned int type = SYMTAB_ALL_TYPES,
-			       unsigned int scope = SYMTAB_ALL_SCOPES) const;
+  static std::list<symbol_record>
+  glob (const std::string& pattern, scope_id scope = xcurrent_scope)
+  {
+    symbol_table *inst = get_instance (scope);
+
+    return inst ? inst->do_glob (pattern) : std::list<symbol_record> ();
+  }
+
+  static std::list<symbol_record>
+  glob_variables (const std::string& pattern, scope_id scope = xcurrent_scope)
+  {
+    symbol_table *inst = get_instance (scope);
+
+    return inst ? inst->do_glob (pattern, true) : std::list<symbol_record> ();
+  }
+
+  static std::list<symbol_record>
+  glob_variables (const string_vector& patterns,
+		  scope_id scope = xcurrent_scope)
+  {
+    std::list<symbol_record> retval;
+
+    size_t len = patterns.length ();
 
-  void push_context (void);
+    for (size_t i = 0; i < len; i++)
+      {
+	std::list<symbol_record> tmp = glob_variables (patterns[i], scope);
+
+	retval.insert (retval.begin (), tmp.begin (), tmp.end ());
+      }
+
+    return retval;
+  }
+
+  static std::list<std::string> user_function_names (void)
+  {
+    std::list<std::string> retval;
+
+    for (fcn_table_iterator p = fcn_table.begin ();
+	 p != fcn_table.end (); p++)
+      {
+	if (p->second.is_user_function_defined ())
+	  retval.push_back (p->first);
+      }
+
+    if (! retval.empty ())
+      retval.sort ();
+
+    return retval;
+  }
 
-  void pop_context (void);
+  static std::list<std::string>
+  variable_names (scope_id scope = xcurrent_scope)
+  {
+    symbol_table *inst = get_instance (scope);
+
+    return inst ? inst->do_variable_names () : std::list<std::string> ();
+  }
+
+  static std::list<std::string> built_in_function_names (void)
+  {
+    std::list<std::string> retval;
+
+    for (const_fcn_table_iterator p = fcn_table.begin ();
+	 p != fcn_table.end (); p++)
+      {
+	octave_value fcn = p->second.find_built_in_function ();
+
+	if (fcn.is_defined ())
+	  retval.push_back (p->first);
+      }
+
+    if (! retval.empty ())
+      retval.sort ();
 
-  // Create a new symbol table with the same entries.  Only the symbol
-  // names and some attributes are copied, not values.
-  symbol_table *dup (void);
+    return retval;
+  }
+
+  static bool is_local_variable (const std::string& name,
+				 scope_id scope = xcurrent_scope)
+  {
+    if (scope == xglobal_scope)
+      return false;
+    else
+      {
+	symbol_table *inst = get_instance (scope);
 
-  // Inherit some values from the parent_sym_tab.
-  void inherit (symbol_table *parent_sym_tab);
+	return inst ? inst->do_is_local_variable (name) : false;
+      }
+  }
 
-  void print_info (std::ostream& os) const;
+  static bool is_global (const std::string& name,
+			 scope_id scope = xcurrent_scope)
+  {
+    if (scope == xglobal_scope)
+      return true;
+    else
+      {
+	symbol_table *inst = get_instance (scope);
+
+	return inst ? inst->do_is_global (name) : false;
+      }
+  }
 
 private:
 
-  unsigned int table_size;
+  typedef std::map<std::string, symbol_record>::const_iterator const_table_iterator;
+  typedef std::map<std::string, symbol_record>::iterator table_iterator;
+
+  typedef std::map<std::string, octave_value>::const_iterator const_persistent_table_iterator;
+  typedef std::map<std::string, octave_value>::iterator persistent_table_iterator;
+
+  typedef std::map<scope_id, symbol_table*>::const_iterator all_instances_const_iterator;
+  typedef std::map<scope_id, symbol_table*>::iterator all_instances_iterator;
+
+  typedef std::map<std::string, fcn_info>::const_iterator const_fcn_table_iterator;
+  typedef std::map<std::string, fcn_info>::iterator fcn_table_iterator;
+
+  typedef std::set<scope_id>::const_iterator scope_ids_free_list_const_iterator;
+  typedef std::set<scope_id>::iterator scope_ids_free_list_iterator;
+
+  typedef std::set<scope_id>::const_iterator scope_ids_in_use_const_iterator;
+  typedef std::set<scope_id>::iterator scope_ids_in_use_iterator;
+
+  // Map from symbol names to symbol info.
+  std::map<std::string, symbol_record> table;
+
+  // Map from names of persistent variables to values.
+  std::map<std::string, octave_value> persistent_table;
+
+  // Pointer to symbol table for current scope (variables only).
+  static symbol_table *instance;
 
-  symbol_record *table;
+  // Map from scope id to symbol table instances.
+  static std::map<scope_id, symbol_table*> all_instances;
+
+  // Map from function names to function info (subfunctions, private
+  // functions, class constructors, class methods, etc.)
+  static std::map<std::string, fcn_info> fcn_table;
+
+  static const scope_id xglobal_scope;
+  static const scope_id xtop_scope;
+
+  static scope_id xcurrent_scope;
+  static scope_id xcurrent_caller_scope;
+
+  // We use parent_scope to handle parsing subfunctions.
+  static scope_id xparent_scope;
+
+  static std::deque<scope_id> scope_stack;
+
+  // The next available scope ID.
+  static scope_id next_available_scope;
+
+  // The set of scope IDs that are currently allocated.
+  static std::set<scope_id> scope_ids_in_use;
+
+  // The set of scope IDs that are currently available.
+  static std::set<scope_id> scope_ids_free_list;
+
+  symbol_table (void) : table () { }
+
+  ~symbol_table (void) { }
 
-  std::string table_name;
+  static void free_scope (scope_id scope)
+  {
+    if (scope == xglobal_scope || scope == xtop_scope)
+      error ("can't free global or top-level scopes!");
+    else
+      {
+	scope_ids_in_use_iterator p = scope_ids_in_use.find (scope);
+
+	if (p != scope_ids_in_use.end ())
+	  {
+	    scope_ids_in_use.erase (p);
+	    scope_ids_free_list.insert (*p);
+	  }
+	else
+	  error ("scope id = %ld not found!", scope);
+      }
+  }
+
+  static symbol_table *get_instance (scope_id scope)
+  {
+    symbol_table *retval = 0;
+
+    if (scope == xcurrent_scope)
+      {
+	if (! instance)
+	  {
+	    instance = new symbol_table ();
 
-  static unsigned long int symtab_count;
+	    all_instances[scope] = instance;
+	  }
+
+	if (! instance)
+	  error ("unable to create symbol_table object!");
+
+	retval = instance;
+      }
+    else
+      {
+	all_instances_iterator p = all_instances.find (scope);
+
+	if (p == all_instances.end ())
+	  {
+	    retval = new symbol_table ();
+
+	    all_instances[scope] = retval;
+	  }
+	else
+	  retval = p->second;
+      }
+
+    return retval;
+  }
+
+  void insert_symbol_record (const symbol_record& sr)
+  {
+    table[sr.name ()] = sr;
+  }
 
   void
-  print_descriptor (std::ostream& os, 
-		    std::list<whos_parameter> params) const;
+  do_dup_scope (symbol_table& new_symbol_table) const
+  {
+    for (const_table_iterator p = table.begin (); p != table.end (); p++)
+      new_symbol_table.insert_symbol_record (p->second.dup ());
+  }
+
+  symbol_record do_find_symbol (const std::string& name)
+  {
+    table_iterator p = table.find (name);
+
+    if (p == table.end ())
+      return do_insert (name);
+    else
+      return p->second;
+  }
+
+  void do_inherit (scope_id donor_scope)
+  {
+    for (table_iterator p = table.begin (); p != table.end (); p++)
+      {
+	symbol_record& sr = p->second;
+
+	std::string nm = sr.name ();
+
+	if (! (sr.is_automatic () || sr.is_formal () || nm == "__retval__"))
+	  {
+	    octave_value val = symbol_table::varval (nm, donor_scope);
+
+	    if (val.is_defined ())
+	      {
+		sr.varref () = val;
+
+		sr.mark_inherited ();
+	      }
+	  }
+      }
+  }
+
+  octave_value
+  do_find (const std::string& name, tree_argument_list *args,
+	   const string_vector& arg_names,
+	   octave_value_list& evaluated_args, bool& args_evaluated,
+	   scope_id scope, bool skip_variables);
+
+  symbol_record& do_insert (const std::string& name)
+  {
+    table_iterator p = table.find (name);
+
+    return p == table.end ()
+      ? (table[name] = symbol_record (name)) : p->second;
+  }
+
+  octave_value& do_varref (const std::string& name)
+  {
+    table_iterator p = table.find (name);
+
+    if (p == table.end ())
+      {
+	symbol_record& sr = do_insert (name);
+
+	return sr.varref ();
+      }
+    else
+      return p->second.varref ();
+  }
 
-  std::list<whos_parameter>
-  parse_whos_line_format (Array<symbol_record *>& symbols) const;
+  octave_value do_varval (const std::string& name) const
+  {
+    const_table_iterator p = table.find (name);
+
+    return (p != table.end ()) ? p->second.varval () : octave_value ();
+  }
+
+  octave_value& do_persistent_varref (const std::string& name)
+  {
+    persistent_table_iterator p = persistent_table.find (name);
+
+    return (p == persistent_table.end ())
+      ? persistent_table[name] : p->second;
+  }
+
+  octave_value do_persistent_varval (const std::string& name)
+  {
+    const_persistent_table_iterator p = persistent_table.find (name);
+
+    return (p != persistent_table.end ()) ? p->second : octave_value ();
+  }
+
+  void do_erase_persistent (const std::string& name)
+  {
+    persistent_table_iterator p = persistent_table.find (name);
+
+    if (p != persistent_table.end ())
+      persistent_table.erase (p);
+  }
+
+  bool do_is_variable (const std::string& name) const
+  {
+    bool retval = false;
+
+    const_table_iterator p = table.find (name);
+
+    if (p != table.end ())
+      {
+	const symbol_record& sr = p->second;
+
+	retval = sr.is_variable ();
+      }
+
+    return retval;
+  }
+
+  void do_push_context (void)
+  {
+    for (table_iterator p = table.begin (); p != table.end (); p++)
+      p->second.push_context ();
+  }
+
+  void do_pop_context (void)
+  {
+    for (table_iterator p = table.begin (); p != table.end (); p++)
+      p->second.pop_context ();
+  }
+
+  void do_clear_variables (void)
+  {
+    for (table_iterator p = table.begin (); p != table.end (); p++)
+      p->second.clear ();
+  }
+
+  void do_clear_global (const std::string& name)
+  {
+    table_iterator p = table.find (name);
 
-  unsigned int hash (const std::string& s);
+    if (p != table.end ())
+      {
+	symbol_record& sr = p->second;
+
+	if (sr.is_global ())
+	  {
+	    symbol_table::clear_variable (p->first, xglobal_scope);
+
+	    sr.unmark_global ();
+	  }
+      }
+  }
+
+  void do_clear_variable (const std::string& name)
+  {
+    table_iterator p = table.find (name);
+
+    if (p != table.end ())
+      p->second.clear ();
+  }
+
+  void do_clear_global_pattern (const std::string& pat)
+  {
+    glob_match pattern (pat);
+
+    for (table_iterator p = table.begin (); p != table.end (); p++)
+      {
+	symbol_record& sr = p->second;
 
-  // No copying!
+	if (sr.is_global ())
+	  {
+	    if (pattern.match (sr.name ()))
+	      {
+		symbol_table::clear_variable (p->first, xglobal_scope);
+
+		sr.unmark_global ();
+	      }
+	  }
+      }
+  }
+
+  void do_clear_variable_pattern (const std::string& pat)
+  {
+    glob_match pattern (pat);
+
+    for (table_iterator p = table.begin (); p != table.end (); p++)
+      {
+	symbol_record& sr = p->second;
+
+	if (sr.is_defined () || sr.is_global ())
+	  {
+	    if (pattern.match (sr.name ()))
+	      sr.clear ();
+	  }
+      }
+  }
+
+  void do_mark_hidden (const std::string& name)
+  {
+    table_iterator p = table.find (name);
+
+    if (p != table.end ())
+      p->second.mark_hidden ();
+  }
+
+  void do_mark_global (const std::string& name)
+  {
+    table_iterator p = table.find (name);
 
-  symbol_table (const symbol_table&);
+    if (p != table.end ())
+      p->second.mark_global ();
+  }
+
+  std::list<symbol_record> do_all_variables (bool defined_only) const
+  {
+    std::list<symbol_record> retval;
+
+    for (const_table_iterator p = table.begin (); p != table.end (); p++)
+      {
+	const symbol_record& sr = p->second;
+
+	if (defined_only && ! sr.is_defined ())
+	  continue;
+
+	retval.push_back (sr);
+      }
+
+    return retval;
+  }
+
+  std::list<symbol_record> do_glob (const std::string& pattern,
+				    bool vars_only = false) const
+  {
+    std::list<symbol_record> retval;
+
+    glob_match pat (pattern);
+
+    for (const_table_iterator p = table.begin (); p != table.end (); p++)
+      {
+	if (pat.match (p->first))
+	  {
+	    const symbol_record& sr = p->second;
 
-  symbol_table& operator = (const symbol_table&);
+	    if (vars_only && ! sr.is_variable ())
+	      continue;
+
+	    retval.push_back (sr);
+	  }
+      }
+
+    return retval;
+  }
+
+  std::list<std::string> do_variable_names (void)
+  {
+    std::list<std::string> retval;
+
+    for (const_table_iterator p = table.begin (); p != table.end (); p++)
+      retval.push_back (p->first);
+
+    retval.sort ();
+
+    return retval;
+  }
+
+  bool do_is_local_variable (const std::string& name) const
+  {
+    const_table_iterator p = table.find (name);
+
+    return (p != table.end ()
+	    && ! p->second.is_global ()
+	    && p->second.is_defined ());
+  }
+
+  bool do_is_global (const std::string& name) const
+  {
+    const_table_iterator p = table.find (name);
+
+    return p != table.end () && p->second.is_global ();
+  }
 };
 
-// Defines layout for the whos/who -long command.
-extern std::string Vwhos_line_format;
+extern bool out_of_date_check (octave_value& function);
 
 #endif