changeset 3665:0689afb1d001

[project @ 2000-05-11 19:07:56 by jwe]
author jwe
date Thu, 11 May 2000 19:10:09 +0000
parents d178e2bbd873
children 301e0da5b455
files liboctave/Array-d.cc liboctave/Array-idx-vec.cc liboctave/Array.h liboctave/Array2.cc liboctave/Array2.h liboctave/Array3.h liboctave/ArrayN-idx.h liboctave/ArrayN.cc liboctave/ArrayN.h liboctave/ChangeLog liboctave/Makefile.in src/ChangeLog src/Makefile.in src/comment-list.cc src/comment-list.h src/data.cc src/lex.l src/ov-base-nd-array.cc src/ov-base-nd-array.h src/ov-re-nd-array.cc src/ov-re-nd-array.h src/ov-usr-fcn.cc src/ov-usr-fcn.h src/parse.y src/pt-except.cc src/pt-except.h src/pt-loop.cc src/pt-loop.h src/pt-pr-code.cc src/pt-pr-code.h src/pt-select.cc src/pt-select.h src/pt-stmt.cc src/pt-stmt.h
diffstat 34 files changed, 2507 insertions(+), 163 deletions(-) [+]
line wrap: on
line diff
--- a/liboctave/Array-d.cc
+++ b/liboctave/Array-d.cc
@@ -46,6 +46,12 @@
 template int assign (Array2<double>&, const Array2<short>&);
 template int assign (Array2<double>&, const Array2<char>&);
 
+#include "ArrayN.h"
+#include "ArrayN.cc"
+
+template class ArrayN<double>;
+template std::ostream& operator << (std::ostream&, const ArrayN<double>&);
+
 #include "DiagArray2.h"
 #include "DiagArray2.cc"
 
new file mode 100644
--- /dev/null
+++ b/liboctave/Array-idx-vec.cc
@@ -0,0 +1,40 @@
+/*
+
+Copyright (C) 1996, 1997 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, 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+// Instantiate Arrays of integer values.
+
+#include "idx-vector.h"
+
+#include "Array.h"
+#include "Array.cc"
+
+template class Array<idx_vector>;
+
+/*
+;;; Local Variables: ***
+;;; mode: C++ ***
+;;; End: ***
+*/
--- a/liboctave/Array.h
+++ b/liboctave/Array.h
@@ -164,6 +164,9 @@
   int capacity (void) const { return rep->length (); }
   int length (void) const { return rep->length (); }
 
+  T range_error (const char *fcn, int n) const;
+  T& range_error (const char *fcn, int n);
+
   // No checking, even for multiple references, ever.
 
   T& xelem (int n) { return rep->elem (n); }
@@ -228,9 +231,6 @@
       return *this;
     }
 
-  T range_error (const char *fcn, int n) const;
-  T& range_error (const char *fcn, int n);
-
 #ifdef HEAVYWEIGHT_INDEXING
   void set_max_indices (int mi) { max_indices = mi; }
 
@@ -251,7 +251,8 @@
 };
 
 template <class LT, class RT>
-int assign (Array<LT>& lhs, const Array<RT>& rhs);
+int
+assign (Array<LT>& lhs, const Array<RT>& rhs);
 
 #endif
 
--- a/liboctave/Array2.cc
+++ b/liboctave/Array2.cc
@@ -42,6 +42,8 @@
 
 #include "lo-error.h"
 
+// Two dimensional array class.
+
 template <class T>
 int
 Array2<T>::get_size (int r, int c) const
@@ -106,8 +108,6 @@
   return foo;
 }
 
-// Two dimensional array class.
-
 template <class T>
 void
 Array2<T>::resize (int r, int c)
--- a/liboctave/Array2.h
+++ b/liboctave/Array2.h
@@ -120,6 +120,9 @@
   int cols (void) const { return d2; }
   int columns (void) const { return d2; }
 
+  T range_error (const char *fcn, int i, int j) const;
+  T& range_error (const char *fcn, int i, int j);
+
   // No checking of any kind, ever.
 
   T& xelem (int i, int j) { return Array<T>::xelem (d1*j+i); }
@@ -132,12 +135,7 @@
   T& checkelem (int i, int j)
     {
       if (i < 0 || j < 0 || i >= d1 || j >= d2)
-	{
-	  (*current_liboctave_error_handler)
-	    ("T& Array2<T>::checkelem (%d, %d): range error", i, j);
-	  static T foo;
-	  return foo;
-	}
+	return range_error ("T& Array2<T>::checkelem", i, j);
       else
 	return Array<T>::elem (d1*j+i);
     }
@@ -153,11 +151,7 @@
   T checkelem (int i, int j) const
     {
       if (i < 0 || j < 0 || i >= d1 || j >= d2)
-	{
-	  (*current_liboctave_error_handler)
-	    ("T Array2<T>::checkelem (%d, %d): range error", i, j);
-	  return T ();
-	}
+	return range_error ("T Array2<T>::checkelem", i, j);
       else
 	return Array<T>::elem (d1*j+i);
     }
@@ -170,9 +164,6 @@
   T operator () (int i, int j) const { return elem (i, j); }
 #endif
 
-  T range_error (const char *fcn, int i, int j) const;
-  T& range_error (const char *fcn, int i, int j);
-
   void resize (int n, int m);
   void resize (int n, int m, const T& val);
 
@@ -196,7 +187,8 @@
 };
 
 template <class LT, class RT>
-int assign (Array2<LT>& lhs, const Array2<RT>& rhs);
+int
+assign (Array2<LT>& lhs, const Array2<RT>& rhs);
 
 #endif
 
--- a/liboctave/Array3.h
+++ b/liboctave/Array3.h
@@ -157,7 +157,8 @@
 };
 
 template <class LT, class RT>
-int assign (Array3<LT>& lhs, const Array3<RT>& rhs);
+int
+assign (Array3<LT>& lhs, const Array3<RT>& rhs);
 
 #endif
 
new file mode 100644
--- /dev/null
+++ b/liboctave/ArrayN-idx.h
@@ -0,0 +1,270 @@
+// Template array classes
+/*
+
+Copyright (C) 2000 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, 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+
+#include "Array-flags.h"
+#include "idx-vector.h"
+#include "lo-error.h"
+
+template <class T>
+void
+ArrayN<T>::maybe_delete_elements (Array<idx_vector>&)
+{
+  assert (0);
+}
+
+template <class T>
+ArrayN<T>
+ArrayN<T>::value (void)
+{
+  ArrayN<T> retval;
+
+  int n_idx = index_count ();
+
+  if (n_idx > 1)
+    {
+      Array<idx_vector> idx (n_idx);
+
+      idx_vector *tmp = get_idx ();
+
+      for (int i = 0; i < n_idx; i++)
+	idx(i) = tmp[i];
+
+      return index (idx);
+    }
+  else if (n_idx == 1)
+    {
+      idx_vector *tmp = get_idx ();
+
+      idx_vector idx = tmp[0];
+
+      return index (idx);
+    }
+  else
+    (*current_liboctave_error_handler)
+      ("invalid number of indices for array expression");
+
+  clear_index ();
+
+  return retval;
+}
+
+template <class T>
+ArrayN<T>
+ArrayN<T>::index (idx_vector& idx) const
+{
+  ArrayN<T> retval;
+  assert (0);
+  return retval;
+}
+
+static Array<int>
+freeze (Array<idx_vector>& idx, const Array<int>& dimensions)
+{
+  Array<int> retval;
+
+  int n = idx.length ();
+
+  assert (n == dimensions.length ());
+
+  retval.resize (n);
+
+  for (int i = 0; i < n; i++)
+    retval(i) = idx(i).freeze (dimensions(i), "XXX FIXME XXX");
+
+  return retval;
+}
+
+static bool
+all_ok (const Array<idx_vector>& idx)
+{
+  bool retval = true;
+
+  int n = idx.length ();
+
+  for (int i = 0; i < n; i++)
+    {
+      if (! idx(i))
+	{
+	  retval = false;
+	  break;
+	}
+    }
+
+  return retval;
+}
+
+static bool
+any_orig_empty (const Array<idx_vector>& idx)
+{
+  bool retval = false;
+
+  int n = idx.length ();
+
+  for (int i = 0; i < n; i++)
+    {
+      if (idx(i).orig_empty ())
+	{
+	  retval = true;
+	  break;
+	}
+    }
+
+  return retval;
+}
+
+static bool
+any_zero_len (const Array<int>& frozen_lengths)
+{
+  bool retval = false;
+
+  int n = frozen_lengths.length ();
+
+  for (int i = 0; i < n; i++)
+    {
+      if (frozen_lengths(i) == 0)
+	{
+	  retval = true;
+	  break;
+	}
+    }
+
+  return retval;
+}
+
+static Array<int>
+get_zero_len_size (const Array<int>& frozen_lengths,
+		   const Array<int>& dimensions)
+{
+  Array<int> retval;
+  assert (0);
+  return retval;
+}
+
+static bool
+all_colon_equiv (const Array<idx_vector>& idx,
+		 const Array<int>& frozen_lengths)
+{
+  bool retval = true;
+
+  int idx_n = idx.length ();
+
+  int n = frozen_lengths.length ();
+
+  assert (idx_n == n);
+
+  for (int i = 0; i < n; i++)
+    {
+      if (! idx(i).is_colon_equiv (frozen_lengths(i)))
+	{
+	  retval = false;
+	  break;
+	}
+    }
+
+  return retval;
+}
+
+static Array<int>
+get_elt_idx (const Array<idx_vector>& idx, const Array<int>& result_idx)
+{
+  int n = idx.length ();
+
+  Array<int> retval (n);
+
+  for (int i = 0; i < n; i++)
+    retval(i) = idx(result_idx(i));
+
+  return retval;
+}
+
+template <class T>
+ArrayN<T>
+ArrayN<T>::index (Array<idx_vector>& idx) const
+{
+  ArrayN<T> retval;
+
+  int n_dims = dimensions.length ();
+
+  Array<int> frozen_lengths = freeze (idx, dimensions);
+
+  if (frozen_lengths.length () == n_dims)
+    {
+      if (all_ok (idx))
+	{
+	  if (any_orig_empty (idx))
+	    {
+	      retval.resize (frozen_lengths);
+	    }
+	  else if (any_zero_len (frozen_lengths))
+	    {
+	      Array<int> new_size = get_zero_len_size (frozen_lengths,
+						       dimensions);
+
+	      retval.resize (new_size);
+	    }
+	  else if (all_colon_equiv (idx, frozen_lengths))
+	    {
+	      retval = *this;
+	    }
+	  else
+	    {
+#if 0
+	      retval.resize (frozen_lengths);
+
+	      int n = Array<T>::get_size (frozen_lengths);
+
+	      Array<int> result_idx (n_dims, 0);
+
+	      for (int i = 0; i < n; i++)
+		{
+		  Array<int> elt_idx = get_elt_idx (result_idx);
+
+		  retval.elem (result_idx) = elem (elt_idx);
+
+		  increment_index (result_idx, frozen_lengths);
+		}
+#endif
+	    }
+	}
+      // idx_vector::freeze() printed an error message for us.
+    }
+  else
+    (*current_liboctave_error_handler)
+      ("invalid number of dimensions for N-dimensional array index");
+
+  return retval;
+}
+
+template <class LT, class RT>
+int
+assign (ArrayN<LT>&, const ArrayN<RT>&)
+{
+  assert (0);
+  return 0;
+}
+
+/*
+;;; Local Variables: ***
+;;; mode: C++ ***
+;;; End: ***
+*/
new file mode 100644
--- /dev/null
+++ b/liboctave/ArrayN.cc
@@ -0,0 +1,379 @@
+// Template array classes
+/*
+
+Copyright (C) 2000 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, 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+
+#if defined (__GNUG__)
+#pragma implementation
+#endif
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <cassert>
+
+#include <iostream>
+
+#include "ArrayN.h"
+
+#if defined (HEAVYWEIGHT_INDEXING)
+#include "idx-vector.h"
+#include "ArrayN-idx.h"
+#endif
+
+#include "lo-error.h"
+
+// N-dimensional array class.
+
+template <class T>
+int
+ArrayN<T>::compute_index (const Array<int>& idx) const
+{
+  int retval = -1;
+
+  int n = dimensions.length ();
+
+  if (n > 0 && n == idx.length ())
+    {
+      retval = idx(--n);
+
+      while (--n >= 0)
+	{
+	  retval *= dimensions(n);
+	  retval += idx(n);
+	}
+    }
+  else
+    (*current_liboctave_error_handler)
+      ("ArrayN<T>::compute_index: invalid indexing operation");
+
+  return retval;
+}
+
+template <class T>
+int
+ArrayN<T>::get_size (const Array<int>& idx)
+{
+  // XXX KLUGE XXX
+
+  // If an allocation of an array with r * c elements of type T
+  // would cause an overflow in the allocator when computing the
+  // size of the allocation, then return a value which, although
+  // not equivalent to the actual request, should be too large for
+  // most current hardware, but not so large to cause the
+  // allocator to barf on computing retval * sizeof (T).
+
+  // A guess (should be quite conservative).
+  static const int MALLOC_OVERHEAD = 1024;
+
+  static int nl;
+  static double dl
+    = frexp (static_cast<double>
+	     (INT_MAX - MALLOC_OVERHEAD) / sizeof (T), &nl);
+
+  // This value should be an integer.  If we return this value and
+  // things work the way we expect, we should be paying a visit to
+  // new_handler in no time flat.
+  static int max_items = static_cast<int> (ldexp (dl, nl));
+
+  int retval = max_items;
+
+  int n = idx.length ();
+
+  int nt = 0;
+  double dt = 1;
+
+  for (int i = 0; i < n; i++)
+    {
+      int nidx;
+      double didx = frexp (static_cast<double> (idx(i)), &nidx);
+
+      nt += nidx;
+      dt *= didx;
+    }
+
+  if (dt <= 0.5)
+    {
+      nt--;
+      dt *= 2;
+
+      if (dt <= 0.5)
+	nt--;
+    }
+
+  if (nt < nl || (nt == nl && dt < dl))
+    {
+      retval = 1;
+
+      for (int i = 0; i < n; i++)
+	retval *= idx(i);
+    }
+
+  return retval;
+}
+
+template <class T>
+T
+ArrayN<T>::range_error (const char *fcn, const Array<int>& idx) const
+{
+  // XXX FIXME XXX -- report index values too!
+
+  (*current_liboctave_error_handler) ("range error");
+
+  return T ();
+}
+
+template <class T>
+T&
+ArrayN<T>::range_error (const char *fcn, const Array<int>& idx)
+{
+  // XXX FIXME XXX -- report index values too!
+
+  (*current_liboctave_error_handler) ("range error");
+
+  static T foo;
+  return foo;
+}
+
+static inline bool
+index_in_bounds (const Array<int>& idx, const Array<int>& dimensions)
+{
+  bool retval = true;
+
+  int n = idx.length ();
+
+  if (n == dimensions.length ())
+    {
+      for (int i = 0; i < n; i++)
+	{
+	  if (idx(i) < 0 || idx(i) >= dimensions (i))
+	    {
+	      retval = false;
+	      break;
+	    }
+	}
+    }
+  else
+    retval = false;
+
+  return retval;
+}
+
+static inline void
+increment_index (Array<int>& idx, const Array<int>& dimensions)
+{
+  idx(0)++;
+
+  int n = idx.length () - 1;
+
+  for (int i = 0; i < n; i++)
+    {
+      if (idx(i) < dimensions(i))
+	break;
+      else
+	{
+	  idx(i) = 0;
+	  idx(i+1)++;
+	}
+    }
+}
+
+template <class T>
+void
+ArrayN<T>::resize (const Array<int>& dims)
+{
+  int n = dims.length ();
+
+  for (int i = 0; i < n; i++)
+    {
+      if (dims(i) < 0)
+	{
+	  (*current_liboctave_error_handler)
+	    ("can't resize to negative dimension");
+	  return;
+	}
+    }
+
+  bool no_change = true;
+
+  for (int i = 0; i < n; i++)
+    {
+      if (dims(i) != dimensions(i))
+	{
+	  no_change = false;
+	  break;
+	}
+    }
+
+  if (no_change)
+    return;
+
+  Array<T>::ArrayRep *old_rep = rep;
+  const T *old_data = data ();
+
+  rep = new Array<T>::ArrayRep (get_size (dims));
+
+  Array<int> old_dimensions = dimensions;
+
+  int old_len = length ();
+
+  dimensions = dims;
+
+  Array<int> idx (dimensions.length (), 0);
+
+  for (int i = 0; i < old_len; i++)
+    {
+      if (index_in_bounds (idx, dimensions))
+	xelem (idx) = old_data[i];
+
+      increment_index (idx, dimensions);
+    }
+
+  if (--old_rep->count <= 0)
+    delete old_rep;
+}
+
+template <class T>
+void
+ArrayN<T>::resize (const Array<int>& dims, const T& val)
+{
+  int n = dims.length ();
+
+  for (int i = 0; i < n; i++)
+    {
+      if (dims(i) < 0)
+	{
+	  (*current_liboctave_error_handler)
+	    ("can't resize to negative dimension");
+	  return;
+	}
+    }
+
+  bool no_change = true;
+
+  for (int i = 0; i < n; i++)
+    {
+      if (dims(i) != dimensions(i))
+	{
+	  no_change = false;
+	  break;
+	}
+    }
+
+  if (no_change)
+    return;
+
+  Array<T>::ArrayRep *old_rep = rep;
+  const T *old_data = data ();
+
+  int len = get_size (dims);
+
+  rep = new Array<T>::ArrayRep (len);
+
+  Array<int> old_dimensions = dimensions;
+
+  int old_len = length ();
+
+  dimensions = dims;
+
+  Array<int> idx (dimensions.length (), 0);
+
+  for (int i = 0; i < len; i++)
+    rep->elem (i) = val;
+
+  for (int i = 0; i < old_len; i++)
+    {
+      if (index_in_bounds (idx, dimensions))
+	xelem (idx) = old_data[i];
+
+      increment_index (idx, dimensions);
+    }
+
+  if (--old_rep->count <= 0)
+    delete old_rep;
+}
+
+template <class T>
+ArrayN<T>&
+ArrayN<T>::insert (const ArrayN<T>& a, const Array<int>& idx)
+{
+  int n = idx.length ();
+
+  if (n == dimensions.length ())
+    {
+      Array<int> a_dims = a.dims ();
+
+      for (int i = 0; i < n; i++)
+	{
+	  if (idx(i) < 0 || idx(i) + a_dims(i) > dimensions(i))
+	    {
+	      (*current_liboctave_error_handler)
+		("ArrayN<T>::insert: range error for insert");
+	      return *this;
+	    }
+	}
+
+#if 0
+      // XXX FIXME XXX -- need to copy elements
+
+      for (int j = 0; j < a_cols; j++)
+	for (int i = 0; i < a_rows; i++)
+	  elem (r+i, c+j) = a.elem (i, j);
+#endif
+
+    }
+  else
+    (*current_liboctave_error_handler)
+      ("ArrayN<T>::insert: invalid indexing operation");
+
+  return *this;
+}
+
+template <class T>
+std::ostream&
+operator << (std::ostream& os, const ArrayN<T>& a)
+{
+  Array<int> dims = a.dimensions;
+
+  int n_dims = dims.length ();
+
+  os << n_dims << "-dimensional array (";
+
+  for (int i = 0; i < n_dims - 1; i++)
+    os << dims(i) << "x";
+  os << dims(n_dims-1) << ")\n\n";
+
+  os << "data:\n";
+
+  int n = ArrayN<T>::get_size (dims);
+
+  //  for (int i = 0; i < n; i++)
+  //    os << a.elem (i) << "\n";
+
+  return os;
+}
+
+/*
+;;; Local Variables: ***
+;;; mode: C++ ***
+;;; End: ***
+*/
new file mode 100644
--- /dev/null
+++ b/liboctave/ArrayN.h
@@ -0,0 +1,202 @@
+// Template array classes
+/*
+
+Copyright (C) 2000 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, 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+
+#if !defined (octave_ArrayN_h)
+#define octave_ArrayN_h 1
+
+#if defined (__GNUG__)
+#pragma interface
+#endif
+
+#include <iostream>
+
+#include <cassert>
+#include <climits>
+#include <cmath>
+#include <cstdlib>
+
+#include "Array.h"
+#include "lo-error.h"
+
+class idx_vector;
+
+// N-dimensional array class.
+
+template <class T>
+class
+ArrayN : public Array<T>
+{
+protected:
+
+  ArrayN (T *d, const Array<int>& dims) : Array<T> (d, get_size (dims))
+    {
+      dimensions = dims;
+      set_max_indices (dimensions.length ());
+    }
+
+public:
+
+  static int get_size (const Array<int>& dims);
+
+  // These really need to be protected (and they will be in the
+  // future, so don't depend on them being here!), but they can't be
+  // until template friends work correctly in g++.
+
+  Array<int> dimensions;
+
+  ArrayN (void) : Array<T> () { }
+
+  ArrayN (const Array<int>& dims) : Array<T> (get_size (dims))
+    {
+      dimensions = dims;
+      set_max_indices (dimensions.length ());
+    }
+
+  ArrayN (const Array<int>& dims, const T& val)
+    : Array<T> (get_size (dims), val)
+    {
+      dimensions = dims;
+      set_max_indices (dimensions.length ());
+    }
+
+  ArrayN (const ArrayN<T>& a) : Array<T> (a)
+    {
+      dimensions = a.dimensions;
+      set_max_indices (dimensions.length ());
+    }
+
+  ArrayN (const Array<T>& a, const Array<int>& dims) : Array<T> (a)
+    {
+      dimensions = dims;
+      set_max_indices (dimensions.length ());
+    }
+
+  ~ArrayN (void) { }
+
+  ArrayN<T>& operator = (const ArrayN<T>& a)
+    {
+      if (this != &a && rep != a.rep)
+	{
+	  Array<T>::operator = (a);
+	  dimensions = a.dimensions;
+	}
+
+      return *this;
+    }
+
+  int compute_index (const Array<int>& idx) const;
+
+  Array<int> dims (void) const { return dimensions; }
+
+  T range_error (const char *fcn, const Array<int>& idx) const;
+  T& range_error (const char *fcn, const Array<int>& idx);
+
+  // No checking of any kind, ever.
+
+  T& xelem (const Array<int>& idx)
+    { return Array<T>::xelem (compute_index (idx)); }
+
+  T xelem (const Array<int>& idx) const
+    { return Array<T>::xelem (compute_index (idx)); }
+
+  // Note that the following element selection methods don't use
+  // xelem() because they need to make use of the code in
+  // Array<T>::elem() that checks the reference count.
+
+  T& checkelem (const Array<int>& idx)
+    {
+      int i = compute_index (idx);
+
+      if (i < 0)
+	return range_error ("ArrayN<T>::checkelem", idx);
+      else
+	return Array<T>::elem (i);
+    }
+
+  T& elem (const Array<int>& idx)
+    {
+      int i = compute_index (idx);
+
+      return Array<T>::elem (i);
+    }
+
+#if defined (BOUNDS_CHECKING)
+  T& operator () (const Array<int>& idx) { return checkelem (idx); }
+#else
+  T& operator () (const Array<int>& idx) { return elem (idx); }
+#endif
+
+  T checkelem (const Array<int>& idx) const
+    {
+      int i = compute_index (idx);
+
+      if (i < 0)
+	return range_error ("ArrayN<T>::checkelem", idx);
+      else
+	return Array<T>::elem (i);
+    }
+
+  T elem (const Array<int>& idx) const
+    {
+      int i = compute_index (idx);
+
+      return Array<T>::elem (i);
+    }
+
+#if defined (BOUNDS_CHECKING)
+  T operator () (const Array<int>& idx) const { return checkelem (idx); }
+#else
+  T operator () (const Array<int>& idx) const { return elem (idx); }
+#endif
+
+  void resize (const Array<int>& dims);
+  void resize (const Array<int>& dims, const T& val);
+
+  ArrayN<T>& insert (const ArrayN<T>& a, const Array<int>& dims);
+
+#ifdef HEAVYWEIGHT_INDEXING
+  void maybe_delete_elements (Array<idx_vector>& idx);
+
+  ArrayN<T> value (void);
+
+  ArrayN<T> index (idx_vector& idx) const;
+
+  ArrayN<T> index (Array<idx_vector>& idx) const;
+#endif
+};
+
+template <class LT, class RT>
+int
+assign (ArrayN<LT>& lhs, const ArrayN<RT>& rhs);
+
+template <class T>
+std::ostream&
+operator << (std::ostream&, const ArrayN<T>&);
+
+#endif
+
+/*
+;;; Local Variables: ***
+;;; mode: C++ ***
+;;; End: ***
+*/
--- a/liboctave/ChangeLog
+++ b/liboctave/ChangeLog
@@ -1,3 +1,9 @@
+2000-05-11  John W. Eaton  <jwe@bevo.che.wisc.edu>
+
+	* Array-d.cc: Instantiate ArrayN<double> here too.
+	* Array-idx-vec.cc, ArrayN-idx.h, ArrayN.cc, ArrayN.h: New files.
+	* Makefile.in: Add them to the appropriate lists.
+
 2000-04-06  John W. Eaton  <jwe@bevo.che.wisc.edu>
 
 	* Array.cc (Array<T>::operator =): Don't set max_indices to 1 here.
--- a/liboctave/Makefile.in
+++ b/liboctave/Makefile.in
@@ -23,7 +23,7 @@
 
 LIBOCTAVE_LIBS = -lcruft -lreadline -lkpathsea -lglob
 
-MATRIX_INC := Array.h Array2.h Array3.h DiagArray2.h Array-flags.h \
+MATRIX_INC := Array.h Array2.h Array3.h ArrayN.h DiagArray2.h Array-flags.h \
 	Array-idx.h Array2-idx.h Array3-idx.h MArray-defs.h \
 	MArray.h MArray2.h MDiagArray2.h Matrix.h \
 	base-lu.h mx-base.h mx-op-defs.h mx-defs.h mx-ext.h \
@@ -59,11 +59,11 @@
 	$(MX_OP_INC) \
 	$(VX_OP_INC)
 
-TEMPLATE_SRC := Array.cc Array2.cc Array3.cc DiagArray2.cc \
+TEMPLATE_SRC := Array.cc Array2.cc Array3.cc ArrayN.cc DiagArray2.cc \
 	MArray.cc MArray2.cc MDiagArray2.cc base-lu.cc
 
 TI_SRC := Array-C.cc Array-b.cc Array-ch.cc Array-i.cc Array-d.cc \
-	Array-s.cc Array-str.cc \
+	Array-s.cc Array-str.cc Array-idx-vec.cc \
 	MArray-C.cc MArray-ch.cc MArray-i.cc MArray-d.cc MArray-s.cc
 
 MATRIX_SRC := Array-flags.cc CColVector.cc CDiagMatrix.cc CMatrix.cc \
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,38 @@
+2000-05-11  John W. Eaton  <jwe@bevo.che.wisc.edu>
+
+	* ov-base-nd-array.h, ov-base-nd-array.cc, ov-re-nd-array.h,
+	ov-re-nd-array.h: New files.
+	* Makefile.in: Add them to the appropriate lists.
+
+	* pt-stmt.h, pt-stmt.cc (class tree_statement):
+	Store comments associated with this parse tree element.
+	* pt-select.h, pt-select.cc (class tree_if_clause,
+	class tree_if_command, class tree_switch_case
+	class tree_switch_command): Likewise.
+	* pt-loop.h, pt-loop.cc (class tree_while_command,
+	class tree_do_until_command, class tree_simple_for_command,
+	class tree_complex_for_command): Likewise.
+	* pt-except.h, pt-except.cc (class tree_try_catch_command,
+	class tree_unwind_protect_command): Likewise.
+	* ov-usr-fcn.h, ov-usr-fcn.cc (class octave_user_function): Likewise.
+	* pt-pr-code.h, pt-pr-code.cc (tree_print_code::print_comment_elt,
+	tree_print_code::print_comment_list,
+	tree_print_code::print_indented_comment): New functions.
+	(tree_print_code::visit_simple_for_command,
+	tree_print_code::visit_complex_for_command,
+	tree_print_code::visit_octave_user_function_header,
+	tree_print_code::visit_octave_user_function_trailer,
+	tree_print_code::visit_if_command, tree_print_code::visit_statement,
+	tree_print_code::visit_switch_case,
+	tree_print_code::visit_switch_command,
+	tree_print_code::visit_try_catch_command,
+	tree_print_code::visit_unwind_protect_command
+	tree_print_code::visit_while_command,
+	tree_print_code::visit_do_until_command): Handle comments.
+	* lex.l, parse.y: Handle comments in parse trees.
+	* comment-list.h, comment-list.cc: New files.
+	* Makefile.in: Add them to the appropriate lists.
+
 2000-04-23  etienne grossmann <etienne@anonimo.isr.ist.utl.pt>
 
 	* pt-mat.cc (tm_row_const::tm_row_const_rep::eval_error):
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -69,7 +69,7 @@
 	ov-colon.h ov-base.h ov-base-mat.h ov-base-scalar.h \
 	ov-str-mat.h ov-bool-mat.h ov-bool.h ov-file.h ov-cell.h ov.h \
 	ov-fcn.h ov-builtin.h ov-dld-fcn.h ov-mapper.h ov-usr-fcn.h \
-	ov-typeinfo.h
+	ov-base-nd-array.h ov-re-nd-array.h ov-typeinfo.h
 
 PT_INCLUDES := pt.h pt-all.h pt-arg-list.h pt-assign.h pt-binop.h \
 	pt-cell.h pt-check.h pt-cmd.h pt-colon.h pt-const.h pt-decl.h \
@@ -78,7 +78,7 @@
 	pt-pr-code.h pt-select.h pt-stmt.h pt-unop.h pt-walk.h
 
 INCLUDES := BaseSLList.h Cell.h DLList.h Map.h Pix.h SLList.h \
-	SLStack.h Stack.h c-file-ptr-stream.h defun-dld.h \
+	SLStack.h Stack.h c-file-ptr-stream.h comment-list.h defun-dld.h \
 	defun-int.h defun.h dirfns.h dynamic-ld.h error.h file-io.h \
 	fn-cache.h gripes.h help.h input.h lex.h load-save.h \
 	oct-fstrm.h oct-hist.h oct-iostrm.h oct-map.h oct-obj.h \
@@ -111,7 +111,8 @@
 	ov-complex.cc ov-str-mat.cc ov-struct.cc ov-va-args.cc \
 	ov-colon.cc ov-bool-mat.cc ov-bool.cc ov-file.cc ov-cell.cc \
 	ov.cc ov-fcn.cc ov-builtin.cc ov-dld-fcn.cc ov-mapper.cc \
-	ov-usr-fcn.cc ov-typeinfo.cc
+	ov-usr-fcn.cc ov-base-nd-array.cc ov-re-nd-array.cc \
+	ov-typeinfo.cc
 
 PT_SRC := pt.cc pt-arg-list.cc pt-assign.cc pt-binop.cc pt-cell.cc \
 	pt-check.cc pt-cmd.cc pt-colon.cc pt-const.cc pt-decl.cc \
@@ -120,7 +121,8 @@
 	pt-select.cc pt-stmt.cc pt-unop.cc
 
 DIST_SRC := BaseSLList.cc Cell.cc DLList.cc Map.cc SLList.cc \
-	SLStack.cc Stack.cc c-file-ptr-stream.cc cutils.c data.cc \
+	SLStack.cc Stack.cc c-file-ptr-stream.cc comment-list.cc \
+	cutils.c data.cc \
 	defaults.cc defun.cc dirfns.cc dynamic-ld.cc error.cc \
 	file-io.cc fn-cache.cc gripes.cc help.cc input.cc lex.l \
 	load-save.cc mappers.cc matherr.c oct-fstrm.cc oct-hist.cc \
new file mode 100644
--- /dev/null
+++ b/src/comment-list.cc
@@ -0,0 +1,101 @@
+/*
+
+Copyright (C) 2000 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, 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+
+#if defined (__GNUG__)
+#pragma implementation
+#endif
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "lo-utils.h"
+
+#include "comment-list.h"
+#include "error.h"
+
+#include "SLList.h"
+#include "SLList.cc"
+
+template SLList<octave_comment_elt>;
+
+octave_comment_buffer *octave_comment_buffer::instance = 0;
+
+bool
+octave_comment_buffer::instance_ok (void)
+{
+  bool retval = true;
+
+  if (! instance)
+    instance = new octave_comment_buffer ();
+
+  if (! instance)
+    {
+      ::error ("unable to create comment buffer object");
+
+      retval = false;
+    }
+
+  return retval;
+}
+
+void
+octave_comment_buffer::append (const std::string& s,
+			       octave_comment_elt::comment_type t)
+{
+  if (instance_ok ())
+    instance->do_append (s, t);
+}
+
+
+octave_comment_list *
+octave_comment_buffer::get_comment (void)
+{
+  return (instance_ok ()) ? instance->do_get_comment () : 0;
+}
+
+void
+octave_comment_buffer::do_append (const std::string& s,
+				  octave_comment_elt::comment_type t)
+{
+  comment_list->append(s, t);
+}
+
+octave_comment_list *
+octave_comment_buffer::do_get_comment (void)
+{
+  octave_comment_list *retval = 0;
+
+  if (comment_list && comment_list->length () > 0)
+    {
+      retval = comment_list;
+      comment_list = new octave_comment_list ();
+    }
+
+  return retval;
+}
+
+/*
+;;; Local Variables: ***
+;;; mode: C++ ***
+;;; End: ***
+*/
new file mode 100644
--- /dev/null
+++ b/src/comment-list.h
@@ -0,0 +1,148 @@
+/*
+
+Copyright (C) 2000 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, 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+
+#if !defined (octave_comment_list_h)
+#define octave_comment_list_h 1
+
+#if defined (__GNUG__)
+#pragma interface
+#endif
+
+#include <string>
+
+#include <SLList.h>
+
+extern std::string get_comment_text (void);
+
+extern char *get_comment_text_c_str (void);
+
+extern void save_comment_text (const std::string& text);
+
+class
+octave_comment_elt
+{
+public:
+
+  enum comment_type
+  {
+    unknown,
+    block,
+    end_of_line,
+    doc_string,
+    copyright
+  };
+
+  octave_comment_elt (const std::string& s = std::string (),
+		      comment_type t = unknown)
+    : txt (s), typ (t) { }
+
+  octave_comment_elt (const octave_comment_elt& oc)
+    : txt (oc.txt), typ (oc.typ) { }
+
+  octave_comment_elt& operator = (const octave_comment_elt& oc)
+    {
+      if (this != &oc)
+	{
+	  txt = oc.txt;
+	  typ = oc.typ;
+	}
+
+      return *this;
+    }
+
+  std::string text (void) const { return txt; }
+
+  comment_type type (void) const { return typ; }
+
+  ~octave_comment_elt (void) { }
+
+private:
+
+  // The text of the comment.
+  std::string txt;
+
+  // The type of comment.
+  comment_type typ;
+};
+
+class
+octave_comment_list : public SLList<octave_comment_elt>
+{
+public:
+
+  octave_comment_list (void) { }
+
+  ~octave_comment_list (void) { }
+
+  void append
+    (const std::string& s,
+     octave_comment_elt::comment_type t = octave_comment_elt::unknown)
+    {
+      SLList<octave_comment_elt>::append (octave_comment_elt (s, t));
+    }
+
+  octave_comment_list (const octave_comment_list& ocb)
+    : SLList<octave_comment_elt> (ocb) { }
+
+  octave_comment_list& operator = (const octave_comment_list& ocb)
+    {
+      if (this != &ocb)
+	SLList<octave_comment_elt>::operator = (ocb);
+
+      return *this;
+    }
+};
+
+class
+octave_comment_buffer
+{
+public:
+
+  octave_comment_buffer (void)
+    : comment_list (new octave_comment_list) { }
+  
+  static bool instance_ok (void);
+
+  static void append
+    (const std::string& s,
+     octave_comment_elt::comment_type t = octave_comment_elt::unknown);
+
+  static octave_comment_list *get_comment (void);
+
+private:
+
+  void do_append (const std::string& s, octave_comment_elt::comment_type t);
+
+  octave_comment_list *do_get_comment (void);
+
+  octave_comment_list *comment_list;
+
+  static octave_comment_buffer *instance;
+};
+
+#endif
+
+/*
+;;; Local Variables: ***
+;;; mode: C++ ***
+;;; End: ***
+*/
--- a/src/data.cc
+++ b/src/data.cc
@@ -37,6 +37,7 @@
 #include "gripes.h"
 #include "oct-map.h"
 #include "ov.h"
+#include "ov-re-nd-array.h"
 #include "variables.h"
 #include "oct-obj.h"
 #include "utils.h"
--- a/src/lex.l
+++ b/src/lex.l
@@ -44,6 +44,7 @@
 // because it may not be protected to allow it to be included multiple
 // times.
 
+#include "comment-list.h"
 #include "defun.h"
 #include "error.h"
 #include "input.h"
@@ -187,6 +188,7 @@
 static int handle_identifier (const std::string& tok, int spc_gobbled);
 static bool have_continuation (bool trailing_comments_ok = true);
 static bool have_ellipsis_continuation (bool trailing_comments_ok = true);
+static void scan_for_comments (const char *);
 static yum_yum eat_whitespace (void);
 static yum_yum eat_continuation (void);
 static void maybe_warn_separator_insert (char sep);
@@ -267,6 +269,7 @@
 %}
 
 <MATRIX>{SNLCMT}*\]{S}* {
+    scan_for_comments (yytext);
     fixup_column_count (yytext);
     int c = yytext[yyleng-1];
     int cont_is_spc = eat_continuation ();
@@ -346,6 +349,7 @@
 %}
 
 <MATRIX>{SNLCMT}*;{SNLCMT}* {
+    scan_for_comments (yytext);
     fixup_column_count (yytext);
     eat_whitespace ();
     lexer_flags.quote_is_transpose = false;
@@ -362,6 +366,7 @@
 
 <MATRIX>{S}*{COMMENT}{SNLCMT}* |
 <MATRIX>{S}*{NL}{SNLCMT}* {
+    scan_for_comments (yytext);
     fixup_column_count (yytext);
     eat_whitespace ();
 
@@ -461,6 +466,7 @@
 
 {CONT}{S}*{NL} |
 {CONT}{S}*{COMMENT} {
+    scan_for_comments (yytext);
     promptflag--;
     current_input_column = 1;
   }
@@ -564,14 +570,28 @@
 	&& lexer_flags.beginning_of_function
 	&& nesting_level.none ())
       {
+	lexer_flags.beginning_of_function = false;
+
 	grab_help_text ();
-	lexer_flags.beginning_of_function = false;
+
+	octave_comment_buffer::append (help_buf);
       }
     else
       {
+	std::string buf;
+
+	bool begin_comment = true;
+
 	int c;
 	while ((c = yyinput ()) != EOF && c != '\n')
-	  ; // Eat comment.
+	  {
+	    if (begin_comment && (c == '#' || c == '%'))
+	      ; /* Skip leading comment characters. */
+	    else
+	      buf += (char) c;
+	  }
+
+	octave_comment_buffer::append (buf);
       }
 
     current_input_column = 1;
@@ -1188,6 +1208,7 @@
   bool begin_comment = true;
   bool in_comment = true;
   bool discard_space = true;
+
   int c = 0;
 
   while ((c = yyinput ()) != EOF)
@@ -1459,6 +1480,81 @@
   return retval;
 }
 
+static void
+scan_for_comments (const char *text)
+{
+  std::string comment_buf;
+
+  bool in_comment = false;
+  bool beginning_of_comment = false;
+
+  int len = strlen (text);
+  int i = 0;
+
+  while (i < len)
+    {
+      char c = text[i++];
+
+      switch (c)
+	{
+	case '%':
+	case '#':
+	  if (in_comment)
+	    {
+	      if (! beginning_of_comment)
+		comment_buf += (char) c;
+	    }
+	  else
+	    {
+	      in_comment = true;
+	      beginning_of_comment = true;
+	    }
+	  break;
+
+	case '\n':
+	  if (in_comment)
+	    {
+	      comment_buf += (char) c;
+	      octave_comment_buffer::append (comment_buf);
+	      comment_buf.resize (0);
+	      in_comment = false;
+	      beginning_of_comment = false;
+	    }
+	  break;
+
+	case '\r':
+	  if (in_comment)
+	    comment_buf += (char) c;
+	  if (i < len)
+	    {
+	      c = text[i++];
+
+	      if (c == '\n')
+		{
+		  if (in_comment)
+		    {
+		      comment_buf += (char) c;
+		      octave_comment_buffer::append (comment_buf);
+		      in_comment = false;
+		      beginning_of_comment = false;
+		    }
+		}
+	    }
+
+	default:
+	  if (in_comment)
+	    {
+	      comment_buf += (char) c;
+	      beginning_of_comment = false;
+	    }
+	  break;
+	}
+    }
+
+  if (! comment_buf.empty ())
+    octave_comment_buffer::append (comment_buf);
+}
+
 // Discard whitespace, including comments and continuations.
 //
 // Return value is logical OR of the following values:
@@ -1471,8 +1567,14 @@
 eat_whitespace (void)
 {
   yum_yum retval = ATE_NOTHING;
+
+  std::string comment_buf;
+
   bool in_comment = false;
-  int c;
+  bool beginning_of_comment = false;
+
+  int c = 0;
+
   while ((c = yyinput ()) != EOF)
     {
       current_input_column++;
@@ -1481,23 +1583,48 @@
 	{
 	case ' ':
 	case '\t':
+	  if (in_comment)
+	    {
+	      comment_buf += (char) c;
+	      beginning_of_comment = false;
+	    }
 	  retval |= ATE_SPACE_OR_TAB;
 	  break;
 
 	case '\n':
 	  retval |= ATE_NEWLINE;
-	  in_comment = false;
+	  if (in_comment)
+	    {
+	      comment_buf += (char) c;
+	      octave_comment_buffer::append (comment_buf);
+	      comment_buf.resize (0);
+	      in_comment = false;
+	      beginning_of_comment = false;
+	    }
 	  current_input_column = 0;
 	  break;
 
 	case '#':
 	case '%':
-	  in_comment = true;
+	  if (in_comment)
+	    {
+	      if (! beginning_of_comment)
+		comment_buf += (char) c;
+	    }
+	  else
+	    {
+	      in_comment = true;
+	      beginning_of_comment = true;
+	    }
 	  break;
 
 	case '.':
 	  if (in_comment)
-	    break;
+	    {
+	      comment_buf += (char) c;
+	      beginning_of_comment = false;
+	      break;
+	    }
 	  else
 	    {
 	      if (have_ellipsis_continuation ())
@@ -1508,7 +1635,11 @@
 
 	case '\\':
 	  if (in_comment)
-	    break;
+	    {
+	      comment_buf += (char) c;
+	      beginning_of_comment = false;
+	      break;
+	    }
 	  else
 	    {
 	      if (have_continuation ())
@@ -1519,12 +1650,19 @@
 
 	default:
 	  if (in_comment)
-	    break;
+	    {
+	      comment_buf += (char) c;
+	      beginning_of_comment = false;
+	      break;
+	    }
 	  else
 	    goto done;
 	}
     }
 
+  if (! comment_buf.empty ())
+    octave_comment_buffer::append (comment_buf);
+
  done:
   unput (c);
   current_input_column--;
@@ -1600,8 +1738,13 @@
 {
   std::ostrstream buf;
 
+  std::string comment_buf;
+
   bool in_comment = false;
-  int c;
+  bool beginning_of_comment = false;
+
+  int c = 0;
+
   while ((c = yyinput ()) != EOF)
     {
       buf << (char) c;
@@ -1610,34 +1753,67 @@
 	{
 	case ' ':
 	case '\t':
+	  if (in_comment)
+	    {
+	      comment_buf += (char) c;
+	      beginning_of_comment = false;
+	    }
 	  break;
 
 	case '%':
 	case '#':
 	  if (trailing_comments_ok)
-	    in_comment = true;
+	    {
+	      if (in_comment)
+		{
+		  if (! beginning_of_comment)
+		    comment_buf += (char) c;
+		}
+	      else
+		{
+		  in_comment = true;
+		  beginning_of_comment = true;
+		}
+	    }
 	  else
 	    goto cleanup;
 	  break;
 
 	case '\n':
+	  if (in_comment)
+	    {
+	      comment_buf += (char) c;
+	      octave_comment_buffer::append (comment_buf);
+	    }
 	  current_input_column = 0;
 	  promptflag--;
 	  return true;
 
 	case '\r':
+	  if (in_comment)
+	    comment_buf += (char) c;
 	  c = yyinput ();
 	  if (c == EOF)
 	    break;
 	  else if (c == '\n')
 	    {
+	      if (in_comment)
+		{
+		  comment_buf += (char) c;
+		  octave_comment_buffer::append (comment_buf);
+		}
 	      current_input_column = 0;
 	      promptflag--;
 	      return true;
-	    }	  
+	    }
 
 	default:
-	  if (! in_comment)
+	  if (in_comment)
+	    {
+	      comment_buf += (char) c;
+	      beginning_of_comment = false;
+	    }
+	  else
 	    goto cleanup;
 	  break;
 	}
@@ -1694,7 +1870,9 @@
 eat_continuation (void)
 {
   int retval = ATE_NOTHING;
+
   int c = yyinput ();
+
   if ((c == '.' && have_ellipsis_continuation ())
       || (c == '\\' && have_continuation ()))
     retval = eat_whitespace ();
@@ -2155,9 +2333,15 @@
   // force the parser to return after reading the function.  Calling
   // unput with EOF does not work.
 
+  std::string comment_buf;
+
   bool in_comment = false;
+  bool beginning_of_comment = true;
+
   int lineno = input_line_number;
-  int c;
+
+  int c = 0;
+
   while ((c = yyinput ()) != EOF)
     {
       switch (c)
@@ -2166,21 +2350,45 @@
 	case '\t':
 	case ';':
 	case ',':
+	  if (in_comment)
+	    {
+	      comment_buf += (char) c;
+	      beginning_of_comment = false;
+	    }
 	  break;
 
 	case '\n':
 	  if (in_comment)
-	    in_comment = false;
+	    {
+	      comment_buf += (char) c;
+	      octave_comment_buffer::append (comment_buf);
+	      comment_buf.resize (0);
+	      in_comment = false;
+	      beginning_of_comment = false;
+	    }
 	  break;
 
 	case '%':
 	case '#':
-	  in_comment = true;
+	  if (in_comment)
+	    {
+	      if (! beginning_of_comment)
+		comment_buf += (char) c;
+	    }
+	  else
+	    {
+	      in_comment = true;
+	      beginning_of_comment = true;
+	    }
 	  break;
 
 	default:
 	  if (in_comment)
-	    break;
+	    {
+	      comment_buf += (char) c;
+	      beginning_of_comment = false;
+	      break;
+	    }
 	  else
 	    {
 	      warning ("ignoring trailing garbage after end of function\n\
@@ -2191,6 +2399,10 @@
 	    }
 	}
     }
+
+  if (! comment_buf.empty ())
+    octave_comment_buffer::append (comment_buf);
+
   unput ('\n');
 }
 
new file mode 100644
--- /dev/null
+++ b/src/ov-base-nd-array.cc
@@ -0,0 +1,148 @@
+/*
+
+Copyright (C) 2000 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, 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+
+#if defined (__GNUG__)
+#pragma implementation
+#endif
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <iostream>
+
+#include "oct-obj.h"
+#include "ov-base.h"
+#include "ov-base-nd-array.h"
+#include "pr-output.h"
+
+static Array<idx_vector>
+idx_list_to_idx_array (const octave_value_list& idx)
+{
+  int n = idx.length ();
+
+  Array<idx_vector> retval (n);
+
+  for (int i = 0; i < n; i++)
+    retval(i) = idx(i).index_vector ();
+
+  return retval;
+}
+
+template <class AT>
+octave_value
+octave_base_nd_array<AT>::do_index_op (const octave_value_list& idx)
+{
+  octave_value retval;
+
+  int len = idx.length ();
+
+  if (len > 1)
+    {
+      Array<idx_vector> i = idx_list_to_idx_array (idx);
+
+      retval
+	= octave_value (new octave_base_nd_array<AT> (AT (array.index (i))));
+    }
+  else if (len == 1)
+    {
+      idx_vector i = idx(0).index_vector ();
+
+      retval
+	= octave_value (new octave_base_nd_array<AT> (AT (array.index (i))));
+    }
+  else
+    {
+      std::string n = type_name ();
+
+      error ("invalid number of indices (%d) for %s value",
+	     len, n.c_str ());
+    }
+
+  return retval;
+}
+
+template <class AT>
+bool
+octave_base_nd_array<AT>::is_true (void) const
+{
+  // XXX FIXME XXX
+  return false;
+}
+
+template <class AT>
+bool
+octave_base_nd_array<AT>::print_as_scalar (void) const
+{
+  // XXX FIXME XXX
+  return false;
+}
+
+template <class AT>
+void
+octave_base_nd_array<AT>::print (std::ostream& os,
+				 bool pr_as_read_syntax) const
+{
+  print_raw (os, pr_as_read_syntax);
+  newline (os);
+}
+
+template <class AT>
+void
+octave_base_nd_array<AT>::print_raw (std::ostream& os,
+				     bool pr_as_read_syntax) const
+{
+  // XXX FIXME XX
+  os << array;
+#if 0
+  octave_print_internal (os, array, pr_as_read_syntax,
+			 current_print_indent_level ());
+#endif
+}
+
+template <class AT>
+bool
+octave_base_nd_array<AT>::print_name_tag (std::ostream& os,
+					  const std::string& name) const
+{
+  bool retval = false;
+
+  indent (os);
+
+  if (print_as_scalar ())
+    os << name << " = ";
+  else
+    {
+      os << name << " =";
+      newline (os);
+      newline (os);
+      retval = true;
+    }
+
+  return retval;
+}
+
+/*
+;;; Local Variables: ***
+;;; mode: C++ ***
+;;; End: ***
+*/
new file mode 100644
--- /dev/null
+++ b/src/ov-base-nd-array.h
@@ -0,0 +1,99 @@
+/*
+
+Copyright (C) 2000 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, 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+
+#if !defined (octave_base_nd_array_h)
+#define octave_base_nd_array_h 1
+
+#if defined (__GNUG__)
+#pragma interface
+#endif
+
+#include <cstdlib>
+
+#include <iostream>
+#include <string>
+
+#include "mx-base.h"
+#include "str-vec.h"
+
+#include "error.h"
+#include "ov-base.h"
+#include "ov-typeinfo.h"
+
+class Octave_map;
+class octave_value_list;
+
+class tree_walker;
+
+// ND array values values.
+
+template <class AT>
+class
+octave_base_nd_array : public octave_base_value
+{
+public:
+
+  octave_base_nd_array (void)
+    : octave_base_value () { }
+
+  octave_base_nd_array (const AT& a)
+    : octave_base_value (), array (a) { }
+
+  octave_base_nd_array (const octave_base_nd_array& a)
+    : octave_base_value (), array (a.array) { }
+
+  ~octave_base_nd_array (void) { }
+
+  octave_value *clone (void) { return new octave_base_nd_array (*this); }
+
+  octave_value do_index_op (const octave_value_list& idx);
+
+  bool is_matrix_type (void) const { return false; }
+
+  bool is_numeric_type (void) const { return true; }
+
+  bool is_defined (void) const { return true; }
+
+  bool is_constant (void) const { return true; }
+
+  bool is_true (void) const;
+
+  virtual bool print_as_scalar (void) const;
+
+  void print (std::ostream& os, bool pr_as_read_syntax = false) const;
+
+  void print_raw (std::ostream& os, bool pr_as_read_syntax = false) const;
+
+  bool print_name_tag (std::ostream& os, const std::string& name) const;
+
+protected:
+
+  AT array;
+};
+
+#endif
+
+/*
+;;; Local Variables: ***
+;;; mode: C++ ***
+;;; End: ***
+*/
new file mode 100644
--- /dev/null
+++ b/src/ov-re-nd-array.cc
@@ -0,0 +1,151 @@
+/*
+
+Copyright (C) 2000 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, 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+
+#if defined (__GNUG__)
+#pragma implementation
+#endif
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <iostream>
+
+#include "lo-ieee.h"
+#include "lo-utils.h"
+#include "mx-base.h"
+
+#include "gripes.h"
+#include "oct-obj.h"
+#include "oct-lvalue.h"
+#include "ops.h"
+#include "ov-base.h"
+#include "ov-base-nd-array.h"
+#include "ov-base-nd-array.cc"
+#include "ov-re-nd-array.h"
+#include "pr-output.h"
+#include "variables.h"
+
+template class octave_base_nd_array<ArrayN<double> >;
+
+DEFINE_OCTAVE_ALLOCATOR (octave_double_nd_array);
+
+DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA (octave_double_nd_array,
+				     "double-nd-array");
+
+#if 0
+octave_value *
+octave_matrix::try_narrowing_conversion (void)
+{
+  octave_value *retval = 0;
+
+  int nr = matrix.rows ();
+  int nc = matrix.cols ();
+
+  if (nr == 1 && nc == 1)
+    retval = new octave_scalar (matrix (0, 0));
+
+  return retval;
+}
+
+#if !defined (CXX_NEW_FRIEND_TEMPLATE_DECL)
+extern void assign (Array2<double>&, const Array2<double>&);
+#endif
+
+void
+octave_matrix::assign (const octave_value_list& idx, const Matrix& rhs)
+{
+  int len = idx.length ();
+
+  switch (len)
+    {
+    case 2:
+      {
+	idx_vector i = idx (0).index_vector ();
+	idx_vector j = idx (1).index_vector ();
+
+	matrix.set_index (i);
+	matrix.set_index (j);
+
+	::assign (matrix, rhs);
+      }
+      break;
+
+    case 1:
+      {
+	idx_vector i = idx (0).index_vector ();
+
+	matrix.set_index (i);
+
+	::assign (matrix, rhs);
+      }
+      break;
+
+    default:
+      error ("invalid number of indices (%d) for indexed matrix assignment",
+	     len);
+      break;
+    }
+}
+
+bool
+octave_matrix::valid_as_scalar_index (void) const
+{
+  // XXX FIXME XXX
+  return false;
+}
+
+double
+octave_matrix::double_value (bool) const
+{
+  double retval = octave_NaN;
+
+  // XXX FIXME XXX -- maybe this should be a function, valid_as_scalar()
+  if ((rows () == 1 && columns () == 1)
+      || (Vdo_fortran_indexing && rows () > 0 && columns () > 0))
+    retval = matrix (0, 0);
+  else
+    gripe_invalid_conversion ("real matrix", "real scalar");
+
+  return retval;
+}
+
+Complex
+octave_matrix::complex_value (bool) const
+{
+  Complex retval (octave_NaN, octave_NaN);
+
+  if ((rows () == 1 && columns () == 1)
+      || (Vdo_fortran_indexing && rows () > 0 && columns () > 0))
+    retval = matrix (0, 0);
+  else
+    gripe_invalid_conversion ("real matrix", "complex scalar");
+
+  return retval;
+}
+#endif
+
+/*
+;;; Local Variables: ***
+;;; mode: C++ ***
+;;; End: ***
+*/
new file mode 100644
--- /dev/null
+++ b/src/ov-re-nd-array.h
@@ -0,0 +1,104 @@
+/*
+
+Copyright (C) 2000 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, 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+
+#if !defined (octave_re_nd_array_h)
+#define octave_re_nd_array_h 1
+
+#if defined (__GNUG__)
+#pragma interface
+#endif
+
+#include <cstdlib>
+
+#include <iostream>
+#include <string>
+
+#include "ArrayN.h"
+#include "oct-alloc.h"
+
+#include "error.h"
+#include "ov-base.h"
+#include "ov-base-nd-array.h"
+#include "ov-typeinfo.h"
+
+class octave_value_list;
+
+// Real N-dimensional array values.
+
+class
+octave_double_nd_array : public octave_base_nd_array<ArrayN<double> >
+{
+public:
+
+  octave_double_nd_array (void)
+    : octave_base_nd_array<ArrayN<double> > () { }
+
+  octave_double_nd_array (const ArrayN<double>& a)
+    : octave_base_nd_array<ArrayN<double> > (a) { }
+
+  octave_double_nd_array (const octave_double_nd_array& a)
+    : octave_base_nd_array<ArrayN<double> > (a) { }
+
+  ~octave_double_nd_array (void) { }
+
+  octave_value *clone (void) { return new octave_double_nd_array (*this); }
+
+#if 0
+  octave_value *try_narrowing_conversion (void);
+
+  void assign (const octave_value_list& idx, const Matrix& rhs);
+
+  idx_vector index_vector (void) const { return idx_vector (matrix); }
+
+  bool is_real_matrix (void) const { return false; }
+
+  bool is_real_type (void) const { return true; }
+
+  bool valid_as_scalar_index (void) const;
+
+  double double_value (bool = false) const;
+
+  double scalar_value (bool frc_str_conv = false) const
+    { return double_value (frc_str_conv); }
+
+  Matrix matrix_value (bool = false) const;
+
+  Complex complex_value (bool = false) const;
+
+  ComplexMatrix complex_matrix_value (bool = false) const
+    { return ComplexMatrix (matrix_value ()); }
+#endif
+
+private:
+
+  DECLARE_OCTAVE_ALLOCATOR
+
+  DECLARE_OV_TYPEID_FUNCTIONS_AND_DATA
+};
+
+#endif
+
+/*
+;;; Local Variables: ***
+;;; mode: C++ ***
+;;; End: ***
+*/
--- a/src/ov-usr-fcn.cc
+++ b/src/ov-usr-fcn.cc
@@ -76,7 +76,8 @@
    tree_statement_list *cl, symbol_table *st)
   : octave_function (std::string (), std::string ()),
     param_list (pl), ret_list (rl), cmd_list (cl),
-    sym_tab (st), file_name (), fcn_name (),
+    sym_tab (st), lead_comm (), trail_comm (),
+    file_name (), fcn_name (),
     t_parsed (static_cast<time_t> (0)),
     t_checked (static_cast<time_t> (0)),
     system_fcn_file (false), call_depth (0),
@@ -100,6 +101,8 @@
   delete sym_tab;
   delete cmd_list;
   delete vr_list;
+  delete lead_comm;
+  delete trail_comm;
 }
 
 octave_user_function *
--- a/src/ov-usr-fcn.h
+++ b/src/ov-usr-fcn.h
@@ -31,6 +31,7 @@
 
 #include <string>
 
+#include "comment-list.h"
 #include "oct-obj.h"
 #include "ov-fcn.h"
 #include "ov-typeinfo.h"
@@ -67,6 +68,10 @@
 
   void stash_fcn_file_name (void);
 
+  void stash_leading_comment (octave_comment_list *lc) { lead_comm = lc; }
+
+  void stash_trailing_comment (octave_comment_list *tc) { trail_comm = tc; }
+
   void mark_fcn_file_up_to_date (const octave_time& t) { t_checked = t; }
 
   void stash_fcn_file_time (const octave_time& t)
@@ -124,6 +129,10 @@
 
   tree_statement_list *body (void) { return cmd_list; }
 
+  octave_comment_list *leading_comment (void) { return lead_comm; }
+
+  octave_comment_list *trailing_comment (void) { return trail_comm; }
+
   void accept (tree_walker& tw);
 
 private:
@@ -145,6 +154,12 @@
   // The local symbol table for this function.
   symbol_table *sym_tab;
 
+  // The comments preceding the FUNCTION token.
+  octave_comment_list *lead_comm;
+
+  // The comments preceding the ENDFUNCTION token.
+  octave_comment_list *trail_comm;
+
   // The name of the file we parsed
   std::string file_name;
 
--- a/src/parse.y
+++ b/src/parse.y
@@ -46,6 +46,7 @@
 #include "file-ops.h"
 #include "file-stat.h"
 
+#include "comment-list.h"
 #include "defun.h"
 #include "dynamic-ld.h"
 #include "error.h"
@@ -103,6 +104,9 @@
 // Buffer for help text snagged from function files.
 std::string help_buf;
 
+// Buffer for comments appearing before a function statement.
+static std::string fcn_comment_header;
+
 // TRUE means we are using readline.
 // (--no-line-editing)
 bool line_editing = true;
@@ -179,28 +183,31 @@
 // Build an unwind-protect command.
 static tree_command *
 make_unwind_command (token *unwind_tok, tree_statement_list *body,
-		     tree_statement_list *cleanup, token *end_tok);
+		     tree_statement_list *cleanup, token *end_tok,
+		     octave_comment_list *lc, octave_comment_list *mc);
 
 // Build a try-catch command.
 static tree_command *
 make_try_command (token *try_tok, tree_statement_list *body,
-		  tree_statement_list *cleanup, token *end_tok);
+		  tree_statement_list *cleanup, token *end_tok,
+		  octave_comment_list *lc, octave_comment_list *mc);
 
 // Build a while command.
 static tree_command *
 make_while_command (token *while_tok, tree_expression *expr,
-		    tree_statement_list *body, token *end_tok);
+		    tree_statement_list *body, token *end_tok,
+		    octave_comment_list *lc);
 
 // Build a do-until command.
 static tree_command *
 make_do_until_command (token *do_tok, tree_statement_list *body,
-		       tree_expression *expr);
+		       tree_expression *expr, octave_comment_list *lc);
 
 // Build a for command.
 static tree_command *
 make_for_command (token *for_tok, tree_argument_list *lhs,
 		  tree_expression *expr, tree_statement_list *body,
-		  token *end_tok);
+		  token *end_tok, octave_comment_list *lc);
 
 // Build a break command.
 static tree_command *
@@ -220,20 +227,24 @@
 
 // Finish an if command.
 static tree_if_command *
-finish_if_command (token *if_tok, tree_if_command_list *list, token *end_tok);
+finish_if_command (token *if_tok, tree_if_command_list *list,
+		   token *end_tok, octave_comment_list *lc);
 
 // Build an elseif clause.
 static tree_if_clause *
-make_elseif_clause (tree_expression *expr, tree_statement_list *list);
+make_elseif_clause (tree_expression *expr, tree_statement_list *list,
+		    octave_comment_list *lc);
 
 // Finish a switch command.
 static tree_switch_command *
 finish_switch_command (token *switch_tok, tree_expression *expr,
-		       tree_switch_case_list *list, token *end_tok);
+		       tree_switch_case_list *list, token *end_tok,
+		       octave_comment_list *lc);
 
 // Build a switch case.
 static tree_switch_case *
-make_switch_case (tree_expression *expr, tree_statement_list *list);
+make_switch_case (tree_expression *expr, tree_statement_list *list,
+		  octave_comment_list *lc);
 
 // Build an assignment to a variable.
 static tree_expression *
@@ -250,11 +261,13 @@
 
 // Finish defining a function.
 static octave_user_function *
-finish_function (tree_identifier *id, octave_user_function *fcn);
+finish_function (tree_identifier *id, octave_user_function *fcn,
+		 octave_comment_list *lc);
 
 // Finish defining a function a different way.
 static octave_user_function *
-finish_function (tree_parameter_list *ret_list, octave_user_function *fcn);
+finish_function (tree_parameter_list *ret_list,
+		 octave_user_function *fcn, octave_comment_list *lc);
 
 // Reset state after parsing function.
 static void
@@ -309,6 +322,9 @@
   // The type of the basic tokens returned by the lexer.
   token *tok_val;
 
+  // Comment strings that we need to deal with mid-rule.
+  octave_comment_list *comment_type;
+
   // Types for the nonterminals we generate.
   char sep_type;
   tree *tree_type;
@@ -375,6 +391,7 @@
 %token USING TITLE WITH AXES COLON OPEN_BRACE CLOSE_BRACE CLEAR
 
 // Nonterminals we construct.
+%type <comment_type> stash_comment function_beg
 %type <sep_type> sep_no_nl opt_sep_no_nl sep opt_sep
 %type <tree_type> input
 %type <tree_constant_type> constant magic_colon
@@ -510,14 +527,28 @@
 		;
 
 statement	: expression
-		  { $$ = new tree_statement ($1); }
+		  {
+		    octave_comment_list *comment
+		      = octave_comment_buffer::get_comment ();
+
+		    $$ = new tree_statement ($1, comment);
+		  }
 		| command
-		  { $$ = new tree_statement ($1); }
+		  {
+		    octave_comment_list *comment
+		      = octave_comment_buffer::get_comment ();
+
+		    $$ = new tree_statement ($1, comment);
+		  }
 		| PLOT CLEAR
 		  {
 		    symbol_record *sr = lookup_by_name ("clearplot", 0);
 		    tree_identifier *id = new tree_identifier (sr);
-		    $$ = new tree_statement (id);
+
+		    octave_comment_list *comment
+		      = octave_comment_buffer::get_comment ();
+
+		    $$ = new tree_statement (id, comment);
 		  }
 		;
 
@@ -880,9 +911,9 @@
 // If statement
 // ============
 
-if_command	: IF if_cmd_list END
+if_command	: IF stash_comment if_cmd_list END
 		  {
-		    if (! ($$ = finish_if_command ($1, $2, $3)))
+		    if (! ($$ = finish_if_command ($1, $3, $4, $2)))
 		      ABORT_PARSE;
 		  }
 		;
@@ -905,21 +936,23 @@
 		  }
 		;
 
-elseif_clause	: ELSEIF opt_sep expression opt_sep opt_list
-		  { $$ = make_elseif_clause ($3, $5); }
+elseif_clause	: ELSEIF stash_comment opt_sep expression opt_sep opt_list
+		  { $$ = make_elseif_clause ($4, $6, $2); }
 		;
 
-else_clause	: ELSE opt_sep opt_list
-		  { $$ = new tree_if_clause ($3); }
+else_clause	: ELSE stash_comment opt_sep opt_list
+		  {
+		    $$ = new tree_if_clause ($4, $2);
+		  }
 		;
 
 // ================
 // Switch statement
 // ================
 
-switch_command	: SWITCH expression opt_sep case_list END
+switch_command	: SWITCH stash_comment expression opt_sep case_list END
 		  {
-		    if (! ($$ = finish_switch_command ($1, $2, $4, $5)))
+		    if (! ($$ = finish_switch_command ($1, $3, $5, $6, $2)))
 		      ABORT_PARSE;
 		  }
 		;
@@ -942,31 +975,33 @@
 		  }
 		;
 
-switch_case	: CASE opt_sep expression opt_sep list
-		  { $$ = make_switch_case ($3, $5); }
+switch_case	: CASE stash_comment opt_sep expression opt_sep list
+		  { $$ = make_switch_case ($4, $6, $2); }
 		;
 
-default_case	: OTHERWISE opt_sep opt_list
-		  { $$ = new tree_switch_case ($3); }
+default_case	: OTHERWISE stash_comment opt_sep opt_list
+		  {
+		    $$ = new tree_switch_case ($4, $2);
+		  }
 		;
 
 // =======
 // Looping
 // =======
 
-loop_command	: WHILE expression opt_sep opt_list END
+loop_command	: WHILE stash_comment expression opt_sep opt_list END
 		  {
-		    if (! ($$ = make_while_command ($1, $2, $4, $5)))
+		    if (! ($$ = make_while_command ($1, $3, $5, $6, $2)))
 		      ABORT_PARSE;
 		  }
-		| DO opt_sep opt_list UNTIL expression
+		| DO stash_comment opt_sep opt_list UNTIL expression
 		  {
-		    if (! ($$ = make_do_until_command ($1, $3, $5)))
+		    if (! ($$ = make_do_until_command ($1, $4, $6, $2)))
 		      ABORT_PARSE;
 		  }
-		| FOR assign_lhs '=' expression opt_sep opt_list END
+		| FOR stash_comment assign_lhs '=' expression opt_sep opt_list END
 		  {
-		    if (! ($$ = make_for_command ($1, $2, $4, $6, $7)))
+		    if (! ($$ = make_for_command ($1, $3, $5, $7, $8, $2)))
 		      ABORT_PARSE;
 		  }
 		;
@@ -996,14 +1031,16 @@
 // Exceptions
 // ==========
 
-except_command	: UNWIND opt_sep opt_list CLEANUP opt_sep opt_list END
+except_command	: UNWIND stash_comment opt_sep opt_list CLEANUP
+		  stash_comment opt_sep opt_list END
 		  {
-		    if (! ($$ = make_unwind_command ($1, $3, $6, $7)))
+		    if (! ($$ = make_unwind_command ($1, $4, $8, $9, $2, $6)))
 		      ABORT_PARSE;
 		  }
-		| TRY opt_sep opt_list CATCH opt_sep opt_list END
+		| TRY stash_comment opt_sep opt_list CATCH
+		  stash_comment opt_sep opt_list END
 		  {
-		    if (! ($$ = make_try_command ($1, $3, $6, $7)))
+		    if (! ($$ = make_try_command ($1, $4, $8, $9, $2, $6)))
 		      ABORT_PARSE;
 		  }
 		;
@@ -1136,23 +1173,25 @@
 // Function definition
 // ===================
 
-function_beg	: FCN global_symtab
+function_beg	: FCN stash_comment global_symtab
+		  { $$ = $2; }
 		;
 
 function	: function_beg function2
 		  {
+		    $2->stash_leading_comment ($1);
 		    recover_from_parsing_function ();
 		    $$ = 0;
 		  }
 		| function_beg identifier function1
 		  {
-		    finish_function ($2, $3);
+		    finish_function ($2, $3, $1);
 		    recover_from_parsing_function ();
 		    $$ = 0;
 		  }
 		| function_beg return_list function1
 		  {
-		    finish_function ($2, $3);
+		    finish_function ($2, $3, $1);
 		    recover_from_parsing_function ();
 		    $$ = 0;
 		  }
@@ -1355,6 +1394,10 @@
 // Miscellaneous
 // =============
 
+stash_comment	: // empty
+		  { $$ = octave_comment_buffer::get_comment (); }
+		;
+
 parse_error	: LEXICAL_ERROR
 		  { yyerror ("parse error"); }
 		| error
@@ -2030,16 +2073,20 @@
 
 static tree_command *
 make_unwind_command (token *unwind_tok, tree_statement_list *body,
-		     tree_statement_list *cleanup, token *end_tok)
+		     tree_statement_list *cleanup, token *end_tok,
+		     octave_comment_list *lc, octave_comment_list *mc)
 {
   tree_command *retval = 0;
 
   if (end_token_ok (end_tok, token::unwind_protect_end))
     {
+      octave_comment_list *tc = octave_comment_buffer::get_comment ();
+
       int l = unwind_tok->line ();
       int c = unwind_tok->column ();
 
-      retval = new tree_unwind_protect_command (body, cleanup, l, c);
+      retval = new tree_unwind_protect_command (body, cleanup,
+						lc, mc, tc, l, c);
     }
 
   return retval;
@@ -2049,16 +2096,20 @@
 
 static tree_command *
 make_try_command (token *try_tok, tree_statement_list *body,
-		  tree_statement_list *cleanup, token *end_tok)
+		  tree_statement_list *cleanup, token *end_tok,
+		  octave_comment_list *lc, octave_comment_list *mc)
 {
   tree_command *retval = 0;
 
   if (end_token_ok (end_tok, token::try_catch_end))
     {
+      octave_comment_list *tc = octave_comment_buffer::get_comment ();
+
       int l = try_tok->line ();
       int c = try_tok->column ();
 
-      retval = new tree_try_catch_command (body, cleanup, l, c);
+      retval = new tree_try_catch_command (body, cleanup,
+					   lc, mc, tc, l, c);
     }
 
   return retval;
@@ -2068,7 +2119,8 @@
 
 static tree_command *
 make_while_command (token *while_tok, tree_expression *expr,
-		    tree_statement_list *body, token *end_tok)
+		    tree_statement_list *body, token *end_tok,
+		    octave_comment_list *lc)
 {
   tree_command *retval = 0;
 
@@ -2076,12 +2128,14 @@
 
   if (end_token_ok (end_tok, token::while_end))
     {
+      octave_comment_list *tc = octave_comment_buffer::get_comment ();
+
       lexer_flags.looping--;
 
       int l = while_tok->line ();
       int c = while_tok->column ();
 
-      retval = new tree_while_command (expr, body, l, c);
+      retval = new tree_while_command (expr, body, lc, tc, l, c);
     }
 
   return retval;
@@ -2091,18 +2145,20 @@
 
 static tree_command *
 make_do_until_command (token *do_tok, tree_statement_list *body,
-		       tree_expression *expr)
+		       tree_expression *expr, octave_comment_list *lc)
 {
   tree_command *retval = 0;
 
   maybe_warn_assign_as_truth_value (expr);
 
+  octave_comment_list *tc = octave_comment_buffer::get_comment ();
+
   lexer_flags.looping--;
 
   int l = do_tok->line ();
   int c = do_tok->column ();
 
-  retval = new tree_do_until_command (expr, body, l, c);
+  retval = new tree_do_until_command (expr, body, lc, tc, l, c);
 
   return retval;
 }
@@ -2112,12 +2168,14 @@
 static tree_command *
 make_for_command (token *for_tok, tree_argument_list *lhs,
 		  tree_expression *expr, tree_statement_list *body,
-		  token *end_tok)
+		  token *end_tok, octave_comment_list *lc)
 {
   tree_command *retval = 0;
 
   if (end_token_ok (end_tok, token::for_end))
     {
+      octave_comment_list *tc = octave_comment_buffer::get_comment ();
+
       lexer_flags.looping--;
 
       int l = for_tok->line ();
@@ -2127,12 +2185,14 @@
 	{
 	  tree_expression *tmp = lhs->remove_front ();
 
-	  retval = new tree_simple_for_command (tmp, expr, body, l, c);
+	  retval = new tree_simple_for_command (tmp, expr, body,
+						lc, tc, l, c);
 
 	  delete lhs;
 	}
       else
-	retval = new tree_complex_for_command (lhs, expr, body, l, c);
+	retval = new tree_complex_for_command (lhs, expr, body,
+					       lc, tc, l, c);
     }
 
   return retval;
@@ -2210,16 +2270,18 @@
 
 static tree_if_command *
 finish_if_command (token *if_tok, tree_if_command_list *list,
-		   token *end_tok)
+		   token *end_tok, octave_comment_list *lc)
 {
   tree_if_command *retval = 0;
 
   if (end_token_ok (end_tok, token::if_end))
     {
+      octave_comment_list *tc = octave_comment_buffer::get_comment ();
+
       int l = if_tok->line ();
       int c = if_tok->column ();
 
-      retval = new tree_if_command (list, l, c);
+      retval = new tree_if_command (list, lc, tc, l, c);
     }
 
   return retval;
@@ -2228,27 +2290,31 @@
 // Build an elseif clause.
 
 static tree_if_clause *
-make_elseif_clause (tree_expression *expr, tree_statement_list *list)
+make_elseif_clause (tree_expression *expr, tree_statement_list *list,
+		    octave_comment_list *lc)
 {
   maybe_warn_assign_as_truth_value (expr);
 
-  return new tree_if_clause (expr, list);
+  return new tree_if_clause (expr, list, lc);
 }
 
 // Finish a switch command.
 
 static tree_switch_command *
 finish_switch_command (token *switch_tok, tree_expression *expr,
-		       tree_switch_case_list *list, token *end_tok)
+		       tree_switch_case_list *list, token *end_tok,
+		       octave_comment_list *lc)
 {
   tree_switch_command *retval = 0;
 
   if (end_token_ok (end_tok, token::switch_end))
     {
+      octave_comment_list *tc = octave_comment_buffer::get_comment ();
+
       int l = switch_tok->line ();
       int c = switch_tok->column ();
 
-      retval = new tree_switch_command (expr, list, l, c);
+      retval = new tree_switch_command (expr, list, lc, tc, l, c);
     }
 
   return retval;
@@ -2257,11 +2323,12 @@
 // Build a switch case.
 
 static tree_switch_case *
-make_switch_case (tree_expression *expr, tree_statement_list *list)
+make_switch_case (tree_expression *expr, tree_statement_list *list,
+		  octave_comment_list *lc)
 {
   maybe_warn_variable_switch_label (expr);
 
-  return new tree_switch_case (expr, list);
+  return new tree_switch_case (expr, list, lc);
 }
 
 // Build an assignment to a variable.
@@ -2362,6 +2429,13 @@
   octave_user_function *fcn
     = new octave_user_function (param_list, 0, body, curr_sym_tab);
 
+  if (fcn)
+    {
+      octave_comment_list *tc = octave_comment_buffer::get_comment ();
+
+      fcn->stash_trailing_comment (tc);
+    }
+
   return fcn;
 }
 
@@ -2439,22 +2513,28 @@
 // Finish defining a function.
 
 static octave_user_function *
-finish_function (tree_identifier *id, octave_user_function *fcn)
+finish_function (tree_identifier *id, octave_user_function *fcn,
+		 octave_comment_list *lc)
 {
   tree_parameter_list *tpl = new tree_parameter_list (id);
 
   tpl->mark_as_formal_parameters ();
 
+  fcn->stash_leading_comment (lc);
+
   return fcn->define_ret_list (tpl);
 }
 
 // Finish defining a function a different way.
 
 static octave_user_function *
-finish_function (tree_parameter_list *ret_list, octave_user_function *fcn)
+finish_function (tree_parameter_list *ret_list,
+		 octave_user_function *fcn, octave_comment_list *lc)
 {
   ret_list->mark_as_formal_parameters ();
 
+  fcn->stash_leading_comment (lc);
+
   return fcn->define_ret_list (ret_list);
 }
 
@@ -2785,13 +2865,16 @@
 // comments read if it doesn't look like a copyright notice.  If
 // IN_PARTS, consider each block of comments separately; otherwise,
 // grab them all at once.  If UPDATE_POS is TRUE, line and column
-// number information is updated.
+// number information is updated.  If SAVE_COPYRIGHT is TRUE, then
+// comments that are recognized as a copyright notice are saved in the
+// comment buffer.
 
 // XXX FIXME XXX -- grab_help_text() in lex.l duplicates some of this
 // code!
 
 static std::string
-gobble_leading_white_space (FILE *ffile, bool in_parts, bool update_pos)
+gobble_leading_white_space (FILE *ffile, bool in_parts,
+			    bool update_pos, bool save_copyright)
 {
   std::string help_txt;
 
@@ -2893,11 +2976,17 @@
 
   if (! help_txt.empty ())
     {
-      if (looks_like_octave_copyright (help_txt)) 
-	help_txt.resize (0);
+      if (looks_like_octave_copyright (help_txt))
+	{
+	  if (save_copyright)
+	    octave_comment_buffer::append (help_txt);
+
+	  help_txt.resize (0);
+	}
 
       if (in_parts && help_txt.empty ())
-	help_txt = gobble_leading_white_space (ffile, in_parts, update_pos);
+	help_txt = gobble_leading_white_space (ffile, in_parts,
+					       update_pos, false);
     }
 
   return help_txt;
@@ -2916,7 +3005,7 @@
 	{
 	  unwind_protect::add (safe_fclose, (void *) fptr);
 
-	  retval = gobble_leading_white_space (fptr, true, true);
+	  retval = gobble_leading_white_space (fptr, true, true, false);
 
 	  unwind_protect::run ();
 	}
@@ -2932,7 +3021,7 @@
 
   long pos = ftell (ffile);
 
-  gobble_leading_white_space (ffile, false, false);
+  gobble_leading_white_space (ffile, false, false, false);
 
   char buf [10];
   fgets (buf, 10, ffile);
@@ -3031,10 +3120,12 @@
 
 	  reset_parser ();
 
-	  help_buf = gobble_leading_white_space (ffile, true, true);
+	  help_buf = gobble_leading_white_space (ffile, true, true, true);
+
+	  octave_comment_buffer::append (help_buf);
 
 	  // XXX FIXME XXX -- this should not be necessary.
-	  gobble_leading_white_space (ffile, false, true);
+	  gobble_leading_white_space (ffile, false, true, false);
 
 	  int status = yyparse ();
 
--- a/src/pt-except.cc
+++ b/src/pt-except.cc
@@ -46,6 +46,9 @@
 {
   delete try_code;
   delete catch_code;
+  delete lead_comm;
+  delete mid_comm;
+  delete trail_comm;
 }
 
 static void
@@ -120,6 +123,9 @@
 {
   delete unwind_protect_code;
   delete cleanup_code;
+  delete lead_comm;
+  delete mid_comm;
+  delete trail_comm;
 }
 
 static void
--- a/src/pt-except.h
+++ b/src/pt-except.h
@@ -31,6 +31,7 @@
 
 class tree_walker;
 
+#include "comment-list.h"
 #include "pt-cmd.h"
 
 // Simple exception handling.
@@ -41,11 +42,16 @@
 public:
 
   tree_try_catch_command (int l = -1, int c = -1)
-    : tree_command (l, c), try_code (0), catch_code (0) { }
+    : tree_command (l, c), try_code (0), catch_code (0), lead_comm (0),
+      mid_comm (0), trail_comm (0) { }
 
   tree_try_catch_command (tree_statement_list *tc, tree_statement_list *cc,
+			  octave_comment_list *cl = 0,
+			  octave_comment_list *cm = 0,
+			  octave_comment_list *ct = 0,
 			  int l = -1, int c = -1)
-    : tree_command (l, c), try_code (tc), catch_code (cc) { }
+    : tree_command (l, c), try_code (tc), catch_code (cc),
+      lead_comm (cl), mid_comm (cm), trail_comm (ct) { }
 
   ~tree_try_catch_command (void);
 
@@ -55,6 +61,12 @@
 
   tree_statement_list *cleanup (void) { return catch_code; }
 
+  octave_comment_list *leading_comment (void) { return lead_comm; }
+
+  octave_comment_list *middle_comment (void) { return mid_comm; }
+
+  octave_comment_list *trailing_comment (void) { return trail_comm; }
+
   void accept (tree_walker& tw);
 
 private:
@@ -65,6 +77,15 @@
   // The code to execute if an error occurs in the first block.
   tree_statement_list *catch_code;
 
+  // Comment preceding TRY token.
+  octave_comment_list *lead_comm;
+
+  // Comment preceding CATCH token.
+  octave_comment_list *mid_comm;
+
+  // Comment preceding END_TRY_CATCH token.
+  octave_comment_list *trail_comm;
+
   // No copying!
 
   tree_try_catch_command (const tree_try_catch_command&);
@@ -80,12 +101,17 @@
 public:
 
   tree_unwind_protect_command (int l = -1, int c = -1)
-    : tree_command (l, c), unwind_protect_code (0), cleanup_code (0) { }
+    : tree_command (l, c), unwind_protect_code (0), cleanup_code (0),
+      lead_comm (0), mid_comm (0), trail_comm (0) { }
 
   tree_unwind_protect_command (tree_statement_list *tc,
 			       tree_statement_list *cc,
+			       octave_comment_list *cl = 0,
+			       octave_comment_list *cm = 0,
+			       octave_comment_list *ct = 0,
 			       int l = -1, int c = -1)
-    : tree_command (l, c), unwind_protect_code (tc), cleanup_code (cc) { }
+    : tree_command (l, c), unwind_protect_code (tc), cleanup_code (cc),
+      lead_comm (cl), mid_comm (cm), trail_comm (ct) { }
 
   ~tree_unwind_protect_command (void);
 
@@ -95,6 +121,12 @@
 
   tree_statement_list *cleanup (void) { return cleanup_code; }
 
+  octave_comment_list *leading_comment (void) { return lead_comm; }
+
+  octave_comment_list *middle_comment (void) { return mid_comm; }
+
+  octave_comment_list *trailing_comment (void) { return trail_comm; }
+
   void accept (tree_walker& tw);
 
 private:
@@ -106,6 +138,15 @@
   // body of code.
   tree_statement_list *cleanup_code;
 
+  // Comment preceding TRY token.
+  octave_comment_list *lead_comm;
+
+  // Comment preceding CATCH token.
+  octave_comment_list *mid_comm;
+
+  // Comment preceding END_TRY_CATCH token.
+  octave_comment_list *trail_comm;
+
   // No copying!
 
   tree_unwind_protect_command (const tree_unwind_protect_command&);
--- a/src/pt-loop.cc
+++ b/src/pt-loop.cc
@@ -67,6 +67,8 @@
 {
   delete expr;
   delete list;
+  delete lead_comm;
+  delete trail_comm;
 }
 
 void
@@ -164,6 +166,8 @@
 {
   delete expr;
   delete list;
+  delete lead_comm;
+  delete trail_comm;
 }
 
 inline void
@@ -364,6 +368,8 @@
 {
   delete expr;
   delete list;
+  delete lead_comm;
+  delete trail_comm;
 }
 
 void
--- a/src/pt-loop.h
+++ b/src/pt-loop.h
@@ -36,6 +36,7 @@
 
 class tree_walker;
 
+#include "comment-list.h"
 #include "pt-cmd.h"
 
 // While.
@@ -46,14 +47,22 @@
 public:
 
   tree_while_command (int l = -1, int c = -1)
-    : tree_command (l, c), expr (0), list (0) { }
+    : tree_command (l, c), expr (0), list (0), lead_comm (0),
+      trail_comm (0) { }
 
-  tree_while_command (tree_expression *e, int l = -1, int c = -1)
-    : tree_command (l, c), expr (e), list (0) { }
+  tree_while_command (tree_expression *e,
+		      octave_comment_list *lc = 0,
+		      octave_comment_list *tc = 0,
+		      int l = -1, int c = -1)
+    : tree_command (l, c), expr (e), list (0), lead_comm (lc),
+      trail_comm (tc) { }
 
   tree_while_command (tree_expression *e, tree_statement_list *lst,
+		      octave_comment_list *lc = 0,
+		      octave_comment_list *tc = 0,
 		      int l = -1, int c = -1)
-    : tree_command (l, c), expr (e), list (lst) { }
+    : tree_command (l, c), expr (e), list (lst), lead_comm (lc),
+      trail_comm (tc) { }
 
   ~tree_while_command (void);
 
@@ -65,6 +74,10 @@
 
   tree_statement_list *body (void) { return list; }
 
+  octave_comment_list *leading_comment (void) { return lead_comm; }
+
+  octave_comment_list *trailing_comment (void) { return trail_comm; }
+
   void accept (tree_walker& tw);
 
 protected:
@@ -75,6 +88,12 @@
   // List of commands to execute.
   tree_statement_list *list;
 
+  // Comment preceding WHILE token.
+  octave_comment_list *lead_comm;
+
+  // Comment preceding ENDWHILE token.
+  octave_comment_list *trail_comm;
+
 private:
 
   // No copying!
@@ -94,12 +113,17 @@
   tree_do_until_command (int l = -1, int c = -1)
     : tree_while_command (l, c) { }
 
-  tree_do_until_command (tree_expression *e, int l = -1, int c = -1)
-    : tree_while_command (e, l, c) { }
+  tree_do_until_command (tree_expression *e,
+			 octave_comment_list *lc = 0,
+			 octave_comment_list *tc = 0,
+			 int l = -1, int c = -1)
+    : tree_while_command (e, lc, tc, l, c) { }
 
   tree_do_until_command (tree_expression *e, tree_statement_list *lst,
-		      int l = -1, int c = -1)
-    : tree_while_command (e, lst, l, c) { }
+			 octave_comment_list *lc = 0,
+			 octave_comment_list *tc = 0,
+			 int l = -1, int c = -1)
+    : tree_while_command (e, lst, lc, tc, l, c) { }
 
   ~tree_do_until_command (void) { }
 
@@ -126,11 +150,16 @@
 public:
 
   tree_simple_for_command (int l = -1, int c = -1)
-    : tree_command (l, c), lhs (0), expr (0), list (0) { }
+    : tree_command (l, c), lhs (0), expr (0), list (0), lead_comm (0),
+      trail_comm (0) { }
 
   tree_simple_for_command (tree_expression *le, tree_expression *re,
-			   tree_statement_list *lst, int l = -1, int c = -1)
-    : tree_command (l, c), lhs (le), expr (re), list (lst) { }
+			   tree_statement_list *lst,
+			   octave_comment_list *lc = 0,
+			   octave_comment_list *tc = 0,
+			   int l = -1, int c = -1)
+    : tree_command (l, c), lhs (le), expr (re), list (lst),
+      lead_comm (lc), trail_comm (tc) { }
 
   ~tree_simple_for_command (void);
 
@@ -144,6 +173,10 @@
 
   tree_statement_list *body (void) { return list; }
 
+  octave_comment_list *leading_comment (void) { return lead_comm; }
+
+  octave_comment_list *trailing_comment (void) { return trail_comm; }
+
   void accept (tree_walker& tw);
 
 private:
@@ -157,6 +190,12 @@
   // List of commands to execute.
   tree_statement_list *list;
 
+  // Comment preceding FOR token.
+  octave_comment_list *lead_comm;
+
+  // Comment preceding ENDFOR token.
+  octave_comment_list *trail_comm;
+
   void do_for_loop_once (octave_lvalue &ult, const octave_value& rhs,
 			 bool& quit);
 
@@ -173,11 +212,16 @@
 public:
 
   tree_complex_for_command (int l = -1, int c = -1)
-    : tree_command (l, c), lhs (0), expr (0), list (0) { }
+    : tree_command (l, c), lhs (0), expr (0), list (0), lead_comm (0),
+      trail_comm (0) { }
 
   tree_complex_for_command (tree_argument_list *le, tree_expression *re,
-			    tree_statement_list *lst, int l = -1, int c = -1)
-    : tree_command (l, c), lhs (le), expr (re), list (lst) { }
+			    tree_statement_list *lst,
+			    octave_comment_list *lc = 0,
+			    octave_comment_list *tc = 0,
+			    int l = -1, int c = -1)
+    : tree_command (l, c), lhs (le), expr (re), list (lst),
+      lead_comm (lc), trail_comm (tc) { }
 
   ~tree_complex_for_command (void);
 
@@ -191,6 +235,10 @@
 
   tree_statement_list *body (void) { return list; }
 
+  octave_comment_list *leading_comment (void) { return lead_comm; }
+
+  octave_comment_list *trailing_comment (void) { return trail_comm; }
+
   void accept (tree_walker& tw);
 
 private:
@@ -204,6 +252,12 @@
   // List of commands to execute.
   tree_statement_list *list;
 
+  // Comment preceding FOR token.
+  octave_comment_list *lead_comm;
+
+  // Comment preceding ENDFOR token.
+  octave_comment_list *trail_comm;
+
   void do_for_loop_once (octave_lvalue &val_ref, octave_lvalue &key_ref,
 			 const octave_value& val, const octave_value& key,
 			 bool& quit);
--- a/src/pt-pr-code.cc
+++ b/src/pt-pr-code.cc
@@ -28,8 +28,11 @@
 #include <config.h>
 #endif
 
+#include <cctype>
+
 #include <iostream>
 
+#include "comment-list.h"
 #include "error.h"
 #include "ov-usr-fcn.h"
 #include "pr-output.h"
@@ -182,6 +185,8 @@
 void
 tree_print_code::visit_simple_for_command (tree_simple_for_command& cmd)
 {
+  print_comment_list (cmd.leading_comment ());
+
   indent ();
 
   os << "for ";
@@ -205,10 +210,14 @@
   if (list)
     {
       increment_indent_level ();
+
       list->accept (*this);
+
       decrement_indent_level ();
     }
 
+  print_indented_comment (cmd.trailing_comment ());
+
   indent ();
 
   os << "endfor";
@@ -217,6 +226,8 @@
 void
 tree_print_code::visit_complex_for_command (tree_complex_for_command& cmd)
 {
+  print_comment_list (cmd.leading_comment ());
+
   indent ();
 
   os << "for [";
@@ -240,10 +251,14 @@
   if (list)
     {
       increment_indent_level ();
+
       list->accept (*this);
+
       decrement_indent_level ();
     }
 
+  print_indented_comment (cmd.trailing_comment ());
+
   indent ();
 
   os << "endfor";
@@ -261,7 +276,9 @@
   if (cmd_list)
     {
       increment_indent_level ();
+
       cmd_list->accept (*this);
+
       decrement_indent_level ();
     }
 
@@ -271,6 +288,14 @@
 void
 tree_print_code::visit_octave_user_function_header (octave_user_function& fcn)
 {
+  octave_comment_list *leading_comment = fcn.leading_comment ();
+
+  if (leading_comment)
+    {
+      print_comment_list (leading_comment);
+      newline ();
+    }
+
   indent ();
 
   os << "function ";
@@ -341,8 +366,10 @@
 }
 
 void
-tree_print_code::visit_octave_user_function_trailer (octave_user_function&)
+tree_print_code::visit_octave_user_function_trailer (octave_user_function& fcn)
 {
+  print_indented_comment (fcn.trailing_comment ());
+
   indent ();
 
   os << "endfunction";
@@ -373,12 +400,12 @@
 
   newline ();
 
-  increment_indent_level ();
-
   tree_statement_list *list = cmd.commands ();
 
   if (list)
     {
+      increment_indent_level ();
+
       list->accept (*this);
 
       decrement_indent_level ();
@@ -388,6 +415,8 @@
 void
 tree_print_code::visit_if_command (tree_if_command& cmd)
 {
+  print_comment_list (cmd.leading_comment ());
+
   indent ();
 
   os << "if ";
@@ -397,6 +426,8 @@
   if (list)
     list->accept (*this);
 
+  print_indented_comment (cmd.trailing_comment ());
+
   indent ();
 
   os << "endif";
@@ -417,6 +448,8 @@
 	{
 	  if (! first_elt)
 	    {
+	      print_indented_comment (elt->leading_comment ());
+
 	      indent ();
 
 	      if (elt->is_else_clause ())
@@ -440,10 +473,16 @@
 
   print_parens (expr, "(");
 
+  bool expr_has_parens = false;
+
   tree_expression *e = expr.expression ();
 
   if (e)
-    e->accept (*this);
+    {
+      e->accept (*this);
+
+      expr_has_parens = e->is_postfix_indexed ();
+    }
 
   tree_argument_list *list = expr.arg_list ();
 
@@ -453,6 +492,8 @@
       list->accept (*this);
       os << ")";
     }
+  else if (expr_has_parens)
+    os << " ()";
 
   print_parens (expr, ")");
 }
@@ -773,6 +814,8 @@
 void
 tree_print_code::visit_statement (tree_statement& stmt)
 {
+  print_comment_list (stmt.comment_text ());
+
   tree_command *cmd = stmt.command ();
 
   if (cmd)
@@ -928,6 +971,8 @@
 void
 tree_print_code::visit_switch_case (tree_switch_case& cs)
 {
+  print_comment_list (cs.leading_comment ());
+
   indent ();
 
   if (cs.is_default_case ())
@@ -942,14 +987,16 @@
 
   newline ();
 
-  increment_indent_level ();
-
   tree_statement_list *list = cs.commands ();
 
   if (list)
     {
+      increment_indent_level ();
+
       list->accept (*this);
 
+      newline ();
+
       decrement_indent_level ();
     }
 }
@@ -973,6 +1020,8 @@
 void
 tree_print_code::visit_switch_command (tree_switch_command& cmd)
 {
+  print_comment_list (cmd.leading_comment ());
+
   indent ();
 
   os << "switch ";
@@ -984,12 +1033,18 @@
 
   newline ();
 
-  increment_indent_level ();
-
   tree_switch_case_list *list = cmd.case_list ();
 
   if (list)
-    list->accept (*this);
+    {
+      increment_indent_level ();
+
+      list->accept (*this);
+
+      decrement_indent_level ();
+    }
+
+  print_indented_comment (cmd.leading_comment ());
 
   indent ();
 
@@ -999,9 +1054,11 @@
 void
 tree_print_code::visit_try_catch_command (tree_try_catch_command& cmd)
 {
+  print_comment_list (cmd.leading_comment ());
+
   indent ();
 
-  os << "try_catch";
+  os << "try";
 
   newline ();
 
@@ -1010,10 +1067,14 @@
   if (try_code)
     {
       increment_indent_level ();
+
       try_code->accept (*this);
+
       decrement_indent_level ();
     }
 
+  print_indented_comment (cmd.middle_comment ());
+
   indent ();
 
   os << "catch";
@@ -1025,10 +1086,14 @@
   if (catch_code)
     {
       increment_indent_level ();
+
       catch_code->accept (*this);
+
       decrement_indent_level ();
     }
 
+  print_indented_comment (cmd.trailing_comment ());
+
   indent ();
 
   os << "end_try_catch";
@@ -1038,6 +1103,8 @@
 tree_print_code::visit_unwind_protect_command
   (tree_unwind_protect_command& cmd)
 {
+  print_comment_list (cmd.leading_comment ());
+
   indent ();
 
   os << "unwind_protect";
@@ -1049,10 +1116,14 @@
   if (unwind_protect_code)
     {
       increment_indent_level ();
+
       unwind_protect_code->accept (*this);
+
       decrement_indent_level ();
     }
 
+  print_indented_comment (cmd.middle_comment ());
+
   indent ();
 
   os << "unwind_protect_cleanup";
@@ -1064,10 +1135,14 @@
   if (cleanup_code)
     {
       increment_indent_level ();
+
       cleanup_code->accept (*this);
+
       decrement_indent_level ();
     }
 
+  print_indented_comment (cmd.trailing_comment ());
+
   indent ();
 
   os << "end_unwind_protect";
@@ -1076,6 +1151,8 @@
 void
 tree_print_code::visit_while_command (tree_while_command& cmd)
 {
+  print_comment_list (cmd.leading_comment ());
+
   indent ();
 
   os << "while ";
@@ -1092,10 +1169,14 @@
   if (list)
     {
       increment_indent_level ();
+
       list->accept (*this);
+
       decrement_indent_level ();
     }
 
+  print_indented_comment (cmd.trailing_comment ());
+
   indent ();
 
   os << "endwhile";
@@ -1104,6 +1185,8 @@
 void
 tree_print_code::visit_do_until_command (tree_do_until_command& cmd)
 {
+  print_comment_list (cmd.leading_comment ());
+
   indent ();
 
   os << "do";
@@ -1115,10 +1198,14 @@
   if (list)
     {
       increment_indent_level ();
+
       list->accept (*this);
+
       decrement_indent_level ();
     }
 
+  print_indented_comment (cmd.trailing_comment ());
+
   indent ();
 
   os << "until";
@@ -1186,6 +1273,91 @@
     os << txt;
 }
 
+void
+tree_print_code::print_comment_elt (const octave_comment_elt& elt)
+{
+  bool printed_something = false;
+
+  bool prev_char_was_newline = false;
+
+  string comment = elt.text ();
+
+  size_t len = comment.length ();
+
+  size_t i = 0;
+
+  while (i < len && comment[i++] == '\n')
+    ; /* Skip leading new lines. */
+  i--;
+
+  while (i < len)
+    {
+      char c = comment[i++];
+
+      if (c == '\n')
+	{
+	  if (prev_char_was_newline)
+	    os << "##";
+
+	  newline ();
+
+	  prev_char_was_newline = true;
+	}
+      else
+	{
+	  if (beginning_of_line)
+	    {
+	      printed_something = true;
+
+	      indent ();
+
+	      os << "##";
+
+	      if (! (isspace (c) || c == '!'))
+		os << " ";
+	    }
+
+	  os << (char) c;
+
+	  prev_char_was_newline = false;
+	}
+    }
+
+  if (printed_something && ! beginning_of_line)
+    newline ();
+}
+
+void
+tree_print_code::print_comment_list (octave_comment_list *comment_list)
+{
+  if (comment_list)
+    {
+      Pix p = comment_list->first ();
+
+      while (p)
+	{
+	  octave_comment_elt elt = comment_list->operator () (p);
+
+	  print_comment_elt (elt);
+
+	  comment_list->next (p);
+
+	  if (p)
+	    newline ();
+	}
+    }
+}
+
+void
+tree_print_code::print_indented_comment (octave_comment_list *comment_list)
+{
+  increment_indent_level ();
+
+  print_comment_list (comment_list);
+
+  decrement_indent_level ();
+}
+
 /*
 ;;; Local Variables: ***
 ;;; mode: C++ ***
--- a/src/pt-pr-code.h
+++ b/src/pt-pr-code.h
@@ -29,6 +29,7 @@
 
 #include <string>
 
+#include "comment-list.h"
 #include "pt-walk.h"
 
 class tree_expression;
@@ -168,6 +169,12 @@
 
   void print_parens (const tree_expression& expr, const char *txt);
 
+  void print_comment_list (octave_comment_list *comment_list);
+
+  void print_comment_elt (const octave_comment_elt& comment_elt);
+
+  void print_indented_comment (octave_comment_list *comment_list);
+
   // Must create with an output stream!
 
   tree_print_code (void);
--- a/src/pt-select.cc
+++ b/src/pt-select.cc
@@ -43,6 +43,7 @@
 {
   delete expr;
   delete list;
+  delete lead_comm;
 }
 
 int
@@ -90,6 +91,8 @@
 tree_if_command::~tree_if_command (void)
 {
   delete list;
+  delete lead_comm;
+  delete trail_comm;
 }
 
 void
@@ -115,6 +118,7 @@
 {
   delete label;
   delete list;
+  delete lead_comm;
 }
 
 bool
@@ -204,6 +208,8 @@
 {
   delete expr;
   delete list;
+  delete lead_comm;
+  delete trail_comm;
 }
 
 void
--- a/src/pt-select.h
+++ b/src/pt-select.h
@@ -34,6 +34,7 @@
 
 class tree_walker;
 
+#include "comment-list.h"
 #include "pt-cmd.h"
 
 // If.
@@ -44,13 +45,14 @@
 public:
 
   tree_if_clause (void)
-    : expr (0), list (0) { }
+    : expr (0), list (0), lead_comm (0) { }
 
-  tree_if_clause (tree_statement_list *l)
-    : expr (0), list (l) { }
+  tree_if_clause (tree_statement_list *l, octave_comment_list *lc = 0)
+    : expr (0), list (l), lead_comm (lc) { }
 
-  tree_if_clause (tree_expression *e, tree_statement_list *l)
-    : expr (e), list (l) { }
+  tree_if_clause (tree_expression *e, tree_statement_list *l,
+		  octave_comment_list *lc = 0)
+    : expr (e), list (l), lead_comm (lc) { }
 
   ~tree_if_clause (void);
 
@@ -63,6 +65,8 @@
 
   tree_statement_list *commands (void) { return list; }
 
+  octave_comment_list *leading_comment (void) { return lead_comm; }
+
   void accept (tree_walker& tw);
 
 private:
@@ -73,6 +77,9 @@
   // The list of statements to evaluate if expr is true.
   tree_statement_list *list;
 
+  // Comment preceding ELSE or ELSEIF token.
+  octave_comment_list *lead_comm;
+
   // No copying!
 
   tree_if_clause (const tree_if_clause&);
@@ -119,10 +126,11 @@
 public:
 
   tree_if_command (int l = -1, int c = -1)
-    : tree_command (l, c), list (0) { }
+    : tree_command (l, c), list (0), lead_comm (0), trail_comm (0) { }
 
-  tree_if_command (tree_if_command_list *lst, int l = -1, int c = -1)
-    : tree_command (l, c), list (lst) { }
+  tree_if_command (tree_if_command_list *lst, octave_comment_list *lc,
+		   octave_comment_list *tc, int l = -1, int c = -1)
+    : tree_command (l, c), list (lst), lead_comm (lc), trail_comm (tc) { }
 
   ~tree_if_command (void);
 
@@ -130,6 +138,10 @@
 
   tree_if_command_list *cmd_list (void) { return list; }
 
+  octave_comment_list *leading_comment (void) { return lead_comm; }
+
+  octave_comment_list *trailing_comment (void) { return trail_comm; }
+
   void accept (tree_walker& tw);
 
 private:
@@ -137,6 +149,12 @@
   // List of if commands (if, elseif, elseif, ... else, endif)
   tree_if_command_list *list;
 
+  // Comment preceding IF token.
+  octave_comment_list *lead_comm;
+
+  // Comment preceding ENDIF token.
+  octave_comment_list *trail_comm;
+
   // No copying!
 
   tree_if_command (const tree_if_command&);
@@ -152,13 +170,14 @@
 public:
 
   tree_switch_case (void)
-    : label (0), list (0) { }
+    : label (0), list (0), lead_comm (0) { }
 
-  tree_switch_case (tree_statement_list *l)
-    : label (0), list (l) { }
+  tree_switch_case (tree_statement_list *l, octave_comment_list *lc = 0)
+    : label (0), list (l), lead_comm (lc) { }
 
-  tree_switch_case (tree_expression *e, tree_statement_list *l)
-    : label (e), list (l) { }
+  tree_switch_case (tree_expression *e, tree_statement_list *l,
+		    octave_comment_list *lc = 0)
+    : label (e), list (l), lead_comm (lc) { }
 
   ~tree_switch_case (void);
 
@@ -175,6 +194,8 @@
 
   tree_statement_list *commands (void) { return list; }
 
+  octave_comment_list *leading_comment (void) { return lead_comm; }
+
   void accept (tree_walker& tw);
 
 private:
@@ -185,6 +206,9 @@
   // The list of statements to evaluate if the label matches.
   tree_statement_list *list;
 
+  // Comment preceding CASE or OTHERWISE token.
+  octave_comment_list *lead_comm;
+
   // No copying!
 
   tree_switch_case (const tree_switch_case&);
@@ -231,11 +255,14 @@
 public:
 
   tree_switch_command (int l = -1, int c = -1)
-    : tree_command (l, c), expr (0), list (0) { }
+    : tree_command (l, c), expr (0), list (0), lead_comm (0),
+      trail_comm (0) { }
 
   tree_switch_command (tree_expression *e, tree_switch_case_list *lst,
+		       octave_comment_list *lc, octave_comment_list *tc, 
 		       int l = -1, int c = -1)
-    : tree_command (l, c), expr (e), list (lst) { }
+    : tree_command (l, c), expr (e), list (lst), lead_comm (lc),
+      trail_comm (tc) { }
 
   ~tree_switch_command (void);
 
@@ -247,6 +274,10 @@
 
   tree_switch_case_list *case_list (void) { return list; }
 
+  octave_comment_list *leading_comment (void) { return lead_comm; }
+
+  octave_comment_list *trailing_comment (void) { return trail_comm; }
+
   void accept (tree_walker& tw);
 
 private:
@@ -257,6 +288,12 @@
   // List of cases (case 1, case 2, ..., default)
   tree_switch_case_list *list;
 
+  // Comment preceding SWITCH token.
+  octave_comment_list *lead_comm;
+
+  // Comment preceding ENDSWITCH token.
+  octave_comment_list *trail_comm;
+
   // No copying!
 
   tree_switch_command (const tree_switch_command&);
--- a/src/pt-stmt.cc
+++ b/src/pt-stmt.cc
@@ -56,6 +56,7 @@
 {
   delete cmd;
   delete expr;
+  delete comm;
 }
 
 int
--- a/src/pt-stmt.h
+++ b/src/pt-stmt.h
@@ -36,6 +36,8 @@
 
 class tree_walker;
 
+#include "comment-list.h"
+
 // A statement is either a command to execute or an expression to
 // evaluate.
 
@@ -45,13 +47,13 @@
 public:
 
   tree_statement (void)
-    : cmd (0), expr (0), print_flag (true) { }
+    : cmd (0), expr (0), comm (0), print_flag (true) { }
 
-  tree_statement (tree_command *c)
-    : cmd (c), expr (0), print_flag (true) { }
+  tree_statement (tree_command *c, octave_comment_list *cl)
+    : cmd (c), expr (0), comm (cl), print_flag (true) { }
 
-  tree_statement (tree_expression *e)
-    : cmd (0), expr (e), print_flag (true) { }
+  tree_statement (tree_expression *e, octave_comment_list *cl)
+    : cmd (0), expr (e), comm (cl), print_flag (true) { }
 
   ~tree_statement (void);
 
@@ -77,6 +79,8 @@
 
   tree_expression *expression (void) { return expr; }
 
+  octave_comment_list *comment_text (void) { return comm; }
+
   void accept (tree_walker& tw);
 
 private:
@@ -89,6 +93,9 @@
   // Expression to evaluate.
   tree_expression *expr;
 
+  // Comment associated with this statement.
+  octave_comment_list *comm;
+
   // Print result of eval for this command?
   bool print_flag;