changeset 1:78fd87e624cb

[project @ 1993-08-08 01:13:40 by jwe] Initial revision
author jwe
date Sun, 08 Aug 1993 01:13:40 +0000
parents 22412e3a4641
children c0190df9885d
files liboctave/idx-vector.cc liboctave/idx-vector.h liboctave/statdefs.h src/SLStack.h src/Stack.h src/arith-ops.cc src/arith-ops.h src/builtins.cc src/builtins.h src/colloc.cc src/dassl.cc src/det.cc src/dynamic-ld.cc src/dynamic-ld.h src/eig.cc src/error.cc src/error.h src/fft.cc src/file-io.cc src/file-io.h src/fsolve.cc src/fsqp.cc src/g-builtins.cc src/g-builtins.h src/gripes.cc src/gripes.h src/help.cc src/help.h src/hess.cc src/ifft.cc src/input.cc src/input.h src/inv.cc src/lex.h src/lex.l src/lpsolve.cc src/lsode.cc src/lu.cc src/mappers.cc src/mappers.h src/npsol.cc src/oct-hist.cc src/oct-hist.h src/octave.cc src/pager.cc src/pager.h src/parse.h src/parse.y src/pr-output.cc src/pr-output.h src/procstream.cc src/procstream.h src/pt-base.h src/pt-const.cc src/pt-const.h src/pt-plot.cc src/qpsol.cc src/qr.cc src/quad.cc src/rand.cc src/schur.cc src/sighandlers.cc src/sighandlers.h src/svd.cc src/symtab.cc src/sysdep.cc src/sysdep.h src/t-builtins.cc src/t-builtins.h src/tc-assign.cc src/tc-extras.cc src/tc-index.cc src/tc-inlines.h src/terminals.cc src/terminals.h src/toplev.h src/tree.h.old src/unwind-prot.cc src/unwind-prot.h src/user-prefs.cc src/user-prefs.h src/utils.cc src/utils.h src/variables.cc src/variables.h src/xdiv.cc src/xdiv.h src/xpow.cc src/xpow.h
diffstat 89 files changed, 32791 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
new file mode 100644
--- /dev/null
+++ b/liboctave/idx-vector.cc
@@ -0,0 +1,249 @@
+// Very simple integer vectors for indexing              -*- C++ -*-
+/*
+
+Copyright (C) 1992, 1993 John W. Eaton
+
+This file is part of Octave.
+
+Octave is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+Octave is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with Octave; see the file COPYING.  If not, write to the Free
+Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifdef __GNUG__
+#pragma implementation
+#endif
+
+#include "idx-vector.h"
+#include "error.h"
+#include "user-prefs.h"
+#include "utils.h"
+
+idx_vector::idx_vector (const idx_vector& a)
+{
+  len = a.len;
+  if (len > 0)
+    {
+      data = new int [len];
+      for (int i = 0; i < len; i++)
+	data[i] = a.data[i];
+
+      num_zeros = a.num_zeros;
+      num_ones = a.num_ones;
+      one_zero = a.one_zero;
+
+      max_val = a.max_val;
+      min_val = a.min_val;
+    }
+  else
+    data = 0;
+}
+
+static inline int
+tree_to_mat_idx (double x)
+{
+  if (x > 0)
+    return ((int) (x + 0.5) - 1);
+  else
+    return ((int) (x - 0.5) - 1);
+}
+
+idx_vector::idx_vector (Matrix& m, int do_ftn_idx, char *rc, int z_len = 0)
+{
+  int nr = m.rows ();
+  int nc = m.columns ();
+
+  if (nr == 0 || nc == 0)
+    {
+      len = 0;
+      data = 0;
+      num_zeros = 0;
+      num_ones = 0;
+      one_zero = 0;
+      return;
+    }
+  else if (nr > 1 && nc > 1 && do_ftn_idx)
+    {
+      double *cop_out = m.fortran_vec ();
+      len = nr * nc;
+      data = new int [len];
+      for (int i = 0; i < len; i++)
+	data[i] = tree_to_mat_idx (*cop_out++);
+    }
+  else if (nr == 1 && nc > 0)
+    {
+      len = nc;
+      data = new int [len];
+      for (int i = 0; i < len; i++)
+	data[i] = tree_to_mat_idx (m.elem (0, i)); 
+    }  
+  else if (nc == 1 && nr > 0)
+    {
+      len = nr;
+      data = new int [len];
+      for (int i = 0; i < len; i++)
+	data[i] = tree_to_mat_idx (m.elem (i, 0));
+    }
+  else
+    {
+      message ((char *) NULL, "invalid matrix index");
+      jump_to_top_level ();
+    }
+
+  init_state (rc, z_len);
+}
+
+idx_vector::idx_vector (const Range& r)
+{
+  len = r.nelem ();
+
+  assert (len != 0);
+
+  double b = r.base ();
+  double step = r.inc ();
+
+  data = new int [len];
+
+  for (int i = 0; i < len; i++)
+    {
+      double val = b + i * step;
+      data[i] = tree_to_mat_idx (val);
+    }
+
+  init_state ();
+}
+
+idx_vector&
+idx_vector::operator = (const idx_vector& a)
+{
+  if (this != &a)
+    {
+      delete [] data;
+      len = a.len;
+      data = new int [len];
+      for (int i = 0; i < len; i++)
+	data[i] = a.data[i];
+
+      num_zeros = a.num_zeros;
+      num_ones = a.num_ones;
+      one_zero = a.one_zero;
+
+      max_val = a.max_val;
+      min_val = a.min_val;
+    }
+  return *this;
+}
+
+void
+idx_vector::init_state (char *rc, int z_len = 0)
+{
+  one_zero = 1;
+  num_zeros = 0;
+  num_ones = 0;
+
+  min_val = max_val = data[0];
+
+  int i = 0;
+  do
+    {
+      if (data[i] == -1)
+	num_zeros++;
+      else if (data[i] == 0)
+	num_ones++;
+
+      if (one_zero && data[i] != -1 && data[i] != 0)
+	one_zero = 0;
+
+      if (data[i] > max_val)
+	max_val = data[i];
+
+      if (data[i] < min_val)
+	min_val = data[i];
+    }
+  while (++i < len);
+
+  if (one_zero && z_len == len)
+    {
+      if (num_zeros == len)
+	{
+	  delete [] data;
+	  len = 0;
+	  data = 0;
+	  num_zeros = 0;
+	  num_ones = 0;
+	  one_zero = 0;
+	}
+      else if (num_ones != len || user_pref.prefer_zero_one_indexing)
+	convert_one_zero_to_idx ();
+    }
+  else if (min_val < 0)
+    {
+      error ("%s index %d out of range", rc, min_val+1);
+      jump_to_top_level ();
+    }
+}
+
+void
+idx_vector::convert_one_zero_to_idx (void)
+{
+  if (num_ones == 0)
+    {
+      len = 0;
+      max_val = 0;
+      min_val = 0;
+      delete [] data;
+    }
+  else
+    {
+      assert (num_ones + num_zeros == len);
+
+      int *new_data = new int [num_ones];
+      int count = 0;
+      for (int i = 0; i < len; i++)
+	if (data[i] == 0)
+	  new_data[count++] = i;
+
+      delete [] data;
+      len = num_ones;
+      data = new_data;
+
+      min_val = max_val = data[0];
+
+      i = 0;
+      do
+	{
+	  if (data[i] > max_val)
+	    max_val = data[i];
+
+	  if (data[i] < min_val)
+	    min_val = data[i];
+	}
+      while (++i < len);
+    }
+}
+
+ostream&
+operator << (ostream& os, const idx_vector& a)
+{
+  for (int i = 0; i < a.len; i++)
+    os << a.data[i] << "\n";
+  return os;
+}
+
+/*
+;;; Local Variables: ***
+;;; mode: C++ ***
+;;; page-delimiter: "^/\\*" ***
+;;; End: ***
+*/
new file mode 100644
--- /dev/null
+++ b/liboctave/idx-vector.h
@@ -0,0 +1,137 @@
+// Very simple integer vectors for indexing              -*- C++ -*-
+/*
+
+Copyright (C) 1992, 1993 John W. Eaton
+
+This file is part of Octave.
+
+Octave is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+Octave is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with Octave; see the file COPYING.  If not, write to the Free
+Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#if !defined (_idx_vector_h)
+#define _idx_vector_h 1
+
+#ifdef __GNUG__
+#pragma interface
+#endif
+
+#include <stdlib.h>
+#include <assert.h>
+#include <iostream.h>
+#include "Matrix.h"
+#include "Range.h"
+
+#define FAIL assert(0) /* XXX FIXME XXX */
+
+class idx_vector
+{
+public:
+  idx_vector (void);
+  idx_vector (const idx_vector& a);
+
+  idx_vector (Matrix& m, int do_ftn_idx, char *rc = (char *) NULL,
+	      int z_len = 0);
+
+  idx_vector (const Range& r);
+
+ ~idx_vector (void);
+
+  idx_vector& operator = (const idx_vector& a);
+
+  int capacity (void) const;
+  int length (void) const;
+
+  int elem (int n) const;
+  int checkelem (int n) const;
+  int operator () (int n) const;
+
+// other stuff
+
+  int max (void) const;
+  int min (void) const;
+
+  int one_zero_only (void) const;
+  int zeros_count (void) const;
+  int ones_count (void) const;
+
+// i/o
+
+  friend ostream& operator << (ostream& os, const idx_vector& a);
+
+private:
+
+  int len;
+  int one_zero;
+  int num_zeros;
+  int num_ones;
+  int max_val;
+  int min_val;
+  int *data;
+
+  void init_state (char *rc = (char *) NULL, int z_len = 0);
+  void convert_one_zero_to_idx (void);
+};
+
+inline idx_vector::idx_vector (void)
+  {
+    len = 0;
+    data = 0;
+    num_zeros = 0;
+    num_ones = 0;
+    one_zero = 0;
+  }
+
+inline idx_vector::~idx_vector (void)
+  {
+    delete [] data;
+    data = 0;
+    num_zeros = 0;
+    num_ones = 0;
+    len = 0;
+    one_zero = 0;
+  }
+
+inline int idx_vector::capacity (void) const { return len; }
+inline int idx_vector::length (void) const { return len; }
+
+inline int idx_vector::elem (int n) const { return data[n]; }
+
+inline int
+idx_vector::checkelem (int n) const
+{
+  if (n < 0 || n >= len)
+    FAIL;
+
+  return elem (n);
+}
+
+inline int idx_vector::operator () (int n) const { return checkelem (n); }
+
+inline int idx_vector::max (void) const { return max_val; }
+inline int idx_vector::min (void) const { return min_val; }
+
+inline int idx_vector::one_zero_only (void) const { return one_zero; }
+inline int idx_vector::zeros_count (void) const { return num_zeros; }
+inline int idx_vector::ones_count (void) const { return num_ones; }
+
+#endif
+
+/*
+;;; Local Variables: ***
+;;; mode: C++ ***
+;;; page-delimiter: "^/\\*" ***
+;;; End: ***
+*/
new file mode 100644
--- /dev/null
+++ b/liboctave/statdefs.h
@@ -0,0 +1,73 @@
+// statdefs.h                                               -*- C++ -*-
+/*
+
+Copyright (C) 1992, 1993 John W. Eaton
+
+This file is part of Octave.
+
+Octave is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+Octave is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with Octave; see the file COPYING.  If not, write to the Free
+Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#if !defined (_statdefs_h)
+#define _statdefs_h 1
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#ifndef S_ISREG			/* Doesn't have POSIX.1 stat stuff. */
+#define mode_t unsigned short
+#endif
+#if !defined(S_ISBLK) && defined(S_IFBLK)
+#define	S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK)
+#endif
+#if !defined(S_ISCHR) && defined(S_IFCHR)
+#define	S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR)
+#endif
+#if !defined(S_ISDIR) && defined(S_IFDIR)
+#define	S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
+#endif
+#if !defined(S_ISREG) && defined(S_IFREG)
+#define	S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
+#endif
+#if !defined(S_ISFIFO) && defined(S_IFIFO)
+#define	S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO)
+#endif
+#if !defined(S_ISLNK) && defined(S_IFLNK)
+#define	S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
+#endif
+#if !defined(S_ISSOCK) && defined(S_IFSOCK)
+#define	S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK)
+#endif
+#if !defined(S_ISMPB) && defined(S_IFMPB) /* V7 */
+#define S_ISMPB(m) (((m) & S_IFMT) == S_IFMPB)
+#define S_ISMPC(m) (((m) & S_IFMT) == S_IFMPC)
+#endif
+#if !defined(S_ISNWK) && defined(S_IFNWK) /* HP/UX */
+#define S_ISNWK(m) (((m) & S_IFMT) == S_IFNWK)
+#endif
+
+#ifndef S_ISLNK
+#define lstat stat
+#endif
+
+#endif
+
+/*
+;;; Local Variables: ***
+;;; mode: C++ ***
+;;; page-delimiter: "^/\\*" ***
+;;; End: ***
+*/
new file mode 100644
--- /dev/null
+++ b/src/SLStack.h
@@ -0,0 +1,135 @@
+// This may look like C code, but it is really -*- C++ -*-
+/*
+Copyright (C) 1988 Free Software Foundation
+    written by Doug Lea (dl@rocky.oswego.edu)
+
+This file is part of the GNU C++ Library.  This library is free
+software; you can redistribute it and/or modify it under the terms of
+the GNU Library General Public License as published by the Free
+Software Foundation; either version 2 of the License, or (at your
+option) any later version.  This library is distributed in the hope
+that it will be useful, but WITHOUT ANY WARRANTY; without even the
+implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+PURPOSE.  See the GNU Library General Public License for more details.
+You should have received a copy of the GNU Library General Public
+License along with this library; if not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+
+#ifndef _SLStack_h
+#ifdef __GNUG__
+//#pragma interface
+#endif
+#define _SLStack_h 1
+
+#include "SLList.h"
+#include "Stack.h"
+
+template <class T>
+class SLStack : public Stack<T>
+{
+ private:
+  SLList<T> p;
+
+ public:
+  SLStack (void);
+  SLStack (const SLStack<T>& s);
+  ~SLStack (void);
+
+  void operator = (const SLStack<T>&);
+
+  void push (const T& item);
+  T pop (void);
+  T& top (void);
+  void del_top (void);
+
+  int empty (void);
+  int full (void);
+  int length (void);
+
+  void clear (void);
+
+  int OK (void);
+};
+
+template <class T>
+inline SLStack<T>::SLStack (void) : p () { }
+
+template <class T>
+inline SLStack<T>::SLStack (const SLStack<T>& a) : p (a.p) { }
+
+template <class T>
+inline SLStack<T>::~SLStack (void) { }
+
+template <class T>
+inline void
+SLStack<T>::push (const T& item)
+{
+  p.prepend (item);
+}
+
+template <class T>
+inline T
+SLStack<T>::pop (void)
+{
+  return p.remove_front ();
+}
+
+template <class T>
+inline T&
+SLStack<T>::top (void)
+{
+  return p.front ();
+}
+
+template <class T>
+inline void
+SLStack<T>::del_top (void)
+{
+  p.del_front ();
+}
+
+template <class T>
+inline void
+SLStack<T>::operator = (const SLStack<T>& s)
+{
+  p = s.p;
+}
+
+template <class T>
+inline int
+SLStack<T>::empty (void)
+{
+  return p.empty ();
+}
+
+template <class T>
+inline int
+SLStack<T>::full (void)
+{
+  return 0;
+}
+
+template <class T>
+inline int
+SLStack<T>::length (void)
+{
+  return p.length ();
+}
+
+template <class T>
+inline int
+SLStack<T>::OK (void)
+{
+  return p.OK ();
+}
+
+template <class T>
+inline void
+SLStack<T>::clear (void)
+{
+  p.clear ();
+}
+
+#endif
new file mode 100644
--- /dev/null
+++ b/src/Stack.h
@@ -0,0 +1,50 @@
+// This may look like C code, but it is really -*- C++ -*-
+/* 
+Copyright (C) 1988 Free Software Foundation
+    written by Doug Lea (dl@rocky.oswego.edu)
+
+This file is part of the GNU C++ Library.  This library is free
+software; you can redistribute it and/or modify it under the terms of
+the GNU Library General Public License as published by the Free
+Software Foundation; either version 2 of the License, or (at your
+option) any later version.  This library is distributed in the hope
+that it will be useful, but WITHOUT ANY WARRANTY; without even the
+implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+PURPOSE.  See the GNU Library General Public License for more details.
+You should have received a copy of the GNU Library General Public
+License along with this library; if not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+
+#ifndef _Stack_h
+#ifdef __GNUG__
+//#pragma interface
+#endif
+#define _Stack_h 1
+
+template <class T>
+class Stack
+{
+ public:
+  Stack (void) { }
+  virtual ~Stack (void) { }
+
+  virtual void push (const T& item) = 0;
+
+  virtual T pop (void) = 0;
+  virtual T& top (void) = 0; 
+
+  virtual void del_top (void) = 0;
+
+  virtual int empty (void) = 0;
+  virtual int full (void) = 0;
+  virtual int length (void) = 0;
+
+  virtual void clear (void) = 0;
+
+  void error (const char *msg);
+  virtual int OK (void) = 0;
+};
+
+#endif
new file mode 100644
--- /dev/null
+++ b/src/arith-ops.cc
@@ -0,0 +1,2368 @@
+// Helper functions for arithmetic operations.            -*- C++ -*-
+// Used by the tree class.                    
+/*
+
+Copyright (C) 1992, 1993 John W. Eaton
+
+This file is part of Octave.
+
+Octave is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+Octave is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with Octave; see the file COPYING.  If not, write to the Free
+Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifdef __GNUG__
+#pragma implementation
+#endif
+
+#include <ctype.h>
+#include <setjmp.h>
+#include <math.h>
+
+#include "error.h"
+#include "gripes.h"
+#include "utils.h"
+#include "mappers.h"
+#include "user-prefs.h"
+#include "tree-const.h"
+#include "arith-ops.h"
+#include "unwind-prot.h"
+#include "xpow.h"
+#include "xdiv.h"
+
+#if defined (HAVE_ISINF) || (defined (HAVE_FINITE) && defined (HAVE_ISNAN))
+#define DIVIDE_BY_ZERO_ERROR \
+  do \
+    { \
+      if (user_pref.warn_divide_by_zero) \
+        warning ("division by zero"); \
+    } \
+  while (0)
+#else
+#define DIVIDE_BY_ZERO_ERROR \
+  do \
+    { \
+      error ("division by zero attempted"); \
+      return tree_constant (); \
+    } \
+  while (0)
+#endif
+
+// But first, some stupid functions that don\'t deserve to be in the
+// Matrix class...
+
+enum
+Matrix_bool_op
+{
+  Matrix_LT,
+  Matrix_LE,
+  Matrix_EQ,
+  Matrix_GE,
+  Matrix_GT,
+  Matrix_NE,
+  Matrix_AND,
+  Matrix_OR, 
+};
+
+/*
+ * Stupid binary comparison operations like the ones Matlab provides.
+ * One for each type combination, in the order given here:
+ *
+ *       op2 \ op1:   s   m   cs   cm
+ *            +--   +---+---+----+----+
+ *   scalar   |     | * | 3 |  * |  9 |
+ *                  +---+---+----+----+
+ *   matrix         | 1 | 4 |  7 | 10 |
+ *                  +---+---+----+----+
+ *   complex_scalar | * | 5 |  * | 11 |
+ *                  +---+---+----+----+
+ *   complex_matrix | 2 | 6 |  8 | 12 |
+ *                  +---+---+----+----+
+ */
+
+/* 1 */
+static Matrix
+mx_stupid_bool_op (Matrix_bool_op op, double s, Matrix& a)
+{
+  int ar = a.rows ();
+  int ac = a.columns ();
+  Matrix t (ar, ac);
+  for (int j = 0; j < ac; j++)
+    for (int i = 0; i < ar; i++)
+      {
+	switch (op)
+	  {
+	  case Matrix_LT:
+	    t.elem (i,j) = s < a.elem (i,j);
+	    break;
+	  case Matrix_LE:
+	    t.elem (i,j) = s <= a.elem (i,j);
+	    break;
+	  case Matrix_EQ:
+	    t.elem (i,j) = s == a.elem (i,j);
+	    break;
+	  case Matrix_GE:
+	    t.elem (i,j) = s >= a.elem (i,j);
+	    break;
+	  case Matrix_GT:
+	    t.elem (i,j) = s > a.elem (i,j);
+	    break;
+	  case Matrix_NE:
+	    t.elem (i,j) = s != a.elem (i,j);
+	    break;
+	  case Matrix_AND:
+	    t.elem (i,j) = s && a.elem (i,j);
+	    break;
+	  case Matrix_OR:
+	    t.elem (i,j) = s || a.elem (i,j);
+	    break;
+	  default:
+	    panic_impossible ();
+	    break;
+	}
+    }
+  return t;
+}
+
+/* 2 */
+static Matrix
+mx_stupid_bool_op (Matrix_bool_op op, double s, ComplexMatrix& a)
+{
+  int ar = a.rows ();
+  int ac = a.columns ();
+  Matrix t (ar, ac);
+  for (int j = 0; j < ac; j++)
+    for (int i = 0; i < ar; i++)
+      {
+	switch (op)
+	  {
+	  case Matrix_LT:
+	    t.elem (i,j) = s < real (a.elem (i,j));
+	    break;
+	  case Matrix_LE:
+	    t.elem (i,j) = s <= real (a.elem (i,j));
+	    break;
+	  case Matrix_EQ:
+	    t.elem (i,j) = s == a.elem (i,j);
+	    break;
+	  case Matrix_GE:
+	    t.elem (i,j) = s >= real (a.elem (i,j));
+	    break;
+	  case Matrix_GT:
+	    t.elem (i,j) = s > real (a.elem (i,j));
+	    break;
+	  case Matrix_NE:
+	    t.elem (i,j) = s != a.elem (i,j);
+	    break;
+	  case Matrix_AND:
+	    t.elem (i,j) = s && (a.elem (i,j) != 0.0);
+	    break;
+	  case Matrix_OR:
+	    t.elem (i,j) = s || (a.elem (i,j) != 0.0);
+	    break;
+	  default:
+	    panic_impossible ();
+	    break;
+	}
+    }
+  return t;
+}
+
+/* 3 */
+static Matrix
+mx_stupid_bool_op (Matrix_bool_op op, Matrix& a, double s)
+{
+  int ar = a.rows ();
+  int ac = a.columns ();
+  Matrix t (ar, ac);
+  for (int j = 0; j < ac; j++)
+    for (int i = 0; i < ar; i++)
+      {
+	switch (op)
+	  {
+	  case Matrix_LT:
+	    t.elem (i,j) = a.elem (i,j) < s;
+	    break;
+	  case Matrix_LE:
+	    t.elem (i,j) = a.elem (i,j) <= s;
+	    break;
+	  case Matrix_EQ:
+	    t.elem (i,j) = a.elem (i,j) == s;
+	    break;
+	  case Matrix_GE:
+	    t.elem (i,j) = a.elem (i,j) >= s;
+	    break;
+	  case Matrix_GT:
+	    t.elem (i,j) = a.elem (i,j) > s;
+	    break;
+	  case Matrix_NE:
+	    t.elem (i,j) = a.elem (i,j) != s;
+	    break;
+	  case Matrix_AND:
+	    t.elem (i,j) = a.elem (i,j) && s;
+	    break;
+	  case Matrix_OR:
+	    t.elem (i,j) = a.elem (i,j) || s;
+	    break;
+	  default:
+	    panic_impossible ();
+	    break;
+	}
+    }
+  return t;
+}
+
+/* 4 */
+static Matrix
+mx_stupid_bool_op (Matrix_bool_op op, Matrix& a, Complex& s)
+{
+  int ar = a.rows ();
+  int ac = a.columns ();
+  Matrix t (ar, ac);
+  for (int j = 0; j < ac; j++)
+    for (int i = 0; i < ar; i++)
+      {
+	switch (op)
+	  {
+	  case Matrix_LT:
+	    t.elem (i,j) = a.elem (i,j) < real (s);
+	    break;
+	  case Matrix_LE:
+	    t.elem (i,j) = a.elem (i,j) <= real (s);
+	    break;
+	  case Matrix_EQ:
+	    t.elem (i,j) = a.elem (i,j) == s;
+	    break;
+	  case Matrix_GE:
+	    t.elem (i,j) = a.elem (i,j) >= real (s);
+	    break;
+	  case Matrix_GT:
+	    t.elem (i,j) = a.elem (i,j) > real (s);
+	    break;
+	  case Matrix_NE:
+	    t.elem (i,j) = a.elem (i,j) != s;
+	    break;
+	  case Matrix_AND:
+	    t.elem (i,j) = a.elem (i,j) && (s != 0.0);
+	    break;
+	  case Matrix_OR:
+	    t.elem (i,j) = a.elem (i,j) || (s != 0.0);
+	    break;
+	  default:
+	    panic_impossible ();
+	    break;
+	}
+    }
+  return t;
+}
+
+/* 5 */
+static Matrix
+mx_stupid_bool_op (Matrix_bool_op op, Matrix& a, Matrix& b)
+{
+  int ar = a.rows ();
+  int ac = a.columns ();
+
+  if (ar != b.rows () || ac != b.columns ())
+    {
+      gripe_nonconformant ();
+      jump_to_top_level ();
+    }
+     
+  Matrix c (ar, ac);
+
+  for (int j = 0; j < ac; j++)
+    for (int i = 0; i < ar; i++)
+      {
+	switch (op)
+	  {
+	  case Matrix_LT:
+	    c.elem (i, j) = a.elem (i, j) <  b.elem (i, j);
+	    break;
+	  case Matrix_LE:
+	    c.elem (i, j) = a.elem (i, j) <= b.elem (i, j);
+	    break;
+	  case Matrix_EQ:
+	    c.elem (i, j) = a.elem (i, j) == b.elem (i, j);
+	    break;
+	  case Matrix_GE:
+	    c.elem (i, j) = a.elem (i, j) >= b.elem (i, j);
+	    break;
+	  case Matrix_GT:
+	    c.elem (i, j) = a.elem (i, j) >  b.elem (i, j);
+	    break;
+	  case Matrix_NE:
+	    c.elem (i, j) = a.elem (i, j) != b.elem (i, j);
+	    break;
+	  case Matrix_AND:
+	    c.elem (i, j) = a.elem (i, j) && b.elem (i, j);
+	    break;
+	  case Matrix_OR:
+	    c.elem (i, j) = a.elem (i, j) || b.elem (i, j);
+	    break;
+	  default:
+	    panic_impossible ();
+	    break;
+	  }
+      }
+  return c;
+}
+
+/* 6 */
+static Matrix
+mx_stupid_bool_op (Matrix_bool_op op, Matrix& a, ComplexMatrix& b)
+{
+  int ar = a.rows ();
+  int ac = a.columns ();
+
+  if (ar != b.rows () || ac != b.columns ())
+    {
+      gripe_nonconformant ();
+      jump_to_top_level ();
+    }
+     
+  Matrix c (ar, ac);
+
+  for (int j = 0; j < ac; j++)
+    for (int i = 0; i < ar; i++)
+      {
+	switch (op)
+	  {
+	  case Matrix_LT:
+	    c.elem (i, j) = a.elem (i, j) <  real (b.elem (i, j));
+	    break;
+	  case Matrix_LE:
+	    c.elem (i, j) = a.elem (i, j) <= real (b.elem (i, j));
+	    break;
+	  case Matrix_EQ:
+	    c.elem (i, j) = a.elem (i, j) == b.elem (i, j);
+	    break;
+	  case Matrix_GE:
+	    c.elem (i, j) = a.elem (i, j) >= real (b.elem (i, j));
+	    break;
+	  case Matrix_GT:
+	    c.elem (i, j) = a.elem (i, j) >  real (b.elem (i, j));
+	    break;
+	  case Matrix_NE:
+	    c.elem (i, j) = a.elem (i, j) != b.elem (i, j);
+	    break;
+	  case Matrix_AND:
+	    c.elem (i, j) = a.elem (i, j) && (b.elem (i, j) != 0.0);
+	    break;
+	  case Matrix_OR:
+	    c.elem (i, j) = a.elem (i, j) || (b.elem (i, j) != 0.0);
+	    break;
+	  default:
+	    panic_impossible ();
+	    break;
+	  }
+      }
+  return c;
+}
+
+/* 7 */
+static Matrix
+mx_stupid_bool_op (Matrix_bool_op op, Complex& s, Matrix& a)
+{
+  int ar = a.rows ();
+  int ac = a.columns ();
+  Matrix t (ar, ac);
+  for (int j = 0; j < ac; j++)
+    for (int i = 0; i < ar; i++)
+      {
+	switch (op)
+	  {
+	  case Matrix_LT:
+	    t.elem (i,j) = real (s) < a.elem (i,j);
+	    break;
+	  case Matrix_LE:
+	    t.elem (i,j) = real (s) <= a.elem (i,j);
+	    break;
+	  case Matrix_EQ:
+	    t.elem (i,j) = s == a.elem (i,j);
+	    break;
+	  case Matrix_GE:
+	    t.elem (i,j) = real (s) >= a.elem (i,j);
+	    break;
+	  case Matrix_GT:
+	    t.elem (i,j) = real (s) > a.elem (i,j);
+	    break;
+	  case Matrix_NE:
+	    t.elem (i,j) = s != a.elem (i,j);
+	    break;
+	  case Matrix_AND:
+	    t.elem (i,j) = (s != 0.0) && a.elem (i,j);
+	    break;
+	  case Matrix_OR:
+	    t.elem (i,j) = (s != 0.0) || a.elem (i,j);
+	    break;
+	  default:
+	    panic_impossible ();
+	    break;
+	}
+    }
+  return t;
+}
+
+/* 8 */
+static Matrix
+mx_stupid_bool_op (Matrix_bool_op op, Complex& s, ComplexMatrix& a)
+{
+  int ar = a.rows ();
+  int ac = a.columns ();
+  Matrix t (ar, ac);
+  for (int j = 0; j < ac; j++)
+    for (int i = 0; i < ar; i++)
+      {
+	switch (op)
+	  {
+	  case Matrix_LT:
+	    t.elem (i,j) = real (s) < real (a.elem (i,j));
+	    break;
+	  case Matrix_LE:
+	    t.elem (i,j) = real (s) <= real (a.elem (i,j));
+	    break;
+	  case Matrix_EQ:
+	    t.elem (i,j) = s == a.elem (i,j);
+	    break;
+	  case Matrix_GE:
+	    t.elem (i,j) = real (s) >= real (a.elem (i,j));
+	    break;
+	  case Matrix_GT:
+	    t.elem (i,j) = real (s) > real (a.elem (i,j));
+	    break;
+	  case Matrix_NE:
+	    t.elem (i,j) = s != a.elem (i,j);
+	    break;
+	  case Matrix_AND:
+	    t.elem (i,j) = (s != 0.0) && (a.elem (i,j) != 0.0);
+	    break;
+	  case Matrix_OR:
+	    t.elem (i,j) = (s != 0.0) || (a.elem (i,j) != 0.0);
+	    break;
+	  default:
+	    panic_impossible ();
+	    break;
+	}
+    }
+  return t;
+}
+
+/* 9 */
+static Matrix
+mx_stupid_bool_op (Matrix_bool_op op, ComplexMatrix& a, double s)
+{
+  int ar = a.rows ();
+  int ac = a.columns ();
+  Matrix t (ar, ac);
+  for (int j = 0; j < ac; j++)
+    for (int i = 0; i < ar; i++)
+      {
+	switch (op)
+	  {
+	  case Matrix_LT:
+	    t.elem (i,j) = real (a.elem (i,j)) < s;
+	    break;
+	  case Matrix_LE:
+	    t.elem (i,j) = real (a.elem (i,j)) <= s;
+	    break;
+	  case Matrix_EQ:
+	    t.elem (i,j) = a.elem (i,j) == s;
+	    break;
+	  case Matrix_GE:
+	    t.elem (i,j) = real (a.elem (i,j)) >= s;
+	    break;
+	  case Matrix_GT:
+	    t.elem (i,j) = real (a.elem (i,j)) > s;
+	    break;
+	  case Matrix_NE:
+	    t.elem (i,j) = a.elem (i,j) != s;
+	    break;
+	  case Matrix_AND:
+	    t.elem (i,j) = (a.elem (i,j) != 0.0) && s;
+	    break;
+	  case Matrix_OR:
+	    t.elem (i,j) = (a.elem (i,j) != 0.0) || s;
+	    break;
+	  default:
+	    panic_impossible ();
+	    break;
+	}
+    }
+  return t;
+}
+
+/* 10 */
+static Matrix
+mx_stupid_bool_op (Matrix_bool_op op, ComplexMatrix& a, Complex& s)
+{
+  int ar = a.rows ();
+  int ac = a.columns ();
+  Matrix t (ar, ac);
+  for (int j = 0; j < ac; j++)
+    for (int i = 0; i < ar; i++)
+      {
+	switch (op)
+	  {
+	  case Matrix_LT:
+	    t.elem (i,j) = real (a.elem (i,j)) < real (s);
+	    break;
+	  case Matrix_LE:
+	    t.elem (i,j) = real (a.elem (i,j)) <= real (s);
+	    break;
+	  case Matrix_EQ:
+	    t.elem (i,j) = a.elem (i,j) == s;
+	    break;
+	  case Matrix_GE:
+	    t.elem (i,j) = real (a.elem (i,j)) >= real (s);
+	    break;
+	  case Matrix_GT:
+	    t.elem (i,j) = real (a.elem (i,j)) > real (s);
+	    break;
+	  case Matrix_NE:
+	    t.elem (i,j) = a.elem (i,j) != s;
+	    break;
+	  case Matrix_AND:
+	    t.elem (i,j) = (a.elem (i,j) != 0.0) && (s != 0.0);
+	    break;
+	  case Matrix_OR:
+	    t.elem (i,j) = (a.elem (i,j) != 0.0) || (s != 0.0);
+	    break;
+	  default:
+	    panic_impossible ();
+	    break;
+	}
+    }
+  return t;
+}
+
+/* 11 */
+static Matrix
+mx_stupid_bool_op (Matrix_bool_op op, ComplexMatrix& a, Matrix& b)
+{
+  int ar = a.rows ();
+  int ac = a.columns ();
+
+  if (ar != b.rows () || ac != b.columns ())
+    {
+      gripe_nonconformant ();
+      jump_to_top_level ();
+    }
+     
+  Matrix c (ar, ac);
+
+  for (int j = 0; j < ac; j++)
+    for (int i = 0; i < ar; i++)
+      {
+	switch (op)
+	  {
+	  case Matrix_LT:
+	    c.elem (i, j) = real (a.elem (i, j)) <  b.elem (i, j);
+	    break;
+	  case Matrix_LE:
+	    c.elem (i, j) = real (a.elem (i, j)) <= b.elem (i, j);
+	    break;
+	  case Matrix_EQ:
+	    c.elem (i, j) = a.elem (i, j) == b.elem (i, j);
+	    break;
+	  case Matrix_GE:
+	    c.elem (i, j) = real (a.elem (i, j)) >= b.elem (i, j);
+	    break;
+	  case Matrix_GT:
+	    c.elem (i, j) = real (a.elem (i, j)) >  b.elem (i, j);
+	    break;
+	  case Matrix_NE:
+	    c.elem (i, j) = a.elem (i, j) != b.elem (i, j);
+	    break;
+	  case Matrix_AND:
+	    c.elem (i, j) = (a.elem (i, j) != 0.0)  && b.elem (i, j);
+	    break;
+	  case Matrix_OR:
+	    c.elem (i, j) = (a.elem (i, j) != 0.0) || b.elem (i, j);
+	    break;
+	  default:
+	    panic_impossible ();
+	    break;
+	  }
+      }
+  return c;
+}
+
+/* 12 */
+static Matrix
+mx_stupid_bool_op (Matrix_bool_op op, ComplexMatrix& a, ComplexMatrix& b)
+{
+  int ar = a.rows ();
+  int ac = a.columns ();
+
+  if (ar != b.rows () || ac != b.columns ())
+    {
+      gripe_nonconformant ();
+      jump_to_top_level ();
+    }
+     
+  Matrix c (ar, ac);
+
+  for (int j = 0; j < ac; j++)
+    for (int i = 0; i < ar; i++)
+      {
+	switch (op)
+	  {
+	  case Matrix_LT:
+	    c.elem (i, j) = real (a.elem (i, j)) <  real (b.elem (i, j));
+	    break;
+	  case Matrix_LE:
+	    c.elem (i, j) = real (a.elem (i, j)) <= real (b.elem (i, j));
+	    break;
+	  case Matrix_EQ:
+	    c.elem (i, j) = a.elem (i, j) == b.elem (i, j);
+	    break;
+	  case Matrix_GE:
+	    c.elem (i, j) = real (a.elem (i, j)) >= real (b.elem (i, j));
+	    break;
+	  case Matrix_GT:
+	    c.elem (i, j) = real (a.elem (i, j)) >  real (b.elem (i, j));
+	    break;
+	  case Matrix_NE:
+	    c.elem (i, j) = a.elem (i, j) != b.elem (i, j);
+	    break;
+	  case Matrix_AND:
+	    c.elem (i, j) = (a.elem (i, j) != 0.0) && (b.elem (i, j) != 0.0);
+	    break;
+	  case Matrix_OR:
+	    c.elem (i, j) = (a.elem (i, j) != 0.0) || (b.elem (i, j) != 0.0);
+	    break;
+	  default:
+	    panic_impossible ();
+	    break;
+	  }
+      }
+  return c;
+}
+
+/*
+ * Check row and column dimensions for binary matrix operations.
+ */
+static inline int
+m_add_conform (Matrix& m1, Matrix& m2, int warn)
+{
+  int ok = (m1.rows () == m2.rows () && m1.columns () == m2.columns ());
+  if (!ok && warn)
+    gripe_nonconformant ();
+  return ok;
+}
+
+static inline int
+m_add_conform (Matrix& m1, ComplexMatrix& m2, int warn)
+{
+  int ok = (m1.rows () == m2.rows () && m1.columns () == m2.columns ());
+  if (!ok && warn)
+    gripe_nonconformant ();
+  return ok;
+}
+
+static inline int
+m_add_conform (ComplexMatrix& m1, Matrix& m2, int warn)
+{
+  int ok = (m1.rows () == m2.rows () && m1.columns () == m2.columns ());
+  if (!ok && warn)
+    gripe_nonconformant ();
+  return ok;
+}
+
+static inline int
+m_add_conform (ComplexMatrix& m1, ComplexMatrix& m2, int warn)
+{
+  int ok = (m1.rows () == m2.rows () && m1.columns () == m2.columns ());
+  if (!ok && warn)
+    gripe_nonconformant ();
+  return ok;
+}
+
+static inline int
+m_mul_conform (Matrix& m1, Matrix& m2, int warn)
+{
+  int ok = (m1.columns () == m2.rows ());
+  if (!ok && warn)
+    gripe_nonconformant ();
+  return ok;
+}
+
+static inline int
+m_mul_conform (Matrix& m1, ComplexMatrix& m2, int warn)
+{
+  int ok = (m1.columns () == m2.rows ());
+  if (!ok && warn)
+    gripe_nonconformant ();
+  return ok;
+}
+
+static inline int
+m_mul_conform (ComplexMatrix& m1, Matrix& m2, int warn)
+{
+  int ok = (m1.columns () == m2.rows ());
+  if (!ok && warn)
+    gripe_nonconformant ();
+  return ok;
+}
+
+static inline int
+m_mul_conform (ComplexMatrix& m1, ComplexMatrix& m2, int warn)
+{
+  int ok = (m1.columns () == m2.rows ());
+  if (!ok && warn)
+    gripe_nonconformant ();
+  return ok;
+}
+
+/*
+ * Unary operations.  One for each numeric data type:
+ *
+ *   scalar
+ *   complex_scalar
+ *   matrix
+ *   complex_matrix
+ *
+ */
+
+tree_constant
+do_unary_op (double d, tree::expression_type t)
+{
+  double result = 0.0;
+  switch (t)
+    {
+    case tree::not:
+      result = (! d);
+      break;
+    case tree::uminus:
+      result = -d;
+      break;
+    case tree::hermitian:
+    case tree::transpose:
+      result = d;
+      break;
+    default:
+      panic_impossible ();
+      break;
+    }
+
+  return tree_constant (result);
+}
+
+tree_constant
+do_unary_op (Matrix& a, tree::expression_type t)
+{
+  Matrix result;
+  switch (t)
+    {
+    case tree::not:
+      result = (! a);
+      break;
+    case tree::uminus:
+      result = -a;
+      break;
+    case tree::hermitian:
+    case tree::transpose:
+      result = a.transpose ();
+      break;
+    default:
+      panic_impossible ();
+      break;
+    }
+
+  return tree_constant (result);
+}
+
+tree_constant
+do_unary_op (Complex& c, tree::expression_type t)
+{
+  Complex result = 0.0;
+  switch (t)
+    {
+    case tree::not:
+      result = (c == 0.0);
+      break;
+    case tree::uminus:
+      result = -c;
+      break;
+    case tree::hermitian:
+      result = conj (c);
+      break;
+    case tree::transpose:
+      result = c;
+      break;
+    default:
+      panic_impossible ();
+      break;
+    }
+
+  return tree_constant (result);
+}
+
+tree_constant
+do_unary_op (ComplexMatrix& a, tree::expression_type t)
+{
+  ComplexMatrix result;
+  switch (t)
+    {
+    case tree::not:
+      result = (! a);
+      break;
+    case tree::uminus:
+      result = -a;
+      break;
+    case tree::hermitian:
+      result = a.hermitian ();
+      break;
+    case tree::transpose:
+      result = a.transpose ();
+      break;
+    default:
+      panic_impossible ();
+      break;
+    }
+
+  return tree_constant (result);
+}
+
+/*
+ * Binary operations.  One for each type combination, in the order
+ * given here:
+ *
+ *       op2 \ op1:   s   m   cs   cm
+ *            +--   +---+---+----+----+
+ *   scalar   |     | 1 | 5 | 9  | 13 |
+ *                  +---+---+----+----+
+ *   matrix         | 2 | 6 | 10 | 14 |
+ *                  +---+---+----+----+
+ *   complex_scalar | 3 | 7 | 11 | 15 |
+ *                  +---+---+----+----+
+ *   complex_matrix | 4 | 8 | 12 | 16 |
+ *                  +---+---+----+----+
+ */
+
+/* 1 */
+tree_constant
+do_binary_op (double a, double b, tree::expression_type t)
+{
+  double result = 0.0;
+  switch (t)
+    {
+    case tree::add:
+      result = a + b;
+      break;
+    case tree::subtract:
+      result = a - b;
+      break;
+    case tree::multiply:
+    case tree::el_mul:
+      result = a * b;
+      break;
+    case tree::divide:
+    case tree::el_div:
+      if (b == 0.0)
+	DIVIDE_BY_ZERO_ERROR;
+      result = a / b;
+      break;
+    case tree::leftdiv:
+    case tree::el_leftdiv:
+      if (a == 0.0)
+	DIVIDE_BY_ZERO_ERROR;
+      result = b / a;
+      break;
+    case tree::power:
+    case tree::elem_pow:
+      return xpow (a, b);
+      break;
+    case tree::cmp_lt:
+      result = a < b;
+      break;
+    case tree::cmp_le:
+      result = a <= b;
+      break;
+    case tree::cmp_eq:
+      result = a == b;
+      break;
+    case tree::cmp_ge:
+      result = a >= b;
+      break;
+    case tree::cmp_gt:
+      result = a > b;
+      break;
+    case tree::cmp_ne:
+      result = a != b;
+      break;
+    case tree::and:
+      result = (a && b);
+      break;
+    case tree::or:
+      result = (a || b);
+      break;
+    default:
+      panic_impossible ();
+      break;
+    }
+
+  return tree_constant (result);
+}
+
+/* 2 */
+tree_constant
+do_binary_op (double a, Matrix& b, tree::expression_type t)
+{
+  Matrix result;
+  switch (t)
+    {
+    case tree::add:
+      result = a + b;
+      break;
+    case tree::subtract:
+      result = a - b;
+      break;
+    case tree::el_leftdiv:
+    case tree::leftdiv:
+      if (a == 0.0)
+	DIVIDE_BY_ZERO_ERROR;
+      a = 1.0 / a;
+// fall through...
+    case tree::multiply:
+    case tree::el_mul:
+      result = a * b;
+      break;
+    case tree::el_div:
+      return x_el_div (a, b);
+      break;
+    case tree::divide:
+      error ("nonconformant right division");
+      return tree_constant ();
+      break;
+    case tree::power:
+      return xpow (a, b);
+      break;
+    case tree::elem_pow:
+      return elem_xpow (a, b);
+      break;
+    case tree::cmp_lt:
+      result = mx_stupid_bool_op (Matrix_LT, a, b);
+      break;
+    case tree::cmp_le:
+      result = mx_stupid_bool_op (Matrix_LE, a, b);
+      break;
+    case tree::cmp_eq:
+      result = mx_stupid_bool_op (Matrix_EQ, a, b);
+      break;
+    case tree::cmp_ge:
+      result = mx_stupid_bool_op (Matrix_GE, a, b);
+      break;
+    case tree::cmp_gt:
+      result = mx_stupid_bool_op (Matrix_GT, a, b);
+      break;
+    case tree::cmp_ne:
+      result = mx_stupid_bool_op (Matrix_NE, a, b);
+      break;
+    case tree::and:
+      result = mx_stupid_bool_op (Matrix_AND, a, b);
+      break;
+    case tree::or:
+      result = mx_stupid_bool_op (Matrix_OR, a, b);
+      break;
+    default:
+      panic_impossible ();
+      break;
+    }
+
+  return tree_constant (result);
+}
+
+/* 3 */
+tree_constant
+do_binary_op (double a, Complex& b, tree::expression_type t)
+{
+  enum RT { RT_unknown, RT_real, RT_complex };
+  RT result_type = RT_unknown;
+
+  double result = 0.0;
+  Complex complex_result;
+  switch (t)
+    {
+    case tree::add:
+      result_type = RT_complex;
+      complex_result = a + b;
+      break;
+    case tree::subtract:
+      result_type = RT_complex;
+      complex_result = a - b;
+      break;
+    case tree::multiply:
+    case tree::el_mul:
+      result_type = RT_complex;
+      complex_result = a * b;
+      break;
+    case tree::divide:
+    case tree::el_div:
+      result_type = RT_complex;
+      if (b == 0.0)
+	DIVIDE_BY_ZERO_ERROR;
+      complex_result = a / b;
+      break;
+    case tree::leftdiv:
+    case tree::el_leftdiv:
+      result_type = RT_complex;
+      if (a == 0.0)
+	DIVIDE_BY_ZERO_ERROR;
+      complex_result = b / a;
+      break;
+    case tree::power:
+    case tree::elem_pow:
+      return xpow (a, b);
+      break;
+    case tree::cmp_lt:
+      result_type = RT_real;
+      result = a < real (b);
+      break;
+    case tree::cmp_le:
+      result_type = RT_real;
+      result = a <= real (b);
+      break;
+    case tree::cmp_eq:
+      result_type = RT_real;
+      result = a == b;
+      break;
+    case tree::cmp_ge:
+      result_type = RT_real;
+      result = a >= real (b);
+      break;
+    case tree::cmp_gt:
+      result_type = RT_real;
+      result = a > real (b);
+      break;
+    case tree::cmp_ne:
+      result_type = RT_real;
+      result = a != b;
+      break;
+    case tree::and:
+      result_type = RT_real;
+      result = (a && (b != 0.0));
+      break;
+    case tree::or:
+      result_type = RT_real;
+      result = (a || (b != 0.0));
+      break;
+    default:
+      panic_impossible ();
+      break;
+    }
+
+  assert (result_type != RT_unknown);
+  if (result_type == RT_real)
+    return tree_constant (result);
+  else
+    return tree_constant (complex_result);
+}
+
+/* 4 */
+tree_constant
+do_binary_op (double a, ComplexMatrix& b, tree::expression_type t)
+{
+  enum RT { RT_unknown, RT_real, RT_complex };
+  RT result_type = RT_unknown;
+
+  Matrix result;
+  ComplexMatrix complex_result;
+  switch (t)
+    {
+    case tree::add:
+      result_type = RT_complex;
+      complex_result = a + b;
+      break;
+    case tree::subtract:
+      result_type = RT_complex;
+      complex_result = a - b;
+      break;
+    case tree::el_leftdiv:
+    case tree::leftdiv:
+      if (a == 0.0)
+	DIVIDE_BY_ZERO_ERROR;
+      a = 1.0 / a;
+// fall through...
+    case tree::multiply:
+    case tree::el_mul:
+      result_type = RT_complex;
+      complex_result = a * b;
+      break;
+    case tree::el_div:
+      return x_el_div (a, b);
+      break;
+    case tree::divide:
+      error ("nonconformant right division");
+      return tree_constant ();
+      break;
+    case tree::power:
+      return xpow (a, b);
+      break;
+    case tree::elem_pow:
+      return elem_xpow (a, b);
+      break;
+    case tree::cmp_lt:
+      result_type = RT_real;
+      result = mx_stupid_bool_op (Matrix_LT, a, b);
+      break;
+    case tree::cmp_le:
+      result_type = RT_real;
+      result = mx_stupid_bool_op (Matrix_LE, a, b);
+      break;
+    case tree::cmp_eq:
+      result_type = RT_real;
+      result = mx_stupid_bool_op (Matrix_EQ, a, b);
+      break;
+    case tree::cmp_ge:
+      result_type = RT_real;
+      result = mx_stupid_bool_op (Matrix_GE, a, b);
+      break;
+    case tree::cmp_gt:
+      result_type = RT_real;
+      result = mx_stupid_bool_op (Matrix_GT, a, b);
+      break;
+    case tree::cmp_ne:
+      result_type = RT_real;
+      result = mx_stupid_bool_op (Matrix_NE, a, b);
+      break;
+    case tree::and:
+      result_type = RT_real;
+      result = mx_stupid_bool_op (Matrix_AND, a, b);
+      break;
+    case tree::or:
+      result_type = RT_real;
+      result = mx_stupid_bool_op (Matrix_OR, a, b);
+      break;
+    default:
+      panic_impossible ();
+      break;
+    }
+
+  assert (result_type != RT_unknown);
+  if (result_type == RT_real)
+    return tree_constant (result);
+  else
+    return tree_constant (complex_result);
+}
+
+/* 5 */
+tree_constant
+do_binary_op (Matrix& a, double b, tree::expression_type t)
+{
+  Matrix result;
+  switch (t)
+    {
+    case tree::add:
+      result = a + b;
+      break;
+    case tree::subtract:
+      result = a - b;
+      break;
+    case tree::multiply:
+    case tree::el_mul:
+      result = a * b;
+      break;
+    case tree::divide:
+    case tree::el_div:
+      result = a / b;
+      break;
+    case tree::el_leftdiv:
+      return x_el_div (b, a);
+      break;
+    case tree::leftdiv:
+      error ("nonconformant left division");
+      return tree_constant ();
+      break;
+    case tree::power:
+      return xpow (a, b);
+      break;
+    case tree::elem_pow:
+      return elem_xpow (a, b);
+      break;
+    case tree::cmp_lt:
+      result = mx_stupid_bool_op (Matrix_LT, a, b);
+      break;
+    case tree::cmp_le:
+      result = mx_stupid_bool_op (Matrix_LE, a, b);
+      break;
+    case tree::cmp_eq:
+      result = mx_stupid_bool_op (Matrix_EQ, a, b);
+      break;
+    case tree::cmp_ge:
+      result = mx_stupid_bool_op (Matrix_GE, a, b);
+      break;
+    case tree::cmp_gt:
+      result = mx_stupid_bool_op (Matrix_GT, a, b);
+      break;
+    case tree::cmp_ne:
+      result = mx_stupid_bool_op (Matrix_NE, a, b);
+      break;
+    case tree::and:
+      result = mx_stupid_bool_op (Matrix_AND, a, b);
+      break;
+    case tree::or:
+      result = mx_stupid_bool_op (Matrix_OR, a, b);
+      break;
+    default:
+      panic_impossible ();
+      break;
+    }
+
+  return tree_constant (result);
+}
+
+/* 6 */
+tree_constant
+do_binary_op (Matrix& a, Matrix& b, tree::expression_type t)
+{
+  Matrix result;
+
+  int error_cond = 0;
+
+  switch (t)
+    {
+    case tree::add:
+      if (m_add_conform (a, b, 1))
+	result = a + b;
+      else
+	error_cond = 1;
+      break;
+    case tree::subtract:
+      if (m_add_conform (a, b, 1))
+	result = a - b;
+      else
+	error_cond = 1;
+      break;
+    case tree::el_mul:
+      if (m_add_conform (a, b, 1))
+	result = a.product (b);
+      else
+	error_cond = 1;
+      break;
+    case tree::multiply:
+      if (m_mul_conform (a, b, 1))
+	result = a * b;
+      else
+	error_cond = 1;
+      break;
+    case tree::el_div:
+      if (m_add_conform (a, b, 1))
+	result = a.quotient (b);
+      else
+	error_cond = 1;
+      break;
+    case tree::el_leftdiv:
+      if (m_add_conform (a, b, 1))
+	result = b.quotient (a);
+      else
+	error_cond = 1;
+      break;
+    case tree::leftdiv:
+      return xleftdiv (a, b);
+      break;
+    case tree::divide:
+      return xdiv (a, b);
+      break;
+    case tree::power:
+      error ("can't do A ^ B for A and B both matrices");
+      error_cond = 1;
+      break;
+    case tree::elem_pow:
+      if (m_add_conform (a, b, 1))
+	return elem_xpow (a, b);
+      else
+	error_cond = 1;
+      break;
+    case tree::cmp_lt:
+      if (m_add_conform (a, b, 1))
+	result = mx_stupid_bool_op (Matrix_LT, a, b);
+      else
+	error_cond = 1;
+      break;
+    case tree::cmp_le:
+      if (m_add_conform (a, b, 1))
+	result = mx_stupid_bool_op (Matrix_LE, a, b);
+      else
+	error_cond = 1;
+      break;
+    case tree::cmp_eq:
+      if (m_add_conform (a, b, 1))
+	result = mx_stupid_bool_op (Matrix_EQ, a, b);
+      else
+	error_cond = 1;
+      break;
+    case tree::cmp_ge:
+      if (m_add_conform (a, b, 1))
+	result = mx_stupid_bool_op (Matrix_GE, a, b);
+      else
+	error_cond = 1;
+      break;
+    case tree::cmp_gt:
+      if (m_add_conform (a, b, 1))
+	result = mx_stupid_bool_op (Matrix_GT, a, b);
+      else
+	error_cond = 1;
+      break;
+    case tree::cmp_ne:
+      if (m_add_conform (a, b, 1))
+	result = mx_stupid_bool_op (Matrix_NE, a, b);
+      else
+	error_cond = 1;
+      break;
+    case tree::and:
+      if (m_add_conform (a, b, 1))
+	result = mx_stupid_bool_op (Matrix_AND, a, b);
+      else
+	error_cond = 1;
+      break;
+    case tree::or:
+      if (m_add_conform (a, b, 1))
+	result = mx_stupid_bool_op (Matrix_OR, a, b);
+      else
+	error_cond = 1;
+      break;
+    default:
+      panic_impossible ();
+      break;
+    }
+
+  if (error_cond)
+    return tree_constant ();
+  else
+    return tree_constant (result);
+}
+
+/* 7 */
+tree_constant
+do_binary_op (Matrix& a, Complex& b, tree::expression_type t)
+{
+  enum RT { RT_unknown, RT_real, RT_complex };
+  RT result_type = RT_unknown;
+
+  Matrix result;
+  ComplexMatrix complex_result;
+  switch (t)
+    {
+    case tree::add:
+      result_type = RT_complex;
+      complex_result = a + b;
+      break;
+    case tree::subtract:
+      result_type = RT_complex;
+      complex_result = a - b;
+      break;
+    case tree::multiply:
+    case tree::el_mul:
+      result_type = RT_complex;
+      complex_result = a * b;
+      break;
+    case tree::divide:
+    case tree::el_div:
+      result_type = RT_complex;
+      complex_result = a / b;
+      break;
+    case tree::el_leftdiv:
+      return x_el_div (b, a);
+      break;
+    case tree::leftdiv:
+      error ("nonconformant left division");
+      return tree_constant ();
+      break;
+    case tree::power:
+      return xpow (a, b);
+      break;
+    case tree::elem_pow:
+      return elem_xpow (a, b);
+      break;
+    case tree::cmp_lt:
+      result_type = RT_real;
+      result = mx_stupid_bool_op (Matrix_LT, a, b);
+      break;
+    case tree::cmp_le:
+      result_type = RT_real;
+      result = mx_stupid_bool_op (Matrix_LE, a, b);
+      break;
+    case tree::cmp_eq:
+      result_type = RT_real;
+      result = mx_stupid_bool_op (Matrix_EQ, a, b);
+      break;
+    case tree::cmp_ge:
+      result_type = RT_real;
+      result = mx_stupid_bool_op (Matrix_GE, a, b);
+      break;
+    case tree::cmp_gt:
+      result_type = RT_real;
+      result = mx_stupid_bool_op (Matrix_GT, a, b);
+      break;
+    case tree::cmp_ne:
+      result_type = RT_real;
+      result = mx_stupid_bool_op (Matrix_NE, a, b);
+      break;
+    case tree::and:
+      result_type = RT_real;
+      result = mx_stupid_bool_op (Matrix_AND, a, b);
+      break;
+    case tree::or:
+      result_type = RT_real;
+      result = mx_stupid_bool_op (Matrix_OR, a, b);
+      break;
+    default:
+      panic_impossible ();
+      break;
+    }
+
+  assert (result_type != RT_unknown);
+  if (result_type == RT_real)
+    return tree_constant (result);
+  else
+    return tree_constant (complex_result);
+}
+
+/* 8 */
+tree_constant
+do_binary_op (Matrix& a, ComplexMatrix& b, tree::expression_type t)
+{
+  enum RT { RT_unknown, RT_real, RT_complex };
+  RT result_type = RT_unknown;
+
+  Matrix result;
+  ComplexMatrix complex_result;
+  switch (t)
+    {
+    case tree::add:
+      result_type = RT_complex;
+      if (m_add_conform (a, b, 1))
+	complex_result = a + b;
+      else
+	return tree_constant ();
+      break;
+    case tree::subtract:
+      result_type = RT_complex;
+      if (m_add_conform (a, b, 1))
+	complex_result = a - b;
+      else
+	return tree_constant ();
+      break;
+    case tree::el_mul:
+      result_type = RT_complex;
+      if (m_add_conform (a, b, 1))
+	complex_result = a.product (b);
+      else
+	return tree_constant ();
+      break;
+    case tree::multiply:
+      result_type = RT_complex;
+      if (m_mul_conform (a, b, 1))
+	complex_result = a * b;
+      else
+	return tree_constant ();
+      break;
+    case tree::el_div:
+      result_type = RT_complex;
+      if (m_add_conform (a, b, 1))
+	complex_result = a.quotient (b);
+      else
+	return tree_constant ();
+      break;
+    case tree::el_leftdiv:
+      result_type = RT_complex;
+      if (m_add_conform (a, b, 1))
+	complex_result = b.quotient (a);
+      else
+	return tree_constant ();
+      break;
+    case tree::leftdiv:
+      return xleftdiv (a, b);
+      break;
+    case tree::divide:
+      return xdiv (a, b);
+      break;
+    case tree::power:
+      error ("can't do A ^ B for A and B both matrices");
+      return tree_constant ();
+      break;
+    case tree::elem_pow:
+      if (m_add_conform (a, b, 1))
+	return elem_xpow (a, b);
+      else
+	return tree_constant ();
+      break;
+    case tree::cmp_lt:
+      result_type = RT_real;
+      if (m_add_conform (a, b, 1))
+	result = mx_stupid_bool_op (Matrix_LT, a, b);
+      else
+	return tree_constant ();
+      break;
+    case tree::cmp_le:
+      result_type = RT_real;
+      if (m_add_conform (a, b, 1))
+	result = mx_stupid_bool_op (Matrix_LE, a, b);
+      else
+	return tree_constant ();
+      break;
+    case tree::cmp_eq:
+      result_type = RT_real;
+      if (m_add_conform (a, b, 1))
+	result = mx_stupid_bool_op (Matrix_EQ, a, b);
+      else
+	return tree_constant ();
+      break;
+    case tree::cmp_ge:
+      result_type = RT_real;
+      if (m_add_conform (a, b, 1))
+	result = mx_stupid_bool_op (Matrix_GE, a, b);
+      else
+	return tree_constant ();
+      break;
+    case tree::cmp_gt:
+      result_type = RT_real;
+      if (m_add_conform (a, b, 1))
+	result = mx_stupid_bool_op (Matrix_GT, a, b);
+      else
+	return tree_constant ();
+      break;
+    case tree::cmp_ne:
+      result_type = RT_real;
+      if (m_add_conform (a, b, 1))
+	result = mx_stupid_bool_op (Matrix_NE, a, b);
+      else
+	return tree_constant ();
+      break;
+    case tree::and:
+      result_type = RT_real;
+      if (m_add_conform (a, b, 1))
+	result = mx_stupid_bool_op (Matrix_AND, a, b);
+      else
+	return tree_constant ();
+      break;
+    case tree::or:
+      result_type = RT_real;
+      if (m_add_conform (a, b, 1))
+	result = mx_stupid_bool_op (Matrix_OR, a, b);
+      else
+	return tree_constant ();
+      break;
+    default:
+      panic_impossible ();
+      break;
+    }
+
+  assert (result_type != RT_unknown);
+  if (result_type == RT_real)
+    return tree_constant (result);
+  else
+    return tree_constant (complex_result);
+}
+
+/* 9 */
+tree_constant
+do_binary_op (Complex& a, double b, tree::expression_type t)
+{
+  enum RT { RT_unknown, RT_real, RT_complex };
+  RT result_type = RT_unknown;
+
+  double result = 0.0;
+  Complex complex_result;
+  switch (t)
+    {
+    case tree::add:
+      result_type = RT_complex;
+      complex_result = a + b;
+      break;
+    case tree::subtract:
+      result_type = RT_complex;
+      complex_result = a - b;
+      break;
+    case tree::multiply:
+    case tree::el_mul:
+      result_type = RT_complex;
+      complex_result = a * b;
+      break;
+    case tree::divide:
+    case tree::el_div:
+      result_type = RT_complex;
+      if (b == 0.0)
+	DIVIDE_BY_ZERO_ERROR;
+      complex_result = a / b;
+      break;
+    case tree::leftdiv:
+    case tree::el_leftdiv:
+      result_type = RT_complex;
+      if (a == 0.0)
+	DIVIDE_BY_ZERO_ERROR;
+      complex_result = b / a;
+      break;
+    case tree::power:
+    case tree::elem_pow:
+      return xpow (a, b);
+      break;
+    case tree::cmp_lt:
+      result_type = RT_real;
+      result = real (a) < b;
+      break;
+    case tree::cmp_le:
+      result_type = RT_real;
+      result = real (a) <= b;
+      break;
+    case tree::cmp_eq:
+      result_type = RT_real;
+      result = a == b;
+      break;
+    case tree::cmp_ge:
+      result_type = RT_real;
+      result = real (a) >= b;
+      break;
+    case tree::cmp_gt:
+      result_type = RT_real;
+      result = real (a) > b;
+      break;
+    case tree::cmp_ne:
+      result_type = RT_real;
+      result = a != b;
+      break;
+    case tree::and:
+      result_type = RT_real;
+      result = ((a != 0.0) && b);
+      break;
+    case tree::or:
+      result_type = RT_real;
+      result = ((a != 0.0) || b);
+      break;
+    default:
+      panic_impossible ();
+      break;
+    }
+
+  assert (result_type != RT_unknown);
+  if (result_type == RT_real)
+    return tree_constant (result);
+  else
+    return tree_constant (complex_result);
+}
+
+/* 10 */
+tree_constant
+do_binary_op (Complex& a, Matrix& b, tree::expression_type t)
+{
+  enum RT { RT_unknown, RT_real, RT_complex };
+  RT result_type = RT_unknown;
+
+  Matrix result;
+  ComplexMatrix complex_result;
+  switch (t)
+    {
+    case tree::add:
+      result_type = RT_complex;
+      complex_result = a + b;
+      break;
+    case tree::subtract:
+      result_type = RT_complex;
+      complex_result = a - b;
+      break;
+    case tree::el_leftdiv:
+    case tree::leftdiv:
+      if (a == 0.0)
+	DIVIDE_BY_ZERO_ERROR;
+      a = 1.0 / a;
+// fall through...
+    case tree::multiply:
+    case tree::el_mul:
+      result_type = RT_complex;
+      complex_result = a * b;
+      break;
+    case tree::el_div:
+      return x_el_div (a, b);
+      break;
+    case tree::divide:
+      error ("nonconformant right division");
+      return tree_constant ();
+      break;
+    case tree::power:
+      return xpow (a, b);
+      break;
+    case tree::elem_pow:
+      return elem_xpow (a, b);
+      break;
+    case tree::cmp_lt:
+      result_type = RT_real;
+      result = mx_stupid_bool_op (Matrix_LT, a, b);
+      break;
+    case tree::cmp_le:
+      result_type = RT_real;
+      result = mx_stupid_bool_op (Matrix_LE, a, b);
+      break;
+    case tree::cmp_eq:
+      result_type = RT_real;
+      result = mx_stupid_bool_op (Matrix_EQ, a, b);
+      break;
+    case tree::cmp_ge:
+      result_type = RT_real;
+      result = mx_stupid_bool_op (Matrix_GE, a, b);
+      break;
+    case tree::cmp_gt:
+      result_type = RT_real;
+      result = mx_stupid_bool_op (Matrix_GT, a, b);
+      break;
+    case tree::cmp_ne:
+      result_type = RT_real;
+      result = mx_stupid_bool_op (Matrix_NE, a, b);
+      break;
+    case tree::and:
+      result_type = RT_real;
+      result = mx_stupid_bool_op (Matrix_AND, a, b);
+      break;
+    case tree::or:
+      result_type = RT_real;
+      result = mx_stupid_bool_op (Matrix_OR, a, b);
+      break;
+    default:
+      panic_impossible ();
+      break;
+    }
+
+  assert (result_type != RT_unknown);
+  if (result_type == RT_real)
+    return tree_constant (result);
+  else
+    return tree_constant (complex_result);
+}
+
+/* 11 */
+tree_constant
+do_binary_op (Complex& a, Complex& b, tree::expression_type t)
+{
+  enum RT { RT_unknown, RT_real, RT_complex };
+  RT result_type = RT_unknown;
+
+  double result = 0.0;
+  Complex complex_result;
+  switch (t)
+    {
+    case tree::add:
+      result_type = RT_complex;
+      complex_result = a + b;
+      break;
+    case tree::subtract:
+      result_type = RT_complex;
+      complex_result = a - b;
+      break;
+    case tree::multiply:
+    case tree::el_mul:
+      result_type = RT_complex;
+      complex_result = a * b;
+      break;
+    case tree::divide:
+    case tree::el_div:
+      result_type = RT_complex;
+      if (b == 0.0)
+	DIVIDE_BY_ZERO_ERROR;
+      complex_result = a / b;
+      break;
+    case tree::leftdiv:
+    case tree::el_leftdiv:
+      result_type = RT_complex;
+      if (a == 0.0)
+	DIVIDE_BY_ZERO_ERROR;
+      complex_result = b / a;
+      break;
+    case tree::power:
+    case tree::elem_pow:
+      return xpow (a, b);
+      break;
+    case tree::cmp_lt:
+      result_type = RT_real;
+      result = real (a) < real (b);
+      break;
+    case tree::cmp_le:
+      result_type = RT_real;
+      result = real (a) <= real (b);
+      break;
+    case tree::cmp_eq:
+      result_type = RT_real;
+      result = a == b;
+      break;
+    case tree::cmp_ge:
+      result_type = RT_real;
+      result = real (a) >= real (b);
+      break;
+    case tree::cmp_gt:
+      result_type = RT_real;
+      result = real (a) > real (b);
+      break;
+    case tree::cmp_ne:
+      result_type = RT_real;
+      result = a != b;
+      break;
+    case tree::and:
+      result_type = RT_real;
+      result = ((a != 0.0) && (b != 0.0));
+      break;
+    case tree::or:
+      result_type = RT_real;
+      result = ((a != 0.0) || (b != 0.0));
+      break;
+    default:
+      panic_impossible ();
+      break;
+    }
+
+  assert (result_type != RT_unknown);
+  if (result_type == RT_real)
+    return tree_constant (result);
+  else
+    return tree_constant (complex_result);
+}
+
+/* 12 */
+tree_constant
+do_binary_op (Complex& a, ComplexMatrix& b, tree::expression_type t)
+{
+  enum RT { RT_unknown, RT_real, RT_complex };
+  RT result_type = RT_unknown;
+
+  Matrix result;
+  ComplexMatrix complex_result;
+  switch (t)
+    {
+    case tree::add:
+      result_type = RT_complex;
+      complex_result = a + b;
+      break;
+    case tree::subtract:
+      result_type = RT_complex;
+      complex_result = a - b;
+      break;
+    case tree::el_leftdiv:
+    case tree::leftdiv:
+      if (a == 0.0)
+	DIVIDE_BY_ZERO_ERROR;
+      a = 1.0 / a;
+// fall through...
+    case tree::multiply:
+    case tree::el_mul:
+      result_type = RT_complex;
+      complex_result = a * b;
+      break;
+    case tree::el_div:
+      return x_el_div (a, b);
+      break;
+    case tree::divide:
+      error ("nonconformant right division");
+      return tree_constant ();
+      break;
+    case tree::power:
+      return xpow (a, b);
+      break;
+    case tree::elem_pow:
+      return elem_xpow (a, b);
+      break;
+    case tree::cmp_lt:
+      result_type = RT_real;
+      result = mx_stupid_bool_op (Matrix_LT, a, b);
+      break;
+    case tree::cmp_le:
+      result_type = RT_real;
+      result = mx_stupid_bool_op (Matrix_LE, a, b);
+      break;
+    case tree::cmp_eq:
+      result_type = RT_real;
+      result = mx_stupid_bool_op (Matrix_EQ, a, b);
+      break;
+    case tree::cmp_ge:
+      result_type = RT_real;
+      result = mx_stupid_bool_op (Matrix_GE, a, b);
+      break;
+    case tree::cmp_gt:
+      result_type = RT_real;
+      result = mx_stupid_bool_op (Matrix_GT, a, b);
+      break;
+    case tree::cmp_ne:
+      result_type = RT_real;
+      result = mx_stupid_bool_op (Matrix_NE, a, b);
+      break;
+    case tree::and:
+      result_type = RT_real;
+      result = mx_stupid_bool_op (Matrix_AND, a, b);
+      break;
+    case tree::or:
+      result_type = RT_real;
+      result = mx_stupid_bool_op (Matrix_OR, a, b);
+      break;
+    default:
+      panic_impossible ();
+      break;
+    }
+
+  assert (result_type != RT_unknown);
+  if (result_type == RT_real)
+    return tree_constant (result);
+  else
+    return tree_constant (complex_result);
+}
+
+/* 13 */
+tree_constant
+do_binary_op (ComplexMatrix& a, double b, tree::expression_type t)
+{
+  enum RT { RT_unknown, RT_real, RT_complex };
+  RT result_type = RT_unknown;
+
+  Matrix result;
+  ComplexMatrix complex_result;
+  switch (t)
+    {
+    case tree::add:
+      result_type = RT_complex;
+      complex_result = a + b;
+      break;
+    case tree::subtract:
+      result_type = RT_complex;
+      complex_result = a - b;
+      break;
+    case tree::multiply:
+    case tree::el_mul:
+      result_type = RT_complex;
+      complex_result = a * b;
+      break;
+    case tree::divide:
+    case tree::el_div:
+      result_type = RT_complex;
+      complex_result = a / b;
+      break;
+    case tree::el_leftdiv:
+      return x_el_div (b, a);
+      break;
+    case tree::leftdiv:
+      error ("nonconformant left division");
+      return tree_constant ();
+      break;
+    case tree::power:
+      return xpow (a, b);
+      break;
+    case tree::elem_pow:
+      return elem_xpow (a, b);
+      break;
+    case tree::cmp_lt:
+      result_type = RT_real;
+      result = mx_stupid_bool_op (Matrix_LT, a, b);
+      break;
+    case tree::cmp_le:
+      result_type = RT_real;
+      result = mx_stupid_bool_op (Matrix_LE, a, b);
+      break;
+    case tree::cmp_eq:
+      result_type = RT_real;
+      result = mx_stupid_bool_op (Matrix_EQ, a, b);
+      break;
+    case tree::cmp_ge:
+      result_type = RT_real;
+      result = mx_stupid_bool_op (Matrix_GE, a, b);
+      break;
+    case tree::cmp_gt:
+      result_type = RT_real;
+      result = mx_stupid_bool_op (Matrix_GT, a, b);
+      break;
+    case tree::cmp_ne:
+      result_type = RT_real;
+      result = mx_stupid_bool_op (Matrix_NE, a, b);
+      break;
+    case tree::and:
+      result_type = RT_real;
+      result = mx_stupid_bool_op (Matrix_AND, a, b);
+      break;
+    case tree::or:
+      result_type = RT_real;
+      result = mx_stupid_bool_op (Matrix_OR, a, b);
+      break;
+    default:
+      panic_impossible ();
+      break;
+    }
+
+  assert (result_type != RT_unknown);
+  if (result_type == RT_real)
+    return tree_constant (result);
+  else
+    return tree_constant (complex_result);
+}
+
+/* 14 */
+tree_constant
+do_binary_op (ComplexMatrix& a, Matrix& b, tree::expression_type t)
+{
+  enum RT { RT_unknown, RT_real, RT_complex };
+  RT result_type = RT_unknown;
+
+  Matrix result;
+  ComplexMatrix complex_result;
+  switch (t)
+    {
+    case tree::add:
+      result_type = RT_complex;
+      if (m_add_conform (a, b, 1))
+	complex_result = a + b;
+      else
+	return tree_constant ();
+      break;
+    case tree::subtract:
+      result_type = RT_complex;
+      if (m_add_conform (a, b, 1))
+	complex_result = a - b;
+      else
+	return tree_constant ();
+      break;
+    case tree::el_mul:
+      result_type = RT_complex;
+      if (m_add_conform (a, b, 1))
+	complex_result = a.product (b);
+      else
+	return tree_constant ();
+      break;
+    case tree::multiply:
+      result_type = RT_complex;
+      if (m_mul_conform (a, b, 1))
+	complex_result = a * b;
+      else
+	return tree_constant ();
+      break;
+    case tree::el_div:
+      result_type = RT_complex;
+      if (m_add_conform (a, b, 1))
+	complex_result = a.quotient (b);
+      else
+	return tree_constant ();
+      break;
+    case tree::el_leftdiv:
+      result_type = RT_complex;
+      if (m_add_conform (a, b, 1))
+	complex_result = a.quotient (b);
+      else
+	return tree_constant ();
+      break;
+    case tree::leftdiv:
+      return xleftdiv (a, b);
+      break;
+    case tree::divide:
+      return xdiv (a, b);
+      break;
+    case tree::power:
+      error ("can't do A ^ B for A and B both matrices");
+      return tree_constant ();
+      break;
+    case tree::elem_pow:
+      if (m_add_conform (a, b, 1))
+	return elem_xpow (a, b);
+      else
+	return tree_constant ();
+      break;
+    case tree::cmp_lt:
+      result_type = RT_real;
+      if (m_add_conform (a, b, 1))
+	result = mx_stupid_bool_op (Matrix_LT, a, b);
+      else
+	return tree_constant ();
+      break;
+    case tree::cmp_le:
+      result_type = RT_real;
+      if (m_add_conform (a, b, 1))
+	result = mx_stupid_bool_op (Matrix_LE, a, b);
+      else
+	return tree_constant ();
+      break;
+    case tree::cmp_eq:
+      result_type = RT_real;
+      if (m_add_conform (a, b, 1))
+	result = mx_stupid_bool_op (Matrix_EQ, a, b);
+      else
+	return tree_constant ();
+      break;
+    case tree::cmp_ge:
+      result_type = RT_real;
+      if (m_add_conform (a, b, 1))
+	result = mx_stupid_bool_op (Matrix_GE, a, b);
+      else
+	return tree_constant ();
+      break;
+    case tree::cmp_gt:
+      result_type = RT_real;
+      if (m_add_conform (a, b, 1))
+	result = mx_stupid_bool_op (Matrix_GT, a, b);
+      else
+	return tree_constant ();
+      break;
+    case tree::cmp_ne:
+      result_type = RT_real;
+      if (m_add_conform (a, b, 1))
+	result = mx_stupid_bool_op (Matrix_NE, a, b);
+      else
+	return tree_constant ();
+      break;
+    case tree::and:
+      result_type = RT_real;
+      if (m_add_conform (a, b, 1))
+	result = mx_stupid_bool_op (Matrix_AND, a, b);
+      else
+	return tree_constant ();
+      break;
+    case tree::or:
+      result_type = RT_real;
+      if (m_add_conform (a, b, 1))
+	result = mx_stupid_bool_op (Matrix_OR, a, b);
+      else
+	return tree_constant ();
+      break;
+    default:
+      panic_impossible ();
+      break;
+    }
+
+  assert (result_type != RT_unknown);
+  if (result_type == RT_real)
+    return tree_constant (result);
+  else
+    return tree_constant (complex_result);
+}
+
+/* 15 */
+tree_constant
+do_binary_op (ComplexMatrix& a, Complex& b, tree::expression_type t)
+{
+  enum RT { RT_unknown, RT_real, RT_complex };
+  RT result_type = RT_unknown;
+
+  Matrix result;
+  ComplexMatrix complex_result;
+  switch (t)
+    {
+    case tree::add:
+      result_type = RT_complex;
+      complex_result = a + b;
+      break;
+    case tree::subtract:
+      result_type = RT_complex;
+      complex_result = a - b;
+      break;
+    case tree::multiply:
+    case tree::el_mul:
+      result_type = RT_complex;
+      complex_result = a * b;
+      break;
+    case tree::divide:
+    case tree::el_div:
+      result_type = RT_complex;
+      complex_result = a / b;
+      break;
+    case tree::el_leftdiv:
+      return x_el_div (b, a);
+      break;
+    case tree::leftdiv:
+      error ("nonconformant left division");
+      return tree_constant ();
+      break;
+    case tree::power:
+      return xpow (a, b);
+      break;
+    case tree::elem_pow:
+      return elem_xpow (a, b);
+      break;
+    case tree::cmp_lt:
+      result_type = RT_real;
+      result = mx_stupid_bool_op (Matrix_LT, a, b);
+      break;
+    case tree::cmp_le:
+      result_type = RT_real;
+      result = mx_stupid_bool_op (Matrix_LE, a, b);
+      break;
+    case tree::cmp_eq:
+      result_type = RT_real;
+      result = mx_stupid_bool_op (Matrix_EQ, a, b);
+      break;
+    case tree::cmp_ge:
+      result_type = RT_real;
+      result = mx_stupid_bool_op (Matrix_GE, a, b);
+      break;
+    case tree::cmp_gt:
+      result_type = RT_real;
+      result = mx_stupid_bool_op (Matrix_GT, a, b);
+      break;
+    case tree::cmp_ne:
+      result_type = RT_real;
+      result = mx_stupid_bool_op (Matrix_NE, a, b);
+      break;
+    case tree::and:
+      result_type = RT_real;
+      result = mx_stupid_bool_op (Matrix_AND, a, b);
+      break;
+    case tree::or:
+      result_type = RT_real;
+      result = mx_stupid_bool_op (Matrix_OR, a, b);
+      break;
+    default:
+      panic_impossible ();
+      break;
+    }
+
+  assert (result_type != RT_unknown);
+  if (result_type == RT_real)
+    return tree_constant (result);
+  else
+    return tree_constant (complex_result);
+}
+
+/* 16 */
+tree_constant
+do_binary_op (ComplexMatrix& a, ComplexMatrix& b, tree::expression_type t)
+{
+  enum RT { RT_unknown, RT_real, RT_complex };
+  RT result_type = RT_unknown;
+
+  Matrix result;
+  ComplexMatrix complex_result;
+  switch (t)
+    {
+    case tree::add:
+      result_type = RT_complex;
+      if (m_add_conform (a, b, 1))
+	complex_result = a + b;
+      else
+	return tree_constant ();
+      break;
+    case tree::subtract:
+      result_type = RT_complex;
+      if (m_add_conform (a, b, 1))
+	complex_result = a - b;
+      else
+	return tree_constant ();
+      break;
+    case tree::el_mul:
+      result_type = RT_complex;
+      if (m_add_conform (a, b, 1))
+	complex_result = a.product (b);
+      else
+	return tree_constant ();
+      break;
+    case tree::multiply:
+      result_type = RT_complex;
+      if (m_mul_conform (a, b, 1))
+	complex_result = a * b;
+      else
+	return tree_constant ();
+      break;
+    case tree::el_div:
+      result_type = RT_complex;
+      if (m_add_conform (a, b, 1))
+	complex_result = a.quotient (b);
+      else
+	return tree_constant ();
+      break;
+    case tree::el_leftdiv:
+      result_type = RT_complex;
+      if (m_add_conform (a, b, 1))
+	complex_result = b.quotient (a);
+      else
+	return tree_constant ();
+      break;
+    case tree::leftdiv:
+      return xleftdiv (a, b);
+      break;
+    case tree::divide:
+      return xdiv (a, b);
+      break;
+    case tree::power:
+      error ("can't do A ^ B for A and B both matrices");
+      return tree_constant ();
+      break;
+    case tree::elem_pow:
+      if (m_add_conform (a, b, 1))
+	return elem_xpow (a, b);
+      else
+	return tree_constant ();
+      break;
+    case tree::cmp_lt:
+      result_type = RT_real;
+      if (m_add_conform (a, b, 1))
+	result = mx_stupid_bool_op (Matrix_LT, a, b);
+      else
+	return tree_constant ();
+      break;
+    case tree::cmp_le:
+      result_type = RT_real;
+      if (m_add_conform (a, b, 1))
+	result = mx_stupid_bool_op (Matrix_LE, a, b);
+      else
+	return tree_constant ();
+      break;
+    case tree::cmp_eq:
+      result_type = RT_real;
+      if (m_add_conform (a, b, 1))
+	result = mx_stupid_bool_op (Matrix_EQ, a, b);
+      else
+	return tree_constant ();
+      break;
+    case tree::cmp_ge:
+      result_type = RT_real;
+      if (m_add_conform (a, b, 1))
+	result = mx_stupid_bool_op (Matrix_GE, a, b);
+      else
+	return tree_constant ();
+      break;
+    case tree::cmp_gt:
+      result_type = RT_real;
+      if (m_add_conform (a, b, 1))
+	result = mx_stupid_bool_op (Matrix_GT, a, b);
+      else
+	return tree_constant ();
+      break;
+    case tree::cmp_ne:
+      result_type = RT_real;
+      if (m_add_conform (a, b, 1))
+	result = mx_stupid_bool_op (Matrix_NE, a, b);
+      else
+	return tree_constant ();
+      break;
+    case tree::and:
+      result_type = RT_real;
+      if (m_add_conform (a, b, 1))
+	result = mx_stupid_bool_op (Matrix_AND, a, b);
+      else
+	return tree_constant ();
+      break;
+    case tree::or:
+      result_type = RT_real;
+      if (m_add_conform (a, b, 1))
+	result = mx_stupid_bool_op (Matrix_OR, a, b);
+      else
+	return tree_constant ();
+      break;
+    default:
+      panic_impossible ();
+      break;
+    }
+
+  assert (result_type != RT_unknown);
+  if (result_type == RT_real)
+    return tree_constant (result);
+  else
+    return tree_constant (complex_result);
+}
+
+/*
+;;; Local Variables: ***
+;;; mode: C++ ***
+;;; page-delimiter: "^/\\*" ***
+;;; End: ***
+*/
new file mode 100644
--- /dev/null
+++ b/src/arith-ops.h
@@ -0,0 +1,101 @@
+// Helper functions for arithmetic operations.            -*- C++ -*-
+// Used by the tree class.                    
+/*
+
+Copyright (C) 1992, 1993 John W. Eaton
+
+This file is part of Octave.
+
+Octave is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+Octave is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with Octave; see the file COPYING.  If not, write to the Free
+Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#if !defined (_arith_ops_h)
+#define _arith_ops_h 1
+
+#ifdef __GNUG__
+#pragma interface
+#endif
+
+#include "tree-const.h"
+
+extern tree_constant
+do_unary_op (double d, tree::expression_type t);
+
+extern tree_constant
+do_unary_op (Matrix& a, tree::expression_type t);
+
+extern tree_constant
+do_unary_op (Complex& c, tree::expression_type t);
+
+extern tree_constant
+do_unary_op (ComplexMatrix& a, tree::expression_type t);
+
+extern tree_constant
+do_binary_op (double a, double b, tree::expression_type t);
+
+extern tree_constant
+do_binary_op (double a, Matrix& b, tree::expression_type t);
+
+extern tree_constant
+do_binary_op (double a, Complex& b, tree::expression_type t);
+
+extern tree_constant
+do_binary_op (double a, ComplexMatrix& b, tree::expression_type t);
+
+extern tree_constant
+do_binary_op (Matrix& a, double b, tree::expression_type t);
+
+extern tree_constant
+do_binary_op (Matrix& a, Matrix& b, tree::expression_type t);
+
+extern tree_constant
+do_binary_op (Matrix& a, Complex& b, tree::expression_type t);
+
+extern tree_constant
+do_binary_op (Matrix& a, ComplexMatrix& b, tree::expression_type t);
+
+extern tree_constant
+do_binary_op (Complex& a, double b, tree::expression_type t);
+
+extern tree_constant
+do_binary_op (Complex& a, Matrix& b, tree::expression_type t);
+
+extern tree_constant
+do_binary_op (Complex& a, Complex& b, tree::expression_type t);
+
+extern tree_constant
+do_binary_op (Complex& a, ComplexMatrix& b, tree::expression_type t);
+
+extern tree_constant
+do_binary_op (ComplexMatrix& a, double b, tree::expression_type t);
+
+extern tree_constant
+do_binary_op (ComplexMatrix& a, Matrix& b, tree::expression_type t);
+
+extern tree_constant
+do_binary_op (ComplexMatrix& a, Complex& b, tree::expression_type t);
+
+extern tree_constant
+do_binary_op (ComplexMatrix& a, ComplexMatrix& b, tree::expression_type t);
+
+#endif
+
+/*
+;;; Local Variables: ***
+;;; mode: C++ ***
+;;; page-delimiter: "^/\\*" ***
+;;; End: ***
+*/
new file mode 100644
--- /dev/null
+++ b/src/builtins.cc
@@ -0,0 +1,1025 @@
+// builtins.cc                                           -*- C++ -*-
+/*
+
+Copyright (C) 1992, 1993 John W. Eaton
+
+This file is part of Octave.
+
+Octave is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+Octave is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with Octave; see the file COPYING.  If not, write to the Free
+Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifdef __GNUG__
+#pragma implementation
+#endif
+
+#include <iostream.h>
+#include <math.h>
+#include <float.h>
+
+#include "tree-const.h"
+#include "symtab.h"
+#include "t-builtins.h"
+#include "g-builtins.h"
+#include "builtins.h"
+#include "octave.h"
+#include "utils.h"
+#include "tree.h"
+#include "mappers.h"
+#include "user-prefs.h"
+#include "variables.h"
+
+// NOTE: nargin == 1 means that the function takes no arguments (just
+// like C, the first argument is (or should be, anyway) the function
+// name).  Also, -1 is shorthand for infinity.
+
+// The following initializations may eventually need to be reworked
+// like the builtin functions in bash were around version 1.12...
+
+static builtin_mapper_functions mapper_functions[] =
+{
+  { "abs", 2, 1, 0, fabs, abs, NULL,
+    "compute abs(X) for each element of X\n", },
+
+  { "acos", 2, 1, 0, acos, NULL, acos,
+    "compute acos(X) for each element of X\n", },
+
+  { "acosh", 2, 1, 0, acosh, NULL, acosh,
+    "compute acosh(X) for each element of X\n", },
+
+  { "angle", 2, 1, 0, arg, arg, NULL,
+    "compute arg(X) for each element of X\n", },
+
+  { "arg", 2, 1, 0, arg, arg, NULL,
+    "compute arg(X) for each element of X\n", },
+
+  { "asin", 2, 1, 0, asin, NULL, asin,
+    "compute asin(X) for each element of X\n", },
+
+  { "asinh", 2, 1, 0, asinh, NULL, asinh,
+    "compute asinh(X) for each element of X\n", },
+
+  { "atan", 2, 1, 0, atan, NULL, atan,
+    "compute atan(X) for each element of X\n", },
+
+  { "atanh", 2, 1, 0, atanh, NULL, atanh,
+    "compute atanh(X) for each element of X\n", },
+
+  { "ceil", 2, 1, 0, ceil, NULL, ceil,
+    "ceil(X): round elements of X toward +Inf\n", },
+
+  { "conj", 2, 1, 0, conj, NULL, conj,
+    "compute complex conjugate for each element of X\n", },
+
+  { "cos", 2, 1, 0, cos, NULL, cos,
+    "compute cos(X) for each element of X\n", },
+
+  { "cosh", 2, 1, 0, cosh, NULL, cosh,
+    "compute cosh(X) for each element of X\n", },
+
+  { "exp", 2, 1, 0, exp, NULL, exp,
+    "compute exp(X) for each element of X\n", },
+
+  { "finite", 2, 1, 0, xfinite, xfinite, NULL,
+    "finite(X): return 1 for finite elements of X\n", },
+
+  { "fix", 2, 1, 0, fix, NULL, fix,
+    "fix(X): round elements of X toward zero\n", },
+
+  { "floor", 2, 1, 0, floor, NULL, floor,
+    "floor(X): round elements of X toward -Inf\n", },
+
+  { "isinf", 2, 1, 0, xisinf, xisinf, NULL,
+    "isinf(X): return 1 for elements of X infinite\n", },
+
+  { "imag", 2, 1, 0, imag, imag, NULL,
+    "return imaginary part for each elements of X\n", },
+
+#ifdef HAVE_ISNAN
+  { "isnan", 2, 1, 0, xisnan, xisnan, NULL,
+    "isnan(X): return 1 where elements of X are NaNs\n", },
+#endif
+
+  { "log", 2, 1, 1, log, NULL, log,
+    "compute log(X) for each element of X\n", },
+
+  { "log10", 2, 1, 1, log10, NULL, log10,
+    "compute log10(X) for each element of X\n", },
+
+  { "real", 2, 1, 0, real, real, NULL,
+    "return real part for each element of X\n", },
+
+  { "round", 2, 1, 0, round, NULL, round,
+    "round(X): round elements of X to nearest integer\n", },
+
+  { "sign", 2, 1, 0, signum, NULL, signum,
+    "sign(X): apply signum function to elements of X\n", },
+
+  { "sin", 2, 1, 0, sin, NULL, sin,
+    "compute sin(X) for each element of X\n", },
+
+  { "sinh", 2, 1, 0, sinh, NULL, sinh,
+    "compute sinh(X) for each element of X\n", },
+
+  { "sqrt", 2, 1, 1, sqrt, NULL, sqrt,
+    "compute sqrt(X) for each element of X\n", },
+
+  { "tan", 2, 1, 0, tan, NULL, tan,
+    "compute tan(X) for each element of X\n", },
+
+  { "tanh", 2, 1, 0, tanh, NULL, tanh,
+    "compute tanh(X) for each element of X\n", },
+
+  { NULL, -1, -1, -1, NULL, NULL, NULL, NULL, },
+};
+
+static builtin_text_functions text_functions[] =
+{
+  { "casesen", 2, builtin_casesen,
+    "print warning if user tries to change case sensitivity\n", },
+
+  { "cd", 2, builtin_cd,
+    "change current working directory\n", },
+
+  { "clear", -1, builtin_clear,
+    "clear symbol(s) from symbol table\n", },
+
+  { "dir", -1, builtin_ls,
+    "print a directory listing\n", },
+
+  { "document", -1, builtin_document,
+    "define help string for symbol\n", },
+
+  { "edit_history", -1, builtin_edit_history,
+    "usage: edit_history [first] [last]\n", },
+
+  { "format", -1, builtin_format,
+    "set output formatting style\n", },
+
+  { "help", -1, builtin_help,
+    "print cryptic yet witty messages\n", },
+
+  { "history", -1, builtin_history,
+    "print/save/load command history\n", },
+
+  { "load", -1, builtin_load,
+    "load variables from a file\n", },
+
+  { "ls", -1, builtin_ls,
+    "print a directory listing\n", },
+
+  { "save", -1, builtin_save,
+    "save variables to a file\n", },
+
+  { "set", -1, builtin_set,
+    "set plotting options\n", },
+
+  { "show", -1, builtin_show,
+    "show plotting options\n", },
+
+  { "who", -1, builtin_who,
+    "list symbols\n", },
+
+  { NULL, -1, NULL, NULL, },
+};
+
+static builtin_general_functions general_functions[] =
+{
+  { "all", 2, 1, builtin_all,
+    "all(X): are all elements of X nonzero?\n", },
+
+  { "any", 2, 1, builtin_any,
+    "any(X): are any elements of X nonzero?\n", },
+
+  { "clc", 1, 0, builtin_clc,
+    "clear screen\n", },
+
+  { "clock", 1, 0, builtin_clock,
+    "return current date and time in vector\n", },
+
+  { "closeplot", 1, 0, builtin_closeplot,
+    "close the stream to plotter\n", },
+
+  { "colloc", 7, 4, builtin_colloc,
+    "[r, A, B, q] = colloc (n [, 'left'] [, 'right']): collocation weights\n", },
+
+  { "cumprod", 2, 1, builtin_cumprod,
+    "cumprod (X): cumulative products\n", },
+
+  { "cumsum", 2, 1, builtin_cumsum,
+    "cumsum (X): cumulative sums\n", },
+
+  { "dassl", 5, 1, builtin_dassl,
+    "solve DAEs using Petzold's DASSL.  Usage:\n\
+\n\
+  dassl ('function_name', x_0, xdot_0, t_out)\n\
+  dassl ('function_name', x_0, xdot_0, t_out, t_crit)\n\
+\n\
+The first argument is the name of the function to call to\n\
+compute the vector of residuals.  It must have the form\n\
+\n\
+  res = f (x, xdot, t)\n\
+\n\
+where x, xdot, and res are vectors, and t is a scalar.\n\n", },
+
+  { "date", 1, 0, builtin_date,
+    "return current date in a string\n", },
+
+  { "det", 2, 1, builtin_det,
+    "det(X): determinant of a square matrix\n", },
+
+  { "diag", 3, 1, builtin_diag,
+    "diag(X [,k]): form/extract diagonals\n", },
+
+  { "disp", 3, 1, builtin_disp,
+    "disp(X): display value\n", },
+
+  { "eig", 2, 1, builtin_eig,
+    "eig (x): compute eigenvalues and eigenvectors of x\n", },
+
+  { "error", 2, 1, builtin_error,
+    "print message and jump to top level\n", },
+
+  { "eval", 2, 1, builtin_eval,
+    "evaluate text as octave source\n", },
+
+  { "exist", 2, 1, builtin_exist,
+    "check if variable or file exists\n", },
+
+  { "exit", 1, 0, builtin_quit,
+    "exit Octave gracefully\n", },
+
+  { "expm", 2, 1, builtin_expm,
+    "Matrix exponential, e^A\n", },
+
+  { "eye", 3, 1, builtin_eye,
+    "create an identity matrix\n", },
+
+  { "fclose", 2, 1, builtin_fclose,
+    "fclose('filename' or filenum): close a file\n", },
+
+  { "feval", -1, 1, builtin_feval,
+    "evaluate argument as function\n", },
+
+  { "fflush", 2, 1, builtin_fflush,
+    "fflush('filename' or filenum): flush buffered data to output file\n", },
+
+  { "fft", 2, 1, builtin_fft,
+    "fft(X): fast fourier transform of a vector\n", },
+
+  { "fgets",3, 2, builtin_fgets,
+    "[string, length] = fgets('filename' or filenum, length): read a string from a file\n", },
+
+  { "find", -1, 1, builtin_find,
+    "find (x): return vector of indices of nonzero elements\n", },
+
+  { "flops", 2, 1, builtin_flops,
+    "count floating point operations\n", },
+
+  { "fopen", 3, 1, builtin_fopen,
+    "filenum = fopen('filename','mode'): open a file\n", },
+
+  { "fprintf", -1, 1, builtin_fprintf,
+    "fprintf ('file', 'fmt', ...)\n", },
+
+  { "freport", 1, 1, builtin_freport,
+    "freport: list open files and their status\n", },
+
+  { "frewind", 2, 1, builtin_frewind,
+    "frewind('filename' or filenum): set file position at beginning of file\n", },
+
+  { "fscanf", 3, -1, builtin_fscanf,
+    "[a,b,c...] = fscanf ('file', 'fmt')\n", },
+
+  { "fseek", 4, 1, builtin_fseek,
+    "fseek('filename' or filenum): set file position for reading or writing\n", },
+
+  { "fsolve", 5, 1, builtin_fsolve,
+    "Solve nonlinear equations using Minpack.  Usage:\n\
+\n\
+  [x, info] = fsolve ('f', x0)\n\
+\n\
+Where the first argument is the name of the  function to call to\n\
+compute the vector of function values.  It must have the form\n\
+\n\
+  y = f (x)
+\n\
+where y and x are vectors.\n\n", },
+
+  { "fsqp", 11, 3, builtin_fsqp,
+    "solve NLPs\n", },
+
+  { "ftell", 2, 1, builtin_ftell,
+    "position = ftell ('filename' or filenum): returns the current file position\n", },
+
+  { "getenv", 2, 1, builtin_getenv,
+    "get environment variable values\n", },
+
+  { "hess", 2, 2, builtin_hess,
+    "Hessenburg decomposition\n",},
+
+  { "home", 1, 0, builtin_clc,
+    "clear screen\n", },
+
+  { "input", 3, 1, builtin_input,
+    "input('prompt' [,'s']): prompt user for [string] input\n", },
+
+  { "ifft", 2, 1, builtin_ifft,
+    "ifft(X): inverse fast fourier transform of a vector\n", },
+
+  { "inv", 2, 1, builtin_inv,
+    "inv(X): inverse of a square matrix\n", },
+
+  { "inverse", 2, 1, builtin_inv,
+    "inverse(X): inverse of a square matrix\n", },
+
+  { "isstr", 2, 1, builtin_isstr,
+    "isstr(X): return 1 if X is a string\n", },
+
+  { "keyboard", 2, 1, builtin_keyboard,
+    "maybe help in debugging M-files\n", },
+
+  { "logm", 2, 1, builtin_logm,
+    "Matrix logarithm, log (A)\n", },
+
+  { "lpsolve", 11, 3, builtin_lpsolve,
+    "Solve linear programs using lp_solve.\n", },
+
+  { "lsode", 6, 1, builtin_lsode,
+    "solve ODEs using Hindmarsh's LSODE.  Usage:\n\
+\n\
+  lsode ('function_name', x0, t_out\n\
+  lsode ('function_name', x0, t_out, t_crit)\n\
+\n\
+The first argument is the name of the function to call to\n\
+compute the vector of right hand sides.  It must have the form\n\
+\n\
+  xdot = f (x, t)\n\
+\n\
+where xdot and x are vectors and t is a scalar.\n\n", },
+
+  { "lu", 2, 3, builtin_lu,
+    "[L, U, P] = lu (A) -- LU factorization\n", },
+
+  { "max", 3, 2, builtin_max,
+    "maximum value(s) of a vector (matrix)\n", },
+
+  { "min", 3, 2, builtin_min,
+    "minimum value(s) of a vector (matrix)\n", },
+
+  { "npsol", 11, 3, builtin_npsol,
+    "Solve nonlinear programs using Gill and Murray's NPSOL.  Usage:\n\
+\n\
+  [x, obj, info, lambda] = npsol (x, 'phi' [, lb, ub] [, lb, A, ub] [, lb, 'g', ub])\n\n\
+Groups of arguments surrounded in `[]' are optional, but\n\
+must appear in the same relative order shown above.\n\
+\n\
+The second argument is a string containing the name of the objective\n\
+function to call.  The objective function must be of the form\n\
+\n\
+  y = phi (x)\n\
+\n\
+where x is a vector and y is a scalar.\n\n", },
+
+  { "ones", 3, 1, builtin_ones,
+    "create a matrix of all ones\n", },
+
+  { "pause", 1, 0, builtin_pause,
+    "suspend program execution\n", },
+
+  { "purge_tmp_files", 5, 1, builtin_purge_tmp_files,
+    "delete temporary data files used for plotting\n", },
+
+  { "printf", -1, 1, builtin_printf,
+    "printf ('fmt', ...)\n", },
+
+  { "prod", 2, 1, builtin_prod,
+    "prod (X): products\n", },
+
+  { "pwd", 1, 0, builtin_pwd,
+    "print current working directory\n", },
+
+  { "qpsol", 9, 3, builtin_qpsol,
+    "Solve nonlinear programs using Gill and Murray's QPSOL.  Usage:\n\
+\n\
+  [x, obj, info, lambda] = qpsol (x, H, c [, lb, ub] [, lb, A, ub])\n\
+\n\
+  Groups of arguments surrounded in `[]' are optional, but\n\
+  must appear in the same relative order shown above.", },
+
+  { "qr", 2, 2, builtin_qr,
+    "[q, r] = qr (X): form QR factorization of X\n", },
+
+  { "quad", 6, 3, builtin_quad,
+    "Integrate a nonlinear function of one variable using Quadpack.\n\
+Usage:\n\
+\n\
+  [v, ier, nfun] = quad ('f', a, b [, tol] [, sing])\n\
+\n\
+Where the first argument is the name of the  function to call to\n\
+compute the value of the integrand.  It must have the form\n\
+\n\
+  y = f (x)
+\n\
+where y and x are scalars.\n\
+\n\
+The second and third arguments are limits of integration.  Either or\n\
+both may be infinite.  The optional argument tol specifies the desired\n\
+accuracy of the result.  The optional argument sing is a vector of\n\
+at which the integrand is singular.\n\n", },
+
+  { "quit", 1, 0, builtin_quit,
+    "exit Octave gracefully\n", },
+
+  { "rand", 2, 1, builtin_rand,
+    "matrices with random elements\n", },
+
+  { "replot", 1, 0, builtin_replot,
+    "redisplay current plot\n", },
+
+  { "scanf", 2, -1, builtin_scanf,
+    "[a,b,c...] = scanf ('fmt')\n", },
+
+  { "setstr", 2, 1, builtin_setstr,
+    "setstr (v): convert a vector to a string\n", },
+
+  { "shell_cmd", 2, 1, builtin_shell_command,
+    "shell_cmd (string [, return_output]): execute shell commands\n", },
+
+  { "schur", 3, 2, builtin_schur,
+    "returns the Schur (straight or ordered) decomposition of matrix\n", },
+
+  { "size", 2, 1, builtin_size,
+    "size(X): return rows and columns of X\n", },
+
+  { "sort", 2, 2, builtin_sort,
+    "[s,i] = sort(x): sort the columns of x, optionally return sort index\n", },
+
+  { "sqrtm", 2, 1, builtin_sqrtm,
+    "Matrix sqrt, sqrt (A)\n", },
+
+  { "sprintf", -1, 1, builtin_sprintf,
+    "s = sprintf ('fmt', ...)\n", },
+
+  { "sscanf", 3, -1, builtin_sscanf,
+    "[a,b,c...] = sscanf (string, 'fmt')\n", },
+
+  { "sum", 2, 1, builtin_sum,
+    "sum (X): sum of elements\n", },
+
+  { "sumsq", 2, 1, builtin_sumsq,
+    "sumsq (X): sum of squares of elements\n", },
+
+  { "svd", 2, 3, builtin_svd,
+    "[U,S,V] = svd(X): return SVD of X\n", },
+
+  { "warranty", 1, 0, builtin_warranty,
+    "describe copying conditions\n", },
+
+  { "zeros", 3, 1, builtin_zeros,
+    "create a matrix of all zeros\n", },
+
+  { NULL, -1, -1, NULL, NULL, },
+};
+
+// This is a lie.  Some of these get reassigned to be numeric
+// variables.  See below.
+
+static builtin_string_variables string_variables[] =
+{
+  { "I", "??", NULL,
+    "sqrt (-1)\n", },
+
+  { "Inf", "??", NULL,
+    "infinity\n", },
+
+  { "J", "??", NULL,
+    "sqrt (-1)\n", },
+
+#if defined (HAVE_ISNAN)
+  { "NaN", "??", NULL,
+    "not a number\n", },
+#endif
+
+  { "LOADPATH", "??", sv_loadpath,
+    "colon separated list of directories to search for scripts\n", },
+
+  { "PAGER", "??", sv_pager_binary,
+    "path to pager binary\n", },
+
+  { "PS1", "\\s:\\#> ", sv_ps1,
+    "primary prompt string\n", },
+
+  { "PS2", "> ", sv_ps2,
+    "secondary prompt string\n", },
+
+  { "PWD", "??PWD??", sv_pwd,
+    "current working directory\n", },
+
+  { "SEEK_SET", "??", NULL,
+    "used with fseek to position file relative to the beginning\n", },
+
+  { "SEEK_CUR", "??", NULL,
+    "used with fseek to position file relative to the current position\n", },
+
+  { "SEEK_END", "??", NULL,
+    "used with fseek to position file relative to the end\n", },
+
+  { "do_fortran_indexing", "false", do_fortran_indexing,
+    "allow single indices for matrices\n", },
+
+  { "empty_list_elements_ok", "warn", empty_list_elements_ok,
+    "ignore the empty element in expressions like `a = [[], 1]'\n", },
+
+  { "eps", "??", NULL,
+      "machine precision\n", },
+
+  { "gnuplot_binary", "gnuplot", sv_gnuplot_binary,
+    "path to gnuplot binary\n", },
+
+  { "i", "??", NULL,
+    "sqrt (-1)\n", },
+
+  { "implicit_str_to_num_ok", "false", implicit_str_to_num_ok,
+    "allow implicit string to number conversion\n", },
+
+  { "inf", "??", NULL,
+    "infinity\n", },
+
+  { "j", "??", NULL,
+    "sqrt (-1)\n", },
+
+#if defined (HAVE_ISNAN)
+  { "nan", "??", NULL,
+    "not a number\n", },
+#endif
+
+  { "ok_to_lose_imaginary_part", "warn", ok_to_lose_imaginary_part,
+    "silently convert from complex to real by dropping imaginary part\n", },
+
+  { "output_max_field_width", "??", set_output_max_field_width,
+    "maximum width of an output field for numeric output\n", },
+
+  { "output_precision", "??", set_output_precision,
+    "number of significant figures to display for numeric output\n", },
+
+  { "page_screen_output", "true", page_screen_output,
+    "if possible, send output intended for the screen through the pager\n", },
+
+  { "pi", "??", NULL,
+    "ratio of the circumference of a circle to its diameter\n", },
+
+  { "prefer_column_vectors", "true", prefer_column_vectors,
+    "prefer column/row vectors\n", },
+
+  { "prefer_zero_one_indexing", "false", prefer_zero_one_indexing,
+    "when there is a conflict, prefer zero-one style indexing\n", },
+
+  { "print_answer_id_name", "true", print_answer_id_name,
+    "set output style to print `var_name = ...'\n", },
+
+  { "print_empty_dimensions", "true", print_empty_dimensions,
+    "also print dimensions of empty matrices\n", },
+
+  { "propagate_empty_matrices", "true", propagate_empty_matrices,
+    "operations on empty matrices return an empty matrix, not an error\n", },
+
+  { "resize_on_range_error", "true", resize_on_range_error,
+    "enlarge matrices on assignment\n", },
+
+  { "return_last_computed_value", "false", return_last_computed_value,
+    "if a function does not return any values explicitly, return the\n\
+last computed value\n", },
+
+  { "silent_functions", "false", silent_functions,
+    "suppress printing results in called functions\n", },
+
+  { "split_long_rows", "true", split_long_rows,
+    "split long matrix rows instead of wrapping\n", },
+
+  { "stdin", "??", NULL,
+    "file number of the standard input stream\n", },
+
+  { "stdout", "??", NULL,
+    "file number of the standard output stream\n", },
+
+  { "stderr", "??", NULL,
+    "file number of the standard error stream\n", },
+
+  { "treat_neg_dim_as_zero", "false", treat_neg_dim_as_zero,
+    "convert negative dimensions to zero\n", },
+
+  { "warn_assign_as_truth_value", "true", warn_assign_as_truth_value,
+    "produce warning for assignments used as truth values\n", },
+
+  { "warn_comma_in_global_decl", "true", warn_comma_in_global_decl,
+    "produce warning for commas in global declarations\n", },
+
+  { "warn_divide_by_zero", "true", warn_divide_by_zero,
+    "on IEEE machines, allow divide by zero errors to be suppressed\n", },
+
+  { NULL, NULL, NULL, NULL, },
+};
+
+void
+make_eternal (char *s)
+{
+  symbol_record *sym_rec = curr_sym_tab->lookup (s, 0, 0);
+  if (sym_rec != (symbol_record *) NULL)
+    sym_rec->make_eternal ();
+}
+
+void
+install_builtins (void)
+{
+  symbol_record *sym_rec;
+
+  tree_builtin *tb_tmp;
+
+// So that the clear function can't delete other builtin variables and
+// functions, they are given eternal life.
+
+  builtin_mapper_functions *mfptr = mapper_functions;
+  while (mfptr->name != (char *) NULL)
+    {
+      sym_rec = curr_sym_tab->lookup (mfptr->name, 1);
+      sym_rec->unprotect ();
+
+      Mapper_fcn mfcn;
+      mfcn.neg_arg_complex = mfptr->neg_arg_complex;
+      mfcn.d_d_mapper = mfptr->d_d_mapper;
+      mfcn.d_c_mapper = mfptr->d_c_mapper;
+      mfcn.c_c_mapper = mfptr->c_c_mapper;
+
+      tb_tmp = new tree_builtin (mfptr->nargin_max, mfptr->nargout_max,
+				 mfcn, sym_rec);
+
+      sym_rec->define (tb_tmp);
+      sym_rec->document (mfptr->help_string);
+      sym_rec->make_eternal ();
+      sym_rec->protect ();
+      mfptr++;
+    }
+
+  builtin_text_functions *tfptr = text_functions;
+  while (tfptr->name != (char *) NULL)
+    {
+      sym_rec = curr_sym_tab->lookup (tfptr->name, 1);
+      sym_rec->unprotect ();
+
+      tb_tmp = new tree_builtin (tfptr->nargin_max, 1,
+				 tfptr->text_fcn, sym_rec);
+
+      sym_rec->define (tb_tmp);
+      sym_rec->document (tfptr->help_string);
+      sym_rec->make_eternal ();
+      sym_rec->protect ();
+      tfptr++;
+    }
+
+  builtin_general_functions *gfptr = general_functions;
+  while (gfptr->name != (char *) NULL)
+    {
+      sym_rec = curr_sym_tab->lookup (gfptr->name, 1);
+      sym_rec->unprotect ();
+
+      tb_tmp = new tree_builtin (gfptr->nargin_max, gfptr->nargout_max,
+				 gfptr->general_fcn, sym_rec);
+
+      sym_rec->define (tb_tmp);
+      sym_rec->document (gfptr->help_string);
+      sym_rec->make_eternal ();
+      sym_rec->protect ();
+      gfptr++;
+    }
+
+// Most built-in variables are not protected because the user should
+// be able to redefine them.
+
+  builtin_string_variables *svptr = string_variables;
+  while (svptr->name != (char *) NULL)
+    {
+      sym_rec = curr_sym_tab->lookup (svptr->name, 1);
+      sym_rec->unprotect ();
+
+      tree_constant *tmp = new tree_constant (svptr->value);
+
+      sym_rec->set_sv_function (svptr->sv_function);
+      sym_rec->define (tmp);
+      sym_rec->document (svptr->help_string);
+      sym_rec->make_eternal ();
+      svptr++;
+    }
+
+// XXX FIXME XXX -- Need a convenient way to document these variables.
+
+// IMPORTANT: Always create a new tree_constant for each variable.
+
+  tree_constant *tmp = NULL_TREE_CONST;
+  bind_variable ("ans", tmp);
+
+  Complex ctmp (0.0, 1.0);
+  tmp = new tree_constant (ctmp);
+  bind_protected_variable ("I", tmp);
+  make_eternal ("I");
+
+  tmp = new tree_constant (ctmp);
+  bind_protected_variable ("J", tmp);
+  make_eternal ("J");
+
+// Let i and j be functions so they can be redefined without being
+// wiped out.
+
+  char *tmp_help;
+
+  tmp = new tree_constant (ctmp);
+  sym_rec = curr_sym_tab->lookup ("i", 1);
+  tmp_help = sym_rec->help ();
+  sym_rec->define_as_fcn (tmp);
+  sym_rec->document (tmp_help);
+  sym_rec->protect ();
+  sym_rec->make_eternal ();
+
+  tmp = new tree_constant (ctmp);
+  sym_rec = curr_sym_tab->lookup ("j", 1);
+  tmp_help = sym_rec->help ();
+  sym_rec->define_as_fcn (tmp);
+  sym_rec->document (tmp_help);
+  sym_rec->protect ();
+  sym_rec->make_eternal ();
+
+  tmp = new tree_constant (get_working_directory ("initialize_globals"));
+  bind_protected_variable ("PWD", tmp);
+  make_eternal ("PWD");
+
+  tmp = new tree_constant (load_path);
+  bind_variable ("LOADPATH", tmp);
+  make_eternal ("LOADPATH");
+
+  tmp = new tree_constant (default_pager ());
+  bind_variable ("PAGER", tmp);
+  make_eternal ("PAGER");
+
+  tmp = new tree_constant (0.0);
+  bind_variable ("SEEK_SET", tmp);
+  make_eternal ("SEEK_SET");
+
+  tmp = new tree_constant (1.0);
+  bind_variable ("SEEK_CUR", tmp);
+  make_eternal ("SEEK_CUR");
+
+  tmp = new tree_constant (2.0);
+  bind_variable ("SEEK_END", tmp);
+  make_eternal ("SEEK_END");
+
+  tmp = new tree_constant (DBL_EPSILON);
+  bind_protected_variable ("eps", tmp);
+  make_eternal ("eps");
+
+  tmp =  new tree_constant (10.0);
+  bind_variable ("output_max_field_width", tmp);
+  make_eternal ("output_max_field_width");
+
+  tmp =  new tree_constant (5.0);
+  bind_variable ("output_precision", tmp);
+  make_eternal ("output_precision");
+
+  tmp =  new tree_constant (4.0 * atan (1.0));
+  bind_protected_variable ("pi", tmp);
+  make_eternal ("pi");
+
+  tmp =  new tree_constant (0.0);
+  bind_protected_variable ("stdin", tmp);
+  make_eternal ("stdin");
+
+  tmp =  new tree_constant (1.0);
+  bind_protected_variable ("stdout", tmp);
+  make_eternal ("stdout");
+
+  tmp =  new tree_constant (2.0);
+  bind_protected_variable ("stderr", tmp);
+  make_eternal ("stderr");
+
+#if defined (HAVE_ISINF) || defined (HAVE_FINITE)
+#ifdef linux
+  tmp = new tree_constant (HUGE_VAL);
+#else
+  tmp = new tree_constant (1.0/0.0);
+#endif
+  bind_protected_variable ("Inf", tmp);
+  make_eternal ("Inf");
+
+#ifdef linux
+  tmp = new tree_constant (HUGE_VAL);
+#else
+  tmp = new tree_constant (1.0/0.0);
+#endif
+  bind_protected_variable ("inf", tmp);
+  make_eternal ("inf");
+
+#else
+
+// This is sort of cheesy, but what can we do, other than blowing it
+// off completely, or writing an entire IEEE emulation package?
+
+  tmp = new tree_constant (DBL_MAX);
+  bind_protected_variable ("Inf", tmp);
+  make_eternal ("Inf");
+
+  tmp = new tree_constant (DBL_MAX);
+  bind_protected_variable ("inf", tmp);
+  make_eternal ("inf");
+#endif
+
+#if defined (HAVE_ISNAN)
+#ifdef linux
+  tmp = new tree_constant (NAN);
+#else
+  tmp = new tree_constant (0.0/0.0);
+#endif
+  bind_protected_variable ("NaN", tmp);
+  make_eternal ("NaN");
+
+#ifdef linux
+  tmp = new tree_constant (NAN);
+#else
+  tmp = new tree_constant (0.0/0.0);
+#endif
+  bind_protected_variable ("nan", tmp);
+  make_eternal ("nan");
+#endif
+}
+
+int
+is_text_function_name (char *s)
+{
+  int retval = 0;
+
+  builtin_text_functions *tfptr = text_functions;
+  while (tfptr->name != (char *) NULL)
+    {
+      if (strcmp (tfptr->name, s) == 0)
+	{
+	  retval = 1;
+	  break;
+	}
+      tfptr++;
+    }
+
+  return retval;
+}
+
+help_list *
+builtin_mapper_functions_help (void)
+{
+  int count = 0;
+  builtin_mapper_functions *mfptr;
+
+  mfptr = mapper_functions;
+  while (mfptr->name != (char *) NULL)
+    {
+      count++;
+      mfptr++;
+    }
+
+  if (count == 0)
+    return (help_list *) NULL;
+
+  help_list *hl = new help_list [count+1];
+
+  int i = 0;
+  mfptr = mapper_functions;
+  while (mfptr->name != (char *) NULL)
+    {
+      hl[i].name = mfptr->name;
+      hl[i].help = mfptr->help_string;
+      i++;
+      mfptr++;
+    }
+
+  hl[count].name = (char *) NULL;
+  hl[count].help = (char *) NULL;
+
+  return hl;
+}
+
+help_list *
+builtin_general_functions_help (void)
+{
+  int count = 0;
+  builtin_general_functions *gfptr;
+
+  gfptr = general_functions;
+  while (gfptr->name != (char *) NULL)
+    {
+      count++;
+      gfptr++;
+    }
+
+  if (count == 0)
+    return (help_list *) NULL;
+
+  help_list *hl = new help_list [count+1];
+
+  int i = 0;
+  gfptr = general_functions;
+  while (gfptr->name != (char *) NULL)
+    {
+      hl[i].name = gfptr->name;
+      hl[i].help = gfptr->help_string;
+      i++;
+      gfptr++;
+    }
+
+  hl[count].name = (char *) NULL;
+  hl[count].help = (char *) NULL;
+
+  return hl;
+}
+
+help_list *
+builtin_text_functions_help (void)
+{
+  int count = 0;
+  builtin_text_functions *tfptr;
+
+  tfptr = text_functions;
+  while (tfptr->name != (char *) NULL)
+    {
+      count++;
+      tfptr++;
+    }
+
+  if (count == 0)
+    return (help_list *) NULL;
+
+  help_list *hl = new help_list [count+1];
+
+  int i = 0;
+  tfptr = text_functions;
+  while (tfptr->name != (char *) NULL)
+    {
+      hl[i].name = tfptr->name;
+      hl[i].help = tfptr->help_string;
+      i++;
+      tfptr++;
+    }
+
+  hl[count].name = (char *) NULL;
+  hl[count].help = (char *) NULL;
+
+  return hl;
+}
+
+help_list *
+builtin_variables_help (void)
+{
+  int count = 0;
+  builtin_string_variables *svptr;
+
+  svptr = string_variables;
+  while (svptr->name != (char *) NULL)
+    {
+      count++;
+      svptr++;
+    }
+
+  if (count == 0)
+    return (help_list *) NULL;
+
+  help_list *hl = new help_list [count+1];
+
+  int i = 0;
+  svptr = string_variables;
+  while (svptr->name != (char *) NULL)
+    {
+      hl[i].name = svptr->name;
+      hl[i].help = svptr->help_string;
+      i++;
+      svptr++;
+    }
+
+  hl[count].name = (char *) NULL;
+  hl[count].help = (char *) NULL;
+
+  return hl;
+}
+
+/*
+;;; Local Variables: ***
+;;; mode: C++ ***
+;;; page-delimiter: "^/\\*" ***
+;;; End: ***
+*/
new file mode 100644
--- /dev/null
+++ b/src/builtins.h
@@ -0,0 +1,94 @@
+// Builtin function support.                               -*- C++ -*-
+/*
+
+Copyright (C) 1992, 1993 John W. Eaton
+
+This file is part of Octave.
+
+Octave is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+Octave is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with Octave; see the file COPYING.  If not, write to the Free
+Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#if !defined (_builtins_h)
+#define _builtins_h 1
+
+#ifdef __GNUG__
+#pragma interface
+#endif
+
+#include <Complex.h>
+
+#include "help.h"
+
+#ifndef MAPPER_FCN_TYPEDEFS
+#define MAPPER_FCN_TYPEDEFS 1
+
+typedef double (*d_d_Mapper)(double);
+typedef double (*d_c_Mapper)(const Complex&);
+typedef Complex (*c_c_Mapper)(const Complex&);
+
+#endif
+
+struct Mapper_fcn
+{
+  int neg_arg_complex;
+  d_d_Mapper d_d_mapper;
+  d_c_Mapper d_c_mapper;
+  c_c_Mapper c_c_mapper;
+};
+
+struct builtin_mapper_functions
+{
+  char *name;
+  int nargin_max;
+  int nargout_max;
+  int neg_arg_complex;
+  d_d_Mapper d_d_mapper;
+  d_c_Mapper d_c_mapper;
+  c_c_Mapper c_c_mapper;
+  char *help_string;
+};
+
+#ifndef SV_FUNCTION_TYPEDEFS
+#define SV_FUNCTION_TYPEDEFS 1
+
+typedef int (*sv_Function)(void);
+
+#endif
+
+struct builtin_string_variables
+{
+  char *name;
+  char *value;
+  sv_Function sv_function;
+  char *help_string;
+};
+
+extern void install_builtins (void);
+extern int is_text_function_name (char *s);
+
+extern help_list *builtin_mapper_functions_help (void);
+extern help_list *builtin_general_functions_help (void);
+extern help_list *builtin_text_functions_help (void);
+extern help_list *builtin_variables_help (void);
+
+#endif
+
+/*
+;;; Local Variables: ***
+;;; mode: C++ ***
+;;; page-delimiter: "^/\\*" ***
+;;; End: ***
+*/
new file mode 100644
--- /dev/null
+++ b/src/colloc.cc
@@ -0,0 +1,129 @@
+// tc-colloc.cc                                           -*- C++ -*-
+/*
+
+Copyright (C) 1993 John W. Eaton
+
+This file is part of Octave.
+
+Octave is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+Octave is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with Octave; see the file COPYING.  If not, write to the Free
+Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifdef __GNUG__
+#pragma implementation
+#endif
+
+#include "CollocWt.h"
+
+#include "tree-const.h"
+#include "error.h"
+#include "utils.h"
+
+#ifdef WITH_DLD
+tree_constant *
+builtin_colloc_2 (tree_constant *args, int nargin, int nargout)
+{
+  return collocation_weights (args, nargin);
+}
+#endif
+
+tree_constant *
+collocation_weights (tree_constant *args, int nargin)
+{
+  tree_constant *retval = NULL_TREE_CONST;
+
+  if (args[1].const_type () != tree_constant_rep::complex_scalar_constant
+      && args[1].const_type () != tree_constant_rep::scalar_constant)
+    {
+      message ("colloc", "first argument must be a scalar");
+      return retval;
+    }
+
+  int ncol = NINT (args[1].double_value ());
+  if (ncol < 0)
+    {
+      message ("colloc", "first argument must be non-negative");
+      return retval;
+    }
+
+  int ntot = ncol;
+  int left = 0;
+  int right = 0;
+
+  for (int i = 2; i < nargin; i++)
+    {
+      if (args[i].is_defined ())
+	{
+	  if (! args[i].is_string_type ())
+	    {
+	      message ("colloc", "expecting string argument");
+	      return retval;
+	    }
+
+	  char *s = args[i].string_value ();
+	  if (s != (char *) NULL
+	      && (((*s == 'R' || *s == 'r') && strlen (s) == 1)
+		  || strcmp (s, "right") == 0))
+	    {
+	      right = 1;
+	    }
+	  else if (s != (char *) NULL
+		   && (((*s == 'L' || *s == 'l') && strlen (s) == 1)
+		       || strcmp (s, "left") == 0))
+	    {
+	      left = 1;
+	    }
+	  else
+	    {
+	      message ("colloc", "unrecognized argument");
+	      return retval;
+	    }
+	}
+      else
+	{
+	  message ("colloc", "unexpected NULL argument");
+	  return retval;
+	}
+    }
+
+  ntot += left + right;
+  if (ntot < 1)
+    message ("colloc", "the total number of roots must be positive");
+  
+  CollocWt wts (ncol, left, right);
+
+  ColumnVector r = wts.roots ();
+  Matrix A = wts.first ();
+  Matrix B = wts.second ();
+  ColumnVector q = wts.quad_weights ();
+
+  retval = new tree_constant [5];
+
+  retval[0] = tree_constant (r);
+  retval[1] = tree_constant (A);
+  retval[2] = tree_constant (B);
+  retval[3] = tree_constant (q);
+  retval[4] = tree_constant ();
+
+  return retval;
+}
+
+/*
+;;; Local Variables: ***
+;;; mode: C++ ***
+;;; page-delimiter: "^/\\*" ***
+;;; End: ***
+*/
+
new file mode 100644
--- /dev/null
+++ b/src/dassl.cc
@@ -0,0 +1,159 @@
+// tc-dassl.cc                                           -*- C++ -*-
+/*
+
+Copyright (C) 1993 John W. Eaton
+
+This file is part of Octave.
+
+Octave is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+Octave is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with Octave; see the file COPYING.  If not, write to the Free
+Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifdef __GNUG__
+#pragma implementation
+#endif
+
+#include "DAE.h"
+
+#include "tree-const.h"
+#include "variables.h"
+#include "gripes.h"
+#include "error.h"
+#include "utils.h"
+
+// Global pointer for user defined function required by dassl.
+static tree *dassl_fcn;
+
+#ifdef WITH_DLD
+tree_constant *
+builtin_dassl_2 (tree_constant *args, int nargin, int nargout)
+{
+  return dassl (args, nargin, nargout);
+}
+#endif
+
+ColumnVector
+dassl_user_function (const ColumnVector& x, const ColumnVector& xdot, double t)
+{
+  ColumnVector retval;
+
+  int nstates = x.capacity ();
+
+  assert (nstates == xdot.capacity ());
+
+//  tree_constant name (dassl_fcn->name ());
+  tree_constant *args = new tree_constant [4];
+//  args[0] = name;
+  args[3] = tree_constant (t);
+
+  if (nstates > 1)
+    {
+      Matrix m1 (nstates, 1);
+      Matrix m2 (nstates, 1);
+      for (int i = 0; i < nstates; i++)
+	{
+	  m1 (i, 0) = x.elem (i);
+	  m2 (i, 0) = xdot.elem (i);
+	}
+      tree_constant state (m1);
+      tree_constant deriv (m2);
+      args[1] = state;
+      args[2] = deriv;
+    }
+  else
+    {
+      double d1 = x.elem (0);
+      double d2 = xdot.elem (0);
+      tree_constant state (d1);
+      tree_constant deriv (d2);
+      args[1] = state;
+      args[2] = deriv;
+    }
+
+  if (dassl_fcn != NULL_TREE)
+    {
+      tree_constant *tmp = dassl_fcn->eval (args, 4, 1, 0);
+      delete [] args;
+      if (tmp != NULL_TREE_CONST && tmp[0].is_defined ())
+	{
+	  retval = tmp[0].to_vector ();
+	  delete [] tmp;
+	}
+      else
+	{
+	  delete [] tmp;
+	  gripe_user_supplied_eval ("dassl");
+	  jump_to_top_level ();
+	}
+    }
+
+  return retval;
+}
+
+tree_constant *
+dassl (tree_constant *args, int nargin, int nargout)
+{
+// Assumes that we have been given the correct number of arguments.
+
+  tree_constant *retval = NULL_TREE_CONST;
+
+  dassl_fcn = is_valid_function (args[1], "dassl", 1);
+  if (dassl_fcn == NULL_TREE
+      || takes_correct_nargs (dassl_fcn, 4, "dassl", 1) != 1)
+    return retval;
+
+  ColumnVector state = args[2].to_vector ();
+  ColumnVector deriv = args[3].to_vector ();
+  ColumnVector out_times = args[4].to_vector ();
+  ColumnVector crit_times;
+  int crit_times_set = 0;
+  if (nargin > 5)
+    {
+      crit_times = args[5].to_vector ();
+      crit_times_set = 1;
+    }
+
+  if (state.capacity () != deriv.capacity ())
+    {
+      message ("dassl", "x and xdot must have the same size");
+      return retval;
+    }
+
+  double tzero = out_times.elem (0);
+
+  DAEFunc func (dassl_user_function);
+  DAE dae (state, deriv, tzero, func);
+
+  Matrix output;
+  Matrix deriv_output;
+
+  if (crit_times_set)
+    output = dae.integrate (out_times, deriv_output, crit_times);
+  else
+    output = dae.integrate (out_times, deriv_output);
+
+  retval = new tree_constant [3];
+  retval[0] = tree_constant (output);
+  retval[1] = tree_constant (deriv_output);
+  return retval;
+}
+
+/*
+;;; Local Variables: ***
+;;; mode: C++ ***
+;;; page-delimiter: "^/\\*" ***
+;;; End: ***
+*/
+
new file mode 100644
--- /dev/null
+++ b/src/det.cc
@@ -0,0 +1,135 @@
+// tc-det.cc                                           -*- C++ -*-
+/*
+
+Copyright (C) 1993 John W. Eaton
+
+This file is part of Octave.
+
+Octave is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+Octave is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with Octave; see the file COPYING.  If not, write to the Free
+Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifdef __GNUG__
+#pragma implementation
+#endif
+
+#include "Matrix.h"
+
+#include "tree-const.h"
+#include "user-prefs.h"
+#include "gripes.h"
+#include "error.h"
+
+#ifdef WITH_DLD
+tree_constant *
+builtin_det_2 (tree_constant *args, int nargin, int nargout)
+{
+  tree_constant *retval = new tree_constant [2];
+  retval[0] = determinant (args[1]);
+  return retval;
+}
+#endif
+
+tree_constant
+determinant (tree_constant& a)
+{
+  tree_constant retval;
+
+  tree_constant tmp = a.make_numeric ();;
+    
+  int nr = tmp.rows ();
+  int nc = tmp.columns ();
+  if (nr == 0 || nc == 0)
+    {
+      int flag = user_pref.propagate_empty_matrices;
+      if (flag < 0)
+	gripe_empty_arg ("det", 0);
+      else if (flag == 0)
+	gripe_empty_arg ("det", 1);
+    }
+
+  if (nr == 0 && nc == 0)
+    return tree_constant (1.0);
+
+  switch (tmp.const_type ())
+    {
+    case tree_constant_rep::matrix_constant:
+      {
+	Matrix m = tmp.matrix_value ();
+	if (m.rows () == m.columns ())
+	  {
+	    int info;
+	    double rcond = 0.0;
+	    DET det = m.determinant (info, rcond);
+	    if (info == -1)
+	      message ("det",
+		       "matrix singular to machine precision, rcond = %g",
+		       rcond);
+	    else
+	      {
+		double d = det.value ();
+		retval = tree_constant (d);
+	      }
+	  }
+	else
+	  gripe_square_matrix_required ("det");
+      }
+      break;
+    case tree_constant_rep::complex_matrix_constant:
+      {
+	ComplexMatrix m = tmp.complex_matrix_value ();
+	if (m.rows () == m.columns ())
+	  {
+	    int info;
+	    double rcond = 0.0;
+	    ComplexDET det = m.determinant (info, rcond);
+	    if (info == -1)
+	      message ("det",
+		       "matrix singular to machine precision, rcond = %g",
+		       rcond);
+	    else
+	      {
+		Complex c = det.value ();
+		retval = tree_constant (c);
+	      }
+	  }
+	else
+	  gripe_square_matrix_required ("det");
+      }
+      break;
+    case tree_constant_rep::scalar_constant:
+      {
+	double d = tmp.double_value ();
+	retval = tree_constant (d);
+      }
+      break;
+    case tree_constant_rep::complex_scalar_constant:
+      {
+	Complex c = tmp.complex_value ();
+	retval = tree_constant (c);
+      }
+      break;
+    default:
+      break;
+    }
+  return retval;
+}
+
+/*
+;;; Local Variables: ***
+;;; mode: C++ ***
+;;; page-delimiter: "^/\\*" ***
+;;; End: ***
+*/
new file mode 100644
--- /dev/null
+++ b/src/dynamic-ld.cc
@@ -0,0 +1,164 @@
+// dynamic-ld.cc                                         -*- C++ -*-
+/*
+
+Copyright (C) 1993 John W. Eaton
+
+This file is part of Octave.
+
+Octave is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+Octave is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with Octave; see the file COPYING.  If not, write to the Free
+Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifdef __GNUG__
+#pragma implementation
+#endif
+
+extern "C"
+{
+#include "dld.h"
+}
+
+#include "dynamic-ld.h"
+#include "tree-const.h"
+#include "user-prefs.h"
+#include "octave.h"
+#include "utils.h"
+#include "error.h"
+
+void
+octave_dld_tc2_unlink_by_symbol (char *name, int hard = 1)
+{
+  char *mangled_fcn_name = strconcat (name, "__FP13tree_constantii");
+  int status = dld_unlink_by_symbol (mangled_fcn_name, hard);
+  if (status != 0)
+    dld_perror ("octave_dld_tc2_unlink_by_symbol");
+  delete [] mangled_fcn_name;
+}
+
+void
+octave_dld_tc2_unlink_by_file (char *name, int hard = 1)
+{
+  int status = dld_unlink_by_file (name, hard);
+  if (status != 0)
+    dld_perror ("octave_dld_tc2_unlink_by_file");
+}
+
+static void
+octave_dld_init (void)
+{
+  static int initialized = 0;
+
+  if (! initialized)
+    {
+      char *full_path = dld_find_executable (raw_prog_name);
+      if (full_path != (char *) NULL)
+	{
+	  int status = dld_init (full_path);
+	  if (status != 0)
+	    {
+	      dld_perror ("octave_dld_tc2_and_go");
+	      error ("failed to load symbols from `%s'", full_path);
+	    }
+	  else
+	    initialized = 1;
+	}
+      else
+	error ("octave_dld_tc2_and_go: can't find full path to `%s'",
+	       prog_name);
+    }
+}
+
+/*
+ * Look for object in path.  It should provide a definition for the
+ * function we just marked as undefined.  If we find it, we\'ll also
+ * try to load the remaining undefined symbols.
+ */
+static int
+octave_dld_link (char *object)
+{
+  char *file = file_in_path (object, (char *) NULL);
+  int status = dld_link (file);
+  if (status != 0)
+    dld_perror ("octave_dld_link");
+    
+  delete [] file;
+  return status;
+}
+
+int
+octave_dld_tc2_link (char *object)
+{
+  int status = octave_dld_link (object);
+  if (status == 0)
+    {
+      status = octave_dld_link ("liboctave.a");
+      if (status == 0)
+	octave_dld_link ("libcruft.a");
+    }
+  return status;
+}
+
+builtin_fcn_ptr
+octave_dld_tc2 (char *name, char *fcn, char *object)
+{
+  builtin_fcn_ptr retval = (builtin_fcn_ptr) NULL;
+
+  octave_dld_init ();
+
+  char *mangled_fcn_name = strconcat (fcn, "__FP13tree_constantii");
+
+// See if the function has already been loaded.  If not, mark it as
+// undefined.
+
+  if (dld_get_func (mangled_fcn_name) == 0)
+    dld_create_reference (mangled_fcn_name);
+
+  int status = octave_dld_link (object);
+  if (status == 0)
+    {
+// Return a pointer to the function we just loaded.  If we can\'t find
+// it, this will return NULL.
+
+      retval = (builtin_fcn_ptr) dld_get_func (mangled_fcn_name);
+    }
+
+  delete [] mangled_fcn_name;
+
+  return retval;
+    
+}
+
+tree_constant *
+octave_dld_tc2_and_go (tree_constant *args, int nargin, int nargout,
+		       char *name, char *fcn, char *object)
+{
+  tree_constant *retval = NULL_TREE_CONST;
+
+  builtin_fcn_ptr fcn_to_call = octave_dld_tc2 (name, fcn, object);
+
+  if (fcn_to_call != (builtin_fcn_ptr) NULL)
+    retval = (*fcn_to_call) (args, nargin, nargout);
+  else
+    error ("octave_dld_tc2_and_go: failed to load `%s'", name);
+
+  return retval;
+}
+
+/*
+;;; Local Variables: ***
+;;; mode: C++ ***
+;;; page-delimiter: "^/\\*" ***
+;;; End: ***
+*/
new file mode 100644
--- /dev/null
+++ b/src/dynamic-ld.h
@@ -0,0 +1,53 @@
+// dynamic-ld.h                                        -*- C++ -*-
+/*
+
+Copyright (C) 1993 John W. Eaton
+
+This file is part of Octave.
+
+Octave is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+Octave is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with Octave; see the file COPYING.  If not, write to the Free
+Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#if !defined (_dynamic_ld_h)
+#define _dynamic_ld_h 1
+
+#ifdef __GNUG__
+#pragma interface
+#endif
+
+class tree_constant;
+
+typedef tree_constant* (*builtin_fcn_ptr) (tree_constant*, int, int);
+
+extern void octave_dld_tc2_unlink_by_symbol (char *name, int hard = 1);
+
+extern void octave_dld_tc2_unlink_by_file (char *name, int hard = 1);
+
+extern builtin_fcn_ptr octave_dld_tc2 (char *name, char *fcn, char *object);
+
+extern tree_constant *octave_dld_tc2_and_go (tree_constant *args,
+					     int nargin, int nargout,
+					     char *name, char *fcn,
+					     char *object);
+
+#endif
+
+/*
+;;; Local Variables: ***
+;;; mode: C++ ***
+;;; page-delimiter: "^/\\*" ***
+;;; End: ***
+*/
new file mode 100644
--- /dev/null
+++ b/src/eig.cc
@@ -0,0 +1,129 @@
+// tc-eig.cc                                           -*- C++ -*-
+/*
+
+Copyright (C) 1993 John W. Eaton
+
+This file is part of Octave.
+
+Octave is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+Octave is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with Octave; see the file COPYING.  If not, write to the Free
+Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifdef __GNUG__
+#pragma implementation
+#endif
+
+#include "Matrix.h"
+
+#include "tree-const.h"
+#include "user-prefs.h"
+#include "gripes.h"
+#include "error.h"
+
+#ifdef WITH_DLD
+tree_constant *
+builtin_eig (tree_constant *args, int nargin, int nargout)
+{
+  return eig (args, nargin, nargout);
+}
+#endif
+
+tree_constant *
+eig (tree_constant *args, int nargin, int nargout)
+{
+  tree_constant *retval = NULL_TREE_CONST;
+
+  tree_constant arg = args[1].make_numeric ();
+
+  int a_nr = arg.rows ();
+  int a_nc = arg.columns ();
+
+  if (a_nr == 0 || a_nc == 0)
+    {
+      int flag = user_pref.propagate_empty_matrices;
+      if (flag != 0)
+	{
+	  if (flag < 0)
+	    gripe_empty_arg ("eig", 0);
+	  Matrix m;
+	  retval = new tree_constant [3];
+	  retval[0] = tree_constant (m);
+	  retval[1] = tree_constant (m);
+	}
+      else
+	gripe_empty_arg ("eig", 1);
+
+      return retval;
+    }
+
+  if (a_nr != a_nc)
+    {
+      gripe_square_matrix_required ("eig");
+      return retval;
+    }
+
+  Matrix tmp;
+  ComplexMatrix ctmp;
+  EIG result;
+  switch (arg.const_type ())
+    {
+    case tree_constant_rep::scalar_constant:
+      tmp.resize (1, 1);
+      tmp.elem (0, 0) = arg.double_value ();
+      result = EIG (tmp);
+      break;
+    case tree_constant_rep::matrix_constant:
+      tmp = arg.matrix_value ();
+      result = EIG (tmp);
+      break;
+    case tree_constant_rep::complex_scalar_constant:
+      ctmp.resize (1, 1);
+      ctmp.elem (0, 0) = arg.complex_value ();
+      result = EIG (ctmp);
+      break;
+    case tree_constant_rep::complex_matrix_constant:
+      ctmp = arg.complex_matrix_value ();
+      result = EIG (ctmp);
+      break;
+    default:
+      panic_impossible ();
+      break;
+    }
+
+  if (nargout == 1)
+    {
+      retval = new tree_constant [2];
+      retval[0] = tree_constant (result.eigenvalues (), 1);
+    }
+  else
+    {
+// Blame it on Matlab.
+
+      ComplexDiagMatrix d (result.eigenvalues ());
+
+      retval = new tree_constant [3];
+      retval[0] = tree_constant (result.eigenvectors ());
+      retval[1] = tree_constant (d);
+    }
+
+  return retval;
+}
+
+/*
+;;; Local Variables: ***
+;;; mode: C++ ***
+;;; page-delimiter: "^/\\*" ***
+;;; End: ***
+*/
new file mode 100644
--- /dev/null
+++ b/src/error.cc
@@ -0,0 +1,96 @@
+// error.cc                                             -*- C++ -*-
+/*
+
+Copyright (C) 1992, 1993 John W. Eaton
+
+This file is part of Octave.
+
+Octave is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+Octave is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with Octave; see the file COPYING.  If not, write to the Free
+Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifdef __GNUG__
+#pragma implementation
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+
+#include "error.h"
+
+static void
+verror (const char *name, const char *fmt, va_list args)
+{
+  if (name != (char *) NULL)
+    fprintf (stderr, "%s: ", name);
+
+  vfprintf (stderr, fmt, args);
+  fprintf (stderr, "\n");
+  fflush (stderr);
+}
+
+void
+message (const char *name, const char *fmt, ...)
+{
+  va_list args;
+  va_start (args, fmt);
+  verror (name, fmt, args);
+  va_end (args);
+}
+
+void
+usage (const char *fmt, ...)
+{
+  va_list args;
+  va_start (args, fmt);
+  verror ("usage", fmt, args);
+  va_end (args);
+}
+
+void
+warning (const char *fmt, ...)
+{
+  va_list args;
+  va_start (args, fmt);
+  verror ("warning", fmt, args);
+  va_end (args);
+}
+
+void
+error (const char *fmt, ...)
+{
+  va_list args;
+  va_start (args, fmt);
+  verror ("error", fmt, args);
+  va_end (args);
+}
+
+void
+panic (const char *fmt, ...)
+{
+  va_list args;
+  va_start (args, fmt);
+  verror ("panic", fmt, args);
+  va_end (args);
+  abort ();
+}
+
+/*
+;;; Local Variables: ***
+;;; mode: C++ ***
+;;; page-delimiter: "^/\\*" ***
+;;; End: ***
+*/
new file mode 100644
--- /dev/null
+++ b/src/error.h
@@ -0,0 +1,48 @@
+// error.h                                              -*- C++ -*-
+/*
+
+Copyright (C) 1992, 1993 John W. Eaton
+
+This file is part of Octave.
+
+Octave is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+Octave is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with Octave; see the file COPYING.  If not, write to the Free
+Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#if !defined (_error_h)
+#define _error_h 1
+
+#ifdef __GNUG__
+#pragma interface
+#endif
+
+#define panic_impossible() \
+  panic ("impossible state reached in file `%s' at line %d", \
+	 __FILE__, __LINE__)
+
+extern void message (const char *name, const char *fmt, ...);
+extern void usage (const char *fmt, ...);
+extern void warning (const char *fmt, ...);
+extern void error (const char *fmt, ...);
+extern void panic (const char *fmt, ...);
+
+#endif
+
+/*
+;;; Local Variables: ***
+;;; mode: C++ ***
+;;; page-delimiter: "^/\\*" ***
+;;; End: ***
+*/
new file mode 100644
--- /dev/null
+++ b/src/fft.cc
@@ -0,0 +1,100 @@
+// tc-fft.cc                                           -*- C++ -*-
+/*
+
+Copyright (C) 1993 John W. Eaton
+
+This file is part of Octave.
+
+Octave is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+Octave is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with Octave; see the file COPYING.  If not, write to the Free
+Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifdef __GNUG__
+#pragma implementation
+#endif
+
+#include "Matrix.h"
+
+#include "tree-const.h"
+#include "user-prefs.h"
+#include "gripes.h"
+#include "error.h"
+
+#ifdef WITH_DLD
+tree_constant *
+builtin_fft_2 (tree_constant *args, int nargin, int nargout)
+{
+  tree_constant *retval = new tree_constant [2];
+  retval[0] = fft (args[1]);
+  return retval;
+}
+#endif
+
+tree_constant
+fft (tree_constant& a)
+{
+  tree_constant retval;
+
+  tree_constant tmp = a.make_numeric ();;
+    
+  if (tmp.rows () == 0 || tmp.columns () == 0)
+    {
+      int flag = user_pref.propagate_empty_matrices;
+      if (flag != 0)
+	{
+	  if (flag < 0)
+	    gripe_empty_arg ("fft", 0);
+	  Matrix m;
+	  retval = tree_constant (m);
+	}
+      else
+	gripe_empty_arg ("fft", 1);
+
+      return retval;
+    }
+
+  switch (tmp.const_type ())
+    {
+    case tree_constant_rep::matrix_constant:
+      {
+	Matrix m = tmp.matrix_value ();
+	ComplexMatrix mfft = m.fourier ();
+	retval = tree_constant (mfft);
+      }
+      break;
+    case tree_constant_rep::complex_matrix_constant:
+      {
+	ComplexMatrix m = tmp.complex_matrix_value ();
+	ComplexMatrix mfft = m.fourier ();
+	retval = tree_constant (mfft);
+      }
+      break;
+    case tree_constant_rep::scalar_constant:
+    case tree_constant_rep::complex_scalar_constant:
+      error ("fft: invalid scalar argument");
+      break;
+    default:
+      panic_impossible ();
+      break;
+    }
+  return retval;
+}
+
+/*
+;;; Local Variables: ***
+;;; mode: C++ ***
+;;; page-delimiter: "^/\\*" ***
+;;; End: ***
+*/
new file mode 100644
--- /dev/null
+++ b/src/file-io.cc
@@ -0,0 +1,1204 @@
+// file-io.cc                                             -*- C++ -*-
+/*
+
+Copyright (C) 1993 John W. Eaton
+
+This file is part of Octave.
+
+Octave is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+Octave is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with Octave; see the file COPYING.  If not, write to the Free
+Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+// Written by John C. Campbell <jcc@che.utexas.edu>.
+
+#ifdef __GNUG__
+#pragma implementation
+#endif
+
+#include <DLList.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strstream.h>
+#include <ctype.h>
+
+#include "statdefs.h"
+#include "file-io.h"
+#include "input.h"
+#include "octave-hist.h"
+#include "tree-const.h"
+#include "error.h"
+#include "utils.h"
+#include "pager.h"
+
+// keeps a count of how many files are open and in the file list
+static int file_count = 0;
+
+// keeps a count of args sent to printf or scanf
+static int fmt_arg_count = 0;
+
+class File_info
+{
+ public:
+  File_info (void);
+  File_info (int num, char *nm, FILE *t, char *md);
+  File_info (const File_info& f);
+
+  File_info& operator = (const File_info& f);
+
+  ~File_info (void);
+
+  int number (void) const;
+  char *name (void) const;
+  FILE *fptr (void) const;
+  char *mode (void) const;
+
+ private:
+  int _number;
+  char *_name;
+  FILE *_fptr;
+  char *_mode;
+};
+
+File_info::File_info (void)
+{
+  _number = -1;
+  _name = (char *) NULL;
+  _fptr = (FILE *) NULL;
+  _mode = (char *) NULL;
+}
+
+File_info::File_info (const File_info& f)
+{
+  _number = f._number;
+  _name = strsave (f._name);
+  _fptr = f._fptr;
+  _mode = strsave (f._mode);
+}
+
+File_info&
+File_info::operator = (const File_info& f)
+{
+  _number = f._number;
+  _name = strsave (f._name);
+  _fptr = f._fptr;
+  _mode = strsave (f._mode);
+
+  return *this;
+}
+
+File_info::~File_info (void)
+{
+  delete [] _name;
+  delete [] _mode;
+}
+
+File_info::File_info (int n, char *nm, FILE *t, char *md)
+{
+  _number = n;
+  _name = strsave (nm);
+  _fptr = t;
+  _mode = strsave (md);
+}
+
+int
+File_info::number (void) const
+{
+  return _number;
+}
+
+char *
+File_info::name (void) const
+{
+  return _name;
+}
+
+FILE *
+File_info::fptr (void) const
+{
+  return _fptr;
+}
+
+char *
+File_info::mode (void) const
+{
+  return _mode;
+}
+
+
+// double linked list containing relevant information about open files
+static DLList <File_info> file_list;
+
+void
+initialize_file_io ()
+{
+  File_info _stdin (0, "stdin", stdin, "r");
+  File_info _stdout (1, "stdout", stdout, "w");
+  File_info _stderr (2, "stderr", stderr, "w");
+
+  file_list.append (_stdin);
+  file_list.append (_stdout);
+  file_list.append (_stderr);
+
+  file_count = 3;
+}
+
+Pix
+return_valid_file (tree_constant& arg)
+{
+  if (arg.is_string_type ())
+    {
+      Pix p = file_list.first ();
+      File_info file;
+      for (int i = 0; i < file_count; i++)
+	{
+	  char *file_name = arg.string_value ();
+	  file = file_list (p);
+	  if (strcmp (file.name (), file_name) == 0)
+	    return p;
+	  file_list.next (p);
+	}
+    }
+  else if (arg.is_scalar_type ())
+    {
+      double file_num = arg.double_value ();
+      if ((double) NINT (file_num) != file_num)
+	error ("file number not an integer value");
+      else
+	{
+	  Pix p = file_list.first ();
+	  File_info file;
+	  for (int i = 0; i < file_count; i++)
+	    {
+	      file = file_list (p);
+	      if (file.number () == file_num)
+		return p;
+	      file_list.next (p);
+	    }
+	  error ("no file with that number");
+	}
+      }
+    else
+      error ("inapproriate file specifier");
+
+  return (Pix) NULL;
+}
+
+static Pix 
+fopen_file_for_user (tree_constant& arg, char *mode)
+{
+  char *file_name = arg.string_value ();
+
+  FILE *file_ptr = fopen (file_name, mode);
+  if (file_ptr != (FILE *) NULL)
+    {
+      File_info file (++file_count, file_name, file_ptr, mode);
+      file_list.append (file);
+      
+      Pix p = file_list.first ();
+      File_info file_from_list;
+      
+      for (int i = 0; i < file_count; i++)
+	{
+	  file_from_list = file_list (p);
+	  if (strcmp (file_from_list.name (), file_name) == 0)
+	    return p;
+	  file_list.next (p);
+	}
+    }
+
+  error ("problems automatically opening file for user");
+  return (Pix) NULL;
+}
+
+
+tree_constant *
+fclose_internal (tree_constant *args)
+{
+  tree_constant *retval = NULL_TREE_CONST;
+
+  Pix p = return_valid_file (args[1]);
+
+  if (p == (Pix) NULL)
+    return retval;
+
+  File_info file = file_list (p);
+
+  if (file.number () < 3)
+    {
+      warning ("fclose: can't close stdin, stdout, or stderr!");
+      return retval;
+    }
+
+  int success = fclose (file.fptr ());
+  file_list.del (p);
+  file_count--;
+
+  retval = new tree_constant[2];
+  if (success == 0)
+    retval[0] = tree_constant (1.0); // succeeded
+  else
+    {
+      error ("fclose: error on closing file");
+      retval[0] = tree_constant (0.0); // failed
+    }
+
+  return retval;
+}
+
+tree_constant *
+fflush_internal (tree_constant *args)
+{
+  tree_constant *retval = NULL_TREE_CONST;
+
+  Pix p = return_valid_file (args[1]);
+
+  if (p == (Pix) NULL)
+    return retval;
+
+  File_info file = file_list (p);
+
+  if (strcmp (file.mode (), "r") == 0)
+    {
+      warning ("can't flush an input stream");
+      return retval;
+    }
+
+  int success = 0;
+  if (file.number () == 1)
+    flush_output_to_pager ();
+  else
+    success = fflush (file.fptr ());
+
+  retval = new tree_constant[2];
+  if (success == 0)
+    retval[0] = tree_constant (1.0); // succeeded
+  else
+    {
+      error ("fflush: write error");
+      retval[0] = tree_constant (0.0); // failed
+    }
+
+  return retval;
+}
+
+static int
+valid_mode (char *mode)
+{
+  if (mode != (char *) NULL)
+    {
+      char m = mode[0];
+      if (m == 'r' || m == 'w' || m == 'a')
+	{
+	  m = mode[1];
+	  return (m == '\0' || (m == '+' && mode[2] == '\0'));
+	}
+    }
+  return 0;
+}
+
+tree_constant *
+fgets_internal (tree_constant *args, int nargout)
+{
+  tree_constant *retval = NULL_TREE_CONST;
+
+  Pix p = return_valid_file (args[1]);
+  
+  if (p == (Pix) NULL)
+    {
+      if (args[1].is_string_type ())
+	{
+	  struct stat buffer;
+	  char *name = args[1].string_value ();
+	  if (stat (name, &buffer) == 0
+	      && (buffer.st_mode & S_IFREG) == S_IFREG)
+	    {
+	      p = fopen_file_for_user (args[1], "r");
+	    }
+	  else
+	    {
+	      error ("fgets: file dosen't exist");
+	      return retval;
+	    }
+	}
+      else
+	return retval;
+    }
+  
+  int length = 0;
+
+  if (args[2].is_scalar_type ())
+    {
+      length = (int) args[2].double_value ();
+      if ((double) NINT (length) != length)
+	{
+	  error ("fgets: length not an integer value");
+	  return retval;
+	}
+    }
+
+  char string[length+1];
+  File_info file = file_list (p);
+  char *success = fgets (string, length+1, file.fptr ());
+
+  if (success == (char *) NULL)
+    {
+      retval = new tree_constant[2];
+      retval[0] = tree_constant (-1.0);
+      return retval;
+    }
+
+  if (nargout == 2)
+    {
+      retval = new tree_constant[3];
+      retval[1] = tree_constant ((double) strlen (string));
+    }
+  else
+    retval = new tree_constant[2];
+
+  retval[0] = tree_constant (string);
+
+  return retval;
+}
+
+tree_constant *
+fopen_internal (tree_constant *args)
+{
+  tree_constant *retval = NULL_TREE_CONST;
+  Pix p;
+
+  if (! args[1].is_string_type ())
+    {
+      error ("fopen: file name must be a string");
+      return retval;
+    }
+
+  p = return_valid_file (args[1]);
+
+  if (p != (Pix) NULL)
+    {
+      File_info file = file_list (p);
+
+      retval = new tree_constant[2];
+      retval[0] = tree_constant ((double) file.number ());
+
+      return retval;
+    }
+
+  if (! args[2].is_string_type ())
+    {
+      error ("fopen: mode must be a string");
+      return retval;
+    }
+
+  char *name = args[1].string_value ();
+  char *mode = args[2].string_value ();
+
+  if (! valid_mode (mode))
+    {
+      error ("fopen: invalid mode");
+      return retval;
+    }
+
+  struct stat buffer;
+  if (stat (name, &buffer) == 0 && (buffer.st_mode & S_IFDIR) == S_IFDIR)
+    {
+      error ("fopen: can't open directory");
+      return retval;
+    }
+
+  FILE *file_ptr = fopen (name, mode);
+
+  if (file_ptr == (FILE *) NULL)
+    {
+      error ("fopen: file does not exist");
+      return retval;
+    }
+
+  int number = file_count++;
+
+  File_info file (number, name, file_ptr, mode);
+  file_list.append (file);
+
+  retval = new tree_constant[2];
+  retval[0] = tree_constant ((double) number);
+
+  return retval;
+}
+
+tree_constant *
+freport_internal ()
+{
+  tree_constant *retval = NULL_TREE_CONST;
+  Pix p = file_list.first ();
+
+  ostrstream output_buf;
+
+  output_buf << "\n number  mode  name\n\n";
+  for (int i = 0; i < file_count; i++)
+    {
+      File_info file = file_list (p);
+      output_buf.form ("%7d%6s  %s\n", file.number (), file.mode (),
+		       file.name ());
+      file_list.next (p);
+    }
+
+  output_buf << "\n" << ends;
+  maybe_page_output (output_buf);
+
+  return retval;
+}
+
+tree_constant *
+frewind_internal (tree_constant *args)
+{
+  tree_constant *retval = NULL_TREE_CONST;
+
+  Pix p = return_valid_file (args[1]);
+  if (p == (Pix) NULL)
+    p = fopen_file_for_user (args[1], "a+");   
+
+  File_info file = file_list (p);
+  rewind (file.fptr ());
+
+  return retval;
+}
+
+tree_constant *
+fseek_internal (tree_constant *args, int nargin)
+{
+  tree_constant *retval = NULL_TREE_CONST;
+
+  Pix p = return_valid_file (args[1]);
+
+  if (p == (Pix) NULL)
+    p = fopen_file_for_user (args[1], "a+");
+
+  long origin = SEEK_SET;
+  long offset = 0;
+  if (args[2].is_scalar_type ())
+    {
+      offset = (long) args[2].double_value ();
+      if ((double) NINT (offset) != offset)
+	{
+	  error ("fseek: offset not an integer value");
+	  return retval;
+	}
+    }
+
+  if (nargin == 4 && args[3].is_scalar_type ())
+    {
+      origin = (long) args[3].double_value ();
+      if (origin == -1)
+	origin = SEEK_CUR;
+      else if (origin == -2)
+	origin = SEEK_END;
+      else
+	{
+	  if ((double) NINT (origin) != origin)
+	    {
+	      error ("fseek: origin not an integer value");
+	      return retval;
+	    }
+	}
+    }
+
+  File_info file = file_list (p);
+  int success = fseek (file.fptr (), offset, origin);
+  retval = new tree_constant[2];
+
+  if (success == 0)
+    retval[0] = tree_constant (1.0); // succeeded
+  else
+    {
+      error ("fseek: file error");
+      retval[0] = tree_constant (0.0); // failed
+    }
+
+  return retval;
+}
+
+tree_constant *
+ftell_internal (tree_constant *args)
+{
+  tree_constant *retval = NULL_TREE_CONST;
+  Pix p = return_valid_file (args[1]);
+
+  if (p == (Pix) NULL)
+    p = fopen_file_for_user (args[1], "a+");
+
+  File_info file = file_list (p);
+  long offset = ftell (file.fptr ());
+  retval = new tree_constant[2];
+  retval[0] = tree_constant ((double) offset);
+
+  if (offset == -1L)
+    error ("ftell: write error");
+
+  return retval;
+}
+
+void
+close_files ()
+{
+  Pix p = file_list.first ();
+
+  for (int i = 0; i < file_count; i++)
+    {
+      File_info file = file_list (p);
+      if (i > 2)   // do not close stdin, stdout, stderr!
+	{
+	  int success = fclose (file.fptr ());
+	  if (success != 0)
+	    error ("closing %s", file.name ());
+	}
+      file_list.del (p);
+    }
+}
+
+static int
+process_printf_format (char *s, tree_constant *args, ostrstream& sb,
+		       char *type, int nargin)
+{
+  ostrstream fmt;
+
+  fmt << "%";  // do_printf() already blew past this one...
+
+  tree_constant_rep::constant_type arg_type;
+
+  int chars_from_fmt_str = 0;
+
+ again:
+  switch (*s)
+    {
+    case '+': case '-': case ' ': case '0': case '#':
+      chars_from_fmt_str++;
+      fmt << *s++;
+      goto again;
+
+    case '\0':
+      goto invalid_format;
+
+    default:
+      break;
+    }
+
+  if (*s == '*')
+    {
+      if (fmt_arg_count >= nargin)
+	{
+	  message (type, "not enough arguments");
+	  return -1;
+	}
+
+      if (args[fmt_arg_count].const_type ()
+	  != tree_constant_rep::scalar_constant)
+	{
+	  message (type, "`*' must be replaced by an integer");
+	  return -1;
+	}
+
+      fmt << (int) (args[fmt_arg_count++].double_value ());
+      s++;
+      chars_from_fmt_str++;
+    }
+  else
+    {
+      while (*s != '\0' && isdigit (*s))
+	{
+	  chars_from_fmt_str++;
+	  fmt << *s++;
+	}
+    }
+
+  if (*s == '\0')
+    goto invalid_format;
+
+  if (*s == '.')
+    {
+      chars_from_fmt_str++;
+      fmt << *s++;
+    }
+
+  if (*s == '*')
+    {
+      if (*(s-1) == '*')
+	goto invalid_format;
+
+      if (fmt_arg_count >= nargin)
+	{
+	  message (type, "not enough arguments");
+	  return -1;
+	}
+
+      if (args[fmt_arg_count].const_type ()
+	  != tree_constant_rep::scalar_constant)
+	{
+	  message (type, "`*' must be replaced by an integer");
+	  return -1;
+	}
+
+      fmt << (int) (args[fmt_arg_count++].double_value ());
+      s++;
+      chars_from_fmt_str++;
+    }
+  else
+    {
+      while (*s != '\0' && isdigit (*s))
+	{
+	  chars_from_fmt_str++;
+	  fmt << *s++;
+	}
+    }
+
+  if (*s == '\0')
+    goto invalid_format;
+
+  if (*s != '\0' && (*s == 'h' || *s == 'l' || *s == 'L'))
+    {
+      chars_from_fmt_str++;
+      fmt << *s++;
+    }
+
+  if (*s == '\0')
+    goto invalid_format;
+
+  if (fmt_arg_count >= nargin)
+    {
+      message (type, "not enough arguments");
+      return -1;
+    }
+
+  arg_type = args[fmt_arg_count].const_type ();
+
+  switch (*s)
+    {
+    case 'd': case 'i': case 'o': case 'u': case 'x': case 'X':
+
+      if (arg_type != tree_constant_rep::scalar_constant)
+	goto invalid_conversion;
+      else
+	{
+	  chars_from_fmt_str++;
+	  fmt << *s << ends;
+	  double d = args[fmt_arg_count++].double_value ();
+	  if ((int) d != d)
+	    goto invalid_conversion;
+	  else
+	    {
+	      char *s = fmt.str ();
+	      sb.form (s, (int) d);
+	      delete [] s;
+	      return chars_from_fmt_str;
+	    }
+	}
+
+    case 'e': case 'E': case 'f': case 'g': case 'G':
+
+      if (arg_type != tree_constant_rep::scalar_constant)
+	goto invalid_conversion;
+      else
+	{
+	  chars_from_fmt_str++;
+	  fmt << *s << ends;
+	  char *s = fmt.str ();
+	  sb.form (s, args[fmt_arg_count++].double_value ());
+	  delete [] s;
+	  return chars_from_fmt_str;
+	}
+
+    case 's':
+
+      if (arg_type != tree_constant_rep::string_constant)
+	goto invalid_conversion;
+      else
+	{
+	  chars_from_fmt_str++;
+	  fmt << *s << ends;
+	  char *s = fmt.str ();
+	  sb.form (s, args[fmt_arg_count++].string_value ());
+	  delete [] s;
+	  return chars_from_fmt_str;
+	}
+
+    case 'c':
+
+      if (arg_type != tree_constant_rep::string_constant)
+	goto invalid_conversion;
+      else
+	{
+	  chars_from_fmt_str++;
+	  fmt << *s << ends;
+	  char *str = args[fmt_arg_count++].string_value ();
+	  if (strlen (str) != 1)
+	    goto invalid_conversion;
+	  else
+	    {
+	      char *s = fmt.str ();
+	      sb.form (s, *str);
+	      delete [] s;
+	      return chars_from_fmt_str;
+	    }
+	}
+
+    default:
+      goto invalid_format;
+   }
+
+ invalid_conversion:
+  message (type, "invalid conversion");
+  return -1;
+
+ invalid_format:
+  message (type, "invalid format");
+  return -1;
+}
+
+
+tree_constant *
+do_printf (char *type, tree_constant *args, int nargin, int nargout)
+{
+  tree_constant *retval = NULL_TREE_CONST;
+  fmt_arg_count = 1;
+  char *fmt;
+  File_info file;
+
+  if (strcmp (type, "fprintf") == 0)
+    {
+      Pix p;
+
+      if (args[2].is_string_type ())
+	{
+	  fmt = args[2].string_value ();
+	  fmt_arg_count++;
+	}
+      else
+	{
+	  error ("%s: format must be a string", type);
+	  return retval;
+	}
+
+      if (args[1].is_scalar_type ())
+	{
+	  p = return_valid_file (args[1]);
+	  if (p == (Pix) NULL)
+	    return retval;
+	}
+      else if (args[1].is_string_type ())
+	{
+	  p = return_valid_file (args[1]);
+	  if (p == (Pix) NULL)
+	    p = fopen_file_for_user (args[1], "a+");
+	}
+      else
+	  {
+	    error ("%s: illegal file specifier", type);
+	    return retval;
+	  }
+
+      file = file_list (p);
+      if (file.mode () == "r")
+	{
+	  error ("%s: file is read only", type);
+	  return retval;
+	}
+      fmt = args[2].string_value ();
+      fmt_arg_count++;
+    }
+  else if (args[1].is_string_type ())
+    {
+      fmt = args[1].string_value ();
+      fmt_arg_count++;
+    }
+  else
+    {
+      error ("%s: invalid format string", type);
+      return retval;
+    }
+
+// Scan fmt for % escapes and print out the arguments.
+
+  ostrstream output_buf;
+
+  char *ptr = fmt;
+
+  for (;;)
+    {
+      char c;
+      while ((c = *ptr++) != '\0' && c != '%')
+	output_buf << c;
+
+      if (c == '\0')
+	break;
+
+      if (*ptr == '%')
+	{
+	  ptr++;
+	  output_buf << c;
+	  continue;
+	}
+
+// We must be looking at a format specifier.  Extract it or fail.
+
+
+      int status = process_printf_format (ptr, args, output_buf, type,
+					  nargin);
+
+      if (status < 0)
+	return retval;
+
+      ptr += status;
+    }
+
+  output_buf << ends;
+  if (strcmp (type, "printf") == 0
+      || (strcmp (type, "fprintf") == 0 && file.number () == 1))
+    {
+      maybe_page_output (output_buf);
+    }
+  else if (strcmp (type, "fprintf") == 0)
+    {
+      char *msg = output_buf.str ();
+      int success = fputs (msg, file.fptr ());
+      if (success == EOF)
+	error ("%s: writing to file", type);
+      delete [] msg;
+    }
+  else if (strcmp (type, "sprintf") == 0)
+    {
+      retval = new tree_constant [2];
+      char *msg = output_buf.str ();
+      retval[0] = tree_constant (msg);
+      delete [] msg;
+    }
+
+  return retval;
+}
+
+static int
+process_scanf_format (char *s, tree_constant *args, ostrstream& fmt,
+		      char *type, int nargout, FILE* fptr,
+		      tree_constant *values)
+{
+  fmt << "%";
+
+  tree_constant_rep::constant_type arg_type;
+
+  int chars_from_fmt_str = 0;
+  int store_value = 1;
+  int string_width = -1;
+  int success = 1;
+
+  if (*s == '*')
+    {
+      store_value = 0;
+      s++;
+      chars_from_fmt_str++;
+    }
+
+  if (isdigit (*s))
+    {
+      ostrstream str_number;
+      while (*s != '\0' && isdigit (*s))
+	{
+	  chars_from_fmt_str++;
+	  str_number << *s;
+	  fmt << *s++;
+	}
+      str_number << ends;
+      char *number = str_number.str ();
+      string_width = atoi (number);
+      delete [] number;
+    }
+
+  if (*s == '\0')
+    goto invalid_format;
+
+  if (*s != '\0' && (*s == 'h' || *s == 'l' || *s == 'L'))
+    {
+      chars_from_fmt_str++;
+      s++;
+    }
+
+  if (*s == '\0')
+    goto invalid_format;
+
+  if (fmt_arg_count >= nargout && store_value)
+    {
+      message (type, "not enough arguments");
+      return -1;
+    }
+
+  arg_type = args[fmt_arg_count].const_type ();
+
+  switch (*s)
+    {
+    case 'd': case 'i': case 'o': case 'u': case 'x': case 'X':
+      {
+	chars_from_fmt_str++;
+	fmt << *s << ends;
+	int temp;
+	char *str = fmt.str ();
+	success = fscanf (fptr, str, &temp);
+	delete [] str;
+	if (success > 0 && store_value)
+	  values[fmt_arg_count++] = tree_constant ((double) temp);
+      }
+      break;
+    case 'e': case 'E': case 'f': case 'g': case 'G':
+      {
+	chars_from_fmt_str++;
+	fmt << 'l' << *s << ends;
+	double temp;
+	char *str = fmt.str ();
+	success = fscanf (fptr, str, &temp);
+	delete [] str;
+	if (success > 0 && store_value)
+	  values[fmt_arg_count++] = tree_constant (temp);
+      }
+      break;
+    case 's':
+      {
+	if (string_width < 1)
+	  {
+	    string_width = 0;
+	    long original_position = ftell (fptr);
+	    int c;
+
+	    while ((c = getc (fptr)) != EOF
+		   && (c == ' ' || c == '\n' || c != '\t'))
+	      ; // Don't count leading whitespace.
+
+	    if (c != EOF)
+	      string_width++;
+
+	    for (;;)
+	      {
+		c = getc (fptr);
+		if (c != EOF && c != ' ' && c != '\n' && c != '\t')
+		  string_width++;
+		else
+		  break;
+	      }
+
+	    fseek (fptr, original_position, SEEK_SET);
+	  }
+	chars_from_fmt_str++;
+	char temp[string_width+1];
+	fmt << *s << ends;
+	char *str = fmt.str ();
+	success = fscanf (fptr, str, temp);
+	delete [] str;
+	if (success && store_value)
+	  values[fmt_arg_count++] = tree_constant (temp);
+      }
+      break;
+    case 'c':
+      {
+	if (string_width < 1)
+	  string_width = 1;
+	chars_from_fmt_str++;
+	char temp[string_width+1];
+	memset (temp, '\0', string_width+1);
+	fmt << *s << ends;
+	char *str = fmt.str ();
+	success = fscanf (fptr, str, temp);
+	delete [] str;
+	temp[string_width] = '\0';
+	if (success > 0 && store_value)
+	  values[fmt_arg_count++] = tree_constant (temp);
+      }
+      break;
+    default:
+      goto invalid_format;
+    }
+
+  if (success > 0 || (success == 0 && store_value == 0))
+    return chars_from_fmt_str;
+
+  if (success == 0)
+    message (type, "invalid conversion");
+  else if (success == EOF)
+    {
+      if (strcmp (type, "fscanf") == 0)
+	message (type, "end of file reached before final conversion");
+      else if (strcmp (type, "sscanf") == 0)
+	message (type, "end of string reached before final conversion");
+      else if (strcmp (type, "scanf") == 0)
+	message (type, "end of input reached before final conversion");
+    }
+  else
+    {
+    invalid_format:
+      message (type, "invalid format");
+    }
+
+  return -1;
+}
+
+tree_constant *
+do_scanf (char *type, tree_constant *args, int nargin, int nargout)
+{
+  tree_constant *retval = NULL_TREE_CONST;
+  char *scanf_fmt = (char *) NULL;
+  char *tmp_file = (char *) NULL;
+  int tmp_file_open = 0;
+  FILE *fptr = (FILE *) NULL;
+  File_info file;
+
+  fmt_arg_count = 0;
+
+  if (strcmp (type, "scanf") != 0)
+    {
+      if ( args[2].is_string_type ())
+	scanf_fmt = args[2].string_value ();
+      else
+	{
+	  error ("%s: format must be a string", type);
+	  return retval;
+	}
+    }
+
+  int doing_fscanf = (strcmp (type, "fscanf") == 0);
+
+  if (doing_fscanf)
+    {
+      Pix p;
+      if (args[1].is_scalar_type ()
+	  || args[1].is_string_type ())
+	{
+	  p = return_valid_file (args[1]);
+	  if (p == (Pix) NULL)
+	    return retval;
+	}
+      else
+	{
+	  error ("%s: illegal file specifier", type);
+	  return retval;
+	}
+
+      file = file_list (p);
+
+      if (strcmp (file.mode (), "w") == 0 || strcmp (file.mode (), "a") == 0)
+	{
+	  error ("%s: this file is opened for writing only", type);
+	  return retval;
+	}
+
+      fptr = file.fptr ();
+    }
+
+  if (args[1].is_string_type () || (doing_fscanf && file.number () == 0))
+    {
+      char *string;
+
+      if (strcmp (type, "scanf") == 0)
+	scanf_fmt = args[1].string_value ();
+
+      if (strcmp (type, "scanf") == 0
+	  || (doing_fscanf && file.number () == 0))
+	{
+	  string = gnu_readline ("");
+	  if (string && *string)
+	    maybe_save_history (string);
+	}
+      else
+	string = args[1].string_value ();
+
+      tmp_file = tmpnam ((char *) NULL);
+
+      fptr = fopen (tmp_file, "w+");
+      if (fptr == (FILE *) NULL)
+	{
+	  error ("%s: error opening temporary file", type);
+	  return retval;
+	}
+      tmp_file_open = 1;
+      unlink (tmp_file);
+
+      if (string == (char *) NULL)
+	panic_impossible ();
+
+      int success = fputs (string, fptr);
+      fflush (fptr);
+      rewind (fptr);
+
+      if (success < 0)
+	{
+	  error ("%s: trouble writing temporary file", type);
+	  fclose (fptr);
+	  return retval;
+	}
+    }
+  else if (! doing_fscanf)
+    {
+      error ("%s: first argument must be a string", type);
+      return retval;
+    }
+
+// Scan scanf_fmt for % escapes and assign the arguments.
+
+  retval = new tree_constant[nargout+1];
+
+  char *ptr = scanf_fmt;
+
+  for (;;)
+    {
+      ostrstream fmt;
+      char c;
+      while ((c = *ptr++) != '\0' && c != '%')
+	fmt << c;
+
+      if (c == '\0')
+	break;
+
+      if (*ptr == '%')
+	{
+	  ptr++;
+	  fmt << c;
+	  continue;
+	}
+
+// We must be looking at a format specifier.  Extract it or fail.
+
+      int status = process_scanf_format (ptr, args, fmt, type,
+					 nargout, fptr, retval);
+
+      if (status < 0)
+	{
+	  if (fmt_arg_count == 0)
+	    {
+	      delete [] retval;
+	      retval = NULL_TREE_CONST;
+	    }
+	  break;
+	}
+
+      ptr += status;
+    }
+
+  if (tmp_file_open)
+    fclose (fptr);
+
+  return retval;
+}
+
+/*
+;;; Local Variables: ***
+;;; mode: C++ ***
+;;; page-delimiter: "^/\\*" ***
+;;; End: ***
+*/
new file mode 100644
--- /dev/null
+++ b/src/file-io.h
@@ -0,0 +1,73 @@
+// file-io.h                                              -*- C++ -*-
+/*
+
+Copyright (C) 1993 John W. Eaton
+
+This file is part of Octave.
+
+Octave is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+Octave is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with Octave; see the file COPYING.  If not, write to the Free
+Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+// Written by John C. Campbell <jcc@che.utexas.edu>.
+
+#if !defined (_files_h)
+#define _files_h 1
+
+#ifdef __GNUG__
+#pragma interface
+#endif
+
+#include "tree-const.h"
+#include "utils.h"
+#include <Pix.h>
+#include <stdio.h>
+
+extern Pix return_valid_file (tree_constant& arg);
+
+extern tree_constant *fclose_internal (tree_constant *args);
+
+extern tree_constant *fflush_internal (tree_constant *args);
+
+extern tree_constant *fgets_internal (tree_constant *args, int nargout);
+
+extern tree_constant *fopen_internal (tree_constant *args);
+
+extern tree_constant *freport_internal ();
+
+extern tree_constant *frewind_internal (tree_constant *args);
+
+extern tree_constant *fseek_internal (tree_constant *args, int nargin);
+
+extern tree_constant *ftell_internal (tree_constant *args);
+
+extern void initialize_file_io ();
+
+extern void close_files ();
+
+extern tree_constant *do_printf (char *type, tree_constant *args,
+				 int nargin, int nargout);
+
+extern tree_constant *do_scanf (char *type, tree_constant *args,
+				int nargin, int nargout);
+
+#endif
+
+/*
+;;; Local Variables: ***
+;;; mode: C++ ***
+;;; page-delimiter: "^/\\*" ***
+;;; End: ***
+*/
new file mode 100644
--- /dev/null
+++ b/src/fsolve.cc
@@ -0,0 +1,164 @@
+// tc-fsolve.cc                                           -*- C++ -*-
+/*
+
+Copyright (C) 1993 John W. Eaton
+
+This file is part of Octave.
+
+Octave is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+Octave is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with Octave; see the file COPYING.  If not, write to the Free
+Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifdef __GNUG__
+#pragma implementation
+#endif
+
+#include "NLEqn.h"
+
+#include "tree-const.h"
+#include "variables.h"
+#include "gripes.h"
+#include "error.h"
+#include "utils.h"
+
+// Global pointer for user defined function required by hybrd1.
+static tree *fsolve_fcn;
+
+#ifdef WITH_DLD
+tree_constant *
+builtin_fsolve (tree_constant *args, int nargin, int nargout)
+{
+  return fsolve (args, nargin, nargout);
+}
+#endif
+
+int
+hybrd_info_to_fsolve_info (int info)
+{
+  switch (info)
+    {
+    case 0:
+      info = -1;
+      break;
+    case 1:
+      break;
+    case 2:
+      info = 4;
+      break;
+    case 3:
+    case 4:
+    case 5:
+      info = 3;
+      break;
+    default:
+      panic_impossible ();
+      break;
+    }
+  return info;
+}
+
+ColumnVector
+fsolve_user_function (ColumnVector& x)
+{
+  ColumnVector retval;
+
+  int n = x.capacity ();
+
+//  tree_constant name = tree_constant (fsolve_fcn->name ());
+  tree_constant *args = new tree_constant [2];
+//  args[0] = name;
+
+  if (n > 1)
+    {
+      Matrix m (n, 1);
+      for (int i = 0; i < n; i++)
+	m (i, 0) = x.elem (i);
+      tree_constant vars (m);
+      args[1] = vars;
+    }
+  else
+    {
+      double d = x.elem (0);
+      tree_constant vars (d);
+      args[1] = vars;
+    }
+
+  if (fsolve_fcn != NULL_TREE)
+    {
+      tree_constant *tmp = fsolve_fcn->eval (args, 2, 1, 0);
+      delete [] args;
+      if (tmp != NULL_TREE_CONST && tmp[0].is_defined ())
+	{
+	  retval = tmp[0].to_vector ();
+	  delete [] tmp;
+	}
+      else
+	{
+	  delete [] tmp;
+	  gripe_user_supplied_eval ("fsolve");
+	  jump_to_top_level ();
+	}
+    }
+
+  return retval;
+}
+
+tree_constant *
+fsolve (tree_constant *args, int nargin, int nargout)
+{
+// Assumes that we have been given the correct number of arguments.
+
+  tree_constant *retval = NULL_TREE_CONST;
+
+  fsolve_fcn = is_valid_function (args[1], "fsolve", 1);
+  if (fsolve_fcn == NULL_TREE
+      || takes_correct_nargs (fsolve_fcn, 2, "fsolve", 1) != 1)
+    return retval;
+
+  ColumnVector x = args[2].to_vector ();
+
+  if (nargin > 3)
+    message ("fsolve", "ignoring optional arguments...");
+
+  if (nargout > 2)
+    message ("fsolve", "can't compute path output yet...");
+
+  NLFunc foo_fcn (fsolve_user_function);
+  NLEqn foo (x, foo_fcn);
+
+  int info;
+  ColumnVector soln = foo.solve (info);
+
+  info = hybrd_info_to_fsolve_info (info);
+
+  retval = new tree_constant [nargout+1];
+  retval[0] = tree_constant (soln, 1);
+
+  if (nargout > 1)
+    retval[1] = tree_constant ((double) info);
+
+  if (nargout > 2)
+    retval[2] = tree_constant ();
+
+  return retval;
+}
+
+/*
+;;; Local Variables: ***
+;;; mode: C++ ***
+;;; page-delimiter: "^/\\*" ***
+;;; End: ***
+*/
+
new file mode 100644
--- /dev/null
+++ b/src/fsqp.cc
@@ -0,0 +1,92 @@
+// tc-fsqp.cc                                           -*- C++ -*-
+/*
+
+Copyright (C) 1993 John W. Eaton
+
+This file is part of Octave.
+
+Octave is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+Octave is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with Octave; see the file COPYING.  If not, write to the Free
+Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifdef __GNUG__
+#pragma implementation
+#endif
+
+#ifndef FSQP_MISSING
+
+#include "FSQP.h"
+
+#include "tree-const.h"
+#include "error.h"
+
+// Global pointers for user defined functions required by fsqp.
+static tree *fsqp_objective;
+static tree *fsqp_constraints;
+
+#ifdef WITH_DLD
+tree_constant *
+builtin_fsqp_2 (tree_constant *args, int nargin, int nargout)
+{
+  return fsqp (args, nargin, nargout);
+}
+#endif
+
+double
+fsqp_objective_function (ColumnVector& x)
+{
+  return 0.0;
+}
+
+ColumnVector
+fsqp_constraint_function (ColumnVector& x)
+{
+  ColumnVector retval;
+  return retval;
+}
+
+tree_constant *
+fsqp (tree_constant *args, int nargin, int nargout)
+{
+/*
+
+Handle all of the following:
+
+  1. fsqp (x, phi)
+  2. fsqp (x, phi, lb, ub)
+  3. fsqp (x, phi, lb, ub, llb, c, lub)
+  4. fsqp (x, phi, lb, ub, llb, c, lub, nllb, g, nlub)
+  5. fsqp (x, phi, lb, ub,              nllb, g, nlub)
+  6. fsqp (x, phi,         llb, c, lub, nllb, g, nlub)
+  7. fsqp (x, phi,         llb, c, lub)
+  8. fsqp (x, phi,                      nllb, g, nlub)
+
+*/
+
+// Assumes that we have been given the correct number of arguments.
+
+  tree_constant *retval = NULL_TREE_CONST;
+  message ("fsqp", "not implemented yet...");
+  return retval;
+}
+
+#endif
+
+/*
+;;; Local Variables: ***
+;;; mode: C++ ***
+;;; page-delimiter: "^/\\*" ***
+;;; End: ***
+*/
new file mode 100644
--- /dev/null
+++ b/src/g-builtins.cc
@@ -0,0 +1,1633 @@
+// g-builtins.cc                                           -*- C++ -*-
+/*
+
+Copyright (C) 1992, 1993 John W. Eaton
+
+This file is part of Octave.
+
+Octave is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+Octave is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with Octave; see the file COPYING.  If not, write to the Free
+Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+/*
+
+The function builtin_pwd adapted from a similar function from GNU
+Bash, the Bourne Again SHell, copyright (C) 1987, 1989, 1991 Free
+Software Foundation, Inc.
+
+*/
+
+#ifdef __GNUG__
+#pragma implementation
+#endif
+
+#include <sys/types.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <strstream.h>
+#include <iostream.h>
+#include <fstream.h>
+#include <stdio.h>
+#include <sys/wait.h>
+#include <sys/param.h>
+#include <signal.h>
+#include <math.h>
+
+#include "procstream.h"
+#include "error.h"
+#include "variables.h"
+#include "builtins.h"
+#include "g-builtins.h"
+#include "user-prefs.h"
+#include "utils.h"
+#include "tree.h"
+#include "input.h"
+#include "pager.h"
+#include "octave.h"
+#include "version.h"
+#include "file-io.h"
+
+extern "C"
+{
+#include <readline/readline.h>
+}
+
+#ifndef MAXPATHLEN
+#define MAXPATHLEN 1024
+#endif
+
+#ifdef WITH_DLD
+#include "dynamic-ld.h"
+#define Q_STR(name) #name
+#define DLD_FCN(name) Q_STR (builtin_##name##_2)
+#define DLD_OBJ(name) Q_STR (tc-##name##.o)
+#define DLD_BUILTIN(args,n_in,n_out,name,code) \
+return octave_dld_tc2_and_go (args, n_in, n_out, Q_STR (name), \
+			      DLD_FCN (name), DLD_OBJ (name));
+
+#else
+#define DLD_BUILTIN(name,args,n_in,n_out,code) code
+#endif
+
+// Non-zero means that pwd always give verbatim directory, regardless
+// of symbolic link following.
+static int verbatim_pwd = 1;
+
+// Signal handler return type.
+#ifndef RETSIGTYPE
+#define RETSIGTYPE void
+#endif
+#ifndef BADSIG
+#define BADSIG (RETSIGTYPE (*)())-1
+#endif
+
+typedef RETSIGTYPE sig_handler (...);
+
+/*
+ * Are all elements of a constant nonzero?
+ */
+tree_constant *
+builtin_all (tree_constant *args, int nargin, int nargout)
+{
+  tree_constant *retval = NULL_TREE_CONST;
+  if (nargin != 2)
+    usage ("all (M)");
+  else
+    {
+      if (args != NULL_TREE_CONST && args[1].is_defined ())
+	{
+	  retval = new tree_constant [2];
+	  retval[0] = args[1].all ();
+	}
+    }
+  return retval;
+}
+
+/*
+ * Are any elements of a constant nonzero?
+ */
+tree_constant *
+builtin_any (tree_constant *args, int nargin, int nargout)
+{
+  tree_constant *retval = NULL_TREE_CONST;
+  if (nargin != 2)
+    usage ("any (M)");
+  else
+    {
+      if (args != NULL_TREE_CONST && args[1].is_defined ())
+	{
+	  retval = new tree_constant [2];
+	  retval[0] = args[1].any ();
+	}
+    }
+  return retval;
+}
+
+/*
+ * Clear the screen?
+ */
+tree_constant *
+builtin_clc (tree_constant *args, int nargin, int nargout)
+{
+  rl_beg_of_line ();
+  rl_kill_line (1);
+  rl_clear_screen ();
+  return NULL_TREE_CONST;
+}
+
+/*
+ * Time in a vector.
+ */
+tree_constant *
+builtin_clock (tree_constant *args, int nargin, int nargout)
+{
+  tree_constant *retval = NULL_TREE_CONST;
+
+  time_t now;
+  struct tm *tm;
+
+  time (&now);
+  tm = localtime (&now);
+
+  Matrix m (1, 6);
+  m.elem (0, 0) = tm->tm_year + 1900;
+  m.elem (0, 1) = tm->tm_mon + 1;
+  m.elem (0, 2) = tm->tm_mday;
+  m.elem (0, 3) = tm->tm_hour;
+  m.elem (0, 4) = tm->tm_min;
+  m.elem (0, 5) = tm->tm_sec;
+
+  retval = new tree_constant [2];
+  retval[0] = tree_constant (m);
+
+  return retval;
+}
+
+/*
+ * Close the stream to the plotter.
+ */
+tree_constant *
+builtin_closeplot (tree_constant *args, int nargin, int nargout)
+{
+  tree_constant *retval = NULL_TREE_CONST;
+  close_plot_stream ();
+  return retval;
+}
+
+/*
+ * Collocation roots and weights.
+ */
+tree_constant *
+builtin_colloc (tree_constant *args, int nargin, int nargout)
+{
+  tree_constant *retval = NULL_TREE_CONST;
+
+  if (nargin < 2 || nargin > 4)
+    usage ("[r, A, B, q] = colloc (n [, \"left\"] [, \"right\"])");
+  else
+    DLD_BUILTIN (args, nargin, nargout, colloc,
+		 retval = collocation_weights (args, nargin);)
+
+  return retval;
+}
+
+/*
+ * Cumulative sums and products.
+ */
+tree_constant *
+builtin_cumprod (tree_constant *args, int nargin, int nargout)
+{
+  tree_constant *retval = NULL_TREE_CONST;
+  if (nargin != 2)
+    usage ("cumprod (M)");
+  else
+    {
+      if (args != NULL_TREE_CONST && args[1].is_defined ())
+	{
+	  retval = new tree_constant [2];
+	  retval[0] = args[1].cumprod ();
+	}
+    }
+  return retval;
+}
+
+tree_constant *
+builtin_cumsum (tree_constant *args, int nargin, int nargout)
+{
+  tree_constant *retval = NULL_TREE_CONST;
+  if (nargin != 2)
+    usage ("cumsum (M)");
+  else
+    {
+      if (args != NULL_TREE_CONST && args[1].is_defined ())
+	{
+	  retval = new tree_constant [2];
+	  retval[0] = args[1].cumsum ();
+	}
+    }
+  return retval;
+}
+
+/*
+ * DAEs.
+ */
+static void
+dassl_usage (void)
+{
+  usage ("dassl (\"function_name\", x_0, xdot_0, t_out\n\
+       dassl (\"function_name\", x_0, xdot_0, t_out, t_crit)\n\
+\n\
+       The first argument is the name of the function to call to\n\
+       compute the vector of residuals.  It must have the form\n\
+\n\
+         res = f (x, xdot, t)\n\
+\n\
+       where x, xdot, and res are vectors, and t is a scalar.");
+}
+
+tree_constant *
+builtin_dassl (tree_constant *args, int nargin, int nargout)
+{
+  tree_constant *retval = new tree_constant [2];
+
+  if ((nargin == 5 || nargin == 6) && nargout > 0)
+    DLD_BUILTIN (args, nargin, nargout, dassl,
+		 retval = dassl (args, nargin, nargout);)
+  else
+    dassl_usage ();
+
+  return retval;
+}
+
+/*
+ * Time in a string.
+ */
+tree_constant *
+builtin_date (tree_constant *args, int nargin, int nargout)
+{
+  tree_constant *retval = NULL_TREE_CONST;
+
+  time_t now;
+  struct tm *tm;
+
+  time (&now);
+  tm = localtime (&now);
+  char date[32];
+  int len = strftime (date, 31, "%d-%b-%y", tm);
+  if (len > 0)
+    {
+      retval = new tree_constant [2];
+      retval[0] = tree_constant (date);
+    }
+
+  return retval;
+}
+
+/*
+ * Determinant of a matrix.
+ */
+tree_constant *
+builtin_det (tree_constant *args, int nargin, int nargout)
+{
+  tree_constant *retval = NULL_TREE_CONST;
+
+  if (nargin == 2)
+    DLD_BUILTIN (args, nargin, nargout, det,
+		 {
+		   retval = new tree_constant [2];
+		   retval[0] = determinant (args[1]);
+		 })
+  else
+    usage ("det (a)");
+
+  return retval;
+}
+
+/*
+ * Diagonal elements of a matrix.
+ */
+tree_constant *
+builtin_diag (tree_constant *args, int nargin, int nargout)
+{
+  tree_constant *retval = NULL_TREE_CONST;
+
+  if (nargin == 2)
+    {
+      retval = new tree_constant [2];
+      retval[0] = args[1].diag ();
+    }
+  else if (nargin == 3)
+    {
+      retval = new tree_constant [2];
+      retval[0] = args[1].diag (args[2]);
+    }
+  else
+    usage ("diag (X [, k])");
+
+  return retval;
+}
+
+/*
+ * Display value without trimmings.
+ */
+tree_constant *
+builtin_disp (tree_constant *args, int nargin, int nargout)
+{
+  tree_constant *retval = NULL_TREE_CONST;
+
+  if (nargin == 2)
+    args[1].eval (1);
+  else
+    usage ("disp (X)");
+
+  return retval;
+}
+
+/*
+ * Compute eigenvalues and eigenvectors.
+ */
+tree_constant *
+builtin_eig (tree_constant *args, int nargin, int nargout)
+{
+  tree_constant *retval = NULL_TREE_CONST;
+
+  if (nargin == 2 && (nargout == 1 || nargout == 2))
+    DLD_BUILTIN (args, nargin, nargout, eig,
+		 retval = eig (args, nargin, nargout);)
+  else
+    usage ("lambda = eig (A)\n\
+       [v, d] = eig (A); d == diag (lambda)");
+
+  return retval;
+}
+
+/*
+ * Print error message and jump to top level.
+ */
+tree_constant *
+builtin_error (tree_constant *args, int nargin, int nargout)
+{
+  tree_constant *retval = NULL_TREE_CONST;
+
+  if (nargin == 2 && args != NULL_TREE_CONST && args[1].is_defined ())
+    args[1].print_if_string (cerr, 1);
+  else
+    message ((char *) NULL, "unspecified error, jumping to top level...");
+
+  jump_to_top_level ();
+
+  return retval;
+}
+
+/*
+ * Evaluate text argument as octave source.
+ */
+tree_constant *
+builtin_eval (tree_constant *args, int nargin, int nargout)
+{
+  tree_constant *retval = NULL_TREE_CONST;
+  if (nargin == 2)
+    {
+      int parse_status = 0;
+      retval = new tree_constant [2];
+      retval[0] = eval_string (args[1], parse_status);
+    }
+  else
+    usage ("eval (\"string\")");
+  return retval;
+}
+
+/*
+ * Check if variable or file exists.
+ */
+tree_constant *
+builtin_exist (tree_constant *args, int nargin, int nargout)
+{
+  tree_constant *retval = NULL_TREE_CONST;
+  if (nargin == 2 && args[1].is_string_type ())
+    {
+      int status = identifier_exists (args[1].string_value ());
+      retval = new tree_constant [2];
+      retval[0] = tree_constant ((double) status);
+    }
+  else
+    usage ("exist (\"string\")");
+  return retval;
+}
+
+/*
+ * Matrix exponential.
+ */
+tree_constant *
+builtin_expm (tree_constant *args, int nargin, int nargout)
+{
+  tree_constant *retval = NULL_TREE_CONST;
+
+  if (nargin == 2)
+    retval = matrix_exp (args[1]);
+  else
+    usage ("expm (A)");
+
+  return retval;
+}
+
+/*
+ * Identity matrix.
+ */
+tree_constant *
+builtin_eye (tree_constant *args, int nargin, int nargout)
+{
+  tree_constant *retval = NULL_TREE_CONST;
+
+  switch (nargin)
+    {
+    case 2:
+      retval = new tree_constant [2];
+      retval[0] = identity_matrix (args[1]);
+      break;
+    case 3:
+      retval = new tree_constant [2];
+      retval[0] = identity_matrix (args[1], args[2]);
+      break;
+    default:
+      usage ("eye (n)\n       eye (A)\n       eye (n, m)");
+      break;
+    }
+  return retval;
+}
+
+
+/*
+ * Closing a file
+ */
+tree_constant *
+builtin_fclose (tree_constant *args, int nargin, int nargout)
+{
+  tree_constant *retval = NULL_TREE_CONST;
+  if (nargin != 2)
+    usage ("success = fclose (\"filename\" or filenum)");
+  else
+    retval = fclose_internal (args);
+  return retval;
+}
+
+/*
+ * Evaluate first argument as a function.
+ */
+tree_constant *
+builtin_feval (tree_constant *args, int nargin, int nargout)
+{
+  tree_constant *retval = NULL_TREE_CONST;
+  if (nargin > 1)
+    retval = feval (args, nargin, nargout);
+  else
+    usage ("feval (\"function_name\" [, ...])");
+  return retval;
+}
+
+/*
+ * Flushing output to a file
+ */
+tree_constant *
+builtin_fflush (tree_constant *args, int nargin, int nargout)
+{
+  tree_constant *retval = NULL_TREE_CONST;
+  if (nargin != 2)
+    usage ("success = fflush (\"filename\" or filenum)");
+  else
+    retval = fflush_internal (args);
+  return retval;
+}
+
+/*
+ * Fast Fourier Transform
+ */
+tree_constant *
+builtin_fft (tree_constant *args, int nargin, int nargout)
+{
+  tree_constant *retval = NULL_TREE_CONST;
+
+  if (nargin == 2)
+    DLD_BUILTIN (args, nargin, nargout, fft,
+		 {
+		   retval = new tree_constant [2];
+		   retval[0] = fft (args[1]);
+		 })
+  else
+    usage ("fft (a)");
+
+  return retval;
+}
+
+/*
+ * get a string from a file
+ */
+tree_constant *
+builtin_fgets (tree_constant *args, int nargin, int nargout)
+{
+  tree_constant *retval = NULL_TREE_CONST;
+  if (nargin != 3  && nargout < 3)
+    usage ("string = fgets (\"filename\" or filenum, length)");
+  else
+    retval = fgets_internal (args, nargout);
+  return retval;
+}
+
+/*
+ * Find nonzero elements.  This should probably only work if
+ * do_fortran_indexing is true...
+ */
+tree_constant *
+builtin_find (tree_constant *args, int nargin, int nargout)
+{
+  tree_constant *retval = NULL_TREE_CONST;
+  if (nargin == 2)
+    {
+      retval = new tree_constant [2];
+      retval[0] = find_nonzero_elem_idx (args[1]);
+    }
+  else
+    usage ("find (x)");
+  return retval;
+}
+
+/*
+ * Don\'t really count floating point operations.
+ */
+tree_constant *
+builtin_flops (tree_constant *args, int nargin, int nargout)
+{
+  tree_constant *retval = NULL_TREE_CONST;
+  if (nargin > 2)
+    usage ("flops\n       flops (0)");
+
+  warning ("flops always returns zero");
+  retval = new tree_constant [2];
+  retval[0] = tree_constant (0.0);
+  return retval;
+}
+
+/*
+ * Opening a file.
+ */
+tree_constant *
+builtin_fopen (tree_constant *args, int nargin, int nargout)
+{
+  tree_constant *retval = NULL_TREE_CONST;
+  if (nargin != 3)
+    {
+      usage ("filenum = fopen (\"file\", \"mode\")\n\n\
+ Legal values for mode include:\n\n\
+   r  : open text file for reading\n\
+   w  : open text file for writing; discard previous contents if any\n\
+   a  : append; open or create text file for writing at end of file\n\
+   r+ : open text file for update (i.e., reading and writing)\n\
+   w+ : create text file for update; discard previous contents if any\n\
+   a+ : append; open or create text file for update, writing at end\n\n\
+ Update mode permits reading from and writing to the same file.\n");
+      }
+  else
+    retval = fopen_internal (args);
+  return retval;
+}
+
+/*
+ * Formatted printing to a file.
+ */
+tree_constant *
+builtin_fprintf (tree_constant *args, int nargin, int nargout)
+{
+  tree_constant *retval = NULL_TREE_CONST;
+  if (nargin < 3)
+    usage ("fprintf (\"filename\" or filenum, \"fmt\" [, ...])");
+  else
+    retval = do_printf ("fprintf", args, nargin, nargout);
+  return retval;
+}
+
+/*
+ * rewind a file
+ */
+tree_constant *
+builtin_frewind (tree_constant *args, int nargin, int nargout)
+{
+  tree_constant *retval = NULL_TREE_CONST;
+  if (nargin != 2)
+    usage ("success = frewind (\"filename\" or filenum)");
+  else
+    retval = frewind_internal (args);
+  return retval;
+}
+
+/*
+ * report on open files
+ */
+tree_constant *
+builtin_freport (tree_constant *args, int nargin, int nargout)
+{
+  tree_constant *retval = NULL_TREE_CONST;
+  if (nargin > 1)
+    warning ("replot: ignoring extra arguments");
+  retval = freport_internal ();
+  return retval;
+}
+
+/*
+ * Formatted reading from a file.
+ */
+tree_constant *
+builtin_fscanf (tree_constant *args, int nargin, int nargout)
+{
+  tree_constant *retval = NULL_TREE_CONST;
+  if (nargin != 2 && nargin != 3)
+    usage ("[...] = fscanf (\"file\", \"fmt\")");
+  else
+    retval = do_scanf ("fscanf", args, nargin, nargout);
+  return retval;
+}
+
+/*
+ * seek a point in a file for reading and/or writing 
+ */
+tree_constant *
+builtin_fseek (tree_constant *args, int nargin, int nargout)
+{
+  tree_constant *retval = NULL_TREE_CONST;
+  if (nargin != 3 && nargin != 4)
+    usage ("success = fseek (\"filename\" or filenum, offset [,origin])");
+  else
+    retval = fseek_internal (args, nargin);
+  return retval;
+}
+
+/*
+ * Nonlinear algebraic equations.
+ */
+static void
+fsolve_usage (void)
+{
+//  usage ("[x, status, path] = fsolve (\"f\", x0 [, opts] [, par] [, \"jac\"] [, scale])");
+
+  usage ("[x, info] = fsolve (\"f\", x0)");
+}
+
+tree_constant *
+builtin_fsolve (tree_constant *args, int nargin, int nargout)
+{
+  tree_constant *retval = NULL_TREE_CONST;
+
+  if (nargin >= 3 && nargin <= 7 && nargout >= 1 && nargout <= 3)
+    DLD_BUILTIN (args, nargin, nargout, fsolve,
+		 retval = fsolve (args, nargin, nargout);)
+  else
+    fsolve_usage ();
+
+  return retval;
+}
+
+/*
+ * NLPs.
+ */
+static void
+fsqp_usage (void)
+{
+#if defined (FSQP_MISSING)
+  message ("fsqp", "this function requires FSQP, which is not freely\n\
+      redistributable.  For more information, read the file\n\
+      libcruft/fsqp/README.MISSING in the source distribution.");
+#else
+  usage ("[x, phi] = fsqp (x, \"phi\" [, lb, ub] [, lb, A, ub] [, lb, \"g\", ub])\n\n\
+  Groups of arguments surrounded in `[]' are optional, but\n\
+  must appear in the same relative order shown above.");
+#endif
+}
+
+tree_constant *
+builtin_fsqp (tree_constant *args, int nargin, int nargout)
+{
+  tree_constant *retval = NULL_TREE_CONST;
+
+#if defined (FSQP_MISSING)
+  fsqp_usage ();
+#else
+  if ((nargin == 3 || nargin == 5 || nargin == 6 || nargin == 8
+       || nargin == 9 || nargin == 11)
+      && (nargout >= 1 && nargout <= 3))
+    DLD_BUILTIN (args, nargin, nargout, fsqp,
+		 retval = fsqp (args, nargin, nargout);)
+  else
+    fsqp_usage ();
+#endif
+
+  return retval;
+}
+
+/*
+ * tell current position of file
+ */
+tree_constant *
+builtin_ftell (tree_constant *args, int nargin, int nargout)
+{
+  tree_constant *retval = NULL_TREE_CONST;
+  if (nargin != 2)
+    usage ("position = ftell (\"filename\" or filenumber)");
+  else
+    retval = ftell_internal (args);
+  return retval;
+}
+
+/*
+ * Get the value of an environment variable.
+ */
+tree_constant *
+builtin_getenv (tree_constant *args, int nargin, int nargout)
+{
+  tree_constant *retval = NULL_TREE_CONST;
+  if (nargin == 2 && args[1].is_string_type ())
+    {
+      retval = new tree_constant [2];
+      char *value = getenv (args[1].string_value ());
+      if (value != (char *) NULL)
+	retval[0] = tree_constant (value);
+      else
+	retval[0] = tree_constant ("");
+    }
+  else
+    usage ("getenv (\"string\")");
+  return retval;
+}
+
+/*
+ * Inverse Fast Fourier Transform
+ */
+tree_constant *
+builtin_ifft (tree_constant *args, int nargin, int nargout)
+{
+  tree_constant *retval = NULL_TREE_CONST;
+
+  if (nargin == 2)
+    DLD_BUILTIN (args, nargin, nargout, ifft,
+		 {
+		   retval = new tree_constant [2];
+		   retval[0] = ifft (args[1]);
+		 })
+  else
+    usage ("ifft (a)");
+
+  return retval;
+}
+
+/*
+ * Inverse of a square matrix.
+ */
+tree_constant *
+builtin_inv (tree_constant *args, int nargin, int nargout)
+{
+  tree_constant *retval = NULL_TREE_CONST;
+
+  if (nargin == 2)
+    DLD_BUILTIN (args, nargin, nargout, inv,
+		 {
+		   retval = new tree_constant [2];
+		   retval[0] = inverse (args[1]);
+		 })
+  else
+    usage ("inv (A)");
+
+  return retval;
+}
+
+/*
+ * Prompt user for input.
+ */
+tree_constant *
+builtin_input (tree_constant *args, int nargin, int nargout)
+{
+  tree_constant *retval = NULL_TREE_CONST;
+
+  if (nargin == 2 || nargin == 3)
+    {
+      retval = new tree_constant [2];
+      retval[0] = get_user_input (args, nargin, nargout);
+    }
+  else
+    usage ("input (\"prompt\" [, \"s\"])");
+
+  return retval;
+}
+
+/*
+ * Is the argument a string?
+ */
+tree_constant *
+builtin_isstr (tree_constant *args, int nargin, int nargout)
+{
+  tree_constant *retval = NULL_TREE_CONST;
+  if (nargin != 2)
+    usage ("isstr (value)");
+  else
+    {
+      if (args != NULL_TREE_CONST && args[1].is_defined ())
+	{
+	  retval = new tree_constant [2];
+	  retval[0] = args[1].isstr ();
+	}
+    }
+  return retval;
+}
+
+/*
+ * Maybe help in debugging.
+ */
+tree_constant *
+builtin_keyboard (tree_constant *args, int nargin, int nargout)
+{
+  tree_constant *retval = NULL_TREE_CONST;
+
+  if (nargin == 1 || nargin == 2)
+    {
+      retval = new tree_constant [2];
+      retval[0] = get_user_input (args, nargin, nargout, 1);
+    }
+  else
+    usage ("keyboard (\"prompt\")");
+
+  return retval;
+}
+
+/*
+ * Matrix logarithm.
+ */
+tree_constant *
+builtin_logm (tree_constant *args, int nargin, int nargout)
+{
+  tree_constant *retval = NULL_TREE_CONST;
+
+  if (nargin == 2)
+    retval = matrix_log (args[1]);
+  else
+    usage ("logm (A)");
+
+  return retval;
+}
+
+/*
+ * LPs.
+ */
+static void
+lpsolve_usage (void)
+{
+  usage ("[x, obj, info] = lpsolve (XXX FIXME XXX)");
+}
+
+tree_constant *
+builtin_lpsolve (tree_constant *args, int nargin, int nargout)
+{
+  tree_constant *retval = NULL_TREE_CONST;
+
+// Force a bad value of inform, and empty matrices for x and phi.
+  retval = new tree_constant [4];
+  Matrix m;
+  retval[0] = tree_constant (m);
+  retval[1] = tree_constant (m);
+  retval[2] = tree_constant (-1.0);
+
+  if (nargin == 0)
+    DLD_BUILTIN (args, nargin, nargout, lpsolve,
+		 retval = lpsolve (args, nargin, nargout);)
+  else
+    lpsolve_usage ();
+
+  return retval;
+}
+
+/*
+ * ODEs.
+ */
+static void
+lsode_usage (void)
+{
+  usage ("lsode (\"function_name\", x0, t_out\n\
+       lsode (\"function_name\", x0, t_out, t_crit)\n\
+\n\
+       The first argument is the name of the function to call to\n\
+       compute the vector of right hand sides.  It must have the form\n\
+\n\
+         xdot = f (x, t)\n\
+\n\
+       where xdot and x are vectors and t is a scalar.");
+}
+
+tree_constant *
+builtin_lsode (tree_constant *args, int nargin, int nargout)
+{
+  tree_constant *retval = NULL_TREE_CONST;
+
+  if ((nargin == 4 || nargin == 5) && nargout == 1)
+    DLD_BUILTIN (args, nargin, nargout, lsode,
+		 retval = lsode (args, nargin, nargout);)
+  else
+    lsode_usage ();
+
+  return retval;
+}
+
+/*
+ * LU factorization.
+ */
+tree_constant *
+builtin_lu (tree_constant *args, int nargin, int nargout)
+{
+  tree_constant *retval = NULL_TREE_CONST;
+
+  if (nargin == 2 && nargout < 4)
+    DLD_BUILTIN (args, nargin, nargout, lu,
+		 retval = lu (args[1], nargout);)
+  else
+    usage ("[L, U, P] = lu (A)");
+
+  return retval;
+}
+
+/*
+ * Max values.
+ */
+tree_constant *
+builtin_max (tree_constant *args, int nargin, int nargout)
+{
+  tree_constant *retval = NULL_TREE_CONST;
+
+  if ((nargin == 2 && (nargout == 1 || nargout == 2))
+      || (nargin == 3 && nargout == 1))
+    retval = column_max (args, nargin, nargout);
+  else
+    usage ("[X, I] = max (A)\n        X = max (A)\n        X = max (A, B)");
+
+  return retval;
+}
+
+/*
+ * Min values.
+ */
+tree_constant *
+builtin_min (tree_constant *args, int nargin, int nargout)
+{
+  tree_constant *retval = NULL_TREE_CONST;
+
+  if ((nargin == 2 && (nargout == 1 || nargout == 2))
+      || (nargin == 3 && nargout == 1))
+    retval = column_min (args, nargin, nargout);
+  else
+    usage ("[X, I] = min (A)\n        X = min (A)\n        X = min (A, B)");
+
+  return retval;
+}
+
+/*
+ * NLPs.
+ */
+static void
+npsol_usage (void)
+{
+#if defined (NPSOL_MISSING)
+  message ("npsol", "this function requires NPSOL, which is not freely\n\
+       redistributable.  For more information, read the file\n\
+       libcruft/npsol/README.MISSING in the source distribution.");
+#else
+  usage ("\n\n\
+  [x, obj, info, lambda] = npsol (x, \"phi\" [, lb, ub] [, lb, A, ub] [, lb, \"g\", ub])\n\n\
+  Groups of arguments surrounded in `[]' are optional, but\n\
+  must appear in the same relative order shown above.\n\
+\n\
+  The second argument is a string containing the name of the objective\n\
+  function to call.  The objective function must be of the form\n\
+\n\
+    y = phi (x)\n\
+\n\
+  where x is a vector and y is a scalar.");
+#endif
+}
+
+tree_constant *
+builtin_npsol (tree_constant *args, int nargin, int nargout)
+{
+  tree_constant *retval = NULL_TREE_CONST;
+
+#if defined (NPSOL_MISSING)
+// Force a bad value of inform, and empty matrices for x, phi, and lambda.
+  retval = new tree_constant [4];
+  Matrix m;
+  retval[0] = tree_constant (m);
+  retval[1] = tree_constant (m);
+  retval[2] = tree_constant (-1.0);
+  retval[3] = tree_constant (m);
+  npsol_usage ();
+#else
+  if ((nargin == 3 || nargin == 5 || nargin == 6 || nargin == 8
+       || nargin == 9 || nargin == 11)
+      && (nargout >= 1 && nargout <= 4))
+    DLD_BUILTIN (args, nargin, nargout, npsol,
+		 retval = npsol (args, nargin, nargout);)
+  else
+    npsol_usage ();
+#endif
+
+  return retval;
+}
+
+/*
+ * A matrix of ones.
+ */
+tree_constant *
+builtin_ones (tree_constant *args, int nargin, int nargout)
+{
+  tree_constant *retval = NULL_TREE_CONST;
+
+  switch (nargin)
+    {
+    case 2:
+      retval = new tree_constant [2];
+      retval[0] = fill_matrix (args[1], 1.0, "ones");
+      break;
+    case 3:
+      retval = new tree_constant [2];
+      retval[0] = fill_matrix (args[1], args[2], 1.0, "ones");
+      break;
+    default:
+      usage ("ones (n)\n       ones (A)\n       ones (n, m)");
+      break;
+    }
+  return retval;
+}
+
+/*
+ * You guessed it.
+ */
+tree_constant *
+builtin_pause (tree_constant *args, int nargin, int nargout)
+{
+  if (! (nargin == 1 || nargin == 2))
+    {
+      usage ("pause ([delay])");
+      return NULL_TREE_CONST;
+    }
+
+  if (interactive)
+    {
+      if (nargin == 2)
+	sleep (NINT (args[1].double_value ()));
+      else if (kbhit () == EOF)
+	clean_up_and_exit (0);
+    }
+  return NULL_TREE_CONST;
+}
+
+/*
+ * Delete turds from /tmp.
+ */
+tree_constant *
+builtin_purge_tmp_files (tree_constant *, int, int)
+{
+  cleanup_tmp_files ();
+  return NULL_TREE_CONST;
+}
+
+/*
+ * Formatted printing.
+ */
+tree_constant *
+builtin_printf (tree_constant *args, int nargin, int nargout)
+{
+  tree_constant *retval = NULL_TREE_CONST;
+  if (nargin < 2)
+    usage ("printf (\"fmt\" [, ...])");
+  else
+    retval = do_printf ("printf", args, nargin, nargout);
+  return retval;
+}
+
+/*
+ * Product.
+ */
+tree_constant *
+builtin_prod (tree_constant *args, int nargin, int nargout)
+{
+  tree_constant *retval = NULL_TREE_CONST;
+  if (nargin != 2)
+    usage ("prod (M)");
+  else
+    {
+      if (args != NULL_TREE_CONST && args[1].is_defined ())
+	{
+	  retval = new tree_constant [2];
+	  retval[0] = args[1].prod ();
+	}
+    }
+  return retval;
+}
+
+/*
+ * Print name of current working directory.
+ */
+tree_constant *
+builtin_pwd (tree_constant *args, int nargin, int nargout)
+{
+  tree_constant *retval = NULL_TREE_CONST;
+  char *directory;
+
+  if (verbatim_pwd)
+    {
+      char *buffer = new char [MAXPATHLEN];
+      directory = getcwd (buffer, MAXPATHLEN);
+
+      if (!directory)
+	{
+	  message ("pwd", "can't find working directory!");
+	  delete buffer;
+	}
+    }
+  else
+    {
+      directory = get_working_directory ("pwd");
+    }
+
+  if (directory)
+    {
+      char *s = strconcat (directory, "\n");
+      retval = new tree_constant [2];
+      retval[0] = tree_constant (s);
+      delete [] s;
+    }
+  return retval;
+}
+
+/*
+ * QPs.
+ */
+static void
+qpsol_usage (void)
+{
+#if defined (QPSOL_MISSING)
+  message ("qpsol", "this function requires QPSOL, which is not freely\n\
+       redistributable.  For more information, read the file\n\
+       libcruft/qpsol/README.MISSING in the source distribution.");
+#else
+  usage ("[x, obj, info, lambda] = qpsol (x, H, c [, lb, ub] [, lb, A, ub])\n\
+\n\
+  Groups of arguments surrounded in `[]' are optional, but\n\
+  must appear in the same relative order shown above.");
+#endif
+}
+
+tree_constant *
+builtin_qpsol (tree_constant *args, int nargin, int nargout)
+{
+  tree_constant *retval = NULL_TREE_CONST;
+
+#if defined (QPSOL_MISSING)
+// Force a bad value of inform, and empty matrices for x, phi, and lambda.
+  retval = new tree_constant [5];
+  Matrix m;
+  retval[0] = tree_constant (m);
+  retval[1] = tree_constant (m);
+  retval[2] = tree_constant (-1.0);
+  retval[3] = tree_constant (m);
+  qpsol_usage ();
+#else
+  if ((nargin == 4 || nargin == 6 || nargin == 7 || nargin == 9)
+      && (nargout >= 1 && nargout <= 4))
+    DLD_BUILTIN (args, nargin, nargout, qpsol,
+		 retval = qpsol (args, nargin, nargout);)
+  else
+    qpsol_usage ();
+#endif
+
+  return retval;
+}
+
+/*
+ * QR factorization.
+ */
+tree_constant *
+builtin_qr (tree_constant *args, int nargin, int nargout)
+{
+  tree_constant *retval = NULL_TREE_CONST;
+
+  if (nargin == 2 && nargout < 3)
+    DLD_BUILTIN (args, nargin, nargout, qr,
+		 retval = qr (args[1], nargout);)
+  else
+    usage ("[Q, R] = qr (A)");
+
+  return retval;
+}
+
+/*
+ * Random numbers.
+ */
+tree_constant *
+builtin_quad (tree_constant *args, int nargin, int nargout)
+{
+  tree_constant *retval = NULL_TREE_CONST;
+
+  if ((nargin > 3 && nargin < 7) && (nargout > 0 && nargout < 5))
+    DLD_BUILTIN (args, nargin, nargout, quad,
+		 retval = do_quad (args, nargin, nargout);)
+  else
+    usage ("[v, ier, nfun, err] = quad (\"f\", a, b)\n\
+                           = quad (\"f\", a, b, tol)\n\
+                           = quad (\"f\", a, b, tol, sing)");
+
+  return retval;
+}
+
+/*
+ * I'm outta here.
+ */
+tree_constant *
+builtin_quit (tree_constant *args, int nargin, int nargout)
+{
+  quitting_gracefully = 1;
+  clean_up_and_exit (0);
+  return NULL_TREE_CONST;
+}
+
+/*
+ * Random numbers.
+ */
+tree_constant *
+builtin_rand (tree_constant *args, int nargin, int nargout)
+{
+  tree_constant *retval = NULL_TREE_CONST;
+
+  if ((nargin > 0 && nargin < 4) && nargout == 1)
+    DLD_BUILTIN (args, nargin, nargout, rand,
+		 retval = rand_internal (args, nargin, nargout);)
+  else
+    usage ("rand                  -- generate a random value\n\
+       rand (n)              -- generate N x N matrix\n\
+       rand (A)              -- generate matrix the size of A\n\
+       rand (n, m)           -- generate N x M matrix\n\
+       rand (\"dist\")         -- get current distribution\n\
+       rand (\"distribution\") -- set distribution\n\
+       rand (\"seed\")         -- get current seed\n\
+       rand (\"seed\", n)      -- set seed");
+
+  return retval;
+}
+
+/*
+ * Replot current plot.
+ */
+tree_constant *
+builtin_replot (tree_constant *args, int nargin, int nargout)
+{
+  tree_constant *retval = NULL_TREE_CONST;
+
+  if (nargin > 1)
+    warning ("replot: ignoring extra arguments");
+
+  send_to_plot_stream ("replot\n");
+
+  return retval;
+}
+
+/*
+ * Formatted reading.
+ */
+tree_constant *
+builtin_scanf (tree_constant *args, int nargin, int nargout)
+{
+  tree_constant *retval = NULL_TREE_CONST;
+  if (nargin != 2)
+    usage ("[...] = scanf (\"fmt\")");
+  else
+    retval = do_scanf ("scanf", args, nargin, nargout);
+  return retval;
+}
+
+/*
+ * Convert a vector to a string.
+ */
+tree_constant *
+builtin_setstr (tree_constant *args, int nargin, int nargout)
+{
+  tree_constant *retval = NULL_TREE_CONST;
+
+  if (nargin == 2)
+    {
+      retval = new tree_constant [2];
+      retval[0] = args[1].convert_to_str ();
+    }
+  else
+    usage ("setstr (v)");
+
+  return retval;
+}
+
+/*
+ * Execute a shell command.
+ */
+tree_constant *
+builtin_shell_command (tree_constant *args, int nargin, int nargout)
+{
+  tree_constant *retval = NULL_TREE_CONST;
+
+  if (nargin == 2 || nargin == 3)
+    {
+      if (args[1].is_string_type ())
+	{
+	  iprocstream cmd (args[1].string_value ());
+	  char ch;
+	  ostrstream output_buf;
+	  while (cmd.get (ch))
+	    output_buf.put (ch);
+
+	  output_buf << ends;
+	  if (nargin == 2)
+	    {
+	      maybe_page_output (output_buf);
+	    }
+	  else
+	    {
+	      retval = new tree_constant [2];
+	      retval[0] = tree_constant (output_buf.str ());
+	    }
+	}
+      else
+	error ("shell_cmd: first argument must be a string");
+    }
+  else
+    usage ("shell_cmd (string [, return_output])");
+
+  return retval;
+}
+
+/*
+ * Report rows and columns.
+ */
+tree_constant *
+builtin_size (tree_constant *args, int nargin, int nargout)
+{
+  tree_constant *retval = NULL_TREE_CONST;
+
+  if (nargin != 2)
+    usage ("size (x)");
+  else
+    {
+      if (args != NULL_TREE_CONST && args[1].is_defined ())
+	{
+	  int nr = args[1].rows ();
+	  int nc = args[1].columns ();
+	  if (nargout == 1)
+	    {
+	      Matrix m (1, 2);
+	      m.elem (0, 0) = nr;
+	      m.elem (0, 1) = nc;
+	      retval = new tree_constant [2];
+	      retval[0] = tree_constant (m);
+	    }
+	  else if (nargout == 2)
+	    {
+	      retval = new tree_constant [3];
+	      retval[0] = tree_constant ((double) nr);
+	      retval[1] = tree_constant ((double) nc);
+	    }
+	  else
+	    usage ("[n, m] = size (A)\n                size (A)");
+	}
+    }
+  return retval;
+}
+
+/*
+ * Sort columns.
+ */
+tree_constant *
+builtin_sort (tree_constant *args, int nargin, int nargout)
+{
+  tree_constant *retval = NULL_TREE_CONST;
+
+  if (nargin == 2)
+    retval = sort (args, nargin, nargout);
+  else
+    usage ("[s, i] = sort (x)");
+
+  return retval;
+}
+
+/*
+ * Formatted printing to a string.
+ */
+tree_constant *
+builtin_sprintf (tree_constant *args, int nargin, int nargout)
+{
+  tree_constant *retval = NULL_TREE_CONST;
+  if (nargin < 2)
+    usage ("string = sprintf (\"fmt\" [, ...])");
+  else
+    retval = do_printf ("sprintf", args, nargin, nargout);
+  return retval;
+}
+
+/*
+ * Matrix sqrt.
+ */
+tree_constant *
+builtin_sqrtm (tree_constant *args, int nargin, int nargout)
+{
+  tree_constant *retval = NULL_TREE_CONST;
+
+  if (nargin == 2)
+    retval = matrix_sqrt (args[1]);
+  else
+    usage ("sqrtm (A)");
+
+  return retval;
+}
+
+/*
+ * Formatted reading from a string.
+ */
+tree_constant *
+builtin_sscanf (tree_constant *args, int nargin, int nargout)
+{
+  tree_constant *retval = NULL_TREE_CONST;
+  if (nargin != 3)
+    usage ("[...] = sscanf (string, \"fmt\")");
+  else
+    retval = do_scanf ("sscanf", args, nargin, nargout);
+  return retval;
+}
+
+/*
+ * Sum.
+ */
+tree_constant *
+builtin_sum (tree_constant *args, int nargin, int nargout)
+{
+  tree_constant *retval = NULL_TREE_CONST;
+  if (nargin != 2)
+    usage ("sum (M)");
+  else
+    {
+      if (args != NULL_TREE_CONST && args[1].is_defined ())
+	{
+	  retval = new tree_constant [2];
+	  retval[0] = args[1].sum ();
+	}
+    }
+  return retval;
+}
+
+/*
+ * Sum of squares.
+ */
+tree_constant *
+builtin_sumsq (tree_constant *args, int nargin, int nargout)
+{
+  tree_constant *retval = NULL_TREE_CONST;
+  if (nargin != 2)
+    usage ("sumsq (M)");
+  else
+    {
+      if (args != NULL_TREE_CONST && args[1].is_defined ())
+	{
+	  retval = new tree_constant [2];
+	  retval[0] = args[1].sumsq ();
+	}
+    }
+  return retval;
+}
+
+/*
+ * Singluar value decomposition.
+ */
+tree_constant *
+builtin_svd (tree_constant *args, int nargin, int nargout)
+{
+  tree_constant *retval = NULL_TREE_CONST;
+
+  if (nargin == 2 && (nargout == 1 || nargout == 3))
+    DLD_BUILTIN (args, nargin, nargout, svd,
+		 retval = svd (args, nargin, nargout);)
+  else
+    usage ("[U, S, V] = svd (A)\n               S = svd (A)");
+
+  return retval;
+}
+
+/*
+ * Schur Decomposition
+ */
+tree_constant *
+builtin_schur (tree_constant *args, int nargin, int nargout)
+{
+  tree_constant *retval = NULL_TREE_CONST;
+
+  if ((nargin == 3 || nargin == 2) && (nargout == 1 || nargout == 2))
+    DLD_BUILTIN (args, nargin, nargout, hess,
+		 retval = schur (args, nargin, nargout);)
+  else
+    usage ("[U, S] = schur (A)\n\
+            S = schur (A)\n\n\
+ or, for ordered Schur:\n\n\
+       [U, S] = schur (A, \"A, D, or U\")\n\
+            S = schur (A, \"A, D, or U\")\n\
+ where:\n\n\
+   A = continuous time poles\n\
+   D = discrete time poles\n\
+   U = unordered schur (default)");
+
+  return retval;
+}
+
+/*
+ * Hessenburg Decomposition
+ */
+tree_constant *
+builtin_hess (tree_constant *args, int nargin, int nargout)
+{
+  tree_constant *retval = NULL_TREE_CONST;
+
+  if (nargin == 2 && (nargout == 1 || nargout == 2))
+    DLD_BUILTIN (args, nargin, nargout, hess,
+		 retval = hess (args, nargin, nargout);)
+  else
+    usage ("[P, H] = hess (A)\n            H = hess (A)");
+
+  return retval;
+}
+
+/*
+ * Copying information.
+ */
+tree_constant *
+builtin_warranty (tree_constant *args, int nargin, int nargout)
+{
+  ostrstream output_buf;
+  output_buf << "\n    Octave, version " << version_string
+	     << ".  Copyright (C) 1992, 1993, John W. Eaton\n"
+	     << "\n\
+    This program is free software; you can redistribute it and/or modify\n\
+    it under the terms of the GNU General Public License as published by\n\
+    the Free Software Foundation; either version 2 of the License, or\n\
+    (at your option) any later version.\n\n\
+    This program is distributed in the hope that it will be useful,\n\
+    but WITHOUT ANY WARRANTY; without even the implied warranty of\n\
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n\
+    GNU General Public License for more details.\n\n\
+    You should have received a copy of the GNU General Public License\n\
+    along with this program. If not, write to the Free Software\n\
+    Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.\n\n";
+
+  output_buf << ends;
+  maybe_page_output (output_buf);
+
+  return NULL_TREE_CONST;
+}
+
+/*
+ * A matrix of zeros.
+ */
+tree_constant *
+builtin_zeros (tree_constant *args, int nargin, int nargout)
+{
+  tree_constant *retval = NULL_TREE_CONST;
+
+  switch (nargin)
+    {
+    case 2:
+      retval = new tree_constant [2];
+      retval[0] = fill_matrix (args[1], 0.0, "zeros");
+      break;
+    case 3:
+      retval = new tree_constant [2];
+      retval[0] = fill_matrix (args[1], args[2], 0.0, "zeros");
+      break;
+    default:
+      usage ("zeros (n)\n       zeros (A)\n       zeros (n, m)");
+      break;
+    }
+  return retval;
+}
+
+/*
+;;; Local Variables: ***
+;;; mode: C++ ***
+;;; page-delimiter: "^/\\*" ***
+;;; End: ***
+*/
new file mode 100644
--- /dev/null
+++ b/src/g-builtins.h
@@ -0,0 +1,125 @@
+// Builtin general function support.                          -*- C++ -*-
+/*
+
+Copyright (C) 1992, 1993 John W. Eaton
+
+This file is part of Octave.
+
+Octave is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+Octave is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with Octave; see the file COPYING.  If not, write to the Free
+Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#if !defined (_g_builtins_h)
+#define _g_builtins_h 1
+
+#ifdef __GNUG__
+#pragma interface
+#endif
+
+#include "tree-const.h"
+
+struct builtin_general_functions
+{
+  char *name;
+  int nargin_max;
+  int nargout_max;
+  General_fcn general_fcn;
+  char *help_string;
+};
+
+extern tree_constant *builtin_all (tree_constant *, int, int);
+extern tree_constant *builtin_any (tree_constant *, int, int);
+extern tree_constant *builtin_clc (tree_constant *, int, int);
+extern tree_constant *builtin_clock (tree_constant *, int, int);
+extern tree_constant *builtin_closeplot (tree_constant *, int, int);
+extern tree_constant *builtin_colloc (tree_constant *, int, int);
+extern tree_constant *builtin_cumprod (tree_constant *, int, int);
+extern tree_constant *builtin_cumsum (tree_constant *, int, int);
+extern tree_constant *builtin_dassl (tree_constant *, int, int);
+extern tree_constant *builtin_date (tree_constant *, int, int);
+extern tree_constant *builtin_det (tree_constant *, int, int);
+extern tree_constant *builtin_diag (tree_constant *, int, int);
+extern tree_constant *builtin_disp (tree_constant *, int, int);
+extern tree_constant *builtin_eig (tree_constant *, int, int);
+extern tree_constant *builtin_error (tree_constant *, int, int);
+extern tree_constant *builtin_eval (tree_constant *, int, int);
+extern tree_constant *builtin_exist (tree_constant *, int, int);
+extern tree_constant *builtin_expm (tree_constant *, int, int);
+extern tree_constant *builtin_eye (tree_constant *, int, int);
+extern tree_constant *builtin_fclose (tree_constant *, int, int);
+extern tree_constant *builtin_feval (tree_constant *, int, int);
+extern tree_constant *builtin_fflush (tree_constant *, int, int);
+extern tree_constant *builtin_fft (tree_constant *, int, int);
+extern tree_constant *builtin_fgets (tree_constant *, int, int);
+extern tree_constant *builtin_find (tree_constant *, int, int);
+extern tree_constant *builtin_flops (tree_constant *, int, int);
+extern tree_constant *builtin_fopen (tree_constant *, int, int);
+extern tree_constant *builtin_fprintf (tree_constant *, int, int);
+extern tree_constant *builtin_frewind (tree_constant *, int, int);
+extern tree_constant *builtin_freport (tree_constant *, int, int);
+extern tree_constant *builtin_fscanf (tree_constant *, int, int);
+extern tree_constant *builtin_fseek (tree_constant *, int, int);
+extern tree_constant *builtin_fsolve (tree_constant *, int, int);
+extern tree_constant *builtin_fsqp (tree_constant *, int, int);
+extern tree_constant *builtin_ftell (tree_constant *, int, int);
+extern tree_constant *builtin_getenv (tree_constant *, int, int);
+extern tree_constant *builtin_hess (tree_constant *, int, int);
+extern tree_constant *builtin_input (tree_constant *, int, int);
+extern tree_constant *builtin_ifft (tree_constant *, int, int);
+extern tree_constant *builtin_inv (tree_constant *, int, int);
+extern tree_constant *builtin_isstr (tree_constant *, int, int);
+extern tree_constant *builtin_keyboard (tree_constant *, int, int);
+extern tree_constant *builtin_logm (tree_constant *, int, int);
+extern tree_constant *builtin_lpsolve (tree_constant *, int, int);
+extern tree_constant *builtin_lsode (tree_constant *, int, int);
+extern tree_constant *builtin_lu (tree_constant *, int, int);
+extern tree_constant *builtin_max (tree_constant *, int, int);
+extern tree_constant *builtin_min (tree_constant *, int, int);
+extern tree_constant *builtin_npsol (tree_constant *, int, int);
+extern tree_constant *builtin_ones (tree_constant *, int, int);
+extern tree_constant *builtin_pause (tree_constant *, int, int);
+extern tree_constant *builtin_purge_tmp_files (tree_constant *, int, int);
+extern tree_constant *builtin_printf (tree_constant *, int, int);
+extern tree_constant *builtin_prod (tree_constant *, int, int);
+extern tree_constant *builtin_pwd (tree_constant *, int, int);
+extern tree_constant *builtin_qpsol (tree_constant *, int, int);
+extern tree_constant *builtin_qr (tree_constant *, int, int);
+extern tree_constant *builtin_quad (tree_constant *, int, int);
+extern tree_constant *builtin_quit (tree_constant *, int, int);
+extern tree_constant *builtin_rand (tree_constant *, int, int);
+extern tree_constant *builtin_replot (tree_constant *, int, int);
+extern tree_constant *builtin_setstr (tree_constant *, int, int);
+extern tree_constant *builtin_scanf (tree_constant *, int, int);
+extern tree_constant *builtin_schur (tree_constant *, int, int);
+extern tree_constant *builtin_shell_command (tree_constant *, int, int);
+extern tree_constant *builtin_size (tree_constant *, int, int);
+extern tree_constant *builtin_sort (tree_constant *, int, int);
+extern tree_constant *builtin_sprintf (tree_constant *, int, int);
+extern tree_constant *builtin_sqrtm (tree_constant *, int, int);
+extern tree_constant *builtin_sscanf (tree_constant *, int, int);
+extern tree_constant *builtin_sum (tree_constant *, int, int);
+extern tree_constant *builtin_sumsq (tree_constant *, int, int);
+extern tree_constant *builtin_svd (tree_constant *, int, int);
+extern tree_constant *builtin_warranty (tree_constant *, int, int);
+extern tree_constant *builtin_zeros (tree_constant *, int, int);
+
+#endif
+
+/*
+;;; Local Variables: ***
+;;; mode: C++ ***
+;;; page-delimiter: "^/\\*" ***
+;;; End: ***
+*/
new file mode 100644
--- /dev/null
+++ b/src/gripes.cc
@@ -0,0 +1,81 @@
+// gripes.cc                                             -*- C++ -*-
+/*
+
+Copyright (C) 1992, 1993 John W. Eaton
+
+This file is part of Octave.
+
+Octave is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+Octave is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with Octave; see the file COPYING.  If not, write to the Free
+Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifdef __GNUG__
+#pragma implementation
+#endif
+
+#include "gripes.h"
+#include "error.h"
+
+void
+gripe_string_invalid (void)
+{
+  error ("string constant used in invalid context");
+}
+
+void
+gripe_range_invalid (void)
+{
+  error ("range constant used in invalid context");
+}
+
+void
+gripe_nonconformant (void)
+{
+  error ("nonconformant matrices");
+}
+
+void
+gripe_empty_arg (const char *name, int is_error)
+{
+  if (is_error)
+    error ("%s: empty matrix is invalid as an argument", name);
+  else
+    warning ("%s: argument is empty matrix", name);
+}
+
+void
+gripe_square_matrix_required (const char *name)
+{
+  error ("%s: argument must be a square matrix", name);
+}
+
+void
+gripe_user_supplied_eval (const char *name)
+{
+  error ("%s: evaluation of user-supplied function failed", name);
+}
+
+void
+gripe_user_returned_invalid (const char *name)
+{
+  error ("%s: user-supplied function returned invalid value", name);
+}
+
+/*
+;;; Local Variables: ***
+;;; mode: C++ ***
+;;; page-delimiter: "^/\\*" ***
+;;; End: ***
+*/
new file mode 100644
--- /dev/null
+++ b/src/gripes.h
@@ -0,0 +1,46 @@
+// gripes.h                                              -*- C++ -*-
+/*
+
+Copyright (C) 1992, 1993 John W. Eaton
+
+This file is part of Octave.
+
+Octave is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+Octave is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with Octave; see the file COPYING.  If not, write to the Free
+Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#if !defined (_gripes_h)
+#define _gripes_h 1
+
+#ifdef __GNUG__
+#pragma interface
+#endif
+
+extern void gripe_string_invalid (void);
+extern void gripe_range_invalid (void);
+extern void gripe_nonconformant (void);
+extern void gripe_empty_arg (const char *name, int is_error);
+extern void gripe_square_matrix_required (const char *name);
+extern void gripe_user_supplied_eval (const char *name);
+extern void gripe_user_returned_invalid (const char *name);
+
+#endif
+
+/*
+;;; Local Variables: ***
+;;; mode: C++ ***
+;;; page-delimiter: "^/\\*" ***
+;;; End: ***
+*/
new file mode 100644
--- /dev/null
+++ b/src/help.cc
@@ -0,0 +1,264 @@
+// help.cc                                             -*- C++ -*-
+/*
+
+Copyright (C) 1992, 1993 John W. Eaton
+
+This file is part of Octave.
+
+Octave is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+Octave is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with Octave; see the file COPYING.  If not, write to the Free
+Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifdef __GNUG__
+#pragma implementation
+#endif
+
+#include <iostream.h>
+#include "builtins.h"
+#include "help.h"
+
+static help_list operators[] =
+{
+  { "!",
+    "Logical not operator.  See also `~'.\n", },
+
+  { "!=",
+    "Logical not equals operator.  See also `~' and `<>'.\n", },
+
+  { "\"",
+    "String delimiter.\n", },
+
+  { "#",
+    "Begin comment character.  See also `%'.\n", },
+
+  { "%",
+    "Begin comment charcter.  See also `#'.\n", },
+
+  { "&",
+    "Logical and operator.  See also `&&'.\n", },
+
+  { "&&",
+    "Logical and operator.  See also `&'.\n", },
+
+  { "'",
+    "Matrix transpose operator.  For complex matrices, computes the\n\
+complex conjugate (Hermitian) transpose.  See also `.''\n\
+\n\
+The single quote character may also be used to delimit strings, but\n\
+it is better to use the double quote character, since that is never\n\
+ambiguous\n", },
+
+  { "(",
+    "Array index or function argument delimiter.\n", },
+
+  { ")",
+    "Array index or function argument delimiter.\n", },
+
+  { "*",
+    "Multiplication operator.  See also `.*'\n", },
+
+  { "**",
+    "Power operator.  See also `^', `.**', and `.^'\n", },
+
+  { "+",
+    "Addition operator.\n", },
+
+  { "++",
+    "Increment operator.  As in C, may be applied as a prefix or postfix operator.\n", },
+
+  { ",",
+    "Array index, function argument, or command separator.\n", },
+
+  { "-",
+    "Subtraction or unary negation operator.\n", },
+
+  { "--",
+    "Decrement operator.  As in C, may be applied as a prefix or postfix operator.\n", },
+
+  { ".'",
+    "Matrix transpose operator.  For complex matrices, computes the\n\
+transpose, *not* the complex conjugate transpose.  See also `''.\n", },
+
+  { ".*",
+    "Element by element multiplication operator.  See also `*'.\n", },
+
+  { ".**",
+    "Element by element power operator.  See also `**', `^', and `.^'.\n", },
+
+  { "./",
+    "Element by element division operator.  See also `/' and `\\'.\n", },
+
+  { ".^",
+    "Element by element division operator.  See also `/' and `\\'.\n", },
+
+  { "/",
+    "Right division.  See also `\\' and `./'.\n", },
+
+  { ":",
+    "Select entire rows or columns of matrices.\n", },
+
+  { ";",
+    "Array row or command separator.  See also `,'.\n", },
+
+  { "<",
+    "Less than operator.\n", },
+
+  { "<=",
+    "Less than or equals operator.\n", },
+
+  { "<>",
+    "Logical not equals operator.  See also `!=' and `~='.\n", },
+
+  { "=",
+    "Assignment operator.\n", },
+
+  { "==",
+    "Equality test operator.\n", },
+
+  { ">",
+    "Greater than operator.\n", },
+
+  { ">=",
+    "Greater than or equals operator.\n", },
+
+  { "[",
+    "Return list delimiter.  See also `]'.\n", },
+
+  { "\\",
+    "Left division operator.  See also `/' and `./'.\n", },
+
+  { "]",
+    "Return list delimiter.  See also `['.\n", },
+
+  { "^",
+    "Power operator.  See also `**', `.^', and `.**.'\n", },
+
+  { "|",
+    "Logical or operator.  See also `||'.\n", },
+
+  { "||",
+    "Logical or operator.  See also `|'.\n", },
+
+  { "~",
+    "Logical not operator.  See also `!' and `~'.\n", },
+
+  { "~=",
+    "Logical not equals operator.  See also `<>' and `!='.\n", },
+
+  { (char *) NULL, (char *) NULL, },
+};
+
+static help_list keywords[] =
+{
+  { "break",
+    "Exit the innermost enclosing while or for loop.\n", },
+
+  { "continue",
+    "Jump to the end of the innermost enclosing while or for loop.\n", },
+
+  { "else",
+    "Alternate action for an if block.\n", },
+
+  { "elseif",
+    "Alternate conditional test for an if block.\n", },
+
+  { "end",
+    "Mark the end of any for, if, while, or function block.\n", },
+
+  { "endfor",
+    "Mark the end of a for loop.\n", },
+
+  { "endfunction",
+    "Mark the end of a function.\n", },
+
+  { "endif",
+    "Mark the end of an if block.\n", },
+
+  { "endwhile",
+    "Mark the end of a while loop.\n", },
+
+  { "for",
+    "Begin a for loop.\n", },
+
+  { "function",
+    "Begin a function body.\n", },
+
+  { "global",
+    "Declare variables to have global scope.\n", },
+
+  { "gplot",
+    "Produce 2-D plots using gnuplot-like command syntax.\n", },
+
+  { "gsplot",
+    "Produce 3-D plots using gnuplot-like command syntax.\n", },
+
+  { "if",
+    "Begin an if block.\n", },
+
+  { "return",
+    "Return from a function.\n", },
+
+  { "while",
+    "Begin a while loop.\n", },
+
+  { (char *) NULL, (char *) NULL, },
+};
+
+char **
+names (help_list *lst, int& count)
+{
+  count = 0;
+  help_list *ptr = lst;
+  while (ptr->name != (char *) NULL)
+    {
+      count++;
+      ptr++;
+    }
+
+  if (count == 0)
+    return (char **) NULL;
+    
+  char **name_list = new char * [count+1];
+
+  ptr = lst;
+  int i = 0;
+  while (ptr->name != (char *) NULL)
+    {
+      name_list[i++] = ptr->name;
+      ptr++;
+    }
+
+  name_list[count] = (char *) NULL;
+  return name_list;
+}
+
+help_list *
+operator_help (void)
+{
+  return operators;
+}
+
+help_list *
+keyword_help (void)
+{
+  return keywords;
+}
+
+/*
+;;; Local Variables: ***
+;;; mode: C++ ***
+;;; page-delimiter: "^/\\*" ***
+;;; End: ***
+*/
new file mode 100644
--- /dev/null
+++ b/src/help.h
@@ -0,0 +1,48 @@
+// help.h                                              -*- C++ -*-
+/*
+
+Copyright (C) 1992, 1993 John W. Eaton
+
+This file is part of Octave.
+
+Octave is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+Octave is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with Octave; see the file COPYING.  If not, write to the Free
+Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#if !defined (_help_h)
+#define _help_h 1
+
+#ifdef __GNUG__
+#pragma interface
+#endif
+
+typedef struct help_list
+{
+  char *name;
+  char *help;
+};
+
+extern char **names (help_list *l, int& count);
+extern help_list *operator_help (void);
+extern help_list *keyword_help (void);
+
+#endif
+
+/*
+;;; Local Variables: ***
+;;; mode: C++ ***
+;;; page-delimiter: "^/\\*" ***
+;;; End: ***
+*/
new file mode 100644
--- /dev/null
+++ b/src/hess.cc
@@ -0,0 +1,164 @@
+// tc-hess.cc                                           -*- C++ -*-
+/*
+
+Copyright (C) 1993 John W. Eaton
+
+This file is part of Octave.
+
+Octave is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+Octave is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with Octave; see the file COPYING.  If not, write to the Free
+Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifdef __GNUG__
+#pragma implementation
+#endif
+
+#include "Matrix.h"
+
+#include "tree-const.h"
+#include "user-prefs.h"
+#include "error.h"
+#include "gripes.h"
+
+#ifdef WITH_DLD
+tree_constant *
+builtin_hess_2 (tree_constant *args, int nargin, int nargout)
+{
+  return hess (args, nargin, nargout);
+}
+#endif
+
+tree_constant *
+hess (tree_constant *args, int nargin, int nargout)
+{
+  tree_constant *retval = NULL_TREE_CONST;
+
+  tree_constant arg = args[1].make_numeric ();
+
+  int a_nr = arg.rows ();
+  int a_nc = arg.columns ();
+
+  if (a_nr == 0 || a_nc == 0)
+    {
+      int flag = user_pref.propagate_empty_matrices;
+      if (flag != 0)
+	{
+	  if (flag < 0)
+	    warning ("hess: argument is empty matrix");
+	  Matrix m;
+	  retval = new tree_constant [3];
+	  retval[0] = tree_constant (m);
+	  retval[1] = tree_constant (m);
+        }
+      else
+	error ("hess: empty matrix is invalid as argument");
+
+      return retval;
+    }
+
+  if (a_nr != a_nc)
+    {
+      gripe_square_matrix_required ("hess");
+      return retval;
+    }
+
+  Matrix tmp;
+  ComplexMatrix ctmp;
+
+  switch (arg.const_type ())
+    {
+    case tree_constant_rep::matrix_constant:
+      {
+	tmp = arg.matrix_value ();
+
+	HESS result (tmp);
+
+	if (nargout == 1)
+	  {
+	    retval = new tree_constant [2];
+	    retval[0] = tree_constant (result.hess_matrix ());
+	  }
+        else
+	  {
+	    retval = new tree_constant [3];
+	    retval[0] = tree_constant (result.unitary_hess_matrix ());
+	    retval[1] = tree_constant (result.hess_matrix ());
+          }
+      }
+      break;
+    case tree_constant_rep::complex_matrix_constant:
+      {
+	ctmp = arg.complex_matrix_value ();
+
+	ComplexHESS result (ctmp);
+
+	if (nargout == 1)
+	  {
+	    retval = new tree_constant [2];
+	    retval[0] = tree_constant (result.hess_matrix ());
+	  }
+  	else
+	  {
+	    retval = new tree_constant [3];
+	    retval[0] = tree_constant (result.unitary_hess_matrix ());
+	    retval[1] = tree_constant (result.hess_matrix ());
+	  }
+      }
+      break;
+    case tree_constant_rep::scalar_constant:
+      {
+	double d = arg.double_value ();
+	if (nargout == 1)
+	  {
+	    retval = new tree_constant [2];
+	    retval[0] = tree_constant (d);
+	  }
+	else
+	  {
+	    retval = new tree_constant [3];
+	    retval[0] = tree_constant (1);
+	    retval[1] = tree_constant (d);
+	  }
+      }
+      break;
+    case tree_constant_rep::complex_scalar_constant:
+      {
+	Complex c = arg.complex_value ();
+	if (nargout == 1)
+ 	  {
+	    retval = new tree_constant [2];
+	    retval[0] = tree_constant (c);
+	  }
+	else
+	  {
+	    retval = new tree_constant [3];
+	    retval[0] = tree_constant (1);
+	    retval[1] = tree_constant (c);
+	  }
+      }
+      break;
+    default:
+      panic_impossible ();
+      break;
+    }
+  return retval;
+}
+
+/*
+;;; Local Variables: ***
+;;; mode: C++ ***
+;;; page-delimiter: "^/\\*" ***
+;;; End: ***
+*/
new file mode 100644
--- /dev/null
+++ b/src/ifft.cc
@@ -0,0 +1,101 @@
+// tc-ifft.cc                                           -*- C++ -*-
+/*
+
+Copyright (C) 1993 John W. Eaton
+
+This file is part of Octave.
+
+Octave is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+Octave is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with Octave; see the file COPYING.  If not, write to the Free
+Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifdef __GNUG__
+#pragma implementation
+#endif
+
+#include "Matrix.h"
+
+#include "tree-const.h"
+#include "user-prefs.h"
+#include "gripes.h"
+#include "error.h"
+
+#ifdef WITH_DLD
+tree_constant *
+builtin_ifft_2 (tree_constant *args, int nargin, int nargout)
+{
+  tree_constant *retval = new tree_constant [2];
+  retval[0] = ifft (args[1]);
+  return retval;
+}
+#endif
+
+tree_constant
+ifft (tree_constant& a)
+{
+  tree_constant retval;
+
+  tree_constant tmp = a.make_numeric ();;
+    
+  if (tmp.rows () == 0 || tmp.columns () == 0)
+    {
+      int flag = user_pref.propagate_empty_matrices;
+      if (flag != 0)
+	{
+	  if (flag < 0)
+	    gripe_empty_arg ("ifft", 0);
+	  Matrix m;
+	  retval = tree_constant (m);
+	}
+      else
+	gripe_empty_arg ("ifft", 1);
+
+      return retval;
+    }
+
+  switch (tmp.const_type ())
+    {
+    case tree_constant_rep::matrix_constant:
+      {
+	Matrix m = tmp.matrix_value ();
+	ComplexMatrix mifft = m.ifourier ();
+	retval = tree_constant (mifft);
+      }
+      break;
+    case tree_constant_rep::complex_matrix_constant:
+      {
+	ComplexMatrix m = tmp.complex_matrix_value ();
+	ComplexMatrix mifft = m.ifourier ();
+	retval = tree_constant (mifft);
+      }
+      break;
+    case tree_constant_rep::scalar_constant:
+    case tree_constant_rep::complex_scalar_constant:
+      error ("ifft: invalid scalar arguement");
+      break;
+    default:
+      panic_impossible ();
+      break;
+    }
+  return retval;
+}
+
+
+/*
+;;; Local Variables: ***
+;;; mode: C++ ***
+;;; page-delimiter: "^/\\*" ***
+;;; End: ***
+*/
new file mode 100644
--- /dev/null
+++ b/src/input.cc
@@ -0,0 +1,342 @@
+// input.cc                                             -*- C++ -*-
+/*
+
+Copyright (C) 1992, 1993 John W. Eaton
+
+This file is part of Octave.
+
+Octave is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+Octave is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with Octave; see the file COPYING.  If not, write to the Free
+Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+// Use the GNU readline library for command line editing and hisory.
+
+#ifdef __GNUG__
+#pragma implementation
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <assert.h>
+
+// This must come before anything that includes iostream.h...
+extern "C"
+{
+#include "readline/readline.h"
+
+/*
+ * Yes, this sucks, but it avoids a conflict with another readline
+ * function declared in iostream.h.
+ */
+#if 0
+#define LINE_SIZE 8192
+static int no_line_editing = 1;
+#endif
+
+char *
+gnu_readline (char *s)
+{
+#if 0
+  static int state = 0;
+  static char *line_from_stdin = (char *) NULL;
+  if (no_line_editing)
+    {
+      if (! state)
+	{
+	  line_from_stdin = (char *) malloc (LINE_SIZE);
+	  state = 1;
+	}
+      fputs ("octave> ", stdout);
+      fgets (line_from_stdin, LINE_SIZE, stdin);
+      return line_from_stdin;
+    }
+  else
+#endif
+    return readline (s);
+}
+}
+
+#include "variables.h"
+#include "error.h"
+#include "utils.h"
+#include "input.h"
+#include "pager.h"
+#include "help.h"
+#include "symtab.h"
+#include "octave-hist.h"
+#include "sighandlers.h"
+#include "parse.h"
+#include "user-prefs.h"
+#include "builtins.h"
+
+// Global pointer for eval().
+char *current_eval_string = (char *) NULL;
+
+// Nonzero means get input from current_eval_string.
+int get_input_from_eval_string = 0;
+
+// Nonzero means we're parsing an M-file.
+int reading_m_file = 0;
+
+// Simple name of M-file we are reading.
+char *curr_m_file_name = (char *) NULL;
+
+// Nonzero means we're parsing a script file.
+int reading_script_file = 0;
+
+// If we are reading from an M-file, this is it.
+FILE *mf_instream = (FILE *) NULL;
+
+// Nonzero means we are using readline.
+int using_readline = 1;
+
+// Nonzero means commands are echoed as they are executed (-x).
+int echo_input = 0;
+
+// Nonzero means this is an interactive shell.
+int interactive = 0;
+
+// Nonzero means the user forced this shell to be interactive (-i).
+int forced_interactive = 0;
+
+// Should we issue a prompt?
+int promptflag = 1;
+
+// The current line of input, from wherever.
+char *current_input_line = (char *) NULL;
+
+// A line of input from readline.
+static char *octave_gets_line = (char *) NULL;
+
+/*
+ * Use GNU readline to get an input line and store it in the history
+ * list.
+ */
+char *
+octave_gets (void)
+{
+  if (octave_gets_line != NULL)
+    free (octave_gets_line);
+
+  if (interactive || forced_interactive)
+    {
+      char *ps = (promptflag > 0) ? user_pref.ps1 : user_pref.ps2;
+      char *prompt = decode_prompt_string (ps);
+
+      if (interactive)
+	{
+	  pipe_handler_error_count = 0;
+	  flush_output_to_pager ();
+	}
+
+      octave_gets_line = gnu_readline (prompt);
+      delete [] prompt;
+    }
+  else
+    octave_gets_line = gnu_readline ("");
+
+  current_input_line = octave_gets_line;
+
+  if (octave_gets_line && *octave_gets_line)
+    {
+      maybe_save_history (octave_gets_line);
+
+      if (echo_input)
+	{
+	  if (!forced_interactive)
+	    cout << "+ ";
+	  if (octave_gets_line != (char *) NULL)
+	    cout << octave_gets_line << "\n";
+	}
+    }
+  return octave_gets_line;
+}
+
+/*
+ * Read a line from the input stream.
+ */
+int 
+octave_read (char *buf, int max_size)
+{
+  int status = 0;
+
+  static char *stashed_line = (char *) NULL;
+
+  if (get_input_from_eval_string)
+    {
+      int len = strlen (current_eval_string);
+      if (len < max_size - 1)
+	{
+	  strcpy (buf, current_eval_string);
+	  buf[len++] = '\n';
+	  buf[len] = '\0';    // Paranoia.
+	  status = len;
+	}
+      else
+	status = -1;
+
+      if (stashed_line)
+	delete [] stashed_line;
+
+      stashed_line = strsave (buf);
+      current_input_line = stashed_line;
+    }
+  else if (using_readline)
+    {
+      char *cp = octave_gets ();
+      if (cp != (char *) NULL)
+	{
+	  int len = strlen (cp);
+	  if (len >= max_size)
+	    status = -1;
+	  else
+	    {
+	      strcpy (buf, cp);
+	      buf[len++] = '\n';
+	      buf[len] = '\0';    // Paranoia.
+	      status = len;
+	    }
+	}
+      current_input_line = cp;
+    }
+  else
+    {
+      FILE *curr_stream = rl_instream;
+      if (reading_m_file || reading_script_file)
+	curr_stream = mf_instream;
+
+      assert (curr_stream != (FILE *) NULL);
+
+// Why is this required?
+      buf[0] = '\0';
+
+      if (fgets (buf, max_size, curr_stream) != (char *) NULL)
+	{
+	  int len = strlen (buf);
+	  if (len > max_size - 2)
+	    status = -1;
+	  else
+	    {
+	      if (buf[len-1] != '\n')
+		{
+		  buf[len++] = '\n';
+		  buf[len] = '\0';
+		}
+	      status = len;
+	    }
+	}
+      else
+	status = 0; // Tell yylex that we found EOF.
+
+      if (stashed_line)
+	delete [] stashed_line;
+
+      stashed_line = strsave (buf);
+      current_input_line = stashed_line;
+    }
+  input_line_number++;
+  return status;
+}
+
+/*
+ * Fix things up so that input can come from file `name', printing a
+ * warning if the file doesn't exist.
+ */
+FILE *
+get_input_from_file (char *name, int warn = 1)
+{
+  FILE *instream = (FILE *) NULL;
+
+  if (name && *name)
+    instream = fopen (name, "r");
+
+  if (instream == (FILE *) NULL && warn)
+    message (name, "no such file or directory");
+
+  if (reading_m_file || reading_script_file)
+    mf_instream = instream;
+  else
+    rl_instream = instream;
+
+  return instream;
+}
+
+/*
+ * Fix things up so that input can come from the standard input.  This
+ * may need to become much more complicated, which is why it's in a
+ * separate function.
+ */
+FILE *
+get_input_from_stdin (void)
+{
+  rl_instream = stdin;
+  return rl_instream;
+}
+
+char *
+command_generator (char *text, int state)
+{
+  static int len = 0;
+  static int list_index = 0;
+
+  static char **name_list = (char **) NULL;
+
+  if (state == 0)
+    {
+      list_index = 0;
+      len = strlen (text);
+
+      if (name_list != (char **) NULL)
+	delete [] name_list;
+
+      name_list = make_name_list ();
+    }
+
+  char *name;
+  while ((name = name_list[list_index]) != (char *) NULL)
+    {
+      list_index++;
+      if (strncmp (name, text, len) == 0)
+	return name;
+    }
+
+  return (char *) NULL;
+}
+
+char **
+command_completer (char *text, int start, int end)
+{
+  char **matches = (char **) NULL;
+  matches = completion_matches (text, command_generator);
+  return matches;
+}
+
+void
+initialize_readline (void)
+{
+// Allow conditional parsing of the ~/.inputrc file
+  rl_readline_name = "Octave";
+
+// Tell the completer that we want to try first.
+  rl_attempted_completion_function = (Function *) command_completer;
+}
+
+/*
+;;; Local Variables: ***
+;;; mode: C++ ***
+;;; page-delimiter: "^/\\*" ***
+;;; End: ***
+*/
new file mode 100644
--- /dev/null
+++ b/src/input.h
@@ -0,0 +1,91 @@
+// input.h                                              -*- C++ -*-
+/*
+
+Copyright (C) 1992, 1993 John W. Eaton
+
+This file is part of Octave.
+
+Octave is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+Octave is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with Octave; see the file COPYING.  If not, write to the Free
+Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+// Use the GNU readline library for command line editing and hisory.
+
+#if !defined (_input_h)
+#define _input_h 1
+
+#ifdef __GNUG__
+#pragma interface
+#endif
+
+#include <stdio.h>
+
+extern char *octave_gets (void);
+extern int octave_read (char *buf, int max_size);
+extern FILE *get_input_from_file (char *name, int warn = 1);
+extern FILE *get_input_from_stdin (void);
+extern char *command_generator (char *text, int state);
+extern char **command_completer (char *text, int start, int end);
+extern void initialize_readline (void);
+
+// Global pointer for eval().
+extern char *current_eval_string;
+
+// Nonzero means get input from current_eval_string.
+extern int get_input_from_eval_string;
+
+// Nonzero means we're parsing an M-file.
+extern int reading_m_file;
+
+// Simple name of M-file we are reading.
+extern char *curr_m_file_name;
+
+// Nonzero means we're parsing a script file.
+extern int reading_script_file;
+
+// If we are reading from an M-file, this is it.
+extern FILE *mf_instream;
+
+// Nonzero means we are using readline.
+extern int using_readline;
+
+// Nonzero means commands are echoed as they are executed (-x).
+extern int echo_input;
+
+// Nonzero means this is an interactive shell.
+extern int interactive;
+
+// Nonzero means the user forced this shell to be interactive (-i).
+extern int forced_interactive;
+
+// Should we issue a prompt?
+extern int promptflag;
+
+// A line of input.
+extern char *current_input_line;
+
+extern "C"
+{
+char *gnu_readline (char *s);
+}
+
+#endif
+
+/*
+;;; Local Variables: ***
+;;; mode: C++ ***
+;;; page-delimiter: "^/\\*" ***
+;;; End: ***
+*/
new file mode 100644
--- /dev/null
+++ b/src/inv.cc
@@ -0,0 +1,130 @@
+// tc-inv.cc                                           -*- C++ -*-
+/*
+
+Copyright (C) 1993 John W. Eaton
+
+This file is part of Octave.
+
+Octave is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+Octave is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with Octave; see the file COPYING.  If not, write to the Free
+Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifdef __GNUG__
+#pragma implementation
+#endif
+
+#include "Matrix.h"
+
+#include "tree-const.h"
+#include "user-prefs.h"
+#include "gripes.h"
+#include "error.h"
+
+#ifdef WITH_DLD
+tree_constant *
+builtin_inv (tree_constant *args, int nargin, int nargout)
+{
+  tree_constant *retval = new tree_constant [2];
+  retval[0] = inverse (args[1]);
+  return retval;
+}
+#endif
+
+tree_constant
+inverse (tree_constant& a)
+{
+  tree_constant retval;
+
+  tree_constant tmp = a.make_numeric ();
+
+  int nr = tmp.rows ();
+  int nc = tmp.columns ();
+  if (nr == 0 || nc == 0)
+    {
+      int flag = user_pref.propagate_empty_matrices;
+      if (flag < 0)
+	gripe_empty_arg ("inverse", 0);
+      else if (flag == 0)
+	gripe_empty_arg ("inverse", 1);
+    }
+
+  Matrix mtmp;
+  if (nr == 0 && nc == 0)
+    return tree_constant (mtmp);
+
+  switch (tmp.const_type ())
+    {
+    case tree_constant_rep::matrix_constant:
+      {
+	Matrix m = tmp.matrix_value ();
+	if (m.rows () == m.columns ())
+	  {
+	    int info;
+	    double rcond = 0.0;
+	    Matrix minv = m.inverse (info, rcond);
+	    if (info == -1)
+	      message ("inverse",
+		       "matrix singular to machine precision, rcond = %g",
+		       rcond);
+	    else
+	      retval = tree_constant (minv);
+	  }
+	else
+	  gripe_square_matrix_required ("inverse");
+      }
+      break;
+    case tree_constant_rep::scalar_constant:
+      {
+	double d = 1.0 / tmp.double_value ();
+	retval = tree_constant (d);
+      }
+      break;
+    case tree_constant_rep::complex_matrix_constant:
+      {
+	ComplexMatrix m = tmp.complex_matrix_value ();
+	if (m.rows () == m.columns ())
+	  {
+	    int info;
+	    double rcond = 0.0;
+	    ComplexMatrix minv = m.inverse (info, rcond);
+	    if (info == -1)
+	      message ("inverse",
+		       "matrix singular to machine precision, rcond = %g",
+		       rcond);
+	    else
+	      retval = tree_constant (minv);
+	  }
+	else
+	  gripe_square_matrix_required ("inverse");
+      }
+      break;
+    case tree_constant_rep::complex_scalar_constant:
+      {
+	Complex c = 1.0 / tmp.complex_value ();
+	retval = tree_constant (c);
+      }
+      break;
+    default:
+      break;
+    }
+  return retval;
+}
+
+/*
+;;; Local Variables: ***
+;;; mode: C++ ***
+;;; page-delimiter: "^/\\*" ***
+;;; End: ***
+*/
new file mode 100644
--- /dev/null
+++ b/src/lex.h
@@ -0,0 +1,57 @@
+// lex.h                                                 -*- C++ -*-
+/*
+
+Copyright (C) 1992, 1993 John W. Eaton
+
+This file is part of Octave.
+
+Octave is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+Octave is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with Octave; see the file COPYING.  If not, write to the Free
+Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#if !defined (_lex_h)
+#define _lex_h 1
+
+typedef struct yy_buffer_state *YY_BUFFER_STATE;
+
+// Associate a buffer with a new file to read.
+extern YY_BUFFER_STATE create_buffer (FILE *f);
+
+// Report the current buffer.
+extern YY_BUFFER_STATE current_buffer (void);
+
+// Connect to new buffer buffer.
+extern void switch_to_buffer (YY_BUFFER_STATE buf);
+
+// Delete a buffer.
+extern void delete_buffer (YY_BUFFER_STATE buf);
+
+// Restore a buffer (for unwind-prot).
+extern void restore_input_buffer (void *buf);
+
+// Delete a buffer (for unwind-prot).
+extern void delete_input_buffer (void *buf);
+
+// See if a function file has extra garbage after the end statement.
+extern void check_for_garbage_after_fcn_def (void);
+
+#endif
+
+/*
+;;; Local Variables: ***
+;;; mode: C++ ***
+;;; page-delimiter: "^/\\*" ***
+;;; End: ***
+*/
new file mode 100644
--- /dev/null
+++ b/src/lex.l
@@ -0,0 +1,1340 @@
+/* lex.l                                                -*- C -*-
+
+Copyright (C) 1992, 1993 John W. Eaton
+
+This file is part of Octave.
+
+Octave is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+Octave is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU CC; see the file COPYING.  If not, write to the Free
+Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+%x COMMENT
+%x NEW_MATRIX
+%x HELP_FCN
+%s TEXT_FCN
+%s DQSTRING
+%s STRING
+%s MATRIX
+
+%{
+
+// Arrange to get input via readline.
+
+#ifdef YY_INPUT
+#undef YY_INPUT
+#define YY_INPUT(buf,result,max_size) \
+  if ((result = octave_read (buf, max_size)) < 0) \
+    YY_FATAL_ERROR ("octave_read () in flex scanner failed");
+#endif
+
+// Try to avoid crashing out completely on fatal scanner errors.
+
+#ifdef YY_FATAL_ERROR
+#undef YY_FATAL_ERROR
+#define YY_FATAL_ERROR(msg) \
+  do \
+    { \
+      error (msg); \
+      jump_to_top_level (); \
+    } \
+  while (0)
+#endif
+
+#include "input.h"
+
+// The type of an END token.  This declaration is repeated in parse.y.
+// It must appear before y.tab.h is included.
+enum end_tok_type
+  {
+    simple_end,
+    for_end,
+    function_end,
+    if_end,
+    while_end,
+  };
+
+// The type of a PLOT token.  This declaration is repeated in parse.y.
+// It must appear before y.tab.h is included.
+enum plot_tok_type
+  {
+    two_dee = 2,
+    three_dee = 3,
+  };
+
+#include "SLStack.h"
+
+#include "variables.h"
+#include "symtab.h"
+#include "error.h"
+#include "utils.h"
+#include "tree.h"
+#include "y.tab.h"
+#include "parse.h"
+#include "lex.h"
+
+// Nonzero means we thing we are looking at the beginning of a
+// function definition.
+static int beginning_of_function = 0;
+
+// Nonzero means we think we are looking at a set command.
+static int doing_set = 0;
+
+// GAG.  Stupid kludge so that [[1,2][3,4]] will work.
+static do_comma_insert = 0;
+
+// Brace level count.
+static int braceflag = 0;
+
+// Return transpose or start a string?
+static int quote_is_transpose = 0;
+
+// Nonzero means that we should convert spaces to a comma inside a
+// matrix definition.
+static int convert_spaces_to_comma = 1;
+
+// Another context hack, this time for the plot command's `using',
+// `title', and `with' keywords.
+static int cant_be_identifier = 0;
+
+// Is the closest nesting level a square brace or a paren?
+//
+//  1 -> brace, spaces are important (they can turn into commas)
+//  0 -> paren, spaces are not important
+//
+static SLStack <int> in_brace_or_paren;
+
+static void do_string_escapes (char *s);
+static void fixup_column_count (char *s);
+static int do_comma_insert_check (void);
+static int is_plot_keyword (char *s);
+static int is_keyword (char *s);
+static char *plot_style_token (char *s);
+static symbol_record *lookup_identifier (char *s);
+static void grab_help_text (void);
+static int match_any (char c, char *s);
+static int next_token_is_bin_op (int spc_prev, char *yytext);
+static int next_token_is_postfix_unary_op (int spc_prev, char *yytext);
+static char *strip_trailing_whitespace (char *s);
+
+#define DO_COMMA_INSERT_CHECK yyless (do_comma_insert_check ())
+
+#define RETURN(token) \
+  do \
+    { \
+      current_input_column += yyleng; \
+      quote_is_transpose = 0; \
+      cant_be_identifier = 0; \
+      convert_spaces_to_comma = 1; \
+      return (token); \
+    } \
+  while (0)
+
+#define BIN_OP_RETURN(token) \
+  do \
+    { \
+      current_input_column += yyleng; \
+      quote_is_transpose = 0; \
+      cant_be_identifier = 0; \
+      convert_spaces_to_comma = 0; \
+      return (token); \
+    } \
+  while (0)
+
+%}
+
+D	[0-9]
+S	[ \t]
+N	[\n]
+SN	[ \t\n]
+EL	(\.\.\.)
+Im	[iIjJ]
+QQ	(\'\')
+ECHAR	(\\.)
+QSTR	([^\n\'\\]*({QQ}|{ECHAR})*)
+DQSTR	([^\n\"\\]*{ECHAR}*)
+IDENT	([_a-zA-Z][_a-zA-Z0-9]*)
+EXPON	([DdEe][+-]?{D}+)
+%%
+
+\%			|
+\#			{
+			  if (beginning_of_function)
+			    {
+			      grab_help_text ();
+			      beginning_of_function = 0;
+			    }
+
+			  BEGIN COMMENT;
+			  current_input_column += yyleng;
+			}
+
+<COMMENT>\n		{
+			  BEGIN 0;
+			  current_input_column = 0;
+			  quote_is_transpose = 0;
+			  cant_be_identifier = 0;
+			  convert_spaces_to_comma = 1;
+			  return '\n';
+			}
+
+<COMMENT><<EOF>>	{ RETURN (END_OF_INPUT); }
+
+<COMMENT>.*$		{ current_input_column += yyleng; }
+
+<NEW_MATRIX>[^ \t\n]	{
+			  yyless (0);
+			  BEGIN MATRIX;
+			}
+
+<NEW_MATRIX>{SN}*	{
+			  fixup_column_count (yytext);
+			  BEGIN MATRIX;
+			}
+
+<HELP_FCN>\n		|
+<TEXT_FCN>\n		{
+		          BEGIN 0;
+			  current_input_column = 0;
+			  quote_is_transpose = 0;
+			  cant_be_identifier = 0;
+			  convert_spaces_to_comma = 1;
+			  return '\n';
+			}
+
+<TEXT_FCN>[\;\,]	{
+			  if (doing_set)
+			    {
+			      yylval.string = strsave (yytext);
+			      RETURN (TEXT);
+			    }
+			  else
+			    {
+			      BEGIN 0;
+			      RETURN (',');
+			    }
+		        }
+
+<HELP_FCN>[^ \t\n]*{S}*	    |
+<TEXT_FCN>[^ \t\n\;\,]*{S}* {
+
+			  static char *tok = (char *) NULL;
+			  delete [] tok;
+			  tok = strip_trailing_whitespace (yytext);
+
+			  yylval.string = strsave (tok);
+			  RETURN (TEXT);
+			}
+
+<TEXT_FCN>\'{QSTR}*[\n\'] {
+			  if (yytext[yyleng-1] == '\n')
+			    {
+			      error ("unterminated string constant");
+			      current_input_column = 0;
+			      jump_to_top_level ();
+			    }
+			  else
+			    {
+			      int off1 = doing_set ? 0 : 1;
+			      int off2 = doing_set ? 0 : 2;
+			      yylval.string = strsave (&yytext[off1]);
+			      yylval.string[yyleng-off2] = '\0';
+			      current_input_column += yyleng;
+			    }
+			  do_string_escapes (yylval.string);
+			  return TEXT;
+			}
+
+<TEXT_FCN>\"{DQSTR}*[\n\"] {
+			  if (yytext[yyleng-1] == '\n')
+			    {
+			      error ("unterminated string constant");
+			      current_input_column = 0;
+			      jump_to_top_level ();
+			    }
+			  else
+			    {
+			      int off1 = doing_set ? 0 : 1;
+			      int off2 = doing_set ? 0 : 2;
+			      yylval.string = strsave (&yytext[off1]);
+			      yylval.string[yyleng-off2] = '\0';
+			      current_input_column += yyleng;
+			    }
+			  do_string_escapes (yylval.string);
+			  return TEXT;
+			}
+
+<TEXT_FCN>{S}*		{ current_input_column += yyleng; }
+
+<STRING>{QSTR}*[\n\']	{
+			  if (braceflag)
+			    BEGIN MATRIX;
+			  else
+			    BEGIN 0;
+
+			  if (yytext[yyleng-1] == '\n')
+			    {
+			      error ("unterminated string constant");
+			      current_input_column = 0;
+			      jump_to_top_level ();
+			    }
+			  else
+			    {
+			      yylval.string = strsave (yytext);
+			      yylval.string[yyleng-1] = '\0';
+			      current_input_column += yyleng;
+			    }
+			  do_string_escapes (yylval.string);
+			  quote_is_transpose = 1;
+			  cant_be_identifier = 1;
+			  convert_spaces_to_comma = 1;
+			  return TEXT;
+			}
+
+
+<DQSTRING>{DQSTR}*[\n\"] {
+			  if (braceflag)
+			    BEGIN MATRIX;
+			  else
+			    BEGIN 0;
+
+			  if (yytext[yyleng-1] == '\n')
+			    {
+			      error ("unterminated string constant");
+			      current_input_column = 0;
+			      jump_to_top_level ();
+			    }
+			  else
+			    {
+			      yylval.string = strsave (yytext);
+			      yylval.string[yyleng-1] = '\0';
+			      current_input_column += yyleng;
+			    }
+			  do_string_escapes (yylval.string);
+			  quote_is_transpose = 1;
+			  cant_be_identifier = 1;
+			  convert_spaces_to_comma = 1;
+			  return TEXT;
+			}
+
+<MATRIX>{SN}*\]{S}*/==	{
+
+// For this and the next two rules, we're looking at ']', and we
+// need to know if the next token is '='.
+//
+// All this so we can handle the bogus syntax 
+//
+//   [x,y]                % an expression by itself
+//   [x,y] = expression   % assignment to a list of identifiers
+//   [x,y] == expression  % test for equality
+//
+// It would have been so much easier if the delimiters were simply
+// different for the expression on the left hand side of the equals
+// operator.
+
+			  in_brace_or_paren.pop ();
+			  braceflag--;
+			  if (braceflag == 0)
+			    {
+			      if (!defining_func)
+				promptflag++;
+			      BEGIN 0;
+			    }
+			  fixup_column_count (yytext);
+			  quote_is_transpose = 0;
+			  cant_be_identifier = 0;
+			  convert_spaces_to_comma = 1;
+			  return ']';
+			}
+
+<MATRIX>{SN}*\]{S}*/=	{
+			  in_brace_or_paren.pop ();
+			  braceflag--;
+			  if (braceflag == 0)
+			    {
+			      BEGIN 0;
+			      if (!defining_func)
+				promptflag++;
+			    }
+			  fixup_column_count (yytext);
+			  quote_is_transpose = 0;
+			  cant_be_identifier = 0;
+			  convert_spaces_to_comma = 1;
+			  if (maybe_screwed_again)
+			    return SCREW_TWO;
+			  else
+			    return ']';
+			}
+
+<MATRIX>{SN}*\]{S}*	{
+			  fixup_column_count (yytext);
+
+			  in_brace_or_paren.pop ();
+			  braceflag--;
+			  if (braceflag == 0)
+			    {
+			      if (!defining_func)
+				promptflag++;
+			      BEGIN 0;
+			    }
+			  else
+			    {
+			      int c0 = yytext[yyleng-1];
+			      int spc_prev = (c0 == ' ' || c0 == '\t');
+			      int bin_op = next_token_is_bin_op (spc_prev,
+								 yytext);
+			      int postfix_un_op
+				= next_token_is_postfix_unary_op (spc_prev,
+								  yytext);
+
+			      int c1 = yyinput ();
+			      unput (c1);
+			      int other_op = match_any (c1, ",;\n]");
+
+			      if (! (postfix_un_op || bin_op || other_op)
+				     && in_brace_or_paren.top ()
+				     && convert_spaces_to_comma)
+				{
+				  unput (',');
+				  return ']';
+				}
+			    }
+
+			  quote_is_transpose = 1;
+			  cant_be_identifier = 0;
+			  convert_spaces_to_comma = 1;
+			  return ']';
+			}
+
+<MATRIX>{S}*\,{S}*	{ RETURN (','); }
+
+<MATRIX>{S}+		{
+			  int bin_op = next_token_is_bin_op (1, yytext);
+			  int postfix_un_op
+			    = next_token_is_postfix_unary_op (1, yytext);
+
+ 			  if (! (postfix_un_op || bin_op)
+			      && in_brace_or_paren.top ()
+			      && convert_spaces_to_comma)
+			    RETURN (',');
+			}
+
+<MATRIX>{SN}*\;{SN}*	|
+<MATRIX>{N}{SN}*	{
+			  fixup_column_count (yytext);
+			  quote_is_transpose = 0;
+			  cant_be_identifier = 0;
+			  convert_spaces_to_comma = 1;
+			  return ';';
+			}
+
+\]			{
+			  if (! in_brace_or_paren.empty ())
+			    in_brace_or_paren.pop ();
+
+			  if (plotting)
+			    {
+			      in_plot_range = 0;
+			      RETURN (CLOSE_BRACE);
+			    }
+			  else
+			    RETURN (']');
+			}
+
+{D}+{EXPON}?{Im}	|
+{D}+\.{D}*{EXPON}?{Im}	|
+\.{D}+{EXPON}?{Im}	{
+			  int nread = sscanf (yytext, "%lf", &(yylval.number));
+			  assert (nread == 1);
+			  quote_is_transpose = 1;
+			  cant_be_identifier = 1;
+			  convert_spaces_to_comma = 1;
+			  current_input_column += yyleng;
+			  DO_COMMA_INSERT_CHECK;
+			  return IMAG_NUM;
+			}
+
+{D}+{EXPON}?		|
+{D}+\.{D}*{EXPON}?	|
+\.{D}+{EXPON}?		|
+			{
+			  int nread = sscanf (yytext, "%lf", &(yylval.number));
+			  assert (nread == 1);
+			  quote_is_transpose = 1;
+			  cant_be_identifier = 1;
+			  convert_spaces_to_comma = 1;
+			  current_input_column += yyleng;
+			  DO_COMMA_INSERT_CHECK;
+			  return NUM;
+			}
+
+\[{S}*		{
+		  in_brace_or_paren.push (1);
+		  if (plotting)
+		    {
+		      in_plot_range = 1;
+		      RETURN (OPEN_BRACE);
+		    }
+
+		  if (do_comma_insert)
+		    {
+		      yyless (0);
+		      do_comma_insert = 0;
+		      quote_is_transpose = 0;
+		      cant_be_identifier = 0;
+		      convert_spaces_to_comma = 1;
+		      return (',');
+		    }
+		  else
+		    {
+		      mlnm.push (1);
+		      braceflag++;
+		      promptflag--;
+		      BEGIN NEW_MATRIX;
+		      RETURN ('[');
+		    }
+		}
+
+{S}*		{ current_input_column += yyleng; }
+
+{EL}{S}*\n	{
+
+// Line continuation.
+
+		  promptflag--;
+		  current_input_column = 0;
+		}
+
+<<EOF>>		RETURN (END_OF_INPUT);
+
+{IDENT}{S}*	{
+
+// Truncate the token at the first space or tab but don't write
+// directly on yytext.
+
+		  static char *tok = (char *) NULL;
+		  delete [] tok;
+		  tok = strip_trailing_whitespace (yytext);
+
+		  int kw_token = is_keyword (tok);
+		  if (kw_token)
+		    RETURN (kw_token);
+
+		  if (plotting && cant_be_identifier)
+		    {
+		      int plot_option_kw = is_plot_keyword (tok);
+		      if (plot_option_kw)
+			{
+			  quote_is_transpose = 0;
+			  cant_be_identifier = 0;
+			  convert_spaces_to_comma = 1;
+			  current_input_column += yyleng;
+			  return plot_option_kw;
+			}
+		    }
+
+		  if (plotting && in_plot_style)
+		    {
+		      char *sty = plot_style_token (&tok[1]);
+		      if (sty != (char *) NULL)
+			{
+			  yylval.string = strsave (sty);
+			  if (in_plot_style)
+			    {
+			      in_plot_style = 0;
+			      RETURN (STYLE);
+			    }
+			}
+		    }
+
+		  cant_be_identifier = 1;
+
+// If we are looking at a text style function, set up to gobble its
+// arguments.  These are also reserved words, but only because it
+// would be very difficult to do anything intelligent with them if
+// they were not reserved.
+
+		  if (is_text_function_name (tok))
+		    {
+		      BEGIN TEXT_FCN;
+
+		      if (strcmp (tok, "clear") == 0)
+			return CLEAR;
+		      else if (strcmp (tok, "help") == 0)
+			BEGIN HELP_FCN;
+		      else if (strcmp (tok, "set") == 0)
+			doing_set = 1;
+		    }
+
+		  yylval.sym_rec = lookup_identifier (tok);
+
+		  quote_is_transpose = 1;
+		  current_input_column += yyleng;
+		  DO_COMMA_INSERT_CHECK;
+
+		  if (! in_brace_or_paren.empty ()
+		      && in_brace_or_paren.top ())
+		    {
+		      int c0 = yytext[yyleng-1];
+		      int spc_prev = (c0 == ' ' || c0 == '\t');
+		      int bin_op = next_token_is_bin_op (spc_prev, yytext);
+
+		      int postfix_un_op
+			= next_token_is_postfix_unary_op (spc_prev, yytext);
+
+		      int c1 = yyinput ();
+		      unput (c1);
+		      int other_op = match_any (c1, ",;\n](");
+
+		      if (! (postfix_un_op || bin_op || other_op))
+			unput (',');
+		    }
+
+		  convert_spaces_to_comma = 1;
+		  return NAME;
+		}
+
+{IDENT}/{S}*=	{
+
+// We've found an identifier followed by some space and an equals
+// sign.  If we are working on a function definition and the previous
+// token was `function', we have something like this
+//
+//    function x = y <list> end
+//
+// which is a function named y returning a variable named x.  The
+// symbol y belongs in the global symbol table (nested function
+// definitions are illegal) and the symbol x belongs in the 
+// symbol table local to the function. 
+//
+// If we're not defining a function, this should function exactly like
+// the case above.  I suppose it would be nice to avoid duplicating
+// all the code, eh?
+
+		  int kw_token = is_keyword (yytext);
+		  if (kw_token)
+		    RETURN (kw_token);
+
+		  if (plotting && cant_be_identifier)
+		    {
+		      int plot_option_kw = is_plot_keyword (yytext);
+		      if (plot_option_kw)
+			{
+			  quote_is_transpose = 0;
+		  	  convert_spaces_to_comma = 1;
+			  current_input_column += yyleng;
+			  return plot_option_kw;
+			}
+		    }
+		
+		  cant_be_identifier = 1;
+
+// If we are looking at a text style function, set up to gobble its
+// arguments.  These are also reserved words, but only because it
+// would be very difficult to do anything intelligent with them if
+// they were not reserved.
+
+		  if (is_text_function_name (yytext))
+		    {
+		      BEGIN TEXT_FCN;
+
+		      if (strcmp (yytext, "clear") == 0)
+			return CLEAR;
+		      else if (strcmp (yytext, "help") == 0)
+			BEGIN HELP_FCN;
+		      else if (strcmp (yytext, "set") == 0)
+			doing_set = 1;
+		    }
+
+		  if (defining_func && maybe_screwed)
+		    curr_sym_tab = tmp_local_sym_tab;
+
+		  yylval.sym_rec = lookup_identifier (yytext);
+
+		  convert_spaces_to_comma = 1;
+		  current_input_column += yyleng;
+		  if (defining_func && maybe_screwed)
+		    {
+		      return SCREW;
+		    }
+		  else
+		    {
+		      quote_is_transpose = 1;
+		      DO_COMMA_INSERT_CHECK;
+		      return NAME;
+		    }
+		}
+
+"\n"		{
+		  quote_is_transpose = 0;
+		  cant_be_identifier = 0;
+		  current_input_column = 0;
+		  convert_spaces_to_comma = 1;
+		  return '\n';
+		}
+
+"'"		{
+		  current_input_column++;
+		  convert_spaces_to_comma = 1;
+
+		  if (quote_is_transpose)
+		    {
+		      DO_COMMA_INSERT_CHECK;
+		      return QUOTE;
+		    }
+		  else
+		    BEGIN STRING;
+		}
+
+":"		{
+		  if (plotting && (in_plot_range || in_plot_using))
+		    RETURN (COLON);
+		  else
+		    BIN_OP_RETURN (':');
+		}
+
+\"		{ BEGIN DQSTRING; }
+".**"		{ BIN_OP_RETURN (EPOW); }
+".*"		{ BIN_OP_RETURN (EMUL); }
+"./"		{ BIN_OP_RETURN (EDIV); }
+".\\"		{ BIN_OP_RETURN (ELEFTDIV); }
+".^"		{ BIN_OP_RETURN (EPOW); }
+".'"		{ DO_COMMA_INSERT_CHECK; RETURN (TRANSPOSE); }
+"++"		{ DO_COMMA_INSERT_CHECK; RETURN (PLUS_PLUS); }
+"--"		{ DO_COMMA_INSERT_CHECK; RETURN (MINUS_MINUS); }
+"<="		{ BIN_OP_RETURN (EXPR_LE); }
+"=="		{ BIN_OP_RETURN (EXPR_EQ); }
+"~="		{ BIN_OP_RETURN (EXPR_NE); }
+"!="		{ BIN_OP_RETURN (EXPR_NE); }
+"<>"		{ BIN_OP_RETURN (EXPR_NE); }
+">="		{ BIN_OP_RETURN (EXPR_GE); }
+"||"		{ BIN_OP_RETURN (EXPR_OR); }
+"&&"		{ BIN_OP_RETURN (EXPR_AND); }
+"|"		{ BIN_OP_RETURN (EXPR_OR); }
+"&"		{ BIN_OP_RETURN (EXPR_AND); }
+"!"		{ RETURN (EXPR_NOT); }
+"~"		{ BIN_OP_RETURN (EXPR_NOT); }
+"<"		{ BIN_OP_RETURN (EXPR_LT); }
+">"		{ BIN_OP_RETURN (EXPR_GT); }
+"+"		{ BIN_OP_RETURN ('+'); }
+"-"		{ BIN_OP_RETURN ('-'); }
+"**"		{ BIN_OP_RETURN (POW); }
+"*"		{ BIN_OP_RETURN ('*'); }
+"/"		{ BIN_OP_RETURN ('/'); }
+"\\"		{ BIN_OP_RETURN (LEFTDIV); }
+";"		{ RETURN (';'); }
+","		{ RETURN (','); }
+"^"		{ BIN_OP_RETURN (POW); }
+"="		{ RETURN ('='); }
+"("		{
+		  in_brace_or_paren.push (0);
+		  RETURN ('(');
+		}
+")"		{
+		  if (! in_brace_or_paren.empty ())
+		    in_brace_or_paren.pop ();
+		  DO_COMMA_INSERT_CHECK;
+		  current_input_column++;
+		  quote_is_transpose = 1;
+		  return ')';
+		}
+
+.		{
+
+// We return everything else as single character tokens, which should
+// eventually result in a parse error.
+
+		  RETURN (yytext[0]);
+		}
+
+%%
+
+/*
+ * GAG.
+ *
+ * If we're reading a matrix and the next character is '[', make sure
+ * that we insert a comma ahead of it.
+ */
+int
+do_comma_insert_check (void)
+{
+  int tmp_len = yyleng;
+  int c = yyinput ();
+  do_comma_insert = (braceflag && c == '[');
+  return tmp_len;
+}
+
+/*
+ * Fix things up for errors or interrupts.
+ */
+void
+reset_parser (void)
+{
+  BEGIN 0;
+  promptflag = 1;
+  doing_set = 0;
+  braceflag = 0;
+  maybe_screwed = 0;
+  maybe_screwed_again = 0;
+  looping = 0;
+  iffing = 0;
+  ml.clear ();
+  mlnm.clear ();
+  defining_func = 0;
+  curr_sym_tab = top_level_sym_tab;
+  get_input_from_eval_string = 0;
+  quote_is_transpose = 0;
+  current_input_column = 0;
+  do_comma_insert = 0;
+  plotting = 0;
+  in_plot_range = 0;
+  in_plot_using = 0;
+  in_plot_style = 0;
+  cant_be_identifier = 0;
+  convert_spaces_to_comma = 1;
+  beginning_of_function = 0;
+  in_brace_or_paren.clear ();
+  yyrestart (stdin);
+}
+
+static void
+do_string_escapes (char *s)
+{
+  char *p1 = s;
+  char *p2 = s;
+  while (*p2 != '\0')
+    {
+      if (*p2 == '\\' && *(p2+1) != '\0')
+	{
+	  switch (*++p2)
+	    {
+	    case 'a':
+	      *p1 = '\a';
+	      break;
+	    case 'b': // backspace
+	      *p1 = '\b';
+	      break;
+	    case 'f': // formfeed
+	      *p1 = '\f';
+	      break;
+	    case 'n': // newline
+	      *p1 = '\n';
+	      break;
+	    case 'r': // carriage return
+	      *p1 = '\r';
+	      break;
+	    case 't': // horizontal tab
+	      *p1 = '\t';
+	      break;
+	    case 'v': // vertical tab
+	      *p1 = '\v';
+	      break;
+	    case '\\': // backslash
+	      *p1 = '\\';
+	      break;
+	    case '\'': // quote
+	      *p1 = '\'';
+	      break;
+	    case '"': // double quote
+	      *p1 = '"';
+	      break;
+	    default:
+          warning ("unrecognized escape sequence `\\%c' -- converting to `%c'",
+		   *p2, *p2);
+	      *p1 = *p2;
+	      break;
+	    }
+	}
+      else if (*p2 == '\'' && *(p2+1) == '\'')
+	{
+	  *p1 = '\'';
+	  p2++;
+	}
+      else
+	{
+	  *p1 = *p2;
+	}
+
+      p1++;
+      p2++;
+    }
+
+  *p1 = '\0';
+}
+
+static void
+fixup_column_count (char *s)
+{
+  char c;
+  while ((c = *s++) != '\0')
+    {
+      if (c == '\n')
+	  current_input_column = 0;
+      else
+	current_input_column++;
+    }
+}
+
+#ifdef yywrap
+#undef yywrap
+#endif
+int
+yywrap (void)
+{
+  return 0;
+}
+
+/*
+ * Tell us all what the current buffer is.
+ */
+YY_BUFFER_STATE
+current_buffer (void)
+{
+  return YY_CURRENT_BUFFER;
+}
+
+/*
+ * Create a new buffer.
+ */
+YY_BUFFER_STATE
+create_buffer (FILE *f)
+{
+  return yy_create_buffer (f, YY_BUF_SIZE);
+}
+
+/*
+ * Start reading a new buffer.
+ */
+void
+switch_to_buffer (YY_BUFFER_STATE buf)
+{
+  yy_switch_to_buffer (buf);
+}
+
+/*
+ * Delete a buffer.
+ */
+void
+delete_buffer (YY_BUFFER_STATE buf)
+{
+  yy_delete_buffer (buf);
+}
+
+/*
+ * Restore a buffer (for unwind-prot).
+ */
+void
+restore_input_buffer (void *buf)
+{
+  switch_to_buffer ((YY_BUFFER_STATE) buf);
+}
+
+/*
+ * Delete a buffer (for unwind-prot).
+ */
+void
+delete_input_buffer (void *buf)
+{
+  delete_buffer ((YY_BUFFER_STATE) buf);
+}
+
+static char *plot_styles[] = 
+  {
+    "dots",
+    "dots",
+    "errorbars",
+    "impulses",
+    "lines",
+    "linespoints",
+    "points",
+    (char *) NULL,
+  };
+
+static char *
+plot_style_token (char *s)
+{
+  char **tmp = plot_styles;
+  while (*tmp != (char *) NULL)
+    {
+      if (almost_match (*tmp, s))
+	return *tmp;
+
+      tmp++;
+    }
+
+  return (char *) NULL;
+}
+
+static int
+is_plot_keyword (char *s)
+{
+  if (almost_match ("title", s))
+    return TITLE;
+  else if (almost_match ("using", s))
+    { in_plot_using = 1; return USING; }
+  else if (almost_match ("with", s))
+    { in_plot_style = 1; return WITH; }
+  else
+    return 0;
+}
+
+/*
+ * Handle keywords.  Could probably be more efficient...
+ */
+static int
+is_keyword (char *s)
+{
+  if (plotting && in_plot_style)
+    {
+      char *sty = plot_style_token (s);
+      if (sty != (char *) NULL)
+	{
+	  in_plot_style = 0;
+	  yylval.string = strsave (sty);
+	  return STYLE;
+	}
+    }
+
+  int end_found = 0;
+  if (strcmp ("break", s) == 0)
+    return BREAK;
+  else if (strcmp ("continue", s) == 0)
+    return CONTINUE;
+  else if (strcmp ("else", s) == 0)
+    { return ELSE; }
+  else if (strcmp ("elseif", s) == 0)
+    { return ELSEIF; }
+  else if (strcmp ("end", s) == 0)
+    { end_found = 1; yylval.ettype = simple_end; }
+  else if (strcmp ("endfor", s) == 0)
+    { end_found = 1; yylval.ettype = for_end; }
+  else if (strcmp ("endfunction", s) == 0)
+    { end_found = 1; yylval.ettype = function_end; }
+  else if (strcmp ("endif", s) == 0)
+    { end_found = 1; yylval.ettype = if_end; }
+  else if (strcmp ("endwhile", s) == 0)
+    { end_found = 1; yylval.ettype = while_end; }
+  else if (strcmp ("for", s) == 0)
+    { promptflag--; looping++; return FOR; }
+  else if (strcmp ("function", s) == 0)
+    {
+      if (defining_func)
+	{
+	  error ("sorry, nested functions are a no-no...");
+	  jump_to_top_level ();
+	}
+      else
+	{
+	  tmp_local_sym_tab = new symbol_table ();
+	  curr_sym_tab = tmp_local_sym_tab;
+	  defining_func = 1;
+	  promptflag--;
+	  beginning_of_function = 1;
+	  help_buf[0] = '\0';
+	  return FCN;
+	}
+    }
+  else if (strcmp ("global", s) == 0)
+    return GLOBAL;
+  else if (strcmp ("gplot", s) == 0)
+    { plotting = 1; yylval.pttype = two_dee; return PLOT; }
+  else if (strcmp ("gsplot", s) == 0)
+    { plotting = 1; yylval.pttype = three_dee; return PLOT; }
+  else if (strcmp ("if", s) == 0)
+    { iffing++; promptflag--; return IF; }
+  else if (strcmp ("return", s) == 0)
+    return FUNC_RET;
+  else if (strcmp ("while", s) == 0)
+    { promptflag--; looping++; return WHILE; }
+
+  if (end_found)
+    {
+      if (!defining_func && !looping)
+	promptflag++;
+      return END;
+    }
+
+  return 0;
+}
+
+static symbol_record *
+lookup_identifier (char *name)
+{
+  symbol_record *gsr = global_sym_tab->lookup (name, 0, 0);
+
+  if (curr_sym_tab == top_level_sym_tab && gsr != (symbol_record *) NULL)
+    return gsr;
+
+  return curr_sym_tab->lookup (name, 1, 0);
+}
+
+static void
+grab_help_text (void)
+{
+  int max_len = HELP_BUF_LENGTH - 1;
+
+  int in_comment = 1;
+  int len = 0;
+  int c;
+
+  while ((c = yyinput ()) != EOF)
+    {
+      if (in_comment)
+	{
+	  help_buf[len++] = c;
+	  if (c == '\n')
+	    in_comment = 0;
+	}
+      else
+	{
+	  switch (c)
+	    {
+	    case '%':
+	    case '#':
+	      in_comment = 1;
+	    case ' ':
+	    case '\t':
+	      break;
+	    default:
+	      goto done;
+	    }
+	}
+
+      if (len > max_len)
+	{
+	  message ("grab_help_text",
+		   "buffer overflow after caching %d characters",
+		   max_len);
+
+	  goto done;
+	}
+    }
+
+ done:
+
+// Make sure there's an end of line so yylex sees an end to the
+// comment immediately.
+
+  yyunput (c, yytext);
+  if (c != '\n')
+    yyunput ('\n', yytext);
+
+  help_buf[len] =  '\0';
+}
+
+static int
+match_any (char c, char *s)
+{
+  char tmp;
+  while ((tmp = *s++) != '\0')
+    {
+      if (c == tmp)
+	return 1;
+    }
+  return 0;
+}
+
+static int
+looks_like_bin_op (int spc_prev, int spc_next)
+{
+  return ((spc_prev && spc_next) || ! (spc_prev || spc_next));
+}
+
+static int
+next_char_is_space (void)
+{
+  int c = yyinput ();
+  yyunput (c, yytext);
+  return (c == ' ' || c == '\t');
+}
+
+static int
+next_token_is_postfix_unary_op (int spc_prev, char *yytext)
+{
+  int un_op = 0;
+
+  int c0 = yyinput ();
+  int c1 = yyinput ();
+
+  yyunput (c1, yytext);
+  yyunput (c0, yytext);
+
+  int transpose = (c0 == '.' && c1 == '\'');
+  int hermitian = (c0 == '\'');
+
+  un_op = (transpose || (hermitian && ! spc_prev));
+
+  return un_op;
+}
+
+static int
+next_token_is_bin_op (int spc_prev, char *yytext)
+{
+  int bin_op = 0;
+  int spc_next = 0;