diff src/symtab.cc @ 195:13c6086c325c

[project @ 1993-11-06 10:12:29 by jwe]
author jwe
date Sat, 06 Nov 1993 10:14:11 +0000
parents b6b4d8c513fe
children 2e4d2596f2c3
line wrap: on
line diff
--- a/src/symtab.cc	Wed Nov 03 21:38:05 1993 +0000
+++ b/src/symtab.cc	Sat Nov 06 10:14:11 1993 +0000
@@ -39,38 +39,41 @@
  */
 symbol_def::symbol_def (void)
 {
-  help_string = (char *) NULL;
-  type = unknown_type;
-  lifespan = temporary;
-  sym_class = read_write;
-  definition = (tree *) NULL;
+  init_state ();
 }
 
 symbol_def::symbol_def (tree_constant *t)
 {
-  help_string = (char *) NULL;
-  type = variable;
-  lifespan = temporary;
-  sym_class = read_write;
+  init_state ();
   definition = t;
+  type = USER_VARIABLE;
 }
 
 symbol_def::symbol_def (tree_builtin *t)
 {
-  help_string = (char *) NULL;
-  type = builtin_function;
-  lifespan = temporary;
-  sym_class = read_write;
+  init_state ();
   definition = t;
+  type = BUILTIN_FUNCTION;
 }
 
 symbol_def::symbol_def (tree_function *t)
 {
+  init_state ();
+  definition = t;
+  type = USER_FUNCTION;
+}
+
+void
+symbol_def::init_state (void)
+{
+  type = UNKNOWN;
+  eternal = 0;
+  read_only = 0;
+
   help_string = (char *) NULL;
-  type = user_function;
-  lifespan = temporary;
-  sym_class = read_write;
-  definition = t;
+  definition = NULL_TREE;
+  next_elem = (symbol_def *) NULL;
+  count = 0;
 }
 
 symbol_def::~symbol_def (void)
@@ -79,25 +82,81 @@
   delete definition;
 }
 
+int
+symbol_def::is_variable (void) const
+{
+  return (type == USER_VARIABLE || type == BUILTIN_VARIABLE);
+}
+
+int
+symbol_def::is_function (void) const
+{
+  return (type == USER_FUNCTION || type == BUILTIN_FUNCTION);
+}
+
+int
+symbol_def::is_user_variable (void) const
+{
+  return (type == USER_VARIABLE);
+}
+
+int
+symbol_def::is_user_function (void) const
+{
+  return (type == USER_FUNCTION);
+}
+
+int
+symbol_def::is_builtin_variable (void) const
+{
+  return (type == BUILTIN_VARIABLE);
+}
+
+int
+symbol_def::is_builtin_function (void) const
+{
+  return (type == BUILTIN_FUNCTION);
+}
+
 void
 symbol_def::define (tree_constant *t)
 {
   definition = t;
-  type = variable;
+  if (! is_builtin_variable ())
+    type = USER_VARIABLE;
 }
 
 void
 symbol_def::define (tree_builtin *t)
 {
   definition = t;
-  type = builtin_function;
+  type = BUILTIN_FUNCTION;
 }
 
 void
 symbol_def::define (tree_function *t)
 {
   definition = t;
-  type = user_function;
+  type = USER_FUNCTION;
+}
+
+void
+symbol_def::protect (void)
+{
+  read_only = 1;
+}
+
+void
+symbol_def::unprotect (void)
+{
+  read_only = 0;
+
+}
+
+void
+symbol_def::make_eternal (void)
+{
+  eternal = 1;
 }
 
 tree *
@@ -125,51 +184,53 @@
   return definition->save (os, mark_as_global);
 }
 
+int
+maybe_delete (symbol_def *def)
+{
+  int count = 0;
+  if (def != (symbol_def *) NULL)
+    {
+      if (def->count > 0)
+	{
+	  def->count--;
+	  count = def->count;
+	  if (def->count == 0)
+	    delete def;
+	}
+    }
+  return count;
+}
+
 /*
  * Individual records in a symbol table.
  */
 symbol_record::symbol_record (void)
 {
-  nm = (char *) NULL;
-  formal_param = 0;
-  forced_global = 0;
-  var = (symbol_def *) NULL;
-  fcn = (symbol_def *) NULL;
-  sv_fcn = (sv_Function) NULL;
-  next_elem = (symbol_record *) NULL;
+  init_state ();
 }
 
-symbol_record::symbol_record (const char *n)
+symbol_record::symbol_record (const char *n,
+			      symbol_record *nxt = (symbol_record *) NULL)
 {
+  init_state ();
   nm = strsave (n);
-  formal_param = 0;
-  forced_global = 0;
-  var = (symbol_def *) NULL;
-  fcn = (symbol_def *) NULL;
-  sv_fcn = (sv_Function) NULL;
-  next_elem = (symbol_record *) NULL;
+  next_elem = nxt;
 }
 
-symbol_record::symbol_record (const char *n, symbol_record *nxt)
+void
+symbol_record::init_state (void)
 {
-  nm = strsave (n);
   formal_param = 0;
-  forced_global = 0;
-  var = (symbol_def *) NULL;
-  fcn = (symbol_def *) NULL;
+  linked_to_global = 0;
+  nm = (char *) NULL;
   sv_fcn = (sv_Function) NULL;
-  next_elem = nxt;
+  definition = (symbol_def *) NULL;
+  next_elem = (symbol_record *) NULL;
 }
 
 symbol_record::~symbol_record (void)
 {
   delete [] nm;
-
-  if (var != (symbol_def *) NULL && --var->count <= 0)
-    delete var;
-
-  if (fcn != (symbol_def *) NULL && --fcn->count <= 0)
-    delete fcn;
 }
 
 char *
@@ -181,41 +242,147 @@
 char *
 symbol_record::help (void) const
 {
-  if (var != (symbol_def *) NULL)
-    return var->help ();
-  else if (fcn != (symbol_def *) NULL)
-    return fcn->help ();
+  if (definition != (symbol_def *) NULL)
+    return definition->help ();
   else
     return (char *) NULL;
 }
 
+void
+symbol_record::rename (const char *n)
+{
+  delete [] nm;
+  nm = strsave (n);
+}
+
 tree *
 symbol_record::def (void) const
 {
-  if (var != (symbol_def *) NULL)
-    return var->def ();
-  else if (fcn != (symbol_def *) NULL)
-    return fcn->def ();
+  if (definition != (symbol_def *) NULL)
+    return definition->def ();
   else
-    return (tree *) NULL;
+    return NULL_TREE;
 }
 
 int
 symbol_record::is_function (void) const
 {
-  return (var == (symbol_def *) NULL && fcn != (symbol_def *) NULL);
+  if (definition != (symbol_def *) NULL)
+    return definition->is_function ();
+  else
+    return 0;
+}
+
+int
+symbol_record::is_user_function (void) const
+{
+  if (definition != (symbol_def *) NULL)
+    return definition->is_user_function ();
+  else
+    return 0;
+}
+
+int
+symbol_record::is_builtin_function (void) const
+{
+  if (definition != (symbol_def *) NULL)
+    return definition->is_builtin_function ();
+  else
+    return 0;
 }
 
 int
 symbol_record::is_variable (void) const
 {
-  return (var != (symbol_def *) NULL);
+  if (definition != (symbol_def *) NULL)
+    return definition->is_variable ();
+  else
+    return 0;
+}
+
+int
+symbol_record::is_user_variable (void) const
+{
+  if (definition != (symbol_def *) NULL)
+    return definition->is_user_variable ();
+  else
+    return 0;
+}
+
+int
+symbol_record::is_builtin_variable (void) const
+{
+  if (definition != (symbol_def *) NULL)
+    return definition->is_builtin_variable ();
+  else
+    return 0;
+}
+
+unsigned
+symbol_record::type (void) const
+{
+  if (definition != (symbol_def *) NULL)
+    return definition->type;
+  else
+    return 0;
 }
 
 int
 symbol_record::is_defined (void) const
 {
-  return (var != (symbol_def *) NULL || fcn != (symbol_def *) NULL);
+  if (definition != (symbol_def *) NULL)
+    return (definition->def () != NULL_TREE);
+  else
+    return 0;
+}
+
+int
+symbol_record::is_read_only (void) const
+{
+  if (definition != (symbol_def *) NULL)
+    return definition->read_only;
+  else
+    return 0;
+}
+
+int
+symbol_record::is_eternal (void) const
+{
+  if (definition != (symbol_def *) NULL)
+    return definition->eternal;
+  else
+    return 0;
+}
+
+void
+symbol_record::protect (void)
+{
+  if (definition != (symbol_def *) NULL)
+    {
+      definition->protect ();
+
+      if (! is_defined ())
+	warning ("protecting undefined variable `%s'", nm);
+    }
+}
+
+void
+symbol_record::unprotect (void)
+{
+  if (definition != (symbol_def *) NULL)
+    definition->unprotect ();
+}
+
+void
+symbol_record::make_eternal (void)
+{
+  if (definition != (symbol_def *) NULL)
+    {
+      definition->make_eternal ();
+
+      if (! is_defined ())
+	warning ("giving eternal life to undefined variable `%s'", nm);
+    }
 }
 
 void
@@ -225,55 +392,34 @@
 }
 
 int
-symbol_record::var_read_only (void)
-{
-  if (var != (symbol_def *) NULL
-       && var->sym_class == symbol_def::read_only)
-    {
-      error ("can't assign to read only symbol `%s'", nm);
-      return 1;
-    }
-  else
-    return 0;
-}
-
-int
-symbol_record::read_only (void)
-{
-  if ((var != (symbol_def *) NULL
-       && var->sym_class == symbol_def::read_only)
-      || (fcn != (symbol_def *) NULL
-	  && fcn->sym_class == symbol_def::read_only))
-    {
-      error ("can't assign to read only symbol `%s'", nm);
-      return 1;
-    }
-  else
-    return 0;
-}
-
-int
 symbol_record::define (tree_constant *t)
 {
-  if (var_read_only ())
+  if (is_variable () && read_only_error ())
     return 0;
 
-  tree_constant *saved_def = NULL_TREE_CONST;
-
-  if (var != (symbol_def *) NULL)
+  tree *saved_def = NULL_TREE;
+  if (definition == (symbol_def *) NULL)
+    {
+      definition = new symbol_def ();
+      definition->count = 1;
+    }
+  else if (is_function ())
     {
-      saved_def = (tree_constant *) var->def ();  // XXX FIXME XXX
-      var->define (t);
+      symbol_def *new_def = new symbol_def ();
+      push_def (new_def);
+      definition->count = 1;
     }
-  else
+  else if (is_variable ())
     {
-      var = new symbol_def (t);
-      var->count = 1;
+      saved_def = definition->def ();
     }
 
+  definition->define (t);
+
   if (sv_fcn != (sv_Function) NULL && sv_fcn () < 0)
     {
-      var->define (saved_def);
+// Would be nice to be able to avoid this cast.  XXX FIXME XXX
+      definition->define ((tree_constant *) saved_def);
       delete t;
       return 0;
     }
@@ -286,115 +432,97 @@
 int
 symbol_record::define (tree_builtin *t)
 {
-  if (read_only ())
+  if (read_only_error ())
     return 0;
 
-  if (var != (symbol_def *) NULL)
+  if (is_variable ())
     {
-      if (--var->count <= 0)
-	delete var;
-      var = (symbol_def *) NULL;
+      symbol_def *old_def = pop_def ();
+      maybe_delete (old_def);
     }
 
-  if (fcn != (symbol_def *) NULL)
-    fcn->define (t);
-  else
+  if (is_function ())
     {
-      fcn = new symbol_def (t);
-      fcn->count = 1;
+      symbol_def *old_def = pop_def ();
+      maybe_delete (old_def);
     }
 
+  symbol_def *new_def = new symbol_def (t);
+  push_def (new_def);
+  definition->count = 1;
+
   return 1;
 }
 
 int
 symbol_record::define (tree_function *t)
 {
-  if (read_only ())
+  if (read_only_error ())
     return 0;
 
-  if (var != (symbol_def *) NULL)
+  if (is_variable ())
     {
-      if (--var->count <= 0)
-	delete var;
-      var = (symbol_def *) NULL;
+      symbol_def *old_def = pop_def ();
+      maybe_delete (old_def);
     }
 
-  if (fcn != (symbol_def *) NULL)
-    fcn->define (t);
-  else
+  if (is_function ())
     {
-      fcn = new symbol_def (t);
-      fcn->count = 1;
+      symbol_def *old_def = pop_def ();
+      maybe_delete (old_def);
     }
 
+  symbol_def *new_def = new symbol_def (t);
+  push_def (new_def);
+  definition->count = 1;
+
   return 1;
 }
 
 int
 symbol_record::define_as_fcn (tree_constant *t)
 {
-  if (read_only ())
+  if (is_variable () && read_only_error ())
     return 0;
 
-  if (var != (symbol_def *) NULL)
+  if (is_variable ())
     {
-      if (--var->count <= 0)
-	delete var;
-      var = (symbol_def *) NULL;
+      symbol_def *old_def = pop_def ();
+      maybe_delete (old_def);
+    }
+
+  if (is_function ())
+    {
+      symbol_def *old_def = pop_def ();
+      maybe_delete (old_def);
     }
 
-  if (fcn != (symbol_def *) NULL)
-    fcn->define (t);
-  else
-    {
-      fcn = new symbol_def (t);
-      fcn->count = 1;
-    }
+  symbol_def *new_def = new symbol_def (t);
+  push_def (new_def);
+  definition->count = 1;
+  definition->type = symbol_def::BUILTIN_FUNCTION;
 
   return 1;
 }
 
+int
+symbol_record::define_builtin_var (tree_constant *t)
+{
+  define (t);
+  if (is_variable ())
+    definition->type = symbol_def::BUILTIN_VARIABLE;
+}
+
 void
 symbol_record::document (const char *h)
 {
-  if (var != (symbol_def *) NULL)
-    var->document (h);
-  else if (fcn != (symbol_def *) NULL)
-    fcn->document (h);
-  else
-    warning ("couldn't document undefined variable `%s'", nm);
-}
-
-void
-symbol_record::protect (void)
-{
-  if (var != (symbol_def *) NULL)
-    var->sym_class = symbol_def::read_only;
-  else if (fcn != (symbol_def *) NULL)
-    fcn->sym_class = symbol_def::read_only;
-  else
-    warning ("couldn't protect undefined variable `%s'", nm);
-}
+  if (definition != (symbol_def *) NULL)
+    {
+      definition->document (h);
 
-void
-symbol_record::unprotect (void)
-{
-  if (var != (symbol_def *) NULL)
-    var->sym_class = symbol_def::read_write;
-  else if (fcn != (symbol_def *) NULL)
-    fcn->sym_class = symbol_def::read_write;
-}
-
-void
-symbol_record::make_eternal (void)
-{
-  if (var != (symbol_def *) NULL)
-    var->lifespan = symbol_def::eternal;
-  else if (fcn != (symbol_def *) NULL)
-    fcn->lifespan = symbol_def::eternal;
-  else
-    warning ("couldn't give eternal life to the variable `%s'", nm);
+      if (! is_defined ())
+	warning ("documenting undefined variable `%s'", nm);
+    }
 }
 
 int
@@ -402,74 +530,65 @@
 {
   int status = 0;
 
-  if (var != (symbol_def *) NULL && var->def () != (tree *) NULL)
+// This is a kludge, but hey, it doesn't make sense to save them
+// anyway, does it?  Even if it did, we would just have trouble trying
+// to read NaN and Inf on lots of systems anyway...
+
+  if (is_read_only ())
     {
-// For now, eternal implies builtin.
-      if (var->lifespan != symbol_def::eternal)
-	{
-// Should we also save the help string?  Maybe someday.
-	 os << "# name: " << nm << "\n";
-	 status = var->save (os, mark_as_global);
-       }
+      warning ("save: sorry, can't save read-only variable `%s'", nm);
+      status = -1;
     }
-  else if (fcn != (symbol_def *) NULL)
-    message ("save", "sorry, can't save functions yet");
+  else if (is_function ())
+    {
+      warning ("save: sorry, can't save function `%s'", nm);
+      status = -1;
+    }
   else
     {
-// Kludge!  We probably don't want to print warnings for ans, but it
-// does seem reasonable to print them for other undefined variables.
-      if (strcmp (nm, "ans") != 0)
-	warning ("not saving undefined symbol `%s'", nm);
+// Should we also save the help string?  Maybe someday.
+
+      os << "# name: " << nm << "\n";
+
+      status = definition->save (os, mark_as_global);
     }
 
   return status;
 }
 
 int
-symbol_record::clear_visible (void)
+symbol_record::clear (void)
 {
-  int status = 0;
-
-  if (is_defined ())
+  int count = 0;
+  if (linked_to_global)
     {
-      if (var != (symbol_def *) NULL
-	  && var->lifespan != symbol_def::eternal)
-	{
-	  if (--var->count <= 0)
-	    delete var;
-	  var = (symbol_def *) NULL;
-	  forced_global = 0;
-	  status = 1;
-	}
-      else if (fcn != (symbol_def *) NULL
-	       && fcn->lifespan != symbol_def::eternal)
-	{
-	  if (--fcn->count <= 0)
-	    delete fcn;
-	  fcn = (symbol_def *) NULL;
-	  status = 1;
-	}
+      count = maybe_delete (definition);
+      definition = (symbol_def *) NULL;
+      linked_to_global = 0;
     }
-
-  return status;
+  else
+    {
+      symbol_def *old_def = pop_def ();
+      count = maybe_delete (old_def);
+    }
+  return count;
 }
 
 void
-symbol_record::clear_all (void)
+symbol_record::alias (symbol_record *s, int force = 0)
 {
-  if (var != (symbol_def *) NULL && var->lifespan != symbol_def::eternal)
+  sv_fcn = s->sv_fcn;
+
+  if (force && s->definition == (symbol_def *) NULL)
     {
-      if (--var->count <= 0)
-	delete var;
-      var = (symbol_def *) NULL;
-      forced_global = 0;
+      s->definition = new symbol_def ();
+      definition = s->definition;
+      definition->count = 2; // Yes, this is correct.
     }
-
-  if (fcn != (symbol_def *) NULL && fcn->lifespan != symbol_def::eternal)
+  else if (s->definition != (symbol_def *) NULL)
     {
-      if (--fcn->count <= 0)
-	delete fcn;
-      fcn = (symbol_def *) NULL;
+      definition = s->definition;
+      definition->count++;
     }
 }
 
@@ -486,44 +605,15 @@
 }
 
 void
-symbol_record::mark_as_forced_global (void)
+symbol_record::mark_as_linked_to_global (void)
 {
-  forced_global = 1;
+  linked_to_global = 1;
 }
 
 int
-symbol_record::is_forced_global (void) const
-{
-  return forced_global;
-}
-
-void
-symbol_record::alias (symbol_record *s, int force = 0)
+symbol_record::is_linked_to_global (void) const
 {
-  sv_fcn = s->sv_fcn; // Maybe this should go in the var symbol_def?
-
-//  formal_param = s->formal_param; // Hmm.
-//  forced_global = s->forced_global; // Hmm.
-
-  if (force && s->var == (symbol_def *) NULL
-      && s->fcn == (symbol_def *) NULL)
-    {
-      s->var = new symbol_def ();
-      var = s->var;
-      var->count = 2; // Yes, this is correct.
-      return;
-    }
-
-  if (s->var != (symbol_def *) NULL)
-    {
-      var = s->var;
-      var->count++;
-    }
-  else if (s->fcn != (symbol_def *) NULL)
-    {
-      fcn = s->fcn;
-      fcn->count++;
-    }
+  return linked_to_global;
 }
 
 symbol_record *
@@ -532,6 +622,247 @@
   return next_elem;
 }
 
+void
+symbol_record::chain (symbol_record *s)
+{
+  next_elem = s;
+}
+
+int
+symbol_record::read_only_error (void)
+{
+  if (is_read_only ())
+    {
+      char *tag = "symbol";
+      if (is_variable ())
+	tag = "variable";
+      else if (is_function ())
+	tag = "function";
+	
+      error ("can't redefined read-only %s `%s'", tag, nm);
+
+      return 1;
+    }
+  else
+    return 0;
+}
+
+void
+symbol_record::push_def (symbol_def *sd)
+{
+  if (sd == (symbol_def *) NULL)
+    return;
+
+  sd->next_elem = definition;
+  definition = sd;
+}
+
+symbol_def *
+symbol_record::pop_def (void)
+{
+  symbol_def *top = definition;
+  if (definition != (symbol_def *) NULL)
+    definition = definition->next_elem;
+  return top;
+}
+
+/*
+ * A structure for handling verbose information about a symbol_record.
+ */
+
+symbol_record_info::symbol_record_info (void)
+{
+  init_state ();
+}
+
+symbol_record_info::symbol_record_info (const symbol_record& sr)
+{
+  init_state ();
+
+  type = sr.type ();
+
+  if (sr.is_variable () && sr.is_defined ())
+    {
+// Would be nice to avoid this cast.  XXX FIXME XXX
+      tree_constant *tmp = (tree_constant *) sr.def ();
+      switch (tmp->const_type ())
+	{
+	case tree_constant_rep::scalar_constant:
+	  const_type = SR_INFO_SCALAR;
+	  break;
+	case tree_constant_rep::complex_scalar_constant:
+	  const_type = SR_INFO_COMPLEX_SCALAR;
+	  break;
+	case tree_constant_rep::matrix_constant:
+	  const_type = SR_INFO_MATRIX;
+	  break;
+	case tree_constant_rep::complex_matrix_constant:
+	  const_type = SR_INFO_COMPLEX_MATRIX;
+	  break;
+	case tree_constant_rep::range_constant:
+	  const_type = SR_INFO_RANGE;
+	  break;
+	case tree_constant_rep::string_constant:
+	  const_type = SR_INFO_STRING;
+	  break;
+	default:
+	  break;
+	}
+
+      nr = tmp->rows ();
+      nc = tmp->columns ();
+
+      symbol_def *sr_def = sr.definition;
+      symbol_def *hidden_def = sr_def->next_elem;
+      if (hidden_def != (symbol_def *) NULL)
+	{
+	  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 = strsave (sr.name ());
+
+  initialized = 1;
+}
+
+symbol_record_info::symbol_record_info (const symbol_record_info& s)
+{
+  type = s.type;
+  const_type = s.const_type;
+  hides = s.hides;
+  eternal = s.eternal;
+  read_only = s.read_only;
+  nr = s.nr;
+  nc = s.nc;
+  nm = strsave (s.nm);
+  initialized = s.initialized;
+}
+
+symbol_record_info::~symbol_record_info (void)
+{
+  delete nm;
+}
+
+symbol_record_info&
+symbol_record_info::operator = (const symbol_record_info& s)
+{
+  if (this != &s)
+    {
+      delete nm;
+      type = s.type;
+      const_type = s.const_type;
+      hides = s.hides;
+      eternal = s.eternal;
+      read_only = s.read_only;
+      nr = s.nr;
+      nc = s.nc;
+      nm = strsave (s.nm);
+      initialized = s.initialized;
+    }
+  return *this;
+}
+
+int
+symbol_record_info::is_defined (void) const
+{
+  return initialized;
+}
+
+int
+symbol_record_info::is_read_only (void) const
+{
+  return read_only;
+}
+
+int
+symbol_record_info::is_eternal (void) const
+{
+  return eternal;
+}
+
+int
+symbol_record_info::hides_fcn (void) const
+{
+  return (hides & SR_INFO_USER_FUNCTION);
+}
+
+int
+symbol_record_info::hides_builtin (void) const
+{
+  return (hides & SR_INFO_BUILTIN_FUNCTION);
+}
+
+char *
+symbol_record_info::type_as_string (void) const
+{
+  if (type == symbol_def::USER_FUNCTION)
+    return "user function";
+  else if (type == symbol_def::BUILTIN_FUNCTION)
+    return "builtin function";
+  else
+    {
+      if (const_type == SR_INFO_SCALAR)
+	return "real scalar";
+      else if (const_type == SR_INFO_COMPLEX_SCALAR)
+	return "complex scalar";
+      else if (const_type == SR_INFO_MATRIX)
+	return "real matrix";
+      else if (const_type == SR_INFO_COMPLEX_MATRIX)
+	return "complex matrix";
+      else if (const_type == SR_INFO_RANGE)
+	return "range";
+      else if (const_type == SR_INFO_STRING)
+	return "string";
+      else
+	return "";
+    }
+}
+
+int
+symbol_record_info::is_function (void) const
+{
+  return (type == symbol_def::USER_FUNCTION
+	  || type == symbol_def::BUILTIN_FUNCTION);
+}
+
+int
+symbol_record_info::rows (void) const
+{
+  return nr;
+}
+
+int
+symbol_record_info::columns (void) const
+{
+  return nc;
+}
+
+char *
+symbol_record_info::name (void) const
+{
+  return nm;
+}
+
+void
+symbol_record_info::init_state (void)
+{
+  initialized = 0;
+  type = symbol_def::UNKNOWN;
+  const_type = SR_INFO_UNKNOWN;
+  hides = SR_INFO_NONE;
+  eternal = 0;
+  read_only = 0;
+  nr = -1;
+  nc = -1;
+  nm = (char *) NULL;
+}
+
 /*
  * A symbol table.
  */
@@ -558,7 +889,7 @@
     {
       symbol_record *new_sym;
       new_sym = new symbol_record (nm, table[index].next ());
-      table[index].next_elem = new_sym;
+      table[index].chain (new_sym);
       return new_sym;
     }
   else if (warn)
@@ -568,7 +899,7 @@
 }
 
 void
-symbol_table::clear (void)
+symbol_table::clear (int clear_user_functions = 1)
 {
   for (int i = 0; i < HASH_TABLE_SIZE; i++)
     {
@@ -576,61 +907,45 @@
 
       while (ptr != (symbol_record *) NULL)
 	{
-	  ptr->clear_all ();
+	  if (ptr->is_user_variable ()
+	      || (clear_user_functions && ptr->is_user_function ()))
+	    {
+	      ptr->clear ();
+	    }
+
 	  ptr = ptr->next ();
 	}
     }
 }
 
 int
-symbol_table::clear (const char *nm)
+symbol_table::clear (const char *nm, int clear_user_functions = 1)
 {
   int index = hash (nm) & HASH_MASK;
 
-  symbol_record *prev = &table[index];
-  symbol_record *curr = prev->next ();
+  symbol_record *ptr = table[index].next ();
 
-  while (curr != (symbol_record *) NULL)
+  while (ptr != (symbol_record *) NULL)
     {
-      if (strcmp (curr->name (), nm) == 0)
+      if (strcmp (ptr->name (), nm) == 0
+	  && (ptr->is_user_variable ()
+	      || (clear_user_functions && ptr->is_user_function ())))
 	{
-	  if (curr->clear_visible ())
-	    return 1;
+	  ptr->clear ();
+	  return 1;
 	}
-      prev = curr;
-      curr = curr->next ();
+      ptr = ptr->next ();
     }
 
   return 0;
 }
 
-// Ugh.
-
-void
-symbol_table::bind_globals (void)
-{
-  assert (this != global_sym_tab);
-
-  for (int i = 0; i < HASH_TABLE_SIZE; i++)
-    {
-      symbol_record *ptr = table[i].next ();
-
-      while (ptr != (symbol_record *) NULL && ! ptr->formal_param)
-	{
-	  char *nm = ptr->name ();
-	  symbol_record *sr = global_sym_tab->lookup (nm, 0, 0);
-	  if (sr != (symbol_record *) NULL && sr->is_forced_global ())
-	    ptr->alias (sr, 1);
-	  ptr = ptr->next ();
-	}
-    }
-}
-
 int
 symbol_table::save (ostream& os, int mark_as_global = 0)
 {
   int status = 0;
-  char **names = sorted_var_list ();
+  int count;
+  char **names = list (count, 1, symbol_def::USER_VARIABLE);
   if (names != (char **) NULL)
     {
       while (*names != (char *) NULL)
@@ -670,52 +985,60 @@
   return count;
 }
 
-char **
-symbol_table::list (void) const
+static inline int
+pstrcmp (char **a, char **b)
 {
-  int count;
-  return list (count);
+  return strcmp (*a, *b);
 }
 
-char **
-symbol_table::var_list (void) const
+static inline int
+symbol_record_info_cmp (symbol_record_info *a, symbol_record_info *b)
 {
-  int count;
-  return var_list (count);
+  return strcmp (a->name (), b->name ());
 }
 
-char **
-symbol_table::fcn_list (void) const
-{
-  int count;
-  return fcn_list (count);
-}
+// This function should probably share code with symbol_table::list.
+// XXX FIXME XXX
 
-char **
-symbol_table::list (int& count) const
+symbol_record_info *
+symbol_table::long_list (int& count, int sort = 0,
+			 unsigned type = SYMTAB_ALL_TYPES,
+			 unsigned scope = SYMTAB_ALL_SCOPES) const
 {
   count = 0;
   int n = size ();
   if (n == 0)
-    return (char **) NULL;
+    return (symbol_record_info *) NULL;
 
-  char **symbols = new char * [n+1];
+  symbol_record_info *symbols = new symbol_record_info [n+1];
   for (int i = 0; i < HASH_TABLE_SIZE; i++)
     {
       symbol_record *ptr = table[i].next ();
       while (ptr != (symbol_record *) NULL)
 	{
 	  assert (count < n);
-	  symbols[count++] = strsave (ptr->name ());
+	  unsigned my_scope = ptr->is_linked_to_global () + 1; // Tricky...
+	  unsigned my_type = ptr->type ();
+	  if ((type & my_type) && (scope & my_scope))
+	    {
+	      symbols[count++] = symbol_record_info (*ptr);
+	    }
 	  ptr = ptr->next ();
 	}
     }
-  symbols[count] = (char *) NULL;
+  symbols[count] = symbol_record_info ();
+
+  if (sort && symbols != (symbol_record_info *) NULL)
+    qsort ((void *) symbols, count, sizeof (symbol_record_info),
+	   (int (*)(void*, void*)) symbol_record_info_cmp);
+
   return symbols;
 }
 
 char **
-symbol_table::var_list (int& count) const
+symbol_table::list (int& count, int sort = 0,
+		    unsigned type = SYMTAB_ALL_TYPES,
+		    unsigned scope = SYMTAB_ALL_SCOPES) const
 {
   count = 0;
   int n = size ();
@@ -729,93 +1052,19 @@
       while (ptr != (symbol_record *) NULL)
 	{
 	  assert (count < n);
-	  if (ptr->is_variable ())
-	    symbols[count++] = strsave (ptr->name ());
-	  ptr = ptr->next ();
-	}
-    }
-  symbols[count] = (char *) NULL;
-  return symbols;
-}
-
-char **
-symbol_table::fcn_list (int& count) const
-{
-  count = 0;
-  int n = size ();
-  if (n == 0)
-    return (char **) NULL;
-
-  char **symbols = new char * [n+1];
-  for (int i = 0; i < HASH_TABLE_SIZE; i++)
-    {
-      symbol_record *ptr = table[i].next ();
-      while (ptr != (symbol_record *) NULL)
-	{
-	  assert (count < n);
-	  if (ptr->is_function ())
+	  unsigned my_scope = ptr->is_linked_to_global () + 1; // Tricky...
+	  unsigned my_type = ptr->type ();
+	  if ((type & my_type) && (scope & my_scope))
 	    symbols[count++] = strsave (ptr->name ());
 	  ptr = ptr->next ();
 	}
     }
   symbols[count] = (char *) NULL;
-  return symbols;
-}
 
-static inline int
-pstrcmp (char **a, char **b)
-{
-  return strcmp (*a, *b);
-}
-
-char **
-symbol_table::sorted_list (void) const
-{
-  int count = 0;
-  return sorted_list (count);
-}
-
-char **
-symbol_table::sorted_var_list (void) const
-{
-  int count = 0;
-  return sorted_var_list (count);
-}
-
-char **
-symbol_table::sorted_fcn_list (void) const
-{
-  int count = 0;
-  return sorted_fcn_list (count);
-}
-
-char **
-symbol_table::sorted_list (int& count) const
-{
-  char **symbols = list (count);
-  if (symbols != (char **) NULL)
+  if (sort && symbols != (char **) NULL)
     qsort ((void **) symbols, count, sizeof (char *),
 	   (int (*)(void*, void*)) pstrcmp);
-  return symbols;
-}
 
-char **
-symbol_table::sorted_var_list (int& count) const
-{
-  char **symbols = var_list (count);
-  if (symbols != (char **) NULL)
-    qsort ((void **) symbols, count, sizeof (char *),
-	   (int (*)(void*, void*)) pstrcmp);
-  return symbols;
-}
-
-char **
-symbol_table::sorted_fcn_list (int& count) const
-{
-  char **symbols = fcn_list (count);
-  if (symbols != (char **) NULL)
-    qsort ((void **) symbols, count, sizeof (char *),
-	   (int (*)(void*, void*)) pstrcmp);
   return symbols;
 }