changeset 31610:3b7852a822e8

maint: Merge stable to default.
author John W. Eaton <jwe@octave.org>
date Fri, 02 Dec 2022 10:12:40 -0500
parents 23664317f0d3 (diff) c2a0e546aab1 (current diff)
children 351a4c8e92c3
files
diffstat 73 files changed, 8612 insertions(+), 11192 deletions(-) [+]
line wrap: on
line diff
--- a/.github/workflows/make.yaml	Fri Dec 02 10:11:46 2022 -0500
+++ b/.github/workflows/make.yaml	Fri Dec 02 10:12:40 2022 -0500
@@ -85,7 +85,7 @@
           key: ccache:${{ matrix.os }}:${{ matrix.compiler }}:${{ github.ref }}:${{ steps.ccache_cache_timestamp.outputs.timestamp }}:${{ github.sha }}
           restore-keys: |
             ccache:${{ matrix.os }}:${{ matrix.compiler }}:${{ github.ref }}
-            ccache:${{ matrix.os }}:${{ matrix.compiler }}:refs/heads/stable
+            ccache:${{ matrix.os }}:${{ matrix.compiler }}:refs/heads/default
 
       - name: configure ccache
         env:
@@ -239,7 +239,7 @@
           key: ccache:${{ matrix.os }}:${{ matrix.compiler }}:${{ github.ref }}:${{ steps.ccache_cache_timestamp.outputs.timestamp }}:${{ github.sha }}
           restore-keys: |
             ccache:${{ matrix.os }}:${{ matrix.compiler }}:${{ github.ref }}
-            ccache:${{ matrix.os }}:${{ matrix.compiler }}:refs/heads/stable
+            ccache:${{ matrix.os }}:${{ matrix.compiler }}:refs/heads/default
 
       - name: configure ccache
         # The cache doesn't seem to compress well on macOS. Is it already compressed?
@@ -468,7 +468,7 @@
           key: ccache:${{ matrix.os }}:${{ matrix.msystem }}:${{ github.ref }}:${{ steps.ccache_cache_timestamp.outputs.timestamp }}:${{ github.sha }}
           restore-keys: |
             ccache:${{ matrix.os }}:${{ matrix.msystem }}:${{ github.ref }}
-            ccache:${{ matrix.os }}:${{ matrix.msystem }}:refs/heads/stable
+            ccache:${{ matrix.os }}:${{ matrix.msystem }}:refs/heads/default
 
       - name: configure ccache
         # Limit the maximum size and switch on compression to avoid exceeding the total disk or cache quota.
@@ -707,7 +707,7 @@
           key: ccache:${{ matrix.os }}:cygwin:${{ github.ref }}:${{ steps.ccache_cache_timestamp.outputs.timestamp }}:${{ github.sha }}
           restore-keys: |
             ccache:${{ matrix.os }}:cygwin:${{ github.ref }}
-            ccache:${{ matrix.os }}:cygwin:refs/heads/stable
+            ccache:${{ matrix.os }}:cygwin:refs/heads/default
 
       - name: configure ccache
         run: |
--- a/configure.ac	Fri Dec 02 10:11:46 2022 -0500
+++ b/configure.ac	Fri Dec 02 10:12:40 2022 -0500
@@ -27,7 +27,7 @@
 
 ### Initialize Autoconf
 AC_PREREQ([2.65])
-AC_INIT([GNU Octave], [8.0.1], [https://octave.org/bugs.html], [octave],
+AC_INIT([GNU Octave], [9.0.0], [https://octave.org/bugs.html], [octave],
         [https://www.gnu.org/software/octave/])
 
 ### Declare version numbers
@@ -39,9 +39,9 @@
 ## explains how to update these numbers for release and development
 ## versions.
 
-OCTAVE_MAJOR_VERSION=8
+OCTAVE_MAJOR_VERSION=9
 OCTAVE_MINOR_VERSION=0
-OCTAVE_PATCH_VERSION=1
+OCTAVE_PATCH_VERSION=0
 
 dnl PACKAGE_VERSION is set by the AC_INIT VERSION argument.
 OCTAVE_VERSION="$PACKAGE_VERSION"
--- a/doc/interpreter/contributors.in	Fri Dec 02 10:11:46 2022 -0500
+++ b/doc/interpreter/contributors.in	Fri Dec 02 10:12:40 2022 -0500
@@ -101,6 +101,7 @@
 Massimiliano Fasi
 Stephen Fegan
 Ramon Garcia Fernandez
+Kasper H. Filtenborg
 Torsten Finke
 David Finkel
 Guillaume Flandin
--- a/doc/interpreter/linalg.txi	Fri Dec 02 10:11:46 2022 -0500
+++ b/doc/interpreter/linalg.txi	Fri Dec 02 10:12:40 2022 -0500
@@ -211,6 +211,8 @@
 
 @DOCSTRING(kron)
 
+@DOCSTRING(tensorprod)
+
 @DOCSTRING(blkmm)
 
 @DOCSTRING(sylvester)
--- a/doc/liboctave/range.texi	Fri Dec 02 10:11:46 2022 -0500
+++ b/doc/liboctave/range.texi	Fri Dec 02 10:12:40 2022 -0500
@@ -20,35 +20,4 @@
 @chapter Ranges
 @cindex ranges
 
-@deftypefn  {} {} Range (void)
-@deftypefnx  {} {} Range (const Range &@var{r})
-@deftypefnx  {} {} Range (double @var{b}, double @var{l})
-@deftypefnx  {} {} Range (double @var{b}, double @var{l}, double @var{i})
-@end deftypefn
-
-@deftypefn {} double base (void) const
-@deftypefnx {} double limit (void) const
-@deftypefnx {} double inc (void) const
-@end deftypefn
-
-@deftypefn {} void set_base (double @var{b})
-@deftypefnx {} void set_limit (double @var{l})
-@deftypefnx {} void set_inc (double @var{i})
-@end deftypefn
-
-@deftypefn {} int nelem (void) const
-@end deftypefn
-
-@deftypefn {} double min (void) const
-@deftypefnx {} double max (void) const
-@end deftypefn
-
-@deftypefn {} void sort (void)
-@end deftypefn
-
-@deftypefn {} {ostream&} {operator <<} (ostream &@var{os}, const Range &@var{r})
-@deftypefnx {} {istream&} {operator >>} (istream &@var{is}, Range &@var{r})
-@end deftypefn
-
-@deftypefn {} void print_range (void)
-@end deftypefn
+FIXME: The @code{Range} class is obsolete.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/etc/NEWS.9.md	Fri Dec 02 10:12:40 2022 -0500
@@ -0,0 +1,93 @@
+Summary of important user-visible changes for version 9 (yyyy-mm-dd):
+---------------------------------------------------------------------
+
+### General improvements
+
+- `oruntests`: The current directory now changes to the directory
+containing the files with the tests for the duration of the test.  This
+aligns the behavior of this function with Octave's test suite.  This also
+means that the file encoding specified in the `.oct-config` file for the
+respective directory is taken into account for the tests.
+
+### Graphical User Interface
+
+### Graphics backend
+
+### Matlab compatibility
+
+### Alphabetical list of new functions added in Octave 9
+
+* `tensorprod`
+
+### Deprecated functions, properties, and operators
+
+The following functions and properties have been deprecated in Octave 9
+and will be removed from Octave 11 (or whatever version is the second
+major release after 9):
+
+- Functions
+
+        Function               | Replacement
+        -----------------------|------------------
+
+- Properties
+
+  The following property names are discouraged, but there is no fixed
+  date for their removal.
+
+        Object           | Property    | Replacement
+        -----------------|-------------|------------
+
+The following features were deprecated in Octave 7 and have been removed
+from Octave 9.
+
+- Functions
+
+        Function                   | Replacement
+        ---------------------------|------------------
+        disable_diagonal_matrix    | optimize_diagonal_matrix
+        disable_permutation_matrix | optimize_permutation_matrix
+        disable_range              | optimize_range
+
+- Operators
+
+        Operator | Replacement
+        ---------|------------
+        .+       | +
+        .+=      | +=
+        .-       | -
+        .-=      | -=
+        **       | ^
+        **=      | ^=
+        .**      | .^
+        .**=     | .^=
+
+- Interpreter
+
+    * The use of `'...'` for line continuations *inside* double-quoted
+    strings has been removed.  Use `'\'` for line continuations inside strings
+    instead.
+
+    * The use of `'\'` as a line continuation *outside* of double-quoted
+    strings has been removed.  Use `'...'` for line continuations instead.
+
+    * Support for trailing whitespace after a `'\'` line continuation has been
+    removed.  Delete unnecessary trailing whitespace.
+
+- For plot functions, the use of numbers to select line colors in
+  shorthand formats was an undocumented feature was removed from Octave 9.
+
+- The environment variable used by `mkoctfile` for linker flags is now
+  `LDFLAGS` rather than `LFLAGS`.  `LFLAGS` was deprecated in Octave 6
+  and has been removed.
+
+### Old release news
+
+- [Octave 8.x](etc/NEWS.8)
+- [Octave 7.x](etc/NEWS.7)
+- [Octave 6.x](etc/NEWS.6)
+- [Octave 5.x](etc/NEWS.5)
+- [Octave 4.x](etc/NEWS.4)
+- [Octave 3.x](etc/NEWS.3)
+- [Octave 2.x](etc/NEWS.2)
+- [Octave 1.x](etc/NEWS.1)
--- a/etc/module.mk	Fri Dec 02 10:11:46 2022 -0500
+++ b/etc/module.mk	Fri Dec 02 10:12:40 2022 -0500
@@ -13,6 +13,7 @@
   %reldir%/NEWS.6.md \
   %reldir%/NEWS.7.md \
   %reldir%/NEWS.8.md \
+  %reldir%/NEWS.9.md \
   %reldir%/gdbinit
 
 %canon_reldir%_EXTRA_DIST += \
--- a/libinterp/corefcn/c-file-ptr-stream.h	Fri Dec 02 10:11:46 2022 -0500
+++ b/libinterp/corefcn/c-file-ptr-stream.h	Fri Dec 02 10:12:40 2022 -0500
@@ -232,39 +232,4 @@
 
 OCTAVE_END_NAMESPACE(octave)
 
-#if defined (OCTAVE_PROVIDE_DEPRECATED_SYMBOLS)
-
-OCTAVE_DEPRECATED (7, "use 'octave::i_c_file_ptr_stream' instead")
-typedef octave::i_c_file_ptr_stream i_c_file_ptr_stream;
-
-OCTAVE_DEPRECATED (7, "use 'octave::o_c_file_ptr_stream' instead")
-typedef octave::o_c_file_ptr_stream o_c_file_ptr_stream;
-
-OCTAVE_DEPRECATED (7, "use 'octave::io_c_file_ptr_stream' instead")
-typedef octave::io_c_file_ptr_stream io_c_file_ptr_stream;
-
-// FIXME: HAVE_ZLIB is not defined here because we do not (and should
-// not) include config.h in this header file.  We need to find a way to
-// define this interface without exposing gzFile.  Should this be a
-// private header that can only be used if included after config.h in an
-// Octave source file and not inside another header file?
-
-#  if defined (HAVE_ZLIB)
-
-OCTAVE_DEPRECATED (7, "use 'octave::i_c_zfile_ptr_stream' instead")
-typedef octave::c_file_ptr_stream<std::istream, gzFile, octave::c_zfile_ptr_buf>
-  i_c_zfile_ptr_stream;
-
-OCTAVE_DEPRECATED (7, "use 'octave::o_c_zfile_ptr_stream' instead")
-typedef octave::c_file_ptr_stream<std::ostream, gzFile, octave::c_zfile_ptr_buf>
-  o_c_zfile_ptr_stream;
-
-OCTAVE_DEPRECATED (7, "use 'octave::io_c_zfile_ptr_stream' instead")
-typedef octave::c_file_ptr_stream<std::iostream, gzFile, octave::c_zfile_ptr_buf>
-  io_c_zfile_ptr_stream;
-
-#  endif
-
 #endif
-
-#endif
--- a/libinterp/corefcn/data.cc	Fri Dec 02 10:11:46 2022 -0500
+++ b/libinterp/corefcn/data.cc	Fri Dec 02 10:12:40 2022 -0500
@@ -6523,7 +6523,7 @@
 (@dots{}((@var{A1} * @var{A2}) * @var{A3}) * @dots{})
 @end example
 
-@seealso{times, plus, minus, rdivide, mrdivide, mldivide, mpower}
+@seealso{times, plus, minus, rdivide, mrdivide, mldivide, mpower, tensorprod}
 @end deftypefn */)
 {
   return binary_assoc_op_defun_body (octave_value::op_mul,
--- a/libinterp/corefcn/data.h	Fri Dec 02 10:11:46 2022 -0500
+++ b/libinterp/corefcn/data.h	Fri Dec 02 10:12:40 2022 -0500
@@ -41,14 +41,4 @@
 
 OCTAVE_END_NAMESPACE(octave)
 
-#if defined (OCTAVE_PROVIDE_DEPRECATED_SYMBOLS)
-OCTAVE_DEPRECATED (7, "use 'octave::do_class_concat' instead")
-inline OCTINTERP_API octave_value
-do_class_concat (const octave_value_list& ovl, const std::string& cattype,
-                 int dim)
-{
-  return octave::do_class_concat (ovl, cattype, dim);
-}
 #endif
-
-#endif
--- a/libinterp/corefcn/dot.cc	Fri Dec 02 10:11:46 2022 -0500
+++ b/libinterp/corefcn/dot.cc	Fri Dec 02 10:12:40 2022 -0500
@@ -91,7 +91,7 @@
 the result is equivalent to @code{@var{X}' * @var{Y}}.  Although, @code{dot}
 is defined for integer arrays, the output may differ from the expected result
 due to the limited range of integer objects.
-@seealso{cross, divergence}
+@seealso{cross, divergence, tensorprod}
 @end deftypefn */)
 {
   int nargin = args.length ();
--- a/libinterp/corefcn/error.cc	Fri Dec 02 10:11:46 2022 -0500
+++ b/libinterp/corefcn/error.cc	Fri Dec 02 10:12:40 2022 -0500
@@ -901,17 +901,6 @@
   last_error_stack (make_stack_map (ee.stack_info ()));
 }
 
-// DEPRECATED in Octave 7.
-void error_system::display_exception (const execution_exception& ee,
-                                      std::ostream& os) const
-{
-  if (m_beep_on_error)
-    os << "\a";
-
-  ee.display (octave_diary);
-  ee.display (os);
-}
-
 void error_system::display_exception (const execution_exception& ee) const
 {
   // FIXME: How should we handle beep_on_error?
--- a/libinterp/corefcn/error.h	Fri Dec 02 10:11:46 2022 -0500
+++ b/libinterp/corefcn/error.h	Fri Dec 02 10:12:40 2022 -0500
@@ -334,13 +334,6 @@
 
   OCTINTERP_API void save_exception (const execution_exception& ee);
 
-  // FIXME
-  //#if defined (OCTAVE_PROVIDE_DEPRECATED_SYMBOLS)
-  OCTAVE_DEPRECATED (7, "second argument is no longer accepted")
-  OCTINTERP_API void display_exception (const execution_exception& ee,
-                                        std::ostream& os) const;
-  //#endif
-
   OCTINTERP_API void display_exception (const execution_exception& ee) const;
 
 private:
@@ -573,44 +566,4 @@
 
 OCTAVE_END_NAMESPACE(octave)
 
-#if defined (OCTAVE_PROVIDE_DEPRECATED_SYMBOLS)
-OCTAVE_DEPRECATED (7, "use 'octave::defun_usage_message' instead")
-inline void defun_usage_message (const std::string& msg)
-{
-  octave::defun_usage_message (msg);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::set_warning_state' instead")
-inline octave_value_list
-set_warning_state (const std::string& id, const std::string& state)
-{
-  return octave::set_warning_state (id, state);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::set_warning_state' instead")
-inline octave_value_list set_warning_state (const octave_value_list& args)
-{
-  return octave::set_warning_state (args);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::warning_enabled' instead")
-inline int warning_enabled (const std::string& id)
-{
-  return octave::warning_enabled (id);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::disable_warning' instead")
-inline void disable_warning (const std::string& id)
-{
-  octave::disable_warning (id);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::interpreter_try' instead")
-inline void interpreter_try (octave::unwind_protect& uwp)
-{
-  octave::interpreter_try (uwp);
-}
-
 #endif
-
-#endif
--- a/libinterp/corefcn/graphics.in.h	Fri Dec 02 10:11:46 2022 -0500
+++ b/libinterp/corefcn/graphics.in.h	Fri Dec 02 10:12:40 2022 -0500
@@ -6958,164 +6958,4 @@
 
 OCTAVE_END_NAMESPACE(octave)
 
-#if defined (OCTAVE_PROVIDE_DEPRECATED_SYMBOLS)
-
-OCTAVE_DEPRECATED (7, "use 'octave::base_scaler' instead")
-typedef octave::base_scaler base_scaler;
-
-OCTAVE_DEPRECATED (7, "use 'octave::lin_scaler' instead")
-typedef octave::lin_scaler lin_scaler;
-
-OCTAVE_DEPRECATED (7, "use 'octave::log_scaler' instead")
-typedef octave::log_scaler log_scaler;
-
-OCTAVE_DEPRECATED (7, "use 'octave::neg_log_scaler' instead")
-typedef octave::neg_log_scaler neg_log_scaler;
-
-OCTAVE_DEPRECATED (7, "use 'octave::scaler' instead")
-typedef octave::scaler scaler;
-
-OCTAVE_DEPRECATED (7, "use 'octave::base_property' instead")
-typedef octave::base_property base_property;
-
-OCTAVE_DEPRECATED (7, "use 'octave::string_property' instead")
-typedef octave::string_property string_property;
-
-OCTAVE_DEPRECATED (7, "use 'octave::string_array_property' instead")
-typedef octave::string_array_property string_array_property;
-
-OCTAVE_DEPRECATED (7, "use 'octave::text_label_property' instead")
-typedef octave::text_label_property text_label_property;
-
-OCTAVE_DEPRECATED (7, "use 'octave::radio_values' instead")
-typedef octave::radio_values radio_values;
-
-OCTAVE_DEPRECATED (7, "use 'octave::radio_property' instead")
-typedef octave::radio_property radio_property;
-
-OCTAVE_DEPRECATED (7, "use 'octave::color_values' instead")
-typedef octave::color_values color_values;
-
-OCTAVE_DEPRECATED (7, "use 'octave::color_property' instead")
-typedef octave::color_property color_property;
-
-OCTAVE_DEPRECATED (7, "use 'octave::double_property' instead")
-typedef octave::double_property double_property;
-
-OCTAVE_DEPRECATED (7, "use 'octave::double_radio_property' instead")
-typedef octave::double_radio_property double_radio_property;
-
-OCTAVE_DEPRECATED (7, "use 'octave::array_property' instead")
-typedef octave::array_property array_property;
-
-OCTAVE_DEPRECATED (7, "use 'octave::row_vector_property' instead")
-typedef octave::row_vector_property row_vector_property;
-
-OCTAVE_DEPRECATED (7, "use 'octave::bool_property' instead")
-typedef octave::bool_property bool_property;
-
-OCTAVE_DEPRECATED (7, "use 'octave::handle_property' instead")
-typedef octave::handle_property handle_property;
-
-OCTAVE_DEPRECATED (7, "use 'octave::any_property' instead")
-typedef octave::any_property any_property;
-
-OCTAVE_DEPRECATED (7, "use 'octave::children_property' instead")
-typedef octave::children_property children_property;
-
-OCTAVE_DEPRECATED (7, "use 'octave::callback_property' instead")
-typedef octave::callback_property callback_property;
-
-OCTAVE_DEPRECATED (7, "use 'octave::property' instead")
-typedef octave::property property;
-
-OCTAVE_DEPRECATED (7, "use 'octave::pval_vector' instead")
-typedef octave::pval_vector pval_vector;
-
-OCTAVE_DEPRECATED (7, "use 'octave::property_list' instead")
-typedef octave::property_list property_list;
-
-OCTAVE_DEPRECATED (7, "use 'octave::base_properties' instead")
-typedef octave::base_properties base_properties;
-
-OCTAVE_DEPRECATED (7, "use 'octave::base_graphics_object' instead")
-typedef octave::base_graphics_object base_graphics_object;
-
-OCTAVE_DEPRECATED (7, "use 'octave::graphics_object' instead")
-typedef octave::graphics_object graphics_object;
-
-OCTAVE_DEPRECATED (7, "use 'octave::root_figure' instead")
-typedef octave::root_figure root_figure;
-
-OCTAVE_DEPRECATED (7, "use 'octave::figure' instead")
-typedef octave::figure figure;
-
-OCTAVE_DEPRECATED (7, "use 'octave::graphics_xform' instead")
-typedef octave::graphics_xform graphics_xform;
-
-OCTAVE_DEPRECATED (7, "use 'octave::axes' instead")
-typedef octave::axes axes;
-
-OCTAVE_DEPRECATED (7, "use 'octave::line' instead")
-typedef octave::line line;
-
-OCTAVE_DEPRECATED (7, "use 'octave::text' instead")
-typedef octave::text text;
-
-OCTAVE_DEPRECATED (7, "use 'octave::image' instead")
-typedef octave::image image;
-
-OCTAVE_DEPRECATED (7, "use 'octave::light' instead")
-typedef octave::light light;
-
-OCTAVE_DEPRECATED (7, "use 'octave::patch' instead")
-typedef octave::patch patch;
-
-OCTAVE_DEPRECATED (7, "use 'octave::scatter' instead")
-typedef octave::scatter scatter;
-
-OCTAVE_DEPRECATED (7, "use 'octave::surface' instead")
-typedef octave::surface surface;
-
-OCTAVE_DEPRECATED (7, "use 'octave::hggroup' instead")
-typedef octave::hggroup hggroup;
-
-OCTAVE_DEPRECATED (7, "use 'octave::uimenu' instead")
-typedef octave::uimenu uimenu;
-
-OCTAVE_DEPRECATED (7, "use 'octave::uicontextmenu' instead")
-typedef octave::uicontextmenu uicontextmenu;
-
-OCTAVE_DEPRECATED (7, "use 'octave::uicontrol' instead")
-typedef octave::uicontrol uicontrol;
-
-OCTAVE_DEPRECATED (7, "use 'octave::uibuttongroup' instead")
-typedef octave::uibuttongroup uibuttongroup;
-
-OCTAVE_DEPRECATED (7, "use 'octave::uipanel' instead")
-typedef octave::uipanel uipanel;
-
-OCTAVE_DEPRECATED (7, "use 'octave::uitable' instead")
-typedef octave::uitable uitable;
-
-OCTAVE_DEPRECATED (7, "use 'octave::uitoolbar' instead")
-typedef octave::uitoolbar uitoolbar;
-
-OCTAVE_DEPRECATED (7, "use 'octave::uipushtool' instead")
-typedef octave::uipushtool uipushtool;
-
-OCTAVE_DEPRECATED (7, "use 'octave::uitoggletool' instead")
-typedef octave::uitoggletool uitoggletool;
-
-OCTAVE_DEPRECATED (7, "use 'octave::base_graphics_event' instead")
-typedef octave::base_graphics_event base_graphics_event;
-
-OCTAVE_DEPRECATED (7, "use 'octave::graphics_event' instead")
-typedef octave::graphics_event graphics_event;
-
-OCTAVE_DEPRECATED (7, "use 'octave::gh_manager' instead")
-typedef octave::gh_manager gh_manager;
-
 #endif
-
-#endif
--- a/libinterp/corefcn/hook-fcn.h	Fri Dec 02 10:11:46 2022 -0500
+++ b/libinterp/corefcn/hook-fcn.h	Fri Dec 02 10:12:40 2022 -0500
@@ -214,21 +214,4 @@
 
 OCTAVE_END_NAMESPACE(octave)
 
-#if defined (OCTAVE_PROVIDE_DEPRECATED_SYMBOLS)
-OCTAVE_DEPRECATED (7, "use 'octave::base_hook_function' instead")
-typedef octave::base_hook_function base_hook_function;
-
-OCTAVE_DEPRECATED (7, "use 'octave::hook_function' instead")
-typedef octave::hook_function hook_function;
-
-OCTAVE_DEPRECATED (7, "use 'octave::named_hook_function' instead")
-typedef octave::named_hook_function named_hook_function;
-
-OCTAVE_DEPRECATED (7, "use 'octave::fcn_handle_hook_function' instead")
-typedef octave::fcn_handle_hook_function fcn_handle_hook_function;
-
-OCTAVE_DEPRECATED (7, "use 'octave::hook_function_list' instead")
-typedef octave::hook_function_list hook_function_list;
 #endif
-
-#endif
--- a/libinterp/corefcn/kron.cc	Fri Dec 02 10:11:46 2022 -0500
+++ b/libinterp/corefcn/kron.cc	Fri Dec 02 10:12:40 2022 -0500
@@ -275,6 +275,7 @@
 
 @noindent
 Since the Kronecker product is associative, this is well-defined.
+@seealso{tensorprod}
 @end deftypefn */)
 {
   int nargin = args.length ();
--- a/libinterp/corefcn/load-save.cc	Fri Dec 02 10:11:46 2022 -0500
+++ b/libinterp/corefcn/load-save.cc	Fri Dec 02 10:12:40 2022 -0500
@@ -2060,13 +2060,3 @@
 }
 
 OCTAVE_END_NAMESPACE(octave)
-
-// DEPRECATED in Octave 7
-
-void
-dump_octave_core (void)
-{
-  octave::load_save_system& load_save_sys = octave::__get_load_save_system__ ();
-
-  load_save_sys.dump_octave_core ();
-}
--- a/libinterp/corefcn/load-save.h	Fri Dec 02 10:11:46 2022 -0500
+++ b/libinterp/corefcn/load-save.h	Fri Dec 02 10:12:40 2022 -0500
@@ -294,7 +294,4 @@
 
 OCTAVE_END_NAMESPACE(octave)
 
-OCTAVE_DEPRECATED (7, "use 'load_save_system::dump_octave_core' instead")
-extern OCTINTERP_API void dump_octave_core (void);
-
 #endif
--- a/libinterp/corefcn/ls-ascii-helper.h	Fri Dec 02 10:11:46 2022 -0500
+++ b/libinterp/corefcn/ls-ascii-helper.h	Fri Dec 02 10:12:40 2022 -0500
@@ -44,29 +44,4 @@
 
 OCTAVE_END_NAMESPACE(octave)
 
-#if defined (OCTAVE_PROVIDE_DEPRECATED_SYMBOLS)
-
-OCTAVE_DEPRECATED (7, "use 'octave::skip_until_newline' instead")
-inline void
-skip_until_newline (std::istream& is, bool keep_newline = false)
-{
-  return octave::skip_until_newline (is, keep_newline);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::skip_preceding_newline' instead")
-inline void
-skip_preceeding_newline (std::istream& is)
-{
-  return octave::skip_preceeding_newline (is);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::read_until_newline' instead")
-inline std::string
-read_until_newline (std::istream& is, bool keep_newline = false)
-{
-  return octave::read_until_newline (is, keep_newline);
-}
-
 #endif
-
-#endif
--- a/libinterp/corefcn/ls-utils.h	Fri Dec 02 10:11:46 2022 -0500
+++ b/libinterp/corefcn/ls-utils.h	Fri Dec 02 10:12:40 2022 -0500
@@ -40,22 +40,4 @@
 
 OCTAVE_END_NAMESPACE(octave)
 
-#if defined (OCTAVE_PROVIDE_DEPRECATED_SYMBOLS)
-
-OCTAVE_DEPRECATED (7, "use 'octave::get_save_type' instead")
-inline save_type
-get_save_type (double max_val, double min_val)
-{
-  return octave::get_save_type (max_val, min_val);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::get_save_type' instead")
-inline save_type
-get_save_type (float max_val, float min_val)
-{
-  return octave::get_save_type (max_val, min_val);
-}
-
 #endif
-
-#endif
--- a/libinterp/corefcn/oct-fstrm.h	Fri Dec 02 10:11:46 2022 -0500
+++ b/libinterp/corefcn/oct-fstrm.h	Fri Dec 02 10:12:40 2022 -0500
@@ -90,11 +90,4 @@
 
 OCTAVE_END_NAMESPACE(octave)
 
-#if defined (OCTAVE_PROVIDE_DEPRECATED_SYMBOLS)
-
-OCTAVE_DEPRECATED (7, "use 'octave::fstream' instead")
-typedef octave::fstream octave_fstream;
-
 #endif
-
-#endif
--- a/libinterp/corefcn/oct-hdf5-types.h	Fri Dec 02 10:11:46 2022 -0500
+++ b/libinterp/corefcn/oct-hdf5-types.h	Fri Dec 02 10:12:40 2022 -0500
@@ -38,16 +38,6 @@
 
 OCTAVE_END_NAMESPACE(octave)
 
-#if defined (OCTAVE_PROVIDE_DEPRECATED_SYMBOLS)
-
-OCTAVE_DEPRECATED (7, "use 'octave::check_hdf5_types' instead")
-inline bool check_hdf5_types (bool warn = true)
-{
-  return octave::check_hdf5_types (warn);
-}
-
-#endif
-
 #endif
 
 // Available for C and C++.
--- a/libinterp/corefcn/oct-iostrm.h	Fri Dec 02 10:11:46 2022 -0500
+++ b/libinterp/corefcn/oct-iostrm.h	Fri Dec 02 10:12:40 2022 -0500
@@ -161,17 +161,4 @@
 
 OCTAVE_END_NAMESPACE(octave)
 
-#if defined (OCTAVE_PROVIDE_DEPRECATED_SYMBOLS)
-
-OCTAVE_DEPRECATED (7, "use 'octave::base_iostream' instead")
-typedef octave::base_iostream octave_base_iostream;
-
-OCTAVE_DEPRECATED (7, "use 'octave::istream' instead")
-typedef octave::istream octave_istream;
-
-OCTAVE_DEPRECATED (7, "use 'octave::ostream' instead")
-typedef octave::ostream octave_ostream;
-
 #endif
-
-#endif
--- a/libinterp/corefcn/oct-prcstrm.h	Fri Dec 02 10:11:46 2022 -0500
+++ b/libinterp/corefcn/oct-prcstrm.h	Fri Dec 02 10:12:40 2022 -0500
@@ -98,14 +98,4 @@
 
 OCTAVE_END_NAMESPACE(octave)
 
-#if defined (OCTAVE_PROVIDE_DEPRECATED_SYMBOLS)
-
-OCTAVE_DEPRECATED (7, "use 'octave::octave_iprocstream' instead")
-typedef octave::octave_iprocstream octave_iprocstream;
-
-OCTAVE_DEPRECATED (7, "use 'octave::octave_oprocstream' instead")
-typedef octave::octave_oprocstream octave_oprocstream;
-
 #endif
-
-#endif
--- a/libinterp/corefcn/oct-procbuf.h	Fri Dec 02 10:11:46 2022 -0500
+++ b/libinterp/corefcn/oct-procbuf.h	Fri Dec 02 10:12:40 2022 -0500
@@ -83,11 +83,4 @@
 
 OCTAVE_END_NAMESPACE(octave)
 
-#if defined (OCTAVE_PROVIDE_DEPRECATED_SYMBOLS)
-
-OCTAVE_DEPRECATED (7, "use octave::procbuf' instead")
-typedef octave::procbuf procbuf;
-
 #endif
-
-#endif
--- a/libinterp/corefcn/oct-stdstrm.h	Fri Dec 02 10:11:46 2022 -0500
+++ b/libinterp/corefcn/oct-stdstrm.h	Fri Dec 02 10:12:40 2022 -0500
@@ -199,14 +199,4 @@
 
 OCTAVE_END_NAMESPACE(octave)
 
-#if defined (OCTAVE_PROVIDE_DEPRECATED_SYMBOLS)
-
-OCTAVE_DEPRECATED (7, "use 'octave::stdiostream' instead")
-typedef octave::stdiostream octave_stdiostream;
-
-OCTAVE_DEPRECATED (7, "use 'octave::zstdiostream' instead")
-typedef octave::zstdiostream octave_zstdiostream;
-
 #endif
-
-#endif
--- a/libinterp/corefcn/oct-stream.cc	Fri Dec 02 10:11:46 2022 -0500
+++ b/libinterp/corefcn/oct-stream.cc	Fri Dec 02 10:12:40 2022 -0500
@@ -4288,6 +4288,9 @@
 {
   T value = T ();
 
+    is >> std::ws;  // skip through whitespace and advance stream pointer
+    std::streampos pos = is.tellg ();
+
   switch (fmt.type)
     {
     case 'o':
@@ -4301,11 +4304,7 @@
 
     case 'i':
       {
-        int c1 = std::istream::traits_type::eof ();
-
-        while (is && (c1 = is.get ()) != std::istream::traits_type::eof ()
-               && isspace (c1))
-          ; // skip whitespace
+          int c1 = is.get ();
 
         if (c1 != std::istream::traits_type::eof ())
           {
@@ -4354,18 +4353,33 @@
       break;
     }
 
-  // If conversion produces an integer that overflows, failbit is set but
-  // value is non-zero.  We want to treat this case as success, so clear
-  // failbit from the stream state to keep going.
-  // FIXME: Maybe set error state on octave stream as above? Matlab does
-  // *not* indicate an error message on overflow.
-  if ((is.rdstate () & std::ios::failbit) && value != T ())
-    is.clear (is.rdstate () & ~std::ios::failbit);
-
-  // Only copy the converted value if the stream is in a state where we
-  // want to continue reading.
-  if (! (is.rdstate () & std::ios::failbit))
-    *valptr = value;
+    std::ios::iostate status = is.rdstate ();
+    if (! (status & std::ios::failbit))
+      {
+        // Copy the converted value if the stream is in a good state
+        *valptr = value;
+      }
+    else
+      {
+        if (value != T ())
+          {
+            // If conversion produces an integer that overflows, failbit is set
+            // but value is non-zero.  We want to treat this case as success,
+            // so clear  failbit from the stream state to keep going.
+            // FIXME: Maybe set error state on octave stream?  Matlab does
+            // *not* indicate an error message on overflow.
+            is.clear (status & ~std::ios::failbit);
+            *valptr = value;
+          }
+        else
+          {
+            // True error.
+            // Reset stream to original position, clear eof bit, pass status on.
+            is.clear ();
+            is.seekg (pos);
+            is.setstate (status & ~std::ios_base::eofbit);
+          }
+      }
 
   return is;
 }
@@ -4433,17 +4447,20 @@
     case 'E':
     case 'G':
       {
-        int c1 = std::istream::traits_type::eof ();
-
-        while (is && (c1 = is.get ()) != std::istream::traits_type::eof ()
-               && isspace (c1))
-          ; // skip whitespace
-
-        if (c1 != std::istream::traits_type::eof ())
+          is >> std::ws;  // skip through whitespace and advance stream pointer
+          if (is.good ())
           {
-            is.putback (c1);
+              std::streampos pos = is.tellg ();
 
             ref = read_value<double> (is);
+
+              std::ios::iostate status = is.rdstate ();
+              if (status & std::ios::failbit)
+                {
+                  is.clear ();
+                  is.seekg (pos);
+                  is.setstate (status & ~std::ios_base::eofbit);
+                }
           }
       }
       break;
@@ -4497,11 +4514,16 @@
     {                                                                   \
       int c = std::istream::traits_type::eof ();                        \
                                                                         \
+      /* get all whitespace characters */                               \
       while (is && (c = is.get ()) != std::istream::traits_type::eof () \
              && isspace (c))                                            \
         { /* skip whitespace */ }                                       \
                                                                         \
-      if (c != std::istream::traits_type::eof ())                       \
+      if (c == std::istream::traits_type::eof ())                       \
+        /* reset failbit at eof */                                      \
+        is.clear (is.rdstate () & (~std::ios::failbit));                \
+      else                                                              \
+        /* put back non-whitespace character */                         \
         is.putback (c);                                                 \
     }                                                                   \
   while (0)
@@ -4566,8 +4588,8 @@
          && (c = is.get ()) != std::istream::traits_type::eof ())       \
     tmp[n++] = static_cast<char> (c);                                   \
                                                                         \
-  if (n > 0 && c == std::istream::traits_type::eof ())                  \
-    is.clear ();                                                        \
+  if (c == std::istream::traits_type::eof ())                           \
+    is.clear (is.rdstate () & (~std::ios::failbit));                    \
                                                                         \
   tmp.resize (n)
 
@@ -4609,8 +4631,8 @@
                 tmp[n++] = static_cast<char> (c);                       \
             }                                                           \
                                                                         \
-          if (n > 0 && c == std::istream::traits_type::eof ())          \
-            is.clear ();                                                \
+          if (c == std::istream::traits_type::eof ())                   \
+            is.clear (is.rdstate () & (~std::ios::failbit));            \
                                                                         \
           tmp.resize (n);                                               \
         }                                                               \
@@ -4623,15 +4645,13 @@
 
 // This format must match a nonempty sequence of characters.
 #define BEGIN_CHAR_CLASS_CONVERSION()                                   \
-  int width = elt->width;                                               \
+  int width = (elt->width ? elt->width                                  \
+                          : std::numeric_limits<int>::max ());          \
                                                                         \
   std::string tmp;                                                      \
                                                                         \
   do                                                                    \
     {                                                                   \
-      if (! width)                                                      \
-        width = std::numeric_limits<int>::max ();                       \
-                                                                        \
       std::ostringstream buf;                                           \
                                                                         \
       std::string char_class = elt->char_class;                         \
@@ -4642,29 +4662,39 @@
         {                                                               \
           int chars_read = 0;                                           \
           while (is && chars_read++ < width                             \
-                 && (c = is.get ()) != std::istream::traits_type::eof () \
-                 && char_class.find (c) != std::string::npos)           \
-            buf << static_cast<char> (c);                               \
+                 && (c = is.get ()) != std::istream::traits_type::eof ()) \
+            {                                                           \
+              if (char_class.find (c) != std::string::npos)             \
+                buf << static_cast<char> (c);                           \
+              else                                                      \
+                {                                                       \
+                  is.putback (c);                                       \
+                  break;                                                \
+                }                                                       \
+            }                                                           \
         }                                                               \
       else                                                              \
         {                                                               \
           int chars_read = 0;                                           \
           while (is && chars_read++ < width                             \
-                 && (c = is.get ()) != std::istream::traits_type::eof () \
-                 && char_class.find (c) == std::string::npos)           \
-            buf << static_cast<char> (c);                               \
+                 && (c = is.get ()) != std::istream::traits_type::eof ()) \
+            {                                                           \
+              if (char_class.find (c) == std::string::npos)             \
+                buf << static_cast<char> (c);                           \
+              else                                                      \
+                {                                                       \
+                  is.putback (c);                                       \
+                  break;                                                \
+                }                                                       \
+            }                                                           \
         }                                                               \
                                                                         \
-      if (width == std::numeric_limits<int>::max ()                     \
-          && c != std::istream::traits_type::eof ())                    \
-        is.putback (c);                                                 \
-                                                                        \
       tmp = buf.str ();                                                 \
                                                                         \
       if (tmp.empty ())                                                 \
         is.setstate (std::ios::failbit);                                \
       else if (c == std::istream::traits_type::eof ())                  \
-        is.clear ();                                                    \
+        is.clear (is.rdstate () & (~std::ios::failbit));                \
                                                                         \
     }                                                                   \
   while (0)
@@ -4676,7 +4706,7 @@
         tmp = string::u8_from_encoding (who, tmp, encoding ());         \
       width = tmp.length ();                                            \
                                                                         \
-      if (is)                                                           \
+      if (is && width > 0)                                              \
         {                                                               \
           int i = 0;                                                    \
                                                                         \
@@ -5048,10 +5078,10 @@
 
                   // If it looks like we have a matching failure, then
                   // reset the failbit in the stream state.
-                  if (! is.eof () && is.rdstate () & std::ios::failbit)
+                    if (is.rdstate () & std::ios::failbit)
                     {
-                      error (who, "format failed to match");
                       is.clear (is.rdstate () & (~std::ios::failbit));
+                        error (who, "format failed to match");
                     }
 
                   // FIXME: is this the right thing to do?
--- a/libinterp/corefcn/oct-strstrm.h	Fri Dec 02 10:11:46 2022 -0500
+++ b/libinterp/corefcn/oct-strstrm.h	Fri Dec 02 10:12:40 2022 -0500
@@ -194,17 +194,4 @@
 
 OCTAVE_END_NAMESPACE(octave)
 
-#if defined (OCTAVE_PROVIDE_DEPRECATED_SYMBOLS)
-
-OCTAVE_DEPRECATED (7, "use 'octave::base_strstream' instead")
-typedef octave::base_strstream octave_base_strstream;
-
-OCTAVE_DEPRECATED (7, "use 'octave::istrstream' instead")
-typedef octave::istrstream octave_istrstream;
-
-OCTAVE_DEPRECATED (7, "use 'octave::ostrstream' instead")
-typedef octave::ostrstream octave_ostrstream;
-
 #endif
-
-#endif
--- a/libinterp/corefcn/procstream.h	Fri Dec 02 10:11:46 2022 -0500
+++ b/libinterp/corefcn/procstream.h	Fri Dec 02 10:12:40 2022 -0500
@@ -187,20 +187,4 @@
 
 OCTAVE_END_NAMESPACE(octave)
 
-#if defined (OCTAVE_PROVIDE_DEPRECATED_SYMBOLS)
-
-OCTAVE_DEPRECATED (7, "use 'octave::procstreambase' instead")
-typedef octave::procstreambase procstreambase;
-
-OCTAVE_DEPRECATED (7, "use 'octave::iprocstream' instead")
-typedef octave::iprocstream iprocstream;
-
-OCTAVE_DEPRECATED (7, "use 'octave::oprocstream' instead")
-typedef octave::oprocstream oprocstream;
-
-OCTAVE_DEPRECATED (7, "use 'octave::procstream' instead")
-typedef octave::procstream procstream;
-
 #endif
-
-#endif
--- a/libinterp/corefcn/sparse-xdiv.h	Fri Dec 02 10:11:46 2022 -0500
+++ b/libinterp/corefcn/sparse-xdiv.h	Fri Dec 02 10:12:40 2022 -0500
@@ -104,207 +104,4 @@
 
 OCTAVE_END_NAMESPACE(octave)
 
-#if defined (OCTAVE_PROVIDE_DEPRECATED_SYMBOLS)
-
-OCTAVE_DEPRECATED (7, "use 'octave::xdiv' instead")
-inline Matrix
-xdiv (const Matrix& a, const SparseMatrix& b, MatrixType& typ)
-{
-  return octave::xdiv (a, b, typ);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::xdiv' instead")
-inline ComplexMatrix
-xdiv (const Matrix& a, const SparseComplexMatrix& b, MatrixType& typ)
-{
-  return octave::xdiv (a, b, typ);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::xdiv' instead")
-inline ComplexMatrix
-xdiv (const ComplexMatrix& a, const SparseMatrix& b, MatrixType& typ)
-{
-  return octave::xdiv (a, b, typ);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::xdiv' instead")
-inline ComplexMatrix
-xdiv (const ComplexMatrix& a, const SparseComplexMatrix& b, MatrixType& typ)
-{
-  return octave::xdiv (a, b, typ);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::xdiv' instead")
-inline SparseMatrix
-xdiv (const SparseMatrix& a, const SparseMatrix& b, MatrixType& typ)
-{
-  return octave::xdiv (a, b, typ);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::xdiv' instead")
-inline SparseComplexMatrix
-xdiv (const SparseMatrix& a, const SparseComplexMatrix& b, MatrixType& typ)
-{
-  return octave::xdiv (a, b, typ);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::xdiv' instead")
-inline SparseComplexMatrix
-xdiv (const SparseComplexMatrix& a, const SparseMatrix& b, MatrixType& typ)
-{
-  return octave::xdiv (a, b, typ);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::xdiv' instead")
-inline SparseComplexMatrix
-xdiv (const SparseComplexMatrix& a, const SparseComplexMatrix& b,
-      MatrixType& typ)
-{
-  return octave::xdiv (a, b, typ);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::xdiv' instead")
-inline SparseMatrix
-xdiv (const SparseMatrix& a, const DiagMatrix& b, MatrixType& typ)
-{
-  return octave::xdiv (a, b, typ);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::xdiv' instead")
-inline SparseComplexMatrix
-xdiv (const SparseMatrix& a, const ComplexDiagMatrix& b, MatrixType& typ)
-{
-  return octave::xdiv (a, b, typ);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::xdiv' instead")
-inline SparseComplexMatrix
-xdiv (const SparseComplexMatrix& a, const DiagMatrix& b, MatrixType& typ)
-{
-  return octave::xdiv (a, b, typ);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::xdiv' instead")
-inline SparseComplexMatrix
-xdiv (const SparseComplexMatrix& a, const ComplexDiagMatrix& b, MatrixType& typ)
-{
-  return octave::xdiv (a, b, typ);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::elem_xdiv' instead")
-inline Matrix
-x_el_div (double a, const SparseMatrix& b)
-{
-  return octave::elem_xdiv (a, b);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::elem_xdiv' instead")
-inline ComplexMatrix
-x_el_div (double a, const SparseComplexMatrix& b)
-{
-  return octave::elem_xdiv (a, b);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::elem_xdiv' instead")
-inline ComplexMatrix
-x_el_div (const Complex& a, const SparseMatrix& b)
-{
-  return octave::elem_xdiv (a, b);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::elem_xdiv' instead")
-inline ComplexMatrix
-x_el_div (const Complex& a, const SparseComplexMatrix& b)
-{
-  return octave::elem_xdiv (a, b);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::xleftdiv' instead")
-inline Matrix
-xleftdiv (const SparseMatrix& a, const Matrix& b, MatrixType& typ)
-{
-  return octave::xleftdiv (a, b, typ);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::xleftdiv' instead")
-inline ComplexMatrix
-xleftdiv (const SparseMatrix& a, const ComplexMatrix& b, MatrixType& typ)
-{
-  return octave::xleftdiv (a, b, typ);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::xleftdiv' instead")
-inline ComplexMatrix
-xleftdiv (const SparseComplexMatrix& a, const Matrix& b, MatrixType& typ)
-{
-  return octave::xleftdiv (a, b, typ);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::xleftdiv' instead")
-inline ComplexMatrix
-xleftdiv (const SparseComplexMatrix& a, const ComplexMatrix& b, MatrixType& typ)
-{
-  return octave::xleftdiv (a, b, typ);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::xleftdiv' instead")
-inline SparseMatrix
-xleftdiv (const SparseMatrix& a, const SparseMatrix& b, MatrixType& typ)
-{
-  return octave::xleftdiv (a, b, typ);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::xleftdiv' instead")
-inline SparseComplexMatrix
-xleftdiv (const SparseMatrix& a, const SparseComplexMatrix& b, MatrixType& typ)
-{
-  return octave::xleftdiv (a, b, typ);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::xleftdiv' instead")
-inline SparseComplexMatrix
-xleftdiv (const SparseComplexMatrix& a, const SparseMatrix& b, MatrixType& typ)
-{
-  return octave::xleftdiv (a, b, typ);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::xleftdiv' instead")
-inline SparseComplexMatrix
-xleftdiv (const SparseComplexMatrix& a, const SparseComplexMatrix& b,
-          MatrixType& typ)
-{
-  return octave::xleftdiv (a, b, typ);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::xleftdiv' instead")
-inline SparseMatrix
-xleftdiv (const DiagMatrix& a, const SparseMatrix& b, MatrixType& typ)
-{
-  return octave::xleftdiv (a, b, typ);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::xleftdiv' instead")
-inline SparseComplexMatrix
-xleftdiv (const ComplexDiagMatrix& a, const SparseMatrix& b, MatrixType& typ)
-{
-  return octave::xleftdiv (a, b, typ);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::xleftdiv' instead")
-inline SparseComplexMatrix
-xleftdiv (const DiagMatrix& a, const SparseComplexMatrix& b, MatrixType& typ)
-{
-  return octave::xleftdiv (a, b, typ);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::xleftdiv' instead")
-inline SparseComplexMatrix
-xleftdiv (const ComplexDiagMatrix& a, const SparseComplexMatrix& b,
-          MatrixType& typ)
-{
-  return octave::xleftdiv (a, b, typ);
-}
-
 #endif
-
-#endif
--- a/libinterp/corefcn/sparse-xpow.h	Fri Dec 02 10:11:46 2022 -0500
+++ b/libinterp/corefcn/sparse-xpow.h	Fri Dec 02 10:12:40 2022 -0500
@@ -62,106 +62,4 @@
 
 OCTAVE_END_NAMESPACE(octave)
 
-#if (OCTAVE_PROVIDE_DEPRECATED_SYMBOLS)
-
-OCTAVE_DEPRECATED (7, "use 'octave::xpow' instead")
-inline octave_value
-xpow (const SparseMatrix& a, double b)
-{
-  return octave::xpow (a, b);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::xpow' instead")
-inline octave_value
-xpow (const SparseComplexMatrix& a, double b)
-{
-  return octave::xpow (a, b);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::elem_xpow' instead")
-inline octave_value
-elem_xpow (double a, const SparseMatrix& b)
-{
-  return octave::elem_xpow (a, b);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::elem_xpow' instead")
-inline octave_value
-elem_xpow (double a, const SparseComplexMatrix& b)
-{
-  return octave::elem_xpow (a, b);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::elem_xpow' instead")
-inline octave_value
-elem_xpow (const SparseMatrix& a, double b)
-{
-  return octave::elem_xpow (a, b);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::elem_xpow' instead")
-inline octave_value
-elem_xpow (const SparseMatrix& a, const SparseMatrix& b)
-{
-  return octave::elem_xpow (a, b);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::elem_xpow' instead")
-inline octave_value
-elem_xpow (const SparseMatrix& a, const Complex& b)
-{
-  return octave::elem_xpow (a, b);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::elem_xpow' instead")
-inline octave_value
-elem_xpow (const SparseMatrix& a, const SparseComplexMatrix& b)
-{
-  return octave::elem_xpow (a, b);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::elem_xpow' instead")
-inline octave_value
-elem_xpow (const Complex& a, const SparseMatrix& b)
-{
-  return octave::elem_xpow (a, b);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::elem_xpow' instead")
-inline octave_value
-elem_xpow (const Complex& a, const SparseComplexMatrix& b)
-{
-  return octave::elem_xpow (a, b);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::elem_xpow' instead")
-inline octave_value
-elem_xpow (const SparseComplexMatrix& a, double b)
-{
-  return octave::elem_xpow (a, b);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::elem_xpow' instead")
-inline octave_value
-elem_xpow (const SparseComplexMatrix& a, const SparseMatrix& b)
-{
-  return octave::elem_xpow (a, b);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::elem_xpow' instead")
-inline octave_value
-elem_xpow (const SparseComplexMatrix& a, const Complex& b)
-{
-  return octave::elem_xpow (a, b);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::elem_xpow' instead")
-inline octave_value
-elem_xpow (const SparseComplexMatrix& a, const SparseComplexMatrix& b)
-{
-  return octave::elem_xpow (a, b);
-}
-
 #endif
-
-#endif
--- a/libinterp/corefcn/variables.h	Fri Dec 02 10:11:46 2022 -0500
+++ b/libinterp/corefcn/variables.h	Fri Dec 02 10:12:40 2022 -0500
@@ -107,91 +107,6 @@
 
 OCTAVE_END_NAMESPACE(octave)
 
-#if defined (OCTAVE_PROVIDE_DEPRECATED_SYMBOLS)
-
-OCTAVE_DEPRECATED (7, "use 'octave::symbol_exist' instead")
-inline int
-symbol_exist (const std::string& name, const std::string& type = "any")
-{
-  return octave::symbol_exist (name, type);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::unique_symbol_name' instead")
-inline std::string
-unique_symbol_name (const std::string& basename)
-{
-  return octave::unique_symbol_name (basename);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::set_internal_variable' instead")
-inline octave_value
-set_internal_variable (bool& var, const octave_value_list& args, int nargout,
-                       const char *nm)
-{
-  return octave::set_internal_variable (var, args, nargout, nm);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::set_internal_variable' instead")
-inline octave_value
-set_internal_variable (char& var, const octave_value_list& args, int nargout,
-                       const char *nm)
-{
-  return octave::set_internal_variable (var, args, nargout, nm);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::set_internal_variable' instead")
-inline octave_value
-set_internal_variable (int& var, const octave_value_list& args, int nargout,
-                       const char *nm,
-                       int minval = std::numeric_limits<int>::min (),
-                       int maxval = std::numeric_limits<int>::max ())
-{
-  return octave::set_internal_variable (var, args, nargout, nm, minval, maxval);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::set_internal_variable' instead")
-inline octave_value
-set_internal_variable (double& var, const octave_value_list& args, int nargout,
-                       const char *nm,
-                       double minval = -octave::numeric_limits<double>::Inf (),
-                       double maxval = octave::numeric_limits<double>::Inf ())
-{
-  return octave::set_internal_variable (var, args, nargout, nm, minval, maxval);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::set_internal_variable' instead")
-inline octave_value
-set_internal_variable (std::string& var, const octave_value_list& args,
-                       int nargout, const char *nm, bool empty_ok = true)
-{
-  return octave::set_internal_variable (var, args, nargout, nm, empty_ok);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::set_internal_variable' instead")
-inline octave_value
-set_internal_variable (std::string& var, const octave_value_list& args,
-                       int nargout, const char *nm, const char **choices)
-{
-  return octave::set_internal_variable (var, args, nargout, nm, choices);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::set_internal_variable' instead")
-inline octave_value
-set_internal_variable (int& var, const octave_value_list& args, int nargout,
-                       const char *nm, const char **choices)
-{
-  return octave::set_internal_variable (var, args, nargout, nm, choices);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::maybe_missing_function_hook' instead")
-inline std::string
-maybe_missing_function_hook (const std::string& name)
-{
-  return octave::maybe_missing_function_hook (name);
-}
-
-#endif
-
 // The following macros should also be considered obsolete.
 
 #define SET_INTERNAL_VARIABLE(NM)                       \
--- a/libinterp/corefcn/xdiv.h	Fri Dec 02 10:11:46 2022 -0500
+++ b/libinterp/corefcn/xdiv.h	Fri Dec 02 10:12:40 2022 -0500
@@ -156,415 +156,4 @@
 
 OCTAVE_END_NAMESPACE(octave)
 
-#if defined (OCTAVE_PROVIDE_DEPRECATED_SYMBOLS)
-
-OCTAVE_DEPRECATED (7, "use 'octave::xdiv' instead")
-inline Matrix
-xdiv (const Matrix& a, const Matrix& b, MatrixType& typ)
-{
-  return octave::xdiv (a, b, typ);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::xdiv' instead")
-inline ComplexMatrix
-xdiv (const Matrix& a, const ComplexMatrix& b, MatrixType& typ)
-{
-  return octave::xdiv (a, b, typ);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::xdiv' instead")
-inline ComplexMatrix
-xdiv (const ComplexMatrix& a, const Matrix& b, MatrixType& typ)
-{
-  return octave::xdiv (a, b, typ);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::xdiv' instead")
-inline ComplexMatrix
-xdiv (const ComplexMatrix& a, const ComplexMatrix& b, MatrixType& typ)
-{
-  return octave::xdiv (a, b, typ);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::elem_xdiv' instead")
-inline Matrix
-x_el_div (double a, const Matrix& b)
-{
-  return octave::elem_xdiv (a, b);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::elem_xdiv' instead")
-inline ComplexMatrix
-x_el_div (double a, const ComplexMatrix& b)
-{
-  return octave::elem_xdiv (a, b);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::elem_xdiv' instead")
-inline ComplexMatrix
-x_el_div (const Complex a, const Matrix& b)
-{
-  return octave::elem_xdiv (a, b);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::elem_xdiv' instead")
-inline ComplexMatrix
-x_el_div (const Complex a, const ComplexMatrix& b)
-{
-  return octave::elem_xdiv (a, b);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::elem_xdiv' instead")
-inline NDArray
-x_el_div (double a, const NDArray& b)
-{
-  return octave::elem_xdiv (a, b);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::elem_xdiv' instead")
-inline ComplexNDArray
-x_el_div (double a, const ComplexNDArray& b)
-{
-  return octave::elem_xdiv (a, b);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::elem_xdiv' instead")
-inline ComplexNDArray
-x_el_div (const Complex a, const NDArray& b)
-{
-  return octave::elem_xdiv (a, b);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::elem_xdiv' instead")
-inline ComplexNDArray
-x_el_div (const Complex a, const ComplexNDArray& b)
-{
-  return octave::elem_xdiv (a, b);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::xleftdiv' instead")
-inline Matrix
-xleftdiv (const Matrix& a, const Matrix& b,
-          MatrixType& typ, blas_trans_type transt = blas_no_trans)
-{
-  return octave::xleftdiv (a, b, typ, transt);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::xleftdiv' instead")
-inline ComplexMatrix
-xleftdiv (const Matrix& a, const ComplexMatrix& b,
-          MatrixType& typ, blas_trans_type transt = blas_no_trans)
-{
-  return octave::xleftdiv (a, b, typ, transt);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::xleftdiv' instead")
-inline ComplexMatrix
-xleftdiv (const ComplexMatrix& a, const Matrix& b,
-          MatrixType& typ, blas_trans_type transt = blas_no_trans)
-{
-  return octave::xleftdiv (a, b, typ, transt);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::xleftdiv' instead")
-inline ComplexMatrix
-xleftdiv (const ComplexMatrix& a, const ComplexMatrix& b,
-          MatrixType& typ, blas_trans_type transt = blas_no_trans)
-{
-  return octave::xleftdiv (a, b, typ, transt);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::xdiv' instead")
-inline FloatMatrix
-xdiv (const FloatMatrix& a, const FloatMatrix& b, MatrixType& typ)
-{
-  return octave::xdiv (a, b, typ);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::xdiv' instead")
-inline FloatComplexMatrix
-xdiv (const FloatMatrix& a, const FloatComplexMatrix& b, MatrixType& typ)
-{
-  return octave::xdiv (a, b, typ);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::xdiv' instead")
-inline FloatComplexMatrix
-xdiv (const FloatComplexMatrix& a, const FloatMatrix& b, MatrixType& typ)
-{
-  return octave::xdiv (a, b, typ);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::xdiv' instead")
-inline FloatComplexMatrix
-xdiv (const FloatComplexMatrix& a, const FloatComplexMatrix& b, MatrixType& typ)
-{
-  return octave::xdiv (a, b, typ);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::elem_xdiv' instead")
-inline FloatMatrix
-x_el_div (float a, const FloatMatrix& b)
-{
-  return octave::elem_xdiv (a, b);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::elem_xdiv' instead")
-inline FloatComplexMatrix
-x_el_div (float a, const FloatComplexMatrix& b)
-{
-  return octave::elem_xdiv (a, b);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::elem_xdiv' instead")
-inline FloatComplexMatrix
-x_el_div (const FloatComplex a, const FloatMatrix& b)
-{
-  return octave::elem_xdiv (a, b);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::elem_xdiv' instead")
-inline FloatComplexMatrix
-x_el_div (const FloatComplex a, const FloatComplexMatrix& b)
-{
-  return octave::elem_xdiv (a, b);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::elem_xdiv' instead")
-inline FloatNDArray
-x_el_div (float a, const FloatNDArray& b)
-{
-  return octave::elem_xdiv (a, b);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::elem_xdiv' instead")
-inline FloatComplexNDArray
-x_el_div (float a, const FloatComplexNDArray& b)
-{
-  return octave::elem_xdiv (a, b);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::elem_xdiv' instead")
-inline FloatComplexNDArray
-x_el_div (const FloatComplex a, const FloatNDArray& b)
-{
-  return octave::elem_xdiv (a, b);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::elem_xdiv' instead")
-inline FloatComplexNDArray
-x_el_div (const FloatComplex a, const FloatComplexNDArray& b)
-{
-  return octave::elem_xdiv (a, b);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::xleftdiv' instead")
-inline FloatMatrix
-xleftdiv (const FloatMatrix& a, const FloatMatrix& b,
-          MatrixType& typ, blas_trans_type transt = blas_no_trans)
-{
-  return octave::xleftdiv (a, b, typ, transt);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::xleftdiv' instead")
-inline FloatComplexMatrix
-xleftdiv (const FloatMatrix& a, const FloatComplexMatrix& b,
-          MatrixType& typ, blas_trans_type transt = blas_no_trans)
-{
-  return octave::xleftdiv (a, b, typ, transt);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::xleftdiv' instead")
-inline FloatComplexMatrix
-xleftdiv (const FloatComplexMatrix& a, const FloatMatrix& b,
-          MatrixType& typ, blas_trans_type transt = blas_no_trans)
-{
-  return octave::xleftdiv (a, b, typ, transt);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::xleftdiv' instead")
-inline FloatComplexMatrix
-xleftdiv (const FloatComplexMatrix& a, const FloatComplexMatrix& b,
-          MatrixType& typ, blas_trans_type transt = blas_no_trans)
-{
-  return octave::xleftdiv (a, b, typ, transt);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::xdiv' instead")
-inline Matrix
-xdiv (const Matrix& a, const DiagMatrix& b)
-{
-  return octave::xdiv (a, b);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::xdiv' instead")
-inline ComplexMatrix
-xdiv (const ComplexMatrix& a, const DiagMatrix& b)
-{
-  return octave::xdiv (a, b);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::xdiv' instead")
-inline ComplexMatrix
-xdiv (const ComplexMatrix& a, const ComplexDiagMatrix& b)
-{
-  return octave::xdiv (a, b);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::xdiv' instead")
-inline DiagMatrix
-xdiv (const DiagMatrix& a, const DiagMatrix& b)
-{
-  return octave::xdiv (a, b);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::xdiv' instead")
-inline ComplexDiagMatrix
-xdiv (const ComplexDiagMatrix& a, const DiagMatrix& b)
-{
-  return octave::xdiv (a, b);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::xdiv' instead")
-inline ComplexDiagMatrix
-xdiv (const ComplexDiagMatrix& a, const ComplexDiagMatrix& b)
-{
-  return octave::xdiv (a, b);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::xdiv' instead")
-inline FloatMatrix
-xdiv (const FloatMatrix& a, const FloatDiagMatrix& b)
-{
-  return octave::xdiv (a, b);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::xdiv' instead")
-inline FloatComplexMatrix
-xdiv (const FloatComplexMatrix& a, const FloatDiagMatrix& b)
-{
-  return octave::xdiv (a, b);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::xdiv' instead")
-inline FloatComplexMatrix
-xdiv (const FloatMatrix& a, const FloatComplexDiagMatrix& b)
-{
-  return octave::xdiv (a, b);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::xdiv' instead")
-inline FloatComplexMatrix
-xdiv (const FloatComplexMatrix& a, const FloatComplexDiagMatrix& b)
-{
-  return octave::xdiv (a, b);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::xdiv' instead")
-inline FloatDiagMatrix
-xdiv (const FloatDiagMatrix& a, const FloatDiagMatrix& b)
-{
-  return octave::xdiv (a, b);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::xdiv' instead")
-inline FloatComplexDiagMatrix
-xdiv (const FloatComplexDiagMatrix& a, const FloatDiagMatrix& b)
-{
-  return octave::xdiv (a, b);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::xdiv' instead")
-inline FloatComplexDiagMatrix
-xdiv (const FloatComplexDiagMatrix& a, const FloatComplexDiagMatrix& b)
-{
-  return octave::xdiv (a, b);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::xleftdiv' instead")
-inline Matrix
-xleftdiv (const DiagMatrix& a, const Matrix& b)
-{
-  return octave::xleftdiv (a, b);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::xleftdiv' instead")
-inline ComplexMatrix
-xleftdiv (const DiagMatrix& a, const ComplexMatrix& b)
-{
-  return octave::xleftdiv (a, b);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::xleftdiv' instead")
-inline ComplexMatrix
-xleftdiv (const ComplexDiagMatrix& a, const ComplexMatrix& b)
-{
-  return octave::xleftdiv (a, b);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::xleftdiv' instead")
-inline DiagMatrix
-xleftdiv (const DiagMatrix& a, const DiagMatrix& b)
-{
-  return octave::xleftdiv (a, b);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::xleftdiv' instead")
-inline ComplexDiagMatrix
-xleftdiv (const DiagMatrix& a, const ComplexDiagMatrix& b)
-{
-  return octave::xleftdiv (a, b);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::xleftdiv' instead")
-inline ComplexDiagMatrix
-xleftdiv (const ComplexDiagMatrix& a, const ComplexDiagMatrix& b)
-{
-  return octave::xleftdiv (a, b);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::xleftdiv' instead")
-inline FloatMatrix
-xleftdiv (const FloatDiagMatrix& a, const FloatMatrix& b)
-{
-  return octave::xleftdiv (a, b);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::xleftdiv' instead")
-inline FloatComplexMatrix
-xleftdiv (const FloatDiagMatrix& a, const FloatComplexMatrix& b)
-{
-  return octave::xleftdiv (a, b);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::xleftdiv' instead")
-inline FloatComplexMatrix
-xleftdiv (const FloatComplexDiagMatrix& a, const FloatComplexMatrix& b)
-{
-  return octave::xleftdiv (a, b);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::xleftdiv' instead")
-inline FloatDiagMatrix
-xleftdiv (const FloatDiagMatrix& a, const FloatDiagMatrix& b)
-{
-  return octave::xleftdiv (a, b);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::xleftdiv' instead")
-inline FloatComplexDiagMatrix
-xleftdiv (const FloatDiagMatrix& a, const FloatComplexDiagMatrix& b)
-{
-  return octave::xleftdiv (a, b);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::xleftdiv' instead")
-inline FloatComplexDiagMatrix
-xleftdiv (const FloatComplexDiagMatrix& a, const FloatComplexDiagMatrix& b)
-{
-  return octave::xleftdiv (a, b);
-}
-
 #endif
-
-#endif
--- a/libinterp/corefcn/xnorm.h	Fri Dec 02 10:11:46 2022 -0500
+++ b/libinterp/corefcn/xnorm.h	Fri Dec 02 10:12:40 2022 -0500
@@ -48,36 +48,4 @@
 
 OCTAVE_END_NAMESPACE(octave)
 
-#if defined (OCTAVE_PROVIDE_DEPRECATED_SYMBOLS)
-
-OCTAVE_DEPRECATED (7, "use 'octave::xnorm' instead")
-inline octave_value
-xnorm (const octave_value& x, const octave_value& p)
-{
-  return octave::xnorm (x, p);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::xcolnorms' instead")
-inline octave_value
-xcolnorms (const octave_value& x, const octave_value& p)
-{
-  return octave::xcolnorms (x, p);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::xrownorms' instead")
-inline octave_value
-xrownorms (const octave_value& x, const octave_value& p)
-{
-  return octave::xrownorms (x, p);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::xfrobnorm' instead")
-inline octave_value
-xfrobnorm (const octave_value& x)
-{
-  return octave::xfrobnorm (x);
-}
-
 #endif
-
-#endif
--- a/libinterp/corefcn/xpow.h	Fri Dec 02 10:11:46 2022 -0500
+++ b/libinterp/corefcn/xpow.h	Fri Dec 02 10:12:40 2022 -0500
@@ -44,7 +44,6 @@
 class ComplexNDArray;
 class FloatComplexNDArray;
 class octave_value;
-class Range;
 
 OCTAVE_BEGIN_NAMESPACE(octave)
 
@@ -209,589 +208,4 @@
 
 OCTAVE_END_NAMESPACE(octave)
 
-#if defined (OCTAVE_PROVIDE_DEPRECATED_SYMBOLS)
-
-OCTAVE_DEPRECATED (7, "use 'octave::xpow' instead")
-inline octave_value
-xpow (double a, double b)
-{
-  return octave::xpow (a, b);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::xpow' instead")
-inline octave_value
-xpow (double a, const Matrix& b)
-{
-  return octave::xpow (a, b);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::xpow' instead")
-inline octave_value
-xpow (double a, const Complex& b)
-{
-  return octave::xpow (a, b);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::xpow' instead")
-inline octave_value
-xpow (double a, const ComplexMatrix& b)
-{
-  return octave::xpow (a, b);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::xpow' instead")
-inline octave_value
-xpow (const Matrix& a, double b)
-{
-  return octave::xpow (a, b);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::xpow' instead")
-inline octave_value
-xpow (const Matrix& a, const Complex& b)
-{
-  return octave::xpow (a, b);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::xpow' instead")
-inline octave_value
-xpow (const DiagMatrix& a, double b)
-{
-  return octave::xpow (a, b);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::xpow' instead")
-inline octave_value
-xpow (const DiagMatrix& a, const Complex& b)
-{
-  return octave::xpow (a, b);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::xpow' instead")
-inline octave_value
-xpow (const PermMatrix& a, double b)
-{
-  return octave::xpow (a, b);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::xpow' instead")
-inline octave_value
-xpow (const Complex& a, double b)
-{
-  return octave::xpow (a, b);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::xpow' instead")
-inline octave_value
-xpow (const Complex& a, const Matrix& b)
-{
-  return octave::xpow (a, b);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::xpow' instead")
-inline octave_value
-xpow (const Complex& a, const Complex& b)
-{
-  return octave::xpow (a, b);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::xpow' instead")
-inline octave_value
-xpow (const Complex& a, const ComplexMatrix& b)
-{
-  return octave::xpow (a, b);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::xpow' instead")
-inline octave_value
-xpow (const ComplexMatrix& a, double b)
-{
-  return octave::xpow (a, b);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::xpow' instead")
-inline octave_value
-xpow (const ComplexMatrix& a, const Complex& b)
-{
-  return octave::xpow (a, b);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::xpow' instead")
-inline octave_value
-xpow (const ComplexDiagMatrix& a, double b)
-{
-  return octave::xpow (a, b);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::xpow' instead")
-inline octave_value
-xpow (const ComplexDiagMatrix& a, const Complex& b)
-{
-  return octave::xpow (a, b);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::elem_xpow' instead")
-inline octave_value
-elem_xpow (double a, const Matrix& b)
-{
-  return octave::elem_xpow (a, b);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::elem_xpow' instead")
-inline octave_value
-elem_xpow (double a, const ComplexMatrix& b)
-{
-  return octave::elem_xpow (a, b);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::elem_xpow' instead")
-inline octave_value
-elem_xpow (double a, const octave::range<double>& r)
-{
-  return octave::elem_xpow (a, r);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::elem_xpow' instead")
-inline octave_value
-elem_xpow (const Matrix& a, double b)
-{
-  return octave::elem_xpow (a, b);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::elem_xpow' instead")
-inline octave_value
-elem_xpow (const Matrix& a, const Matrix& b)
-{
-  return octave::elem_xpow (a, b);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::elem_xpow' instead")
-inline octave_value
-elem_xpow (const Matrix& a, const Complex& b)
-{
-  return octave::elem_xpow (a, b);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::elem_xpow' instead")
-inline octave_value
-elem_xpow (const Matrix& a, const ComplexMatrix& b)
-{
-  return octave::elem_xpow (a, b);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::elem_xpow' instead")
-inline octave_value
-elem_xpow (const Complex& a, const Matrix& b)
-{
-  return octave::elem_xpow (a, b);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::elem_xpow' instead")
-inline octave_value
-elem_xpow (const Complex& a, const ComplexMatrix& b)
-{
-  return octave::elem_xpow (a, b);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::elem_xpow' instead")
-inline octave_value
-elem_xpow (const Complex& a, const octave::range<double>& r)
-{
-  return octave::elem_xpow (a, r);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::elem_xpow' instead")
-inline octave_value
-elem_xpow (const ComplexMatrix& a, double b)
-{
-  return octave::elem_xpow (a, b);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::elem_xpow' instead")
-inline octave_value
-elem_xpow (const ComplexMatrix& a, const Matrix& b)
-{
-  return octave::elem_xpow (a, b);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::elem_xpow' instead")
-inline octave_value
-elem_xpow (const ComplexMatrix& a, const Complex& b)
-{
-  return octave::elem_xpow (a, b);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::elem_xpow' instead")
-inline octave_value
-elem_xpow (const ComplexMatrix& a, const ComplexMatrix& b)
-{
-  return octave::elem_xpow (a, b);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::elem_xpow' instead")
-inline octave_value
-elem_xpow (double a, const NDArray& b)
-{
-  return octave::elem_xpow (a, b);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::elem_xpow' instead")
-inline octave_value
-elem_xpow (double a, const ComplexNDArray& b)
-{
-  return octave::elem_xpow (a, b);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::elem_xpow' instead")
-inline octave_value
-elem_xpow (const NDArray& a, double b)
-{
-  return octave::elem_xpow (a, b);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::elem_xpow' instead")
-inline octave_value
-elem_xpow (const NDArray& a, const NDArray& b)
-{
-  return octave::elem_xpow (a, b);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::elem_xpow' instead")
-inline octave_value
-elem_xpow (const NDArray& a, const Complex& b)
-{
-  return octave::elem_xpow (a, b);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::elem_xpow' instead")
-inline octave_value
-elem_xpow (const NDArray& a, const ComplexNDArray& b)
-{
-  return octave::elem_xpow (a, b);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::elem_xpow' instead")
-inline octave_value
-elem_xpow (const Complex& a, const NDArray& b)
-{
-  return octave::elem_xpow (a, b);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::elem_xpow' instead")
-inline octave_value
-elem_xpow (const Complex& a, const ComplexNDArray& b)
-{
-  return octave::elem_xpow (a, b);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::elem_xpow' instead")
-inline octave_value
-elem_xpow (const ComplexNDArray& a, double b)
-{
-  return octave::elem_xpow (a, b);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::elem_xpow' instead")
-inline octave_value
-elem_xpow (const ComplexNDArray& a, const NDArray& b)
-{
-  return octave::elem_xpow (a, b);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::elem_xpow' instead")
-inline octave_value
-elem_xpow (const ComplexNDArray& a, const Complex& b)
-{
-  return octave::elem_xpow (a, b);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::elem_xpow' instead")
-inline octave_value
-elem_xpow (const ComplexNDArray& a, const ComplexNDArray& b)
-{
-  return octave::elem_xpow (a, b);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::xpow' instead")
-inline octave_value
-xpow (float a, float b)
-{
-  return octave::xpow (a, b);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::xpow' instead")
-inline octave_value
-xpow (float a, const FloatMatrix& b)
-{
-  return octave::xpow (a, b);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::xpow' instead")
-inline octave_value
-xpow (float a, const FloatComplex& b)
-{
-  return octave::xpow (a, b);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::xpow' instead")
-inline octave_value
-xpow (float a, const FloatComplexMatrix& b)
-{
-  return octave::xpow (a, b);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::xpow' instead")
-inline octave_value
-xpow (const FloatMatrix& a, float b)
-{
-  return octave::xpow (a, b);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::xpow' instead")
-inline octave_value
-xpow (const FloatMatrix& a, const FloatComplex& b)
-{
-  return octave::xpow (a, b);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::xpow' instead")
-inline octave_value
-xpow (const FloatDiagMatrix& a, float b)
-{
-  return octave::xpow (a, b);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::xpow' instead")
-inline octave_value
-xpow (const FloatDiagMatrix& a, const FloatComplex& b)
-{
-  return octave::xpow (a, b);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::xpow' instead")
-inline octave_value
-xpow (const FloatComplex& a, float b)
-{
-  return octave::xpow (a, b);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::xpow' instead")
-inline octave_value
-xpow (const FloatComplex& a, const FloatMatrix& b)
-{
-  return octave::xpow (a, b);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::xpow' instead")
-inline octave_value
-xpow (const FloatComplex& a, const FloatComplex& b)
-{
-  return octave::xpow (a, b);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::xpow' instead")
-inline octave_value
-xpow (const FloatComplex& a, const FloatComplexMatrix& b)
-{
-  return octave::xpow (a, b);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::xpow' instead")
-inline octave_value
-xpow (const FloatComplexMatrix& a, float b)
-{
-  return octave::xpow (a, b);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::xpow' instead")
-inline octave_value
-xpow (const FloatComplexMatrix& a, const FloatComplex& b)
-{
-  return octave::xpow (a, b);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::xpow' instead")
-inline octave_value
-xpow (const FloatComplexDiagMatrix& a, float b)
-{
-  return octave::xpow (a, b);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::xpow' instead")
-inline octave_value
-xpow (const FloatComplexDiagMatrix& a, const FloatComplex& b)
-{
-  return octave::xpow (a, b);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::elem_xpow' instead")
-inline octave_value
-elem_xpow (float a, const FloatMatrix& b)
-{
-  return octave::elem_xpow (a, b);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::elem_xpow' instead")
-inline octave_value
-elem_xpow (float a, const FloatComplexMatrix& b)
-{
-  return octave::elem_xpow (a, b);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::elem_xpow' instead")
-inline octave_value
-elem_xpow (const FloatMatrix& a, float b)
-{
-  return octave::elem_xpow (a, b);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::elem_xpow' instead")
-inline octave_value
-elem_xpow (const FloatMatrix& a, const FloatMatrix& b)
-{
-  return octave::elem_xpow (a, b);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::elem_xpow' instead")
-inline octave_value
-elem_xpow (const FloatMatrix& a, const FloatComplex& b)
-{
-  return octave::elem_xpow (a, b);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::elem_xpow' instead")
-inline octave_value
-elem_xpow (const FloatMatrix& a, const FloatComplexMatrix& b)
-{
-  return octave::elem_xpow (a, b);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::elem_xpow' instead")
-inline octave_value
-elem_xpow (const FloatComplex& a, const FloatMatrix& b)
-{
-  return octave::elem_xpow (a, b);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::elem_xpow' instead")
-inline octave_value
-elem_xpow (const FloatComplex& a, const FloatComplexMatrix& b)
-{
-  return octave::elem_xpow (a, b);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::elem_xpow' instead")
-inline octave_value
-elem_xpow (const FloatComplexMatrix& a, float b)
-{
-  return octave::elem_xpow (a, b);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::elem_xpow' instead")
-inline octave_value
-elem_xpow (const FloatComplexMatrix& a, const FloatMatrix& b)
-{
-  return octave::elem_xpow (a, b);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::elem_xpow' instead")
-inline octave_value
-elem_xpow (const FloatComplexMatrix& a, const FloatComplex& b)
-{
-  return octave::elem_xpow (a, b);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::elem_xpow' instead")
-inline octave_value
-elem_xpow (const FloatComplexMatrix& a, const FloatComplexMatrix& b)
-{
-  return octave::elem_xpow (a, b);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::elem_xpow' instead")
-inline octave_value
-elem_xpow (float a, const FloatNDArray& b)
-{
-  return octave::elem_xpow (a, b);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::elem_xpow' instead")
-inline octave_value
-elem_xpow (float a, const FloatComplexNDArray& b)
-{
-  return octave::elem_xpow (a, b);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::elem_xpow' instead")
-inline octave_value
-elem_xpow (const FloatNDArray& a, float b)
-{
-  return octave::elem_xpow (a, b);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::elem_xpow' instead")
-inline octave_value
-elem_xpow (const FloatNDArray& a, const FloatNDArray& b)
-{
-  return octave::elem_xpow (a, b);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::elem_xpow' instead")
-inline octave_value
-elem_xpow (const FloatNDArray& a, const FloatComplex& b)
-{
-  return octave::elem_xpow (a, b);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::elem_xpow' instead")
-inline octave_value
-elem_xpow (const FloatNDArray& a, const FloatComplexNDArray& b)
-{
-  return octave::elem_xpow (a, b);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::elem_xpow' instead")
-inline octave_value
-elem_xpow (const FloatComplex& a, const FloatNDArray& b)
-{
-  return octave::elem_xpow (a, b);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::elem_xpow' instead")
-inline octave_value
-elem_xpow (const FloatComplex& a, const FloatComplexNDArray& b)
-{
-  return octave::elem_xpow (a, b);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::elem_xpow' instead")
-inline octave_value
-elem_xpow (const FloatComplexNDArray& a, float b)
-{
-  return octave::elem_xpow (a, b);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::elem_xpow' instead")
-inline octave_value
-elem_xpow (const FloatComplexNDArray& a, const FloatNDArray& b)
-{
-  return octave::elem_xpow (a, b);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::elem_xpow' instead")
-inline octave_value
-elem_xpow (const FloatComplexNDArray& a, const FloatComplex& b)
-{
-  return octave::elem_xpow (a, b);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::elem_xpow' instead")
-inline octave_value
-elem_xpow (const FloatComplexNDArray& a, const FloatComplexNDArray& b)
-{
-  return octave::elem_xpow (a, b);
-}
-
 #endif
-
-#endif
--- a/libinterp/mk-builtins.pl	Fri Dec 02 10:11:46 2022 -0500
+++ b/libinterp/mk-builtins.pl	Fri Dec 02 10:12:40 2022 -0500
@@ -150,23 +150,6 @@
 
   print "\nOCTAVE_END_NAMESPACE(octave)\n";
 
-  print "\n#if defined (OCTAVE_PROVIDE_DEPRECATED_SYMBOLS)\n\n";
-
-  foreach $name (sort (@fcn_names))
-  {
-    print "OCTAVE_DEPRECATED (7, \"use 'octave::$name' instead\")
-inline octave_value_list
-$name (const octave_value_list& args = octave_value_list (), int nargout = 0)
-{
-  return octave::$name (args, nargout);
-}
-
-";
-  }
-
-  ## end OCTAVE_PROVIDE_DEPRECATED_SYMBOLS block
-  print "\n\n#endif\n";
-
   print "\n#endif\n";
 }
 elsif ($make_source)
--- a/libinterp/module.mk	Fri Dec 02 10:11:46 2022 -0500
+++ b/libinterp/module.mk	Fri Dec 02 10:12:40 2022 -0500
@@ -176,11 +176,6 @@
 LIBINTERP_DEFUN_FILES += \
   $(BUILT_IN_DEFUN_FILES)
 
-## FIXME: The following two variables are deprecated and should be removed
-##        in Octave version 3.12.
-DLL_CDEFS = @OCTINTERP_DLL_DEFS@
-DLL_CXXDEFS = @OCTINTERP_DLL_DEFS@
-
 ## Rules to build test files
 
 LIBINTERP_TST_FILES_SRC := $(shell $(SHELL) $(srcdir)/build-aux/find-files-with-tests.sh "$(srcdir)" $(ULT_DIST_SRC) $(DLDFCN_SRC))
--- a/libinterp/octave-value/ov-legacy-range.cc	Fri Dec 02 10:11:46 2022 -0500
+++ b/libinterp/octave-value/ov-legacy-range.cc	Fri Dec 02 10:12:40 2022 -0500
@@ -31,6 +31,7 @@
 #include <ostream>
 #include <sstream>
 
+#include "Range.h"
 #include "lo-ieee.h"
 #include "lo-utils.h"
 
@@ -49,23 +50,326 @@
 #include "ls-hdf5.h"
 #include "ls-utils.h"
 
-#if defined (HAVE_PRAGMA_GCC_DIAGNOSTIC)
-#  pragma GCC diagnostic push
-#  pragma GCC diagnostic ignored "-Wdeprecated-declarations"
-#endif
+class
+Range
+{
+public:
+
+  Range (void)
+    : m_base (0), m_limit (0), m_inc (0), m_numel (0)
+  { }
+
+  // Assume range is already properly constructed, so just copy internal
+  // values.  However, we set LIMIT to the computed final value because
+  // that mimics the behavior of the other Range class constructors that
+  // reset limit to the computed final value.
+
+  Range (const octave::range<double>& r)
+    : m_base (r.base ()), m_limit (r.final_value ()), m_inc (r.increment ()),
+      m_numel (r.numel ())
+  { }
+
+  Range (const Range& r) = default;
+
+  Range& operator = (const Range& r) = default;
+
+  ~Range (void) = default;
+
+  Range (double b, double l)
+    : m_base (b), m_limit (l), m_inc (1), m_numel (numel_internal ())
+  {
+    if (! octave::math::isinf (m_limit))
+      m_limit = limit_internal ();
+  }
+
+  Range (double b, double l, double i)
+    : m_base (b), m_limit (l), m_inc (i), m_numel (numel_internal ())
+  {
+    if (! octave::math::isinf (m_limit))
+      m_limit = limit_internal ();
+  }
+
+  // The range has a finite number of elements.
+  bool ok (void) const
+  {
+    return (octave::math::isfinite (m_limit)
+            && (m_numel >= 0 || m_numel == -2));
+  }
+
+  double base (void) const { return m_base; }
+  double limit (void) const { return m_limit; }
+  double increment (void) const { return m_inc; }
+
+  octave_idx_type numel (void) const { return m_numel; }
+
+  bool all_elements_are_ints (void) const;
+
+  Matrix matrix_value (void) const;
+
+  double min (void) const;
+  double max (void) const;
+
+private:
+
+  double m_base;
+  double m_limit;
+  double m_inc;
+
+  octave_idx_type m_numel;
+
+  octave_idx_type numel_internal (void) const;
+
+  double limit_internal (void) const;
+
+  void init (void);
+};
+
+bool
+Range::all_elements_are_ints (void) const
+{
+  // If the base and increment are ints, the final value in the range will also
+  // be an integer, even if the limit is not.  If there is one or fewer
+  // elements only the base needs to be an integer.
+
+  return (! (octave::math::isnan (m_base) || octave::math::isnan (m_inc))
+          && (octave::math::nint_big (m_base) == m_base || m_numel < 1)
+          && (octave::math::nint_big (m_inc) == m_inc || m_numel <= 1));
+}
+
+Matrix
+Range::matrix_value (void) const
+{
+  Matrix retval (1, m_numel);
+
+  if (m_numel > 0)
+    {
+      // The first element must always be *exactly* the base.
+      // E.g, -0 would otherwise become +0 in the loop (-0 + 0*increment).
+      retval(0) = m_base;
+
+      double b = m_base;
+      double increment = m_inc;
+      for (octave_idx_type i = 1; i < m_numel - 1; i++)
+        retval.xelem (i) = b + i * increment;
+
+      retval.xelem (m_numel - 1) = m_limit;
+    }
+
+  return retval;
+}
+
+// NOTE: max and min only return useful values if numel > 0.
+//       do_minmax_body() in max.cc avoids calling Range::min/max if numel == 0.
+
+double
+Range::min (void) const
+{
+  double retval = 0.0;
+  if (m_numel > 0)
+    {
+      if (m_inc > 0)
+        retval = m_base;
+      else
+        {
+          retval = m_base + (m_numel - 1) * m_inc;
+
+          // Require '<=' test.  See note in max ().
+          if (retval <= m_limit)
+            retval = m_limit;
+        }
+
+    }
+  return retval;
+}
+
+double
+Range::max (void) const
+{
+  double retval = 0.0;
+  if (m_numel > 0)
+    {
+      if (m_inc > 0)
+        {
+          retval = m_base + (m_numel - 1) * m_inc;
+
+          // On some machines (x86 with extended precision floating point
+          // arithmetic, for example) it is possible that we can overshoot the
+          // limit by approximately the machine precision even though we were
+          // very careful in our calculation of the number of elements.
+          // Therefore, we clip the result to the limit if it overshoots.
+          // The test also includes equality (>= m_limit) to have expressions
+          // such as -5:1:-0 result in a -0 endpoint.
+          if (retval >= m_limit)
+            retval = m_limit;
+        }
+      else
+        retval = m_base;
+    }
+  return retval;
+}
+
+// C  See Knuth, Art Of Computer Programming, Vol. 1, Problem 1.2.4-5.
+// C
+// C===Tolerant FLOOR function.
+// C
+// C    X  -  is given as a Double Precision argument to be operated on.
+// C          It is assumed that X is represented with M mantissa bits.
+// C    CT -  is   given   as   a   Comparison   Tolerance   such   that
+// C          0.LT.CT.LE.3-SQRT(5)/2. If the relative difference between
+// C          X and A whole number is  less  than  CT,  then  TFLOOR  is
+// C          returned   as   this   whole   number.   By  treating  the
+// C          floating-point numbers as a finite ordered set  note  that
+// C          the  heuristic  EPS=2.**(-(M-1))   and   CT=3*EPS   causes
+// C          arguments  of  TFLOOR/TCEIL to be treated as whole numbers
+// C          if they are  exactly  whole  numbers  or  are  immediately
+// C          adjacent to whole number representations.  Since EPS,  the
+// C          "distance"  between  floating-point  numbers  on  the unit
+// C          interval, and M, the number of bits in X'S mantissa, exist
+// C          on  every  floating-point   computer,   TFLOOR/TCEIL   are
+// C          consistently definable on every floating-point computer.
+// C
+// C          For more information see the following references:
+// C    (1) P. E. Hagerty, "More On Fuzzy Floor And Ceiling," APL  QUOTE
+// C        QUAD 8(4):20-24, June 1978. Note that TFLOOR=FL5.
+// C    (2) L. M. Breed, "Definitions For Fuzzy Floor And Ceiling",  APL
+// C        QUOTE QUAD 8(3):16-23, March 1978. This paper cites FL1 through
+// C        FL5, the history of five years of evolutionary development of
+// C        FL5 - the seven lines of code below - by open collaboration
+// C        and corroboration of the mathematical-computing community.
+// C
+// C  Penn State University Center for Academic Computing
+// C  H. D. Knoble - August, 1978.
+
+static inline double
+tfloor (double x, double ct)
+{
+// C---------FLOOR(X) is the largest integer algebraically less than
+// C         or equal to X; that is, the unfuzzy FLOOR function.
+
+//  DINT (X) = X - DMOD (X, 1.0);
+//  FLOOR (X) = DINT (X) - DMOD (2.0 + DSIGN (1.0, X), 3.0);
+
+// C---------Hagerty's FL5 function follows...
+
+  double q = 1.0;
+
+  if (x < 0.0)
+    q = 1.0 - ct;
+
+  double rmax = q / (2.0 - ct);
+
+  double t1 = 1.0 + std::floor (x);
+  t1 = (ct / q) * (t1 < 0.0 ? -t1 : t1);
+  t1 = (rmax < t1 ? rmax : t1);
+  t1 = (ct > t1 ? ct : t1);
+  t1 = std::floor (x + t1);
+
+  if (x <= 0.0 || (t1 - x) < rmax)
+    return t1;
+  else
+    return t1 - 1.0;
+}
+
+static inline bool
+teq (double u, double v,
+     double ct = 3.0 * std::numeric_limits<double>::epsilon ())
+{
+  double tu = std::abs (u);
+  double tv = std::abs (v);
+
+  return std::abs (u - v) < ((tu > tv ? tu : tv) * ct);
+}
+
+octave_idx_type
+Range::numel_internal (void) const
+{
+  octave_idx_type retval = -1;
+
+  if (! octave::math::isfinite (m_base) || ! octave::math::isfinite (m_inc)
+      || octave::math::isnan (m_limit))
+    retval = -2;
+  else if (octave::math::isinf (m_limit)
+           && ((m_inc > 0 && m_limit > 0)
+               || (m_inc < 0 && m_limit < 0)))
+    retval = std::numeric_limits<octave_idx_type>::max () - 1;
+  else if (m_inc == 0
+           || (m_limit > m_base && m_inc < 0)
+           || (m_limit < m_base && m_inc > 0))
+    {
+      retval = 0;
+    }
+  else
+    {
+      double ct = 3.0 * std::numeric_limits<double>::epsilon ();
+
+      double tmp = tfloor ((m_limit - m_base + m_inc) / m_inc, ct);
+
+      octave_idx_type n_elt = (tmp > 0.0
+                               ? static_cast<octave_idx_type> (tmp) : 0);
+
+      // If the final element that we would compute for the range is equal to
+      // the limit of the range, or is an adjacent floating point number,
+      // accept it.  Otherwise, try a range with one fewer element.  If that
+      // fails, try again with one more element.
+      //
+      // I'm not sure this is very good, but it seems to work better than just
+      // using tfloor as above.  For example, without it, the expression
+      // 1.8:0.05:1.9 fails to produce the expected result of [1.8, 1.85, 1.9].
+
+      if (! teq (m_base + (n_elt - 1) * m_inc, m_limit))
+        {
+          if (teq (m_base + (n_elt - 2) * m_inc, m_limit))
+            n_elt--;
+          else if (teq (m_base + n_elt * m_inc, m_limit))
+            n_elt++;
+        }
+
+      retval = ((n_elt < std::numeric_limits<octave_idx_type>::max ())
+                ? n_elt : -1);
+    }
+
+  return retval;
+}
+
+double
+Range::limit_internal (void) const
+{
+  double new_limit = m_inc > 0 ? max () : min ();
+
+  // If result must be an integer then force the new_limit to be one.
+  if (all_elements_are_ints ())
+    new_limit = std::round (new_limit);
+
+  return new_limit;
+}
+
+void
+Range::init (void)
+{
+  m_numel = numel_internal ();
+
+  if (! octave::math::isinf (m_limit))
+    m_limit = limit_internal ();
+}
 
 DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA (octave_legacy_range, "range", "double");
 
 octave_legacy_range::octave_legacy_range (void)
-  : octave_base_value (), range () { }
+  : octave_base_value (), m_range (new Range ()) { }
 
 octave_legacy_range::octave_legacy_range (const Range& r)
-  : octave_base_value (), range (r)
+  : octave_base_value (), m_range (new Range (r))
 {
-  if (range.numel () < 0 && range.numel () != -2)
+  if (m_range->numel () < 0 && m_range->numel () != -2)
     error ("invalid range");
 }
 
+octave_legacy_range::octave_legacy_range (const octave_legacy_range& r)
+  : octave_base_value (r), m_range ()
+{
+  m_range.reset (new Range (*(r.m_range)));
+}
+
 static octave_base_value *
 default_numeric_conversion_function (const octave_base_value& a)
 {
@@ -78,7 +382,7 @@
 octave_legacy_range::numeric_conversion_function (void) const
 {
   return octave_base_value::type_conv_info (default_numeric_conversion_function,
-         octave_matrix::static_type_id ());
+                                            octave_matrix::static_type_id ());
 }
 
 octave_base_value *
@@ -86,10 +390,10 @@
 {
   octave_base_value *retval = nullptr;
 
-  switch (range.numel ())
+  switch (m_range->numel ())
     {
     case 1:
-      retval = new octave_scalar (range.base ());
+      retval = new octave_scalar (m_range->base ());
       break;
 
     case 0:
@@ -97,17 +401,17 @@
       break;
 
     case -2:
-      retval = new octave_matrix (range.matrix_value ());
+      retval = new octave_matrix (m_range->matrix_value ());
       break;
 
     default:
       {
-        if (range.increment () == 0)
-          retval = new octave_matrix (range.matrix_value ());
+        if (m_range->increment () == 0)
+          retval = new octave_matrix (m_range->matrix_value ());
         else
           retval = new octave_range
-          (octave::range<double> (range.base (), range.increment (),
-                                  range.limit (), range.numel ()));
+            (octave::range<double> (m_range->base (), m_range->increment (),
+                                    m_range->limit (), m_range->numel ()));
       }
       break;
     }
@@ -145,9 +449,9 @@
     error ("load: failed to load range constant");
 
   if (inc != 0)
-    range = Range (base, limit, inc);
+    m_range.reset (new Range (base, limit, inc));
   else
-    range = Range (base, inc, static_cast<octave_idx_type> (limit));
+    m_range.reset (new Range (base, inc, static_cast<octave_idx_type> (limit)));
 
   return true;
 }
@@ -173,9 +477,9 @@
   if (swap)
     swap_bytes<8> (&inc);
   if (inc != 0)
-    range = Range (bas, lim, inc);
+    m_range.reset (new Range (bas, lim, inc));
   else
-    range = Range (bas, inc, static_cast<octave_idx_type> (lim));
+    m_range.reset (new Range (bas, inc, static_cast<octave_idx_type> (lim)));
 
   return true;
 }
@@ -245,14 +549,14 @@
       octave_idx_type nel;
       if (hdf5_get_scalar_attr (data_hid, H5T_NATIVE_IDX,
                                 "OCTAVE_RANGE_NELEM", &nel))
-        range = Range (rangevals[0], rangevals[2], nel);
+        m_range.reset (new Range (rangevals[0], rangevals[2], nel));
       else
         {
           if (rangevals[2] != 0)
-            range = Range (rangevals[0], rangevals[1], rangevals[2]);
+            m_range.reset (new Range (rangevals[0], rangevals[1], rangevals[2]));
           else
-            range = Range (rangevals[0], rangevals[2],
-                           static_cast<octave_idx_type> (rangevals[1]));
+            m_range.reset (new Range (rangevals[0], rangevals[2],
+                                      static_cast<octave_idx_type> (rangevals[1])));
         }
     }
 
@@ -269,7 +573,3 @@
 
   return retval;
 }
-
-#if defined (HAVE_PRAGMA_GCC_DIAGNOSTIC)
-#  pragma GCC diagnostic pop
-#endif
--- a/libinterp/octave-value/ov-legacy-range.h	Fri Dec 02 10:11:46 2022 -0500
+++ b/libinterp/octave-value/ov-legacy-range.h	Fri Dec 02 10:12:40 2022 -0500
@@ -31,10 +31,9 @@
 #include <cstdlib>
 
 #include <iosfwd>
+#include <memory>
 #include <string>
 
-#include "Range.h"
-
 #include "lo-mappers.h"
 #include "lo-utils.h"
 #include "mx-base.h"
@@ -45,6 +44,8 @@
 #include "ov-re-mat.h"
 #include "ov-typeinfo.h"
 
+class Range;
+
 class octave_value_list;
 
 // Legacy Range values.
@@ -65,13 +66,13 @@
 
   octave_legacy_range (const Range& r);
 
-  octave_legacy_range (const octave_legacy_range& r) = default;
+  octave_legacy_range (const octave_legacy_range& r);
 
   // No assignment.
 
   octave_legacy_range& operator = (const octave_legacy_range&) = delete;
 
-  ~octave_legacy_range (void) { }
+  ~octave_legacy_range (void) = default;
 
   octave_base_value * clone (void) const
   {
@@ -102,7 +103,7 @@
 
 private:
 
-  Range range;
+  std::unique_ptr<Range> m_range;
 
   DECLARE_OV_TYPEID_FUNCTIONS_AND_DATA
 };
--- a/libinterp/octave-value/ov.cc	Fri Dec 02 10:11:46 2022 -0500
+++ b/libinterp/octave-value/ov.cc	Fri Dec 02 10:12:40 2022 -0500
@@ -1073,36 +1073,6 @@
   maybe_mutate ();
 }
 
-// Remove when public constructor that uses this function is removed.
-octave_base_value *
-octave_value::make_range_rep_deprecated (double base, double inc, double limit)
-{
-#if defined (HAVE_PRAGMA_GCC_DIAGNOSTIC)
-#  pragma GCC diagnostic push
-#  pragma GCC diagnostic ignored "-Wdeprecated-declarations"
-#endif
-
-  return dynamic_cast<octave_base_value *>
-         (new octave_legacy_range (Range (base, inc, limit)));
-
-#if defined (HAVE_PRAGMA_GCC_DIAGNOSTIC)
-#  pragma GCC diagnostic pop
-#endif
-}
-
-// Remove when public constructor that uses this function is removed.
-octave_base_value *
-octave_value::make_range_rep_deprecated (const Range& r, bool force_range)
-{
-  if (! force_range && ! r.ok ())
-    error ("invalid range");
-
-  if ((force_range || Voptimize_range))
-    return dynamic_cast<octave_base_value *> (new octave_legacy_range (r));
-  else
-    return dynamic_cast<octave_base_value *> (new octave_matrix (r.matrix_value ()));
-}
-
 octave_value::octave_value (const octave::range<double>& r, bool force_range)
   : m_rep (force_range || Voptimize_range
            ? dynamic_cast<octave_base_value *> (new ov_range<double> (r))
@@ -1201,8 +1171,8 @@
   : m_rep (force_range || optimize_range
            ? dynamic_cast<octave_base_value *> (new octave_char_range (r, type))
            : dynamic_cast<octave_base_value *> (type == '"'
-               ? new octave_char_matrix_dq_str (r.array_value ())
-               : new octave_char_matrix_sq_str (r.array_value ())))
+                                                ? new octave_char_matrix_dq_str (r.array_value ())
+                                                : new octave_char_matrix_sq_str (r.array_value ())))
 #else
   : m_rep (type == '"'
            ? new octave_char_matrix_dq_str (r.array_value ())
@@ -1891,10 +1861,10 @@
 
 ComplexColumnVector
 octave_value::complex_column_vector_value (bool force_string_conv,
-    bool frc_vec_conv) const
+                                           bool frc_vec_conv) const
 {
   return ComplexColumnVector (complex_vector_value (force_string_conv,
-                              frc_vec_conv));
+                                                    frc_vec_conv));
 }
 
 RowVector
@@ -1910,7 +1880,7 @@
                                         bool frc_vec_conv) const
 {
   return ComplexRowVector (complex_vector_value (force_string_conv,
-                           frc_vec_conv));
+                                                 frc_vec_conv));
 }
 
 Array<double>
@@ -1920,8 +1890,8 @@
   Array<double> retval = array_value (force_string_conv);
 
   return retval.reshape (make_vector_dims (retval.dims (),
-                         force_vector_conversion,
-                         type_name (), "real vector"));
+                                           force_vector_conversion,
+                                           type_name (), "real vector"));
 }
 
 template <typename T>
@@ -1989,8 +1959,8 @@
     }
 
   return retval.reshape (make_vector_dims (retval.dims (),
-                         force_vector_conversion,
-                         type_name (), "integer vector"));
+                                           force_vector_conversion,
+                                           type_name (), "integer vector"));
 }
 
 template <typename T>
@@ -2008,8 +1978,8 @@
 
 Array<octave_idx_type>
 octave_value::octave_idx_type_vector_value (bool require_int,
-    bool force_string_conv,
-    bool force_vector_conversion) const
+                                            bool force_string_conv,
+                                            bool force_vector_conversion) const
 {
   Array<octave_idx_type> retval;
 
@@ -2059,8 +2029,8 @@
     }
 
   return retval.reshape (make_vector_dims (retval.dims (),
-                         force_vector_conversion,
-                         type_name (), "integer vector"));
+                                           force_vector_conversion,
+                                           type_name (), "integer vector"));
 }
 
 Array<Complex>
@@ -2070,25 +2040,25 @@
   Array<Complex> retval = complex_array_value (force_string_conv);
 
   return retval.reshape (make_vector_dims (retval.dims (),
-                         force_vector_conversion,
-                         type_name (), "complex vector"));
+                                           force_vector_conversion,
+                                           type_name (), "complex vector"));
 }
 
 FloatColumnVector
 octave_value::float_column_vector_value (bool force_string_conv,
-    bool frc_vec_conv) const
+                                         bool frc_vec_conv) const
 {
   return FloatColumnVector (float_vector_value (force_string_conv,
-                            frc_vec_conv));
+                                                frc_vec_conv));
 }
 
 FloatComplexColumnVector
 octave_value::float_complex_column_vector_value (bool force_string_conv,
-    bool frc_vec_conv) const
+                                                 bool frc_vec_conv) const
 {
   return
     FloatComplexColumnVector (float_complex_vector_value (force_string_conv,
-                              frc_vec_conv));
+                                                          frc_vec_conv));
 }
 
 FloatRowVector
@@ -2096,15 +2066,15 @@
                                       bool frc_vec_conv) const
 {
   return FloatRowVector (float_vector_value (force_string_conv,
-                         frc_vec_conv));
+                                             frc_vec_conv));
 }
 
 FloatComplexRowVector
 octave_value::float_complex_row_vector_value (bool force_string_conv,
-    bool frc_vec_conv) const
+                                              bool frc_vec_conv) const
 {
   return FloatComplexRowVector (float_complex_vector_value (force_string_conv,
-                                frc_vec_conv));
+                                                           frc_vec_conv));
 }
 
 Array<float>
@@ -2114,19 +2084,19 @@
   Array<float> retval = float_array_value (force_string_conv);
 
   return retval.reshape (make_vector_dims (retval.dims (),
-                         force_vector_conversion,
-                         type_name (), "real vector"));
+                                           force_vector_conversion,
+                                           type_name (), "real vector"));
 }
 
 Array<FloatComplex>
 octave_value::float_complex_vector_value (bool force_string_conv,
-    bool force_vector_conversion) const
+                                          bool force_vector_conversion) const
 {
   Array<FloatComplex> retval = float_complex_array_value (force_string_conv);
 
   return retval.reshape (make_vector_dims (retval.dims (),
-                         force_vector_conversion,
-                         type_name (), "complex vector"));
+                                           force_vector_conversion,
+                                           type_name (), "complex vector"));
 }
 
 // NAME can't always be "x ## FCN" because some of the original
@@ -2214,8 +2184,7 @@
 XVALUE_EXTRACTOR (DiagMatrix, xdiag_matrix_value, diag_matrix_value)
 XVALUE_EXTRACTOR (FloatDiagMatrix, xfloat_diag_matrix_value, float_diag_matrix_value)
 XVALUE_EXTRACTOR (ComplexDiagMatrix, xcomplex_diag_matrix_value, complex_diag_matrix_value)
-XVALUE_EXTRACTOR (FloatComplexDiagMatrix, xfloat_complex_diag_matrix_value,
-                  float_complex_diag_matrix_value)
+XVALUE_EXTRACTOR (FloatComplexDiagMatrix, xfloat_complex_diag_matrix_value, float_complex_diag_matrix_value)
 
 XVALUE_EXTRACTOR (PermMatrix, xperm_matrix_value, perm_matrix_value)
 
@@ -2273,16 +2242,13 @@
 XVALUE_EXTRACTOR (ComplexRowVector, xcomplex_row_vector_value, complex_row_vector_value)
 
 XVALUE_EXTRACTOR (FloatColumnVector, xfloat_column_vector_value, float_column_vector_value)
-XVALUE_EXTRACTOR (FloatComplexColumnVector, xfloat_complex_column_vector_value,
-                  float_complex_column_vector_value)
+XVALUE_EXTRACTOR (FloatComplexColumnVector, xfloat_complex_column_vector_value, float_complex_column_vector_value)
 
 XVALUE_EXTRACTOR (FloatRowVector, xfloat_row_vector_value, float_row_vector_value)
-XVALUE_EXTRACTOR (FloatComplexRowVector, xfloat_complex_row_vector_value,
-                  float_complex_row_vector_value)
+XVALUE_EXTRACTOR (FloatComplexRowVector, xfloat_complex_row_vector_value, float_complex_row_vector_value)
 
 XVALUE_EXTRACTOR (Array<int>, xint_vector_value, int_vector_value)
-XVALUE_EXTRACTOR (Array<octave_idx_type>, xoctave_idx_type_vector_value,
-                  octave_idx_type_vector_value)
+XVALUE_EXTRACTOR (Array<octave_idx_type>, xoctave_idx_type_vector_value, octave_idx_type_vector_value)
 
 XVALUE_EXTRACTOR (Array<double>, xvector_value, vector_value)
 XVALUE_EXTRACTOR (Array<Complex>, xcomplex_vector_value, complex_vector_value)
@@ -2520,7 +2486,7 @@
 
           if (! tmp)
             err_unary_op_conversion_failed
-            (octave_value::unary_op_as_string (op), type_name ());
+              (octave_value::unary_op_as_string (op), type_name ());
 
           octave_base_value *old_rep = m_rep;
           m_rep = tmp;
@@ -2692,950 +2658,950 @@
 
 OCTAVE_BEGIN_NAMESPACE(octave)
 
-OCTAVE_NORETURN static void
-err_binary_op (const std::string& on, const std::string& tn1,
-               const std::string& tn2)
-{
-  error ("binary operator '%s' not implemented for '%s' by '%s' operations",
-         on.c_str (), tn1.c_str (), tn2.c_str ());
-}
-
-OCTAVE_NORETURN static void
-err_binary_op_conv (const std::string& on)
-{
-  error ("type conversion failed for binary operator '%s'", on.c_str ());
-}
-
-octave_value
-binary_op (type_info& ti, octave_value::binary_op op,
-           const octave_value& v1, const octave_value& v2)
-{
-  octave_value retval;
-
-  int t1 = v1.type_id ();
-  int t2 = v2.type_id ();
-
-  if (t1 == octave_class::static_type_id ()
-      || t2 == octave_class::static_type_id ()
-      || t1 == octave_classdef::static_type_id ()
-      || t2 == octave_classdef::static_type_id ())
-    {
-      type_info::binary_class_op_fcn f = ti.lookup_binary_class_op (op);
-
-      if (! f)
-        err_binary_op (octave_value::binary_op_as_string (op),
-                       v1.class_name (), v2.class_name ());
-
-      retval = f (v1, v2);
-    }
-  else
-    {
-      // FIXME: we need to handle overloading operators for built-in
-      // classes (double, char, int8, etc.)
-
-      type_info::binary_op_fcn f
-        = ti.lookup_binary_op (op, t1, t2);
-
-      if (f)
-        retval = f (v1.get_rep (), v2.get_rep ());
-      else
-        {
-          octave_value tv1;
-          octave_base_value::type_conv_info cf1
-            = v1.numeric_conversion_function ();
-
-          octave_value tv2;
-          octave_base_value::type_conv_info cf2
-            = v2.numeric_conversion_function ();
-
-          // Try biased (one-sided) conversions first.
-          if (cf2.type_id () >= 0
-              && ti.lookup_binary_op (op, t1, cf2.type_id ()))
-            cf1 = nullptr;
-          else if (cf1.type_id () >= 0
-                   && ti.lookup_binary_op (op, cf1.type_id (), t2))
-            cf2 = nullptr;
-
-          if (cf1)
-            {
-              octave_base_value *tmp = cf1 (v1.get_rep ());
-
-              if (! tmp)
-                err_binary_op_conv (octave_value::binary_op_as_string (op));
-
-              tv1 = octave_value (tmp);
-              t1 = tv1.type_id ();
-            }
-          else
-            tv1 = v1;
-
-          if (cf2)
-            {
-              octave_base_value *tmp = cf2 (v2.get_rep ());
-
-              if (! tmp)
-                err_binary_op_conv (octave_value::binary_op_as_string (op));
-
-              tv2 = octave_value (tmp);
-              t2 = tv2.type_id ();
-            }
-          else
-            tv2 = v2;
-
-          if (cf1 || cf2)
-            {
-              retval = binary_op (op, tv1, tv2);
-            }
-          else
-            {
-              //demote double -> single and try again
-              cf1 = tv1.numeric_demotion_function ();
-
-              cf2 = tv2.numeric_demotion_function ();
-
-              // Try biased (one-sided) conversions first.
-              if (cf2.type_id () >= 0
-                  && ti.lookup_binary_op (op, t1, cf2.type_id ()))
-                cf1 = nullptr;
-              else if (cf1.type_id () >= 0
-                       && ti.lookup_binary_op (op, cf1.type_id (), t2))
-                cf2 = nullptr;
-
-              if (cf1)
-                {
-                  octave_base_value *tmp = cf1 (tv1.get_rep ());
-
-                  if (! tmp)
-                    err_binary_op_conv (octave_value::binary_op_as_string (op));
-
-                  tv1 = octave_value (tmp);
-                  t1 = tv1.type_id ();
-                }
-
-              if (cf2)
-                {
-                  octave_base_value *tmp = cf2 (tv2.get_rep ());
-
-                  if (! tmp)
-                    err_binary_op_conv (octave_value::binary_op_as_string (op));
-
-                  tv2 = octave_value (tmp);
-                  t2 = tv2.type_id ();
-                }
-
-              if (! cf1 && ! cf2)
-                err_binary_op (octave_value::binary_op_as_string (op),
-                               v1.type_name (), v2.type_name ());
-
-              f = ti.lookup_binary_op (op, t1, t2);
-
-              if (! f)
-                err_binary_op (octave_value::binary_op_as_string (op),
-                               v1.type_name (), v2.type_name ());
-
-              retval = f (tv1.get_rep (), tv2.get_rep ());
-            }
-        }
-    }
-
-  return retval;
-}
-
-octave_value
-binary_op (octave_value::binary_op op, const octave_value& v1,
-           const octave_value& v2)
-{
-  type_info& ti = __get_type_info__ ();
-
-  return binary_op (ti, op, v1, v2);
-}
-
-static octave_value
-decompose_binary_op (type_info& ti, octave_value::compound_binary_op op,
-                     const octave_value& v1, const octave_value& v2)
-{
-  switch (op)
-    {
-    case octave_value::op_trans_mul:
-      return binary_op (octave_value::op_mul,
-                        unary_op (octave_value::op_transpose, v1), v2);
-
-    case octave_value::op_mul_trans:
-      return binary_op (ti, octave_value::op_mul,
-                        v1, unary_op (octave_value::op_transpose, v2));
-
-    case octave_value::op_herm_mul:
-      return binary_op (ti, octave_value::op_mul,
-                        unary_op (octave_value::op_hermitian, v1), v2);
-
-    case octave_value::op_mul_herm:
-      return binary_op (ti, octave_value::op_mul,
-                        v1, unary_op (octave_value::op_hermitian, v2));
-
-    case octave_value::op_trans_ldiv:
-      return binary_op (ti, octave_value::op_ldiv,
-                        unary_op (octave_value::op_transpose, v1), v2);
-
-    case octave_value::op_herm_ldiv:
-      return binary_op (ti, octave_value::op_ldiv,
-                        unary_op (octave_value::op_hermitian, v1), v2);
-
-    case octave_value::op_el_not_and:
-      return binary_op (ti, octave_value::op_el_and,
-                        unary_op (octave_value::op_not, v1), v2);
-
-    case octave_value::op_el_not_or:
-      return binary_op (ti, octave_value::op_el_or,
-                        unary_op (octave_value::op_not, v1), v2);
-
-    case octave_value::op_el_and_not:
-      return binary_op (ti, octave_value::op_el_and,
-                        v1, unary_op (octave_value::op_not, v2));
-
-    case octave_value::op_el_or_not:
-      return binary_op (ti, octave_value::op_el_or,
-                        v1, unary_op (octave_value::op_not, v2));
-
-    default:
-      error ("invalid compound operator");
-    }
-}
-
-octave_value
-binary_op (type_info& ti, octave_value::compound_binary_op op,
-           const octave_value& v1, const octave_value& v2)
-{
-  octave_value retval;
-
-  int t1 = v1.type_id ();
-  int t2 = v2.type_id ();
-
-  if (t1 == octave_class::static_type_id ()
-      || t2 == octave_class::static_type_id ()
-      || t1 == octave_classdef::static_type_id ()
-      || t2 == octave_classdef::static_type_id ())
-    {
-      type_info::binary_class_op_fcn f = ti.lookup_binary_class_op (op);
-
-      if (f)
+  OCTAVE_NORETURN static void
+  err_binary_op (const std::string& on, const std::string& tn1,
+                 const std::string& tn2)
+  {
+    error ("binary operator '%s' not implemented for '%s' by '%s' operations",
+           on.c_str (), tn1.c_str (), tn2.c_str ());
+  }
+
+  OCTAVE_NORETURN static void
+  err_binary_op_conv (const std::string& on)
+  {
+    error ("type conversion failed for binary operator '%s'", on.c_str ());
+  }
+
+  octave_value
+  binary_op (type_info& ti, octave_value::binary_op op,
+             const octave_value& v1, const octave_value& v2)
+  {
+    octave_value retval;
+
+    int t1 = v1.type_id ();
+    int t2 = v2.type_id ();
+
+    if (t1 == octave_class::static_type_id ()
+        || t2 == octave_class::static_type_id ()
+        || t1 == octave_classdef::static_type_id ()
+        || t2 == octave_classdef::static_type_id ())
+      {
+        type_info::binary_class_op_fcn f = ti.lookup_binary_class_op (op);
+
+        if (! f)
+          err_binary_op (octave_value::binary_op_as_string (op),
+                         v1.class_name (), v2.class_name ());
+
         retval = f (v1, v2);
-      else
-        retval = decompose_binary_op (ti, op, v1, v2);
-    }
-  else
-    {
-      type_info::binary_op_fcn f = ti.lookup_binary_op (op, t1, t2);
-
-      if (f)
-        retval = f (v1.get_rep (), v2.get_rep ());
-      else
-        retval = decompose_binary_op (ti, op, v1, v2);
-    }
-
-  return retval;
-}
-
-octave_value
-binary_op (octave_value::compound_binary_op op,
-           const octave_value& v1, const octave_value& v2)
-{
-  type_info& ti = __get_type_info__ ();
-
-  return binary_op (ti, op, v1, v2);
-}
-
-OCTAVE_NORETURN static void
-err_cat_op (const std::string& tn1, const std::string& tn2)
-{
-  error ("concatenation operator not implemented for '%s' by '%s' operations",
-         tn1.c_str (), tn2.c_str ());
-}
-
-OCTAVE_NORETURN static void
-err_cat_op_conv (void)
-{
-  error ("type conversion failed for concatenation operator");
-}
-
-octave_value
-cat_op (type_info& ti, const octave_value& v1,
-        const octave_value& v2, const Array<octave_idx_type>& ra_idx)
-{
-  octave_value retval;
-
-  // Can't rapid return for concatenation with an empty object here as
-  // something like cat(1,[],single([]) must return the correct type.
-
-  int t1 = v1.type_id ();
-  int t2 = v2.type_id ();
-
-  type_info::cat_op_fcn f = ti.lookup_cat_op (t1, t2);
-
-  if (f)
-    retval = f (v1.get_rep (), v2.get_rep (), ra_idx);
-  else
-    {
-      octave_value tv1;
-      octave_base_value::type_conv_info cf1 = v1.numeric_conversion_function ();
-
-      octave_value tv2;
-      octave_base_value::type_conv_info cf2 = v2.numeric_conversion_function ();
-
-      // Try biased (one-sided) conversions first.
-      if (cf2.type_id () >= 0 && ti.lookup_cat_op (t1, cf2.type_id ()))
-        cf1 = nullptr;
-      else if (cf1.type_id () >= 0 && ti.lookup_cat_op (cf1.type_id (), t2))
-        cf2 = nullptr;
-
-      if (cf1)
-        {
-          octave_base_value *tmp = cf1 (v1.get_rep ());
-
-          if (! tmp)
-            err_cat_op_conv ();
-
-          tv1 = octave_value (tmp);
-          t1 = tv1.type_id ();
-        }
-      else
-        tv1 = v1;
-
-      if (cf2)
-        {
-          octave_base_value *tmp = cf2 (v2.get_rep ());
-
-          if (! tmp)
-            err_cat_op_conv ();
-
-          tv2 = octave_value (tmp);
-          t2 = tv2.type_id ();
-        }
-      else
-        tv2 = v2;
-
-      if (! cf1 && ! cf2)
-        err_cat_op (v1.type_name (), v2.type_name ());
-
-      retval = cat_op (ti, tv1, tv2, ra_idx);
-    }
-
-  return retval;
-}
-
-octave_value
-cat_op (const octave_value& v1, const octave_value& v2,
-        const Array<octave_idx_type>& ra_idx)
-{
-  type_info& ti = __get_type_info__ ();
-
-  return cat_op (ti, v1, v2, ra_idx);
-}
-
-// Unless the colon operator is used with a class or classdef object,
-// then all arguments must be the same type or mixed with double
-// values.
-
-static builtin_type_t
-get_colon_op_type (builtin_type_t op1_type, builtin_type_t op2_type)
-{
-  if (op1_type == op2_type)
-    return op1_type;
-
-  if (op1_type == btyp_double)
-    return op2_type;
-
-  if (op2_type == btyp_double)
-    return op1_type;
-
-  return btyp_unknown;
-}
-
-static builtin_type_t
-get_colon_op_type (const octave_value& base, const octave_value& increment,
+      }
+    else
+      {
+        // FIXME: we need to handle overloading operators for built-in
+        // classes (double, char, int8, etc.)
+
+        type_info::binary_op_fcn f
+          = ti.lookup_binary_op (op, t1, t2);
+
+        if (f)
+          retval = f (v1.get_rep (), v2.get_rep ());
+        else
+          {
+            octave_value tv1;
+            octave_base_value::type_conv_info cf1
+              = v1.numeric_conversion_function ();
+
+            octave_value tv2;
+            octave_base_value::type_conv_info cf2
+              = v2.numeric_conversion_function ();
+
+            // Try biased (one-sided) conversions first.
+            if (cf2.type_id () >= 0
+                && ti.lookup_binary_op (op, t1, cf2.type_id ()))
+              cf1 = nullptr;
+            else if (cf1.type_id () >= 0
+                     && ti.lookup_binary_op (op, cf1.type_id (), t2))
+              cf2 = nullptr;
+
+            if (cf1)
+              {
+                octave_base_value *tmp = cf1 (v1.get_rep ());
+
+                if (! tmp)
+                  err_binary_op_conv (octave_value::binary_op_as_string (op));
+
+                tv1 = octave_value (tmp);
+                t1 = tv1.type_id ();
+              }
+            else
+              tv1 = v1;
+
+            if (cf2)
+              {
+                octave_base_value *tmp = cf2 (v2.get_rep ());
+
+                if (! tmp)
+                  err_binary_op_conv (octave_value::binary_op_as_string (op));
+
+                tv2 = octave_value (tmp);
+                t2 = tv2.type_id ();
+              }
+            else
+              tv2 = v2;
+
+            if (cf1 || cf2)
+              {
+                retval = binary_op (op, tv1, tv2);
+              }
+            else
+              {
+                //demote double -> single and try again
+                cf1 = tv1.numeric_demotion_function ();
+
+                cf2 = tv2.numeric_demotion_function ();
+
+                // Try biased (one-sided) conversions first.
+                if (cf2.type_id () >= 0
+                    && ti.lookup_binary_op (op, t1, cf2.type_id ()))
+                  cf1 = nullptr;
+                else if (cf1.type_id () >= 0
+                         && ti.lookup_binary_op (op, cf1.type_id (), t2))
+                  cf2 = nullptr;
+
+                if (cf1)
+                  {
+                    octave_base_value *tmp = cf1 (tv1.get_rep ());
+
+                    if (! tmp)
+                      err_binary_op_conv (octave_value::binary_op_as_string (op));
+
+                    tv1 = octave_value (tmp);
+                    t1 = tv1.type_id ();
+                  }
+
+                if (cf2)
+                  {
+                    octave_base_value *tmp = cf2 (tv2.get_rep ());
+
+                    if (! tmp)
+                      err_binary_op_conv (octave_value::binary_op_as_string (op));
+
+                    tv2 = octave_value (tmp);
+                    t2 = tv2.type_id ();
+                  }
+
+                if (! cf1 && ! cf2)
+                  err_binary_op (octave_value::binary_op_as_string (op),
+                                 v1.type_name (), v2.type_name ());
+
+                f = ti.lookup_binary_op (op, t1, t2);
+
+                if (! f)
+                  err_binary_op (octave_value::binary_op_as_string (op),
+                                 v1.type_name (), v2.type_name ());
+
+                retval = f (tv1.get_rep (), tv2.get_rep ());
+              }
+          }
+      }
+
+    return retval;
+  }
+
+  octave_value
+  binary_op (octave_value::binary_op op, const octave_value& v1,
+             const octave_value& v2)
+  {
+    type_info& ti = __get_type_info__ ();
+
+    return binary_op (ti, op, v1, v2);
+  }
+
+  static octave_value
+  decompose_binary_op (type_info& ti, octave_value::compound_binary_op op,
+                       const octave_value& v1, const octave_value& v2)
+  {
+    switch (op)
+      {
+      case octave_value::op_trans_mul:
+        return binary_op (octave_value::op_mul,
+                          unary_op (octave_value::op_transpose, v1), v2);
+
+      case octave_value::op_mul_trans:
+        return binary_op (ti, octave_value::op_mul,
+                          v1, unary_op (octave_value::op_transpose, v2));
+
+      case octave_value::op_herm_mul:
+        return binary_op (ti, octave_value::op_mul,
+                          unary_op (octave_value::op_hermitian, v1), v2);
+
+      case octave_value::op_mul_herm:
+        return binary_op (ti, octave_value::op_mul,
+                          v1, unary_op (octave_value::op_hermitian, v2));
+
+      case octave_value::op_trans_ldiv:
+        return binary_op (ti, octave_value::op_ldiv,
+                          unary_op (octave_value::op_transpose, v1), v2);
+
+      case octave_value::op_herm_ldiv:
+        return binary_op (ti, octave_value::op_ldiv,
+                          unary_op (octave_value::op_hermitian, v1), v2);
+
+      case octave_value::op_el_not_and:
+        return binary_op (ti, octave_value::op_el_and,
+                          unary_op (octave_value::op_not, v1), v2);
+
+      case octave_value::op_el_not_or:
+        return binary_op (ti, octave_value::op_el_or,
+                          unary_op (octave_value::op_not, v1), v2);
+
+      case octave_value::op_el_and_not:
+        return binary_op (ti, octave_value::op_el_and,
+                          v1, unary_op (octave_value::op_not, v2));
+
+      case octave_value::op_el_or_not:
+        return binary_op (ti, octave_value::op_el_or,
+                          v1, unary_op (octave_value::op_not, v2));
+
+      default:
+        error ("invalid compound operator");
+      }
+  }
+
+  octave_value
+  binary_op (type_info& ti, octave_value::compound_binary_op op,
+             const octave_value& v1, const octave_value& v2)
+  {
+    octave_value retval;
+
+    int t1 = v1.type_id ();
+    int t2 = v2.type_id ();
+
+    if (t1 == octave_class::static_type_id ()
+        || t2 == octave_class::static_type_id ()
+        || t1 == octave_classdef::static_type_id ()
+        || t2 == octave_classdef::static_type_id ())
+      {
+        type_info::binary_class_op_fcn f = ti.lookup_binary_class_op (op);
+
+        if (f)
+          retval = f (v1, v2);
+        else
+          retval = decompose_binary_op (ti, op, v1, v2);
+      }
+    else
+      {
+        type_info::binary_op_fcn f = ti.lookup_binary_op (op, t1, t2);
+
+        if (f)
+          retval = f (v1.get_rep (), v2.get_rep ());
+        else
+          retval = decompose_binary_op (ti, op, v1, v2);
+      }
+
+    return retval;
+  }
+
+  octave_value
+  binary_op (octave_value::compound_binary_op op,
+             const octave_value& v1, const octave_value& v2)
+  {
+    type_info& ti = __get_type_info__ ();
+
+    return binary_op (ti, op, v1, v2);
+  }
+
+  OCTAVE_NORETURN static void
+  err_cat_op (const std::string& tn1, const std::string& tn2)
+  {
+    error ("concatenation operator not implemented for '%s' by '%s' operations",
+           tn1.c_str (), tn2.c_str ());
+  }
+
+  OCTAVE_NORETURN static void
+  err_cat_op_conv (void)
+  {
+    error ("type conversion failed for concatenation operator");
+  }
+
+  octave_value
+  cat_op (type_info& ti, const octave_value& v1,
+          const octave_value& v2, const Array<octave_idx_type>& ra_idx)
+  {
+    octave_value retval;
+
+    // Can't rapid return for concatenation with an empty object here as
+    // something like cat(1,[],single([]) must return the correct type.
+
+    int t1 = v1.type_id ();
+    int t2 = v2.type_id ();
+
+    type_info::cat_op_fcn f = ti.lookup_cat_op (t1, t2);
+
+    if (f)
+      retval = f (v1.get_rep (), v2.get_rep (), ra_idx);
+    else
+      {
+        octave_value tv1;
+        octave_base_value::type_conv_info cf1 = v1.numeric_conversion_function ();
+
+        octave_value tv2;
+        octave_base_value::type_conv_info cf2 = v2.numeric_conversion_function ();
+
+        // Try biased (one-sided) conversions first.
+        if (cf2.type_id () >= 0 && ti.lookup_cat_op (t1, cf2.type_id ()))
+          cf1 = nullptr;
+        else if (cf1.type_id () >= 0 && ti.lookup_cat_op (cf1.type_id (), t2))
+          cf2 = nullptr;
+
+        if (cf1)
+          {
+            octave_base_value *tmp = cf1 (v1.get_rep ());
+
+            if (! tmp)
+              err_cat_op_conv ();
+
+            tv1 = octave_value (tmp);
+            t1 = tv1.type_id ();
+          }
+        else
+          tv1 = v1;
+
+        if (cf2)
+          {
+            octave_base_value *tmp = cf2 (v2.get_rep ());
+
+            if (! tmp)
+              err_cat_op_conv ();
+
+            tv2 = octave_value (tmp);
+            t2 = tv2.type_id ();
+          }
+        else
+          tv2 = v2;
+
+        if (! cf1 && ! cf2)
+          err_cat_op (v1.type_name (), v2.type_name ());
+
+        retval = cat_op (ti, tv1, tv2, ra_idx);
+      }
+
+    return retval;
+  }
+
+  octave_value
+  cat_op (const octave_value& v1, const octave_value& v2,
+          const Array<octave_idx_type>& ra_idx)
+  {
+    type_info& ti = __get_type_info__ ();
+
+    return cat_op (ti, v1, v2, ra_idx);
+  }
+
+  // Unless the colon operator is used with a class or classdef object,
+  // then all arguments must be the same type or mixed with double
+  // values.
+
+  static builtin_type_t
+  get_colon_op_type (builtin_type_t op1_type, builtin_type_t op2_type)
+  {
+    if (op1_type == op2_type)
+      return op1_type;
+
+    if (op1_type == btyp_double)
+      return op2_type;
+
+    if (op2_type == btyp_double)
+      return op1_type;
+
+    return btyp_unknown;
+  }
+
+  static builtin_type_t
+  get_colon_op_type (const octave_value& base, const octave_value& increment,
+                     const octave_value& limit)
+  {
+    builtin_type_t typ
+      = get_colon_op_type (base.builtin_type (), increment.builtin_type ());
+
+    if (typ == btyp_unknown)
+      return typ;
+
+    return get_colon_op_type (typ, limit.builtin_type ());
+  }
+
+  // This check depends on the type of VAL either being the expected
+  // integer type or a double value.
+
+  template <typename T>
+  static void
+  check_colon_operand (const octave_value& val, const char *op_str)
+  {
+    if (! val.is_double_type ())
+      return;
+
+    double dval = val.double_value ();
+    double intpart;
+    static const double out_of_range_top
+      = static_cast<double> (std::numeric_limits<typename T::val_type>::max ())
+        + 1.;
+
+    if (dval >= out_of_range_top
+        || dval < std::numeric_limits<typename T::val_type>::min ()
+        || std::modf (dval, &intpart) != 0.0)
+      error ("colon operator %s invalid (not an integer or out of range for given integer type)", op_str);
+  }
+
+  // Return the difference between two unsigned integers as an unsigned
+  // integer of the same type.
+
+  template <typename UT,
+            typename std::enable_if<(std::is_integral<UT>::value
+                                     && std::is_unsigned<UT>::value),
+                                    bool>::type = true>
+  UT
+  integer_difference (UT a, UT b)
+  {
+    return a > b ? a - b : b - a;
+  }
+
+  // Return the difference between two signed integers as an unsigned
+  // integer corresponding to the signed type.
+
+  template <typename ST,
+            typename UT = typename std::make_unsigned<ST>::type,
+            typename std::enable_if<(std::is_integral<ST>::value
+                                     && std::is_signed<ST>::value),
+                                    bool>::type = true>
+  UT
+  integer_difference (ST a, ST b)
+  {
+    // Map to unsigned.
+    // Idea from https://stackoverflow.com/questions/10589559
+
+    static const UT offset
+      = UT (0) - static_cast<UT> (std::numeric_limits<ST>::min ());
+
+    UT au = static_cast<UT> (a) + offset;
+    UT bu = static_cast<UT> (b) + offset;
+
+    return integer_difference (au, bu);
+  }
+
+  // Number of elements in an integer range taking care to avoid
+  // overflow.  Base and limit are of the same type.  If they are
+  // unsigned, then increment is also of the same type.  If they are
+  // signed, then the type of increment is the unsigned type
+  // corresponding to T.  Assumes that the base and limit values are
+  // consistent with the sign of the original increment (not an empty
+  // range) so we can calculate numel with the absolute value of the
+  // increment and the absolute difference between the base and limit
+  // values.
+
+  template <typename T,
+            typename UT = typename std::make_unsigned<T>::type,
+            typename std::enable_if<std::is_integral<T>::value,
+                                    bool>::type = true>
+  octave_idx_type
+  range_numel_aux (T base, UT unsigned_increment, T limit)
+  {
+    // Adding one to DIFF/INCREMENT may overflow, so check whether it is
+    // out of range before adding.
+
+    UT nel_m1 = integer_difference (limit, base) / unsigned_increment;
+
+    // FIXME: fix error message.
+    if (nel_m1 > std::numeric_limits<octave_idx_type>::max () - 1)
+      error ("too many elements for range!");
+
+    return static_cast<octave_idx_type> (nel_m1) + 1;
+  }
+
+  // Convert signed range increment to unsigned.
+
+  template <typename ST,
+            typename UT = typename std::make_unsigned<ST>::type,
+            typename std::enable_if<(std::is_integral<ST>::value
+                                     && std::is_signed<ST>::value),
+                                    bool>::type = true>
+  UT
+  range_increment (ST increment)
+  {
+    return (increment < 0
+            ? UT (0) - static_cast<UT> (increment)
+            : static_cast<UT> (increment));
+  }
+
+  // "Convert" unsigned range increment to unsigned.  A no-op, but
+  // needed to provide a consistent interface for other template
+  // functions.
+
+  template <typename T,
+            typename UT = typename std::make_unsigned<T>::type,
+            typename std::enable_if<(std::is_integral<UT>::value
+                                     && std::is_unsigned<UT>::value),
+                                    bool>::type = true>
+  UT
+  range_increment (UT increment)
+  {
+    return increment;
+  }
+
+  // Convert double range increment to unsigned.  Enable by return type.
+
+  template <typename T,
+            typename UT = typename std::make_unsigned<T>::type>
+  typename std::enable_if<(std::is_integral<UT>::value
+                           && std::is_unsigned<UT>::value), UT>::type
+  range_increment (double increment)
+  {
+    double abs_increment = std::abs (increment);
+
+    return static_cast<UT> (abs_increment);
+  }
+
+  // Number of elements in an integer range base:increment:limit.  Base,
+  // increment, and limit are of the same signed type.
+
+  template <typename ST,
+            typename std::enable_if<(std::is_integral<ST>::value
+                                     && std::is_signed<ST>::value),
+                                    bool>::type = true>
+  octave_idx_type
+  range_numel (ST base, ST increment, ST limit)
+  {
+    typedef typename std::make_unsigned<ST>::type UT;
+
+    if (increment == 0
+        || (increment > 0 && base > limit)
+        || (increment < 0 && base < limit))
+      return 0;
+
+    UT unsigned_increment = range_increment<ST> (increment);
+
+    return range_numel_aux (base, unsigned_increment, limit);
+  }
+
+  // Number of elements in an integer range base:increment:limit.  Base,
+  // increment, and limit are unsigned and of the same type.
+
+  template <typename UT,
+            typename std::enable_if<(std::is_integral<UT>::value
+                                     && std::is_unsigned<UT>::value),
+                                    bool>::type = true>
+  octave_idx_type
+  range_numel (UT base, UT increment, UT limit)
+  {
+    // Unsigned, INCREMENT is always >= 0.
+    if (increment == 0 || base > limit)
+      return 0;
+
+    return range_numel_aux (base, increment, limit);
+  }
+
+  // Number of elements in an integer range base:increment:limit.  Base
+  // and limit are of the same type and increment is a double value.
+
+  template <typename T,
+            typename UT = typename std::make_unsigned<T>::type,
+            typename std::enable_if<std::is_integral<T>::value,
+                                    bool>::type = true>
+  octave_idx_type
+  range_numel (T base, double increment, T limit)
+  {
+    double intpart;
+    if (math::isnan (increment) || std::modf (increment, &intpart) != 0.0)
+      error ("colon operator increment invalid (not an integer)");
+
+    if (increment == 0
+        || (increment > 0 && base > limit)
+        || (increment < 0 && base < limit))
+      return 0;
+
+    static const double out_of_range_top
+      = static_cast<double> (std::numeric_limits<UT>::max ()) + 1.;
+
+    double abs_increment = std::abs (increment);
+
+    // Technically, this condition should be
+    // `abs_increment > std::numeric_limits<UT>::max ()`.
+    // But intmax('uint64') is not representable exactly as floating point
+    // number.  Instead, it "rounds" up by 1 to 2^64.  To account for
+    // this, use the following expression which works for all unsigned
+    // integer types.
+    if (abs_increment >= out_of_range_top)
+      return 1;
+
+    UT unsigned_increment = range_increment<T> (increment);
+
+    return range_numel_aux (base, unsigned_increment, limit);
+  }
+
+  // Make a range from integer values.  Increment may be integer or double.
+
+  template <typename T,
+            typename IT,
+            typename std::enable_if<(std::is_integral<T>::value
+                                     && std::is_arithmetic<IT>::value),
+                                    bool>::type = true>
+  octave_value
+  make_int_range (T base, IT increment, T limit)
+  {
+    octave_idx_type nel = range_numel (base, increment, limit);
+
+    // For now, we create arrays instead of range<T> for all types
+    // except double.
+
+    Array<octave_int<T>> result (dim_vector (1, nel));
+
+    if (nel > 0)
+      {
+        typedef typename std::make_unsigned<T>::type UT;
+
+        UT unsigned_increment = range_increment<T> (increment);
+
+        T val = base;
+        result.xelem (0) = val;
+
+        if (limit > base)
+          {
+            for (octave_idx_type i = 1; i < nel; i++)
+              {
+                val += unsigned_increment;
+                result.xelem (i) = val;
+              }
+          }
+        else
+          {
+            for (octave_idx_type i = 1; i < nel; i++)
+              {
+                val -= unsigned_increment;
+                result.xelem (i) = val;
+              }
+          }
+      }
+
+    return octave_value (result);
+  }
+
+  // Make a range from floating point values.
+
+  // FIXME: Try again to define memory efficient range classes for
+  // integer and floating point values?  Maybe with the templates
+  // defined in this file we could do that in a reasonable way?
+  // Regardless of that, it might be good to provide special treatment
+  // of colon expressions in FOR loops so that we can eliminate the
+  // "is_for_cmd_expr / force_range" flag from the parser and the
+  // octave_value constructors for range objects.
+
+  // NOTE: We define this function separately for float and double so
+  // that we can avoid having to instantiate ov_range<float>.  We DO
+  // instantiate range<float> but only so we can take advantage of the
+  // range<T> class to generate the corresponding array of float values
+  // and not have to duplicate that code here.
+
+  template <typename T,
+            typename std::enable_if<std::is_same<T, double>::value,
+                                    bool>::type = true>
+  octave_value
+  make_float_range (T base, T increment, T limit, bool is_for_cmd_expr)
+  {
+    if (math::isnan (base)
+        || math::isnan (increment)
+        || math::isnan (limit))
+      return octave_value (numeric_limits<T>::NaN ());
+
+    if (increment == 0
+        || (increment > 0 && base > limit)
+        || (increment < 0 && base < limit))
+      return octave_value (Array<T> (dim_vector (1, 0)));
+
+    // At this point, we know that the base and limit values are
+    // consistent with the sign of the increment (not an empty range).
+
+    range<T> r (base, increment, limit);
+
+    if (! is_for_cmd_expr && ! r.is_storable ())
+      error ("range with infinite number of elements cannot be stored");
+
+    return octave_value (r, is_for_cmd_expr);
+  }
+
+  template <typename T,
+            typename std::enable_if<std::is_same<T, float>::value,
+                                    bool>::type = true>
+  octave_value
+  make_float_range (T base, T increment, T limit, bool is_for_cmd_expr)
+  {
+    if (math::isnan (base)
+        || math::isnan (increment)
+        || math::isnan (limit))
+      return octave_value (numeric_limits<T>::NaN ());
+
+    if (increment == 0
+        || (increment > 0 && base > limit)
+        || (increment < 0 && base < limit))
+      return octave_value (Array<T> (dim_vector (1, 0)));
+
+    // At this point, we know that the base and limit values are
+    // consistent with the sign of the increment (not an empty range).
+
+    range<T> r (base, increment, limit);
+
+    if (! is_for_cmd_expr && ! r.is_storable ())
+      error ("range with infinite number of elements cannot be stored");
+
+    return octave_value (r.array_value ());
+  }
+
+  template <typename T,
+            typename std::enable_if<(std::is_same<T, octave_int8>::value
+                                     || std::is_same<T, octave_uint8>::value
+                                     || std::is_same<T, octave_int16>::value
+                                     || std::is_same<T, octave_uint16>::value
+                                     || std::is_same<T, octave_int32>::value
+                                     || std::is_same<T, octave_uint32>::value
+                                     || std::is_same<T, octave_int64>::value
+                                     || std::is_same<T, octave_uint64>::value),
+                                    bool>::type = true>
+  octave_value
+  make_int_range (const octave_value& base, const octave_value& increment,
+                  const octave_value& limit)
+  {
+    if (base.isempty () || increment.isempty () || limit.isempty ())
+      return octave_value (Array<T> (dim_vector (1, 0)));
+
+    check_colon_operand<T> (base, "lower bound");
+    check_colon_operand<T> (limit, "upper bound");
+
+    typename T::val_type base_val = octave_value_extract<T> (base).value ();
+    typename T::val_type limit_val = octave_value_extract<T> (limit).value ();
+
+    if (increment.is_double_type ())
+      {
+        double increment_val = increment.double_value ();
+
+        return make_int_range (base_val, increment_val, limit_val);
+      }
+
+    check_colon_operand<T> (increment, "increment");
+
+    typename T::val_type increment_val
+      = octave_value_extract<T> (increment).value ();
+
+    return make_int_range (base_val, increment_val, limit_val);
+  }
+
+  template <typename T,
+            typename std::enable_if<std::is_floating_point<T>::value,
+                                    bool>::type = true>
+  octave_value
+  make_float_range (const octave_value& base, const octave_value& increment,
+                    const octave_value& limit, bool is_for_cmd_expr)
+  {
+    if (base.isempty () || increment.isempty () || limit.isempty ())
+      return octave_value (Array<T> (dim_vector (1, 0)));
+
+    T base_val = octave_value_extract<T> (base);
+    T increment_val = octave_value_extract<T> (increment);
+    T limit_val = octave_value_extract<T> (limit);
+
+    return make_float_range (base_val, increment_val, limit_val,
+                             is_for_cmd_expr);
+  }
+
+
+  octave_value
+  make_char_range (const octave_value& base, const octave_value& increment,
                    const octave_value& limit)
-{
-  builtin_type_t typ
-    = get_colon_op_type (base.builtin_type (), increment.builtin_type ());
-
-  if (typ == btyp_unknown)
-    return typ;
-
-  return get_colon_op_type (typ, limit.builtin_type ());
-}
-
-// This check depends on the type of VAL either being the expected
-// integer type or a double value.
-
-template <typename T>
-static void
-check_colon_operand (const octave_value& val, const char *op_str)
-{
-  if (! val.is_double_type ())
-    return;
-
-  double dval = val.double_value ();
-  double intpart;
-  static const double out_of_range_top
-    = static_cast<double> (std::numeric_limits<typename T::val_type>::max ())
-      + 1.;
-
-  if (dval >= out_of_range_top
-      || dval < std::numeric_limits<typename T::val_type>::min ()
-      || std::modf (dval, &intpart) != 0.0)
-    error ("colon operator %s invalid (not an integer or out of range for given integer type)", op_str);
-}
-
-// Return the difference between two unsigned integers as an unsigned
-// integer of the same type.
-
-template <typename UT,
-          typename std::enable_if<(std::is_integral<UT>::value
-                                   && std::is_unsigned<UT>::value),
-                                  bool>::type = true>
-UT
-integer_difference (UT a, UT b)
-{
-  return a > b ? a - b : b - a;
-}
-
-// Return the difference between two signed integers as an unsigned
-// integer corresponding to the signed type.
-
-template <typename ST,
-          typename UT = typename std::make_unsigned<ST>::type,
-          typename std::enable_if<(std::is_integral<ST>::value
-                                   && std::is_signed<ST>::value),
-                                  bool>::type = true>
-UT
-integer_difference (ST a, ST b)
-{
-  // Map to unsigned.
-  // Idea from https://stackoverflow.com/questions/10589559
-
-  static const UT offset
-    = UT (0) - static_cast<UT> (std::numeric_limits<ST>::min ());
-
-  UT au = static_cast<UT> (a) + offset;
-  UT bu = static_cast<UT> (b) + offset;
-
-  return integer_difference (au, bu);
-}
-
-// Number of elements in an integer range taking care to avoid
-// overflow.  Base and limit are of the same type.  If they are
-// unsigned, then increment is also of the same type.  If they are
-// signed, then the type of increment is the unsigned type
-// corresponding to T.  Assumes that the base and limit values are
-// consistent with the sign of the original increment (not an empty
-// range) so we can calculate numel with the absolute value of the
-// increment and the absolute difference between the base and limit
-// values.
-
-template <typename T,
-          typename UT = typename std::make_unsigned<T>::type,
-          typename std::enable_if<std::is_integral<T>::value,
-                                  bool>::type = true>
-octave_idx_type
-range_numel_aux (T base, UT unsigned_increment, T limit)
-{
-  // Adding one to DIFF/INCREMENT may overflow, so check whether it is
-  // out of range before adding.
-
-  UT nel_m1 = integer_difference (limit, base) / unsigned_increment;
-
-  // FIXME: fix error message.
-  if (nel_m1 > std::numeric_limits<octave_idx_type>::max () - 1)
-    error ("too many elements for range!");
-
-  return static_cast<octave_idx_type> (nel_m1) + 1;
-}
-
-// Convert signed range increment to unsigned.
-
-template <typename ST,
-          typename UT = typename std::make_unsigned<ST>::type,
-          typename std::enable_if<(std::is_integral<ST>::value
-                                   && std::is_signed<ST>::value),
-                                  bool>::type = true>
-UT
-range_increment (ST increment)
-{
-  return (increment < 0
-          ? UT (0) - static_cast<UT> (increment)
-          : static_cast<UT> (increment));
-}
-
-// "Convert" unsigned range increment to unsigned.  A no-op, but
-// needed to provide a consistent interface for other template
-// functions.
-
-template <typename T,
-          typename UT = typename std::make_unsigned<T>::type,
-          typename std::enable_if<(std::is_integral<UT>::value
-                                   && std::is_unsigned<UT>::value),
-                                  bool>::type = true>
-UT
-range_increment (UT increment)
-{
-  return increment;
-}
-
-// Convert double range increment to unsigned.  Enable by return type.
-
-template <typename T,
-          typename UT = typename std::make_unsigned<T>::type>
-typename std::enable_if<(std::is_integral<UT>::value
-                         && std::is_unsigned<UT>::value), UT>::type
-range_increment (double increment)
-{
-  double abs_increment = std::abs (increment);
-
-  return static_cast<UT> (abs_increment);
-}
-
-// Number of elements in an integer range base:increment:limit.  Base,
-// increment, and limit are of the same signed type.
-
-template <typename ST,
-          typename std::enable_if<(std::is_integral<ST>::value
-                                   && std::is_signed<ST>::value),
-                                  bool>::type = true>
-octave_idx_type
-range_numel (ST base, ST increment, ST limit)
-{
-  typedef typename std::make_unsigned<ST>::type UT;
-
-  if (increment == 0
-      || (increment > 0 && base > limit)
-      || (increment < 0 && base < limit))
-    return 0;
-
-  UT unsigned_increment = range_increment<ST> (increment);
-
-  return range_numel_aux (base, unsigned_increment, limit);
-}
-
-// Number of elements in an integer range base:increment:limit.  Base,
-// increment, and limit are unsigned and of the same type.
-
-template <typename UT,
-          typename std::enable_if<(std::is_integral<UT>::value
-                                   && std::is_unsigned<UT>::value),
-                                  bool>::type = true>
-octave_idx_type
-range_numel (UT base, UT increment, UT limit)
-{
-  // Unsigned, INCREMENT is always >= 0.
-  if (increment == 0 || base > limit)
-    return 0;
-
-  return range_numel_aux (base, increment, limit);
-}
-
-// Number of elements in an integer range base:increment:limit.  Base
-// and limit are of the same type and increment is a double value.
-
-template <typename T,
-          typename UT = typename std::make_unsigned<T>::type,
-          typename std::enable_if<std::is_integral<T>::value,
-                                  bool>::type = true>
-octave_idx_type
-range_numel (T base, double increment, T limit)
-{
-  double intpart;
-  if (math::isnan (increment) || std::modf (increment, &intpart) != 0.0)
-    error ("colon operator increment invalid (not an integer)");
-
-  if (increment == 0
-      || (increment > 0 && base > limit)
-      || (increment < 0 && base < limit))
-    return 0;
-
-  static const double out_of_range_top
-    = static_cast<double> (std::numeric_limits<UT>::max ()) + 1.;
-
-  double abs_increment = std::abs (increment);
-
-  // Technically, this condition should be
-  // `abs_increment > std::numeric_limits<UT>::max ()`.
-  // But intmax('uint64') is not representable exactly as floating point
-  // number.  Instead, it "rounds" up by 1 to 2^64.  To account for
-  // this, use the following expression which works for all unsigned
-  // integer types.
-  if (abs_increment >= out_of_range_top)
-    return 1;
-
-  UT unsigned_increment = range_increment<T> (increment);
-
-  return range_numel_aux (base, unsigned_increment, limit);
-}
-
-// Make a range from integer values.  Increment may be integer or double.
-
-template <typename T,
-          typename IT,
-          typename std::enable_if<(std::is_integral<T>::value
-                                   && std::is_arithmetic<IT>::value),
-                                  bool>::type = true>
-octave_value
-make_int_range (T base, IT increment, T limit)
-{
-  octave_idx_type nel = range_numel (base, increment, limit);
-
-  // For now, we create arrays instead of range<T> for all types
-  // except double.
-
-  Array<octave_int<T>> result (dim_vector (1, nel));
-
-  if (nel > 0)
-    {
-      typedef typename std::make_unsigned<T>::type UT;
-
-      UT unsigned_increment = range_increment<T> (increment);
-
-      T val = base;
-      result.xelem (0) = val;
-
-      if (limit > base)
-        {
-          for (octave_idx_type i = 1; i < nel; i++)
-            {
-              val += unsigned_increment;
-              result.xelem (i) = val;
-            }
-        }
-      else
-        {
-          for (octave_idx_type i = 1; i < nel; i++)
-            {
-              val -= unsigned_increment;
-              result.xelem (i) = val;
-            }
-        }
-    }
-
-  return octave_value (result);
-}
-
-// Make a range from floating point values.
-
-// FIXME: Try again to define memory efficient range classes for
-// integer and floating point values?  Maybe with the templates
-// defined in this file we could do that in a reasonable way?
-// Regardless of that, it might be good to provide special treatment
-// of colon expressions in FOR loops so that we can eliminate the
-// "is_for_cmd_expr / force_range" flag from the parser and the
-// octave_value constructors for range objects.
-
-// NOTE: We define this function separately for float and double so
-// that we can avoid having to instantiate ov_range<float>.  We DO
-// instantiate range<float> but only so we can take advantage of the
-// range<T> class to generate the corresponding array of float values
-// and not have to duplicate that code here.
-
-template <typename T,
-          typename std::enable_if<std::is_same<T, double>::value,
-                                  bool>::type = true>
-octave_value
-make_float_range (T base, T increment, T limit, bool is_for_cmd_expr)
-{
-  if (math::isnan (base)
-      || math::isnan (increment)
-      || math::isnan (limit))
-    return octave_value (numeric_limits<T>::NaN ());
-
-  if (increment == 0
-      || (increment > 0 && base > limit)
-      || (increment < 0 && base < limit))
-    return octave_value (Array<T> (dim_vector (1, 0)));
-
-  // At this point, we know that the base and limit values are
-  // consistent with the sign of the increment (not an empty range).
-
-  range<T> r (base, increment, limit);
-
-  if (! is_for_cmd_expr && ! r.is_storable ())
-    error ("range with infinite number of elements cannot be stored");
-
-  return octave_value (r, is_for_cmd_expr);
-}
-
-template <typename T,
-          typename std::enable_if<std::is_same<T, float>::value,
-                                  bool>::type = true>
-octave_value
-make_float_range (T base, T increment, T limit, bool is_for_cmd_expr)
-{
-  if (math::isnan (base)
-      || math::isnan (increment)
-      || math::isnan (limit))
-    return octave_value (numeric_limits<T>::NaN ());
-
-  if (increment == 0
-      || (increment > 0 && base > limit)
-      || (increment < 0 && base < limit))
-    return octave_value (Array<T> (dim_vector (1, 0)));
-
-  // At this point, we know that the base and limit values are
-  // consistent with the sign of the increment (not an empty range).
-
-  range<T> r (base, increment, limit);
-
-  if (! is_for_cmd_expr && ! r.is_storable ())
-    error ("range with infinite number of elements cannot be stored");
-
-  return octave_value (r.array_value ());
-}
-
-template <typename T,
-          typename std::enable_if<(std::is_same<T, octave_int8>::value
-                                   || std::is_same<T, octave_uint8>::value
-                                   || std::is_same<T, octave_int16>::value
-                                   || std::is_same<T, octave_uint16>::value
-                                   || std::is_same<T, octave_int32>::value
-                                   || std::is_same<T, octave_uint32>::value
-                                   || std::is_same<T, octave_int64>::value
-                                   || std::is_same<T, octave_uint64>::value),
-                                  bool>::type = true>
-octave_value
-make_int_range (const octave_value& base, const octave_value& increment,
-                const octave_value& limit)
-{
-  if (base.isempty () || increment.isempty () || limit.isempty ())
-    return octave_value (Array<T> (dim_vector (1, 0)));
-
-  check_colon_operand<T> (base, "lower bound");
-  check_colon_operand<T> (limit, "upper bound");
-
-  typename T::val_type base_val = octave_value_extract<T> (base).value ();
-  typename T::val_type limit_val = octave_value_extract<T> (limit).value ();
-
-  if (increment.is_double_type ())
-    {
-      double increment_val = increment.double_value ();
-
-      return make_int_range (base_val, increment_val, limit_val);
-    }
-
-  check_colon_operand<T> (increment, "increment");
-
-  typename T::val_type increment_val
-    = octave_value_extract<T> (increment).value ();
-
-  return make_int_range (base_val, increment_val, limit_val);
-}
-
-template <typename T,
-          typename std::enable_if<std::is_floating_point<T>::value,
-                                  bool>::type = true>
-octave_value
-make_float_range (const octave_value& base, const octave_value& increment,
-                  const octave_value& limit, bool is_for_cmd_expr)
-{
-  if (base.isempty () || increment.isempty () || limit.isempty ())
-    return octave_value (Array<T> (dim_vector (1, 0)));
-
-  T base_val = octave_value_extract<T> (base);
-  T increment_val = octave_value_extract<T> (increment);
-  T limit_val = octave_value_extract<T> (limit);
-
-  return make_float_range (base_val, increment_val, limit_val,
-                           is_for_cmd_expr);
-}
-
-
-octave_value
-make_char_range (const octave_value& base, const octave_value& increment,
-                 const octave_value& limit)
-{
-  octave_value retval;
-
-  bool dq_str = (base.is_dq_string () || increment.is_dq_string ()
-                 || limit.is_dq_string ());
-
-  char type = dq_str ? '"' : '\'';
-
-  if (base.isempty () || increment.isempty () || limit.isempty ())
-    retval = octave_value ("", type);
-  else
-    {
-      Matrix mtx_base = base.matrix_value (true);
-      Matrix mtx_increment = increment.matrix_value (true);
-      Matrix mtx_limit = limit.matrix_value (true);
-
-      range<double> tmp (mtx_base(0), mtx_increment(0), mtx_limit(0));
-
-      retval = octave_value (tmp);
-    }
-
-  return retval.convert_to_str (false, true, type);
-}
-
-octave_value
-colon_op (const octave_value& base, const octave_value& increment_arg,
-          const octave_value& limit, bool is_for_cmd_expr)
-{
-  if (base.isobject () || increment_arg.isobject () || limit.isobject ())
-    {
-      octave_value_list tmp1;
-
-      if (increment_arg.is_defined ())
-        {
-          tmp1(2) = limit;
-          tmp1(1) = increment_arg;
-          tmp1(0) = base;
-        }
-      else
-        {
-          tmp1(1) = limit;
-          tmp1(0) = base;
-        }
-
-      interpreter& interp = __get_interpreter__ ();
-
-      symbol_table& symtab = interp.get_symbol_table ();
-
-      octave_value fcn = symtab.find_function ("colon", tmp1);
-
-      if (fcn.is_defined ())
-        {
-          octave_value_list tmp2 = interp.feval (fcn, tmp1, 1);
-
-          return tmp2(0);
-        }
-    }
-
-  octave_value increment
-    = increment_arg.is_defined () ? increment_arg : octave_value (1.0);
-
-  if (base.numel () > 1 || limit.numel () > 1 || increment.numel () > 1)
-    warning_with_id ("Octave:colon-nonscalar-argument",
-                     "colon arguments should be scalars");
-
-  if (base.iscomplex () || limit.iscomplex () || increment.iscomplex ())
-    warning_with_id ("Octave:colon-complex-argument",
-                     "imaginary part of complex colon arguments is ignored");
-
-  // FIXME: is there a better way to do this job, maybe using type traits?
-
-  builtin_type_t type_id = get_colon_op_type (base, increment, limit);
-
-  // For compatibility with Matlab, don't allow the range used in
-  // a FOR loop expression to be converted to a Matrix.
-
-  // For now, these functions create arrays instead of range<T> for
-  // all types except double.
-
-  switch (type_id)
-    {
-    case btyp_double:
-    case btyp_complex:
-      return make_float_range<double> (base, increment, limit, is_for_cmd_expr);
-
-    case btyp_float:
-    case btyp_float_complex:
-      return make_float_range<float> (base, increment, limit, is_for_cmd_expr);
-
-    case btyp_int8:
-      return make_int_range<octave_int8> (base, increment, limit);
-
-    case btyp_int16:
-      return make_int_range<octave_int16> (base, increment, limit);
-
-    case btyp_int32:
-      return make_int_range<octave_int32> (base, increment, limit);
-
-    case btyp_int64:
-      return make_int_range<octave_int64> (base, increment, limit);
-
-    case btyp_uint8:
-      return make_int_range<octave_uint8> (base, increment, limit);
-
-    case btyp_uint16:
-      return make_int_range<octave_uint16> (base, increment, limit);
-
-    case btyp_uint32:
-      return make_int_range<octave_uint32> (base, increment, limit);
-
-    case btyp_uint64:
-      return make_int_range<octave_uint64> (base, increment, limit);
-
-    case btyp_char:
-      return make_char_range (base, increment, limit);
-
-    case btyp_unknown:
-      error ("incompatible types found in range expression");
-
-    default:
-      error ("invalid types found in range expression");
-    }
-
-  return octave_value ();
-}
-
-OCTAVE_NORETURN static void
-err_unary_op_conv (const std::string& on)
-{
-  error ("type conversion failed for unary operator '%s'", on.c_str ());
-}
-
-octave_value
-unary_op (type_info& ti, octave_value::unary_op op,
-          const octave_value& v)
-{
-  octave_value retval;
-
-  int t = v.type_id ();
-
-  if (t == octave_class::static_type_id ()
-      || t == octave_classdef::static_type_id ())
-    {
-      type_info::unary_class_op_fcn f = ti.lookup_unary_class_op (op);
-
-      if (! f)
-        err_unary_op (octave_value::unary_op_as_string (op), v.class_name ());
-
-      retval = f (v);
-    }
-  else
-    {
-      // FIXME: we need to handle overloading operators for built-in
-      // classes (double, char, int8, etc.)
-
-      type_info::unary_op_fcn f = ti.lookup_unary_op (op, t);
-
-      if (f)
-        retval = f (v.get_rep ());
-      else
-        {
-          octave_value tv;
-          octave_base_value::type_conv_fcn cf
-            = v.numeric_conversion_function ();
-
-          if (! cf)
-            err_unary_op (octave_value::unary_op_as_string (op),
-                          v.type_name ());
-
-          octave_base_value *tmp = cf (v.get_rep ());
-
-          if (! tmp)
-            err_unary_op_conv (octave_value::unary_op_as_string (op));
-
-          tv = octave_value (tmp);
-          retval = unary_op (op, tv);
-        }
-    }
-
-  return retval;
-}
-
-octave_value
-unary_op (octave_value::unary_op op, const octave_value& v)
-{
-  type_info& ti = __get_type_info__ ();
-
-  return unary_op (ti, op, v);
-}
+  {
+    octave_value retval;
+
+    bool dq_str = (base.is_dq_string () || increment.is_dq_string ()
+                   || limit.is_dq_string ());
+
+    char type = dq_str ? '"' : '\'';
+
+    if (base.isempty () || increment.isempty () || limit.isempty ())
+      retval = octave_value ("", type);
+    else
+      {
+        Matrix mtx_base = base.matrix_value (true);
+        Matrix mtx_increment = increment.matrix_value (true);
+        Matrix mtx_limit = limit.matrix_value (true);
+
+        range<double> tmp (mtx_base(0), mtx_increment(0), mtx_limit(0));
+
+        retval = octave_value (tmp);
+      }
+
+    return retval.convert_to_str (false, true, type);
+  }
+
+  octave_value
+  colon_op (const octave_value& base, const octave_value& increment_arg,
+            const octave_value& limit, bool is_for_cmd_expr)
+  {
+    if (base.isobject () || increment_arg.isobject () || limit.isobject ())
+      {
+        octave_value_list tmp1;
+
+        if (increment_arg.is_defined ())
+          {
+            tmp1(2) = limit;
+            tmp1(1) = increment_arg;
+            tmp1(0) = base;
+          }
+        else
+          {
+            tmp1(1) = limit;
+            tmp1(0) = base;
+          }
+
+        interpreter& interp = __get_interpreter__ ();
+
+        symbol_table& symtab = interp.get_symbol_table ();
+
+        octave_value fcn = symtab.find_function ("colon", tmp1);
+
+        if (fcn.is_defined ())
+          {
+            octave_value_list tmp2 = interp.feval (fcn, tmp1, 1);
+
+            return tmp2(0);
+          }
+      }
+
+    octave_value increment
+      = increment_arg.is_defined () ? increment_arg : octave_value (1.0);
+
+    if (base.numel () > 1 || limit.numel () > 1 || increment.numel () > 1)
+      warning_with_id ("Octave:colon-nonscalar-argument",
+                       "colon arguments should be scalars");
+
+    if (base.iscomplex () || limit.iscomplex () || increment.iscomplex ())
+      warning_with_id ("Octave:colon-complex-argument",
+                       "imaginary part of complex colon arguments is ignored");
+
+    // FIXME: is there a better way to do this job, maybe using type traits?
+
+    builtin_type_t type_id = get_colon_op_type (base, increment, limit);
+
+    // For compatibility with Matlab, don't allow the range used in
+    // a FOR loop expression to be converted to a Matrix.
+
+    // For now, these functions create arrays instead of range<T> for
+    // all types except double.
+
+    switch (type_id)
+      {
+      case btyp_double:
+      case btyp_complex:
+        return make_float_range<double> (base, increment, limit, is_for_cmd_expr);
+
+      case btyp_float:
+      case btyp_float_complex:
+        return make_float_range<float> (base, increment, limit, is_for_cmd_expr);
+
+      case btyp_int8:
+        return make_int_range<octave_int8> (base, increment, limit);
+
+      case btyp_int16:
+        return make_int_range<octave_int16> (base, increment, limit);
+
+      case btyp_int32:
+        return make_int_range<octave_int32> (base, increment, limit);
+
+      case btyp_int64:
+        return make_int_range<octave_int64> (base, increment, limit);
+
+      case btyp_uint8:
+        return make_int_range<octave_uint8> (base, increment, limit);
+
+      case btyp_uint16:
+        return make_int_range<octave_uint16> (base, increment, limit);
+
+      case btyp_uint32:
+        return make_int_range<octave_uint32> (base, increment, limit);
+
+      case btyp_uint64:
+        return make_int_range<octave_uint64> (base, increment, limit);
+
+      case btyp_char:
+        return make_char_range (base, increment, limit);
+
+      case btyp_unknown:
+        error ("incompatible types found in range expression");
+
+      default:
+        error ("invalid types found in range expression");
+      }
+
+    return octave_value ();
+  }
+
+  OCTAVE_NORETURN static void
+  err_unary_op_conv (const std::string& on)
+  {
+    error ("type conversion failed for unary operator '%s'", on.c_str ());
+  }
+
+  octave_value
+  unary_op (type_info& ti, octave_value::unary_op op,
+            const octave_value& v)
+  {
+    octave_value retval;
+
+    int t = v.type_id ();
+
+    if (t == octave_class::static_type_id ()
+        || t == octave_classdef::static_type_id ())
+      {
+        type_info::unary_class_op_fcn f = ti.lookup_unary_class_op (op);
+
+        if (! f)
+          err_unary_op (octave_value::unary_op_as_string (op), v.class_name ());
+
+        retval = f (v);
+      }
+    else
+      {
+        // FIXME: we need to handle overloading operators for built-in
+        // classes (double, char, int8, etc.)
+
+        type_info::unary_op_fcn f = ti.lookup_unary_op (op, t);
+
+        if (f)
+          retval = f (v.get_rep ());
+        else
+          {
+            octave_value tv;
+            octave_base_value::type_conv_fcn cf
+              = v.numeric_conversion_function ();
+
+            if (! cf)
+              err_unary_op (octave_value::unary_op_as_string (op),
+                            v.type_name ());
+
+            octave_base_value *tmp = cf (v.get_rep ());
+
+            if (! tmp)
+              err_unary_op_conv (octave_value::unary_op_as_string (op));
+
+            tv = octave_value (tmp);
+            retval = unary_op (op, tv);
+          }
+      }
+
+    return retval;
+  }
+
+  octave_value
+  unary_op (octave_value::unary_op op, const octave_value& v)
+  {
+    type_info& ti = __get_type_info__ ();
+
+    return unary_op (ti, op, v);
+  }
 
 OCTAVE_END_NAMESPACE(octave)
 
@@ -3748,8 +3714,7 @@
                    std::string& type_string,
                    std::list<octave_value_list>& idx)
 {
-  const octave_map m =
-    arg.xmap_value ("%s: second argument must be a structure with fields 'type' and 'subs'", name);
+  const octave_map m = arg.xmap_value ("%s: second argument must be a structure with fields 'type' and 'subs'", name);
 
   if (m.nfields () != 2 || ! m.contains ("type") || ! m.contains ("subs"))
     error ("%s: second argument must be a structure with fields 'type' and 'subs'",
--- a/libinterp/octave-value/ov.h	Fri Dec 02 10:11:46 2022 -0500
+++ b/libinterp/octave-value/ov.h	Fri Dec 02 10:12:40 2022 -0500
@@ -36,7 +36,6 @@
 #include <memory>
 #include <map>
 
-#include "Range.h"
 #include "data-conv.h"
 #include "idx-vector.h"
 #include "mach-info.h"
@@ -288,34 +287,6 @@
   OCTINTERP_API octave_value (const Array<std::string>& cellstr);
   OCTINTERP_API octave_value (const octave::idx_vector& idx, bool lazy = true);
 
-private:
-
-  // Remove when public constructors that use this function are removed.
-  static OCTINTERP_API octave_base_value *
-  make_range_rep_deprecated (double base, double inc, double limit);
-
-  // Remove when public constructors that use this function are removed.
-  static OCTINTERP_API octave_base_value *
-  make_range_rep_deprecated (const Range& r, bool force_range);
-
-public:
-
-#if defined (OCTAVE_PROVIDE_DEPRECATED_SYMBOLS)
-  OCTAVE_DEPRECATED (7, "use 'octave_value (range<double>&)' instead")
-  octave_value (double base, double limit, double inc)
-    : m_rep (make_range_rep_deprecated (base, inc, limit))
-  {
-    maybe_mutate ();
-  }
-
-  OCTAVE_DEPRECATED (7, "use 'octave_value (range<double>&)' instead")
-  octave_value (const Range& r, bool force_range = false)
-    : m_rep (make_range_rep_deprecated (r, force_range))
-  {
-    maybe_mutate ();
-  }
-#endif
-
   OCTINTERP_API octave_value (const octave::range<double>& r,
                               bool force_range = false);
 
@@ -552,15 +523,6 @@
     return m_rep->do_index_op (idx, resize_ok);
   }
 
-#if defined (OCTAVE_PROVIDE_DEPRECATED_SYMBOLS)
-  OCTAVE_DEPRECATED (7, "use 'octave_value::index_op' instead")
-  octave_value do_index_op (const octave_value_list& idx,
-                            bool resize_ok = false)
-  {
-    return index_op (idx, resize_ok);
-  }
-#endif
-
   OCTINTERP_API octave_value
   subsasgn (const std::string& type, const std::list<octave_value_list>& idx,
             const octave_value& rhs);
@@ -1459,27 +1421,10 @@
 
   OCTINTERP_API octave_value& non_const_unary_op (unary_op op);
 
-#if defined (OCTAVE_PROVIDE_DEPRECATED_SYMBOLS)
-  OCTAVE_DEPRECATED (7, "use 'octave_value::non_const_unary_op' instead")
-  octave_value& do_non_const_unary_op (unary_op op)
-  {
-    return non_const_unary_op (op);
-  }
-#endif
-
   OCTINTERP_API octave_value&
   non_const_unary_op (unary_op op, const std::string& type,
                       const std::list<octave_value_list>& idx);
 
-#if defined (OCTAVE_PROVIDE_DEPRECATED_SYMBOLS)
-  OCTAVE_DEPRECATED (7, "use 'octave_value::non_const_unary_op' instead")
-  octave_value& do_non_const_unary_op (unary_op op, const std::string& type,
-                                       const std::list<octave_value_list>& idx)
-  {
-    return non_const_unary_op (op, type, idx);
-  }
-#endif
-
   const octave_base_value& get_rep (void) const { return *m_rep; }
 
   bool is_copy_of (const octave_value& val) const { return m_rep == val.m_rep; }
@@ -1736,87 +1681,6 @@
 
 OCTAVE_END_NAMESPACE(octave)
 
-#if defined (OCTAVE_PROVIDE_DEPRECATED_SYMBOLS)
-OCTAVE_DEPRECATED (7, "use 'octave::unary_op' instead")
-inline octave_value
-do_unary_op (octave::type_info& ti, octave_value::unary_op op,
-             const octave_value& a)
-{
-  return octave::unary_op (ti, op, a);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::unary_op' instead")
-inline octave_value
-do_unary_op (octave_value::unary_op op, const octave_value& a)
-{
-  return octave::unary_op (op, a);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::binary_op' instead")
-inline octave_value
-do_binary_op (octave::type_info& ti, octave_value::binary_op op,
-              const octave_value& a, const octave_value& b)
-{
-  return octave::binary_op (ti, op, a, b);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::binary_op' instead")
-inline octave_value
-do_binary_op (octave::type_info& ti, octave_value::compound_binary_op op,
-              const octave_value& a, const octave_value& b)
-{
-  return octave::binary_op (ti, op, a, b);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::binary_op' instead")
-inline octave_value
-do_binary_op (octave_value::binary_op op, const octave_value& a,
-              const octave_value& b)
-{
-  return octave::binary_op (op, a, b);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::binary_op' instead")
-inline octave_value
-do_binary_op (octave_value::compound_binary_op op, const octave_value& a,
-              const octave_value& b)
-{
-  return octave::binary_op (op, a, b);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::cat_op' instead")
-inline octave_value
-do_cat_op (octave::type_info& ti, const octave_value& a,
-           const octave_value& b, const Array<octave_idx_type>& ra_idx)
-{
-  return octave::cat_op (ti, a, b, ra_idx);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::cat_op' instead")
-inline octave_value
-do_cat_op (const octave_value& a, const octave_value& b,
-           const Array<octave_idx_type>& ra_idx)
-{
-  return octave::cat_op (a, b, ra_idx);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::colon_op' instead")
-inline octave_value
-do_colon_op (const octave_value& base, const octave_value& increment,
-             const octave_value& limit, bool is_for_cmd_expr = false)
-{
-  return octave::colon_op (base, increment, limit, is_for_cmd_expr);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::colon_op' instead")
-inline octave_value
-do_colon_op (const octave_value& base, const octave_value& limit,
-             bool is_for_cmd_expr = false)
-{
-  return octave::colon_op (base, limit, is_for_cmd_expr);
-}
-#endif
-
 #define OV_UNOP_FN(name)                                \
   inline octave_value                                   \
   name (const octave_value& a)                          \
--- a/libinterp/parse-tree/bp-table.h	Fri Dec 02 10:11:46 2022 -0500
+++ b/libinterp/parse-tree/bp-table.h	Fri Dec 02 10:12:40 2022 -0500
@@ -39,217 +39,172 @@
 
 OCTAVE_BEGIN_NAMESPACE(octave)
 
-class tree_evaluator;
-
-struct bp_type
-{
-public:
-  bp_type (int l, const std::string& c) : line (l), cond (c) { }
-
-  //--------
+  class tree_evaluator;
 
-  int line;
-  std::string cond;
-};
+  struct bp_type
+  {
+  public:
+    bp_type (int l, const std::string& c) : line (l), cond (c) { }
 
-// Interface to breakpoints.
-class OCTINTERP_API bp_table
-{
-public:
+    //--------
 
-  bp_table (tree_evaluator& tw)
-    : m_evaluator (tw), m_bp_set (), m_errors_that_stop (),
-      m_caught_that_stop (), m_warnings_that_stop ()
-  { }
-
-  ~bp_table (void) = default;
-
-  // Set of breakpoint lines.
-  typedef std::set<int> bp_lines;
+    int line;
+    std::string cond;
+  };
 
-  typedef bp_lines::const_iterator const_bp_lines_iterator;
-  typedef bp_lines::iterator bp_lines_iterator;
-
-  typedef std::map <std::string, bp_lines> fname_line_map;
-
-  typedef fname_line_map::const_iterator const_fname_line_map_iterator;
-  typedef fname_line_map::iterator fname_line_map_iterator;
-
-  typedef std::map <std::string, std::list<bp_type>> fname_bp_map;
-  typedef fname_bp_map::const_iterator const_fname_bp_map_iterator;
-  typedef fname_bp_map::iterator fname_bp_map_iterator;
+  // Interface to breakpoints.
+  class OCTINTERP_API bp_table
+  {
+  public:
 
-#if defined (OCTAVE_PROVIDE_DEPRECATED_SYMBOLS)
-  OCTAVE_DEPRECATED (7, "use 'bp_table::add_breakpoints_in_function' instead")
-  int add_breakpoint (const std::string& fname = "",
-                      const std::string& class_name = "",
-                      int line = 1,
-                      const std::string& condition = "")
-  {
-    return add_breakpoint_in_function (fname, class_name, line, condition);
-  }
+    bp_table (tree_evaluator& tw)
+      : m_evaluator (tw), m_bp_set (), m_errors_that_stop (),
+        m_caught_that_stop (), m_warnings_that_stop ()
+    { }
 
-  OCTAVE_DEPRECATED (7, "use 'bp_table::add_breakpoints_in_function' instead")
-  bp_lines add_breakpoint (const std::string& fname = "",
-                           const std::string& class_name = "",
-                           const bp_lines& lines = bp_lines (),
-                           const std::string& condition = "")
-  {
-    return add_breakpoints_in_function (fname, class_name, lines, condition);
-  }
-#endif
+    ~bp_table (void) = default;
+
+    // Set of breakpoint lines.
+    typedef std::set<int> bp_lines;
+
+    typedef bp_lines::const_iterator const_bp_lines_iterator;
+    typedef bp_lines::iterator bp_lines_iterator;
 
-  // Add a breakpoint at the nearest executable line in a function.
-  int add_breakpoint_in_function (const std::string& fname = "",
-                                  const std::string& class_name = "",
-                                  int line = 1,
-                                  const std::string& condition = "");
+    typedef std::map <std::string, bp_lines> fname_line_map;
+
+    typedef fname_line_map::const_iterator const_fname_line_map_iterator;
+    typedef fname_line_map::iterator fname_line_map_iterator;
 
-  // Add a set of breakpoints at the nearest executable lines in a
-  // function.
-  bp_lines add_breakpoints_in_function (const std::string& fname = "",
-                                        const std::string& class_name = "",
-                                        const bp_lines& lines = bp_lines (),
-                                        const std::string& condition = "");
+    typedef std::map <std::string, std::list<bp_type>> fname_bp_map;
+    typedef fname_bp_map::const_iterator const_fname_bp_map_iterator;
+    typedef fname_bp_map::iterator fname_bp_map_iterator;
 
-  // Add a breakpoint at the nearest executable line in a file.
-  int add_breakpoint_in_file (const std::string& file = "",
-                              int line = 1,
-                              const std::string& condition = "");
-
-  // Add a set of breakpoints at the nearest executable lines in a
-  // file.
-  bp_lines add_breakpoints_in_file (const std::string& file = "",
-                                    const bp_lines& lines = bp_lines (),
+    // Add a breakpoint at the nearest executable line in a function.
+    int add_breakpoint_in_function (const std::string& fname = "",
+                                    const std::string& class_name = "",
+                                    int line = 1,
                                     const std::string& condition = "");
 
-#if defined (OCTAVE_PROVIDE_DEPRECATED_SYMBOLS)
-  OCTAVE_DEPRECATED (7, "use 'bp_table::remove_breakpoint_from_function' instead")
-  int remove_breakpoint (const std::string& fname = "",
-                         int line = 1)
-  {
-    return remove_breakpoint_from_function (fname, line);
-  }
+    // Add a set of breakpoints at the nearest executable lines in a
+    // function.
+    bp_lines add_breakpoints_in_function (const std::string& fname = "",
+                                          const std::string& class_name = "",
+                                          const bp_lines& lines = bp_lines (),
+                                          const std::string& condition = "");
 
-  OCTAVE_DEPRECATED (7, "use 'bp_table::remove_breakpoints_from_function' instead")
-  int remove_breakpoint (const std::string& fname = "",
-                         const bp_lines& lines = bp_lines ())
-  {
-    return remove_breakpoints_from_function (fname, lines);
-  }
-#endif
+    // Add a breakpoint at the nearest executable line in a file.
+    int add_breakpoint_in_file (const std::string& file = "",
+                                int line = 1,
+                                const std::string& condition = "");
+
+    // Add a set of breakpoints at the nearest executable lines in a
+    // file.
+    bp_lines add_breakpoints_in_file (const std::string& file = "",
+                                      const bp_lines& lines = bp_lines (),
+                                      const std::string& condition = "");
 
-  // Remove a breakpoint from the given line in file.
-  int remove_breakpoint_from_function (const std::string& fname = "",
-                                       int line = 1);
+    // Remove a breakpoint from the given line in file.
+    int remove_breakpoint_from_function (const std::string& fname = "",
+                                         int line = 1);
 
-  // Remove a set of breakpoints from the given lines in file.
-  int remove_breakpoints_from_function (const std::string& fname = "",
-                                        const bp_lines& lines = bp_lines ());
+    // Remove a set of breakpoints from the given lines in file.
+    int remove_breakpoints_from_function (const std::string& fname = "",
+                                          const bp_lines& lines = bp_lines ());
 
-  // Remove all the breakpoints in a specified function.
-  bp_lines remove_all_breakpoints_from_function (const std::string& fname,
-      bool silent = false);
+    // Remove all the breakpoints in a specified function.
+    bp_lines remove_all_breakpoints_from_function (const std::string& fname,
+                                                   bool silent = false);
 
-  // Remove a breakpoint from the given line in file.
-  int remove_breakpoint_from_file (const std::string& file = "",
-                                   int line = 1);
+    // Remove a breakpoint from the given line in file.
+    int remove_breakpoint_from_file (const std::string& file = "",
+                                     int line = 1);
 
-  // Remove a set of breakpoints from the given lines in file.
-  int remove_breakpoints_from_file (const std::string& file = "",
-                                    const bp_lines& lines = bp_lines ());
+    // Remove a set of breakpoints from the given lines in file.
+    int remove_breakpoints_from_file (const std::string& file = "",
+                                      const bp_lines& lines = bp_lines ());
 
 
-#if defined (OCTAVE_PROVIDE_DEPRECATED_SYMBOLS)
-  OCTAVE_DEPRECATED (7, "use 'bp_table::remove_all_breakpoints_from_function' instead")
-  bp_lines remove_all_breakpoints_in_file (const std::string& fname,
-      bool silent = false)
-  {
-    return remove_all_breakpoints_from_function (fname, silent);
-  }
-#endif
+    // Remove all the breakpoints from a file.
+    bp_lines remove_all_breakpoints_from_file (const std::string& file,
+                                               bool silent = false);
+
+    // Remove all the breakpoints registered with octave.
+    void remove_all_breakpoints (void);
 
-  // Remove all the breakpoints from a file.
-  bp_lines remove_all_breakpoints_from_file (const std::string& file,
-      bool silent = false);
+    // Return all breakpoints.  Each element of the map is a vector
+    // containing the breakpoints corresponding to a given function name.
+    fname_bp_map get_breakpoint_list (const octave_value_list& fname_list);
+
+    bool have_breakpoints (void) { return (! m_bp_set.empty ()); }
 
-  // Remove all the breakpoints registered with octave.
-  void remove_all_breakpoints (void);
-
-  // Return all breakpoints.  Each element of the map is a vector
-  // containing the breakpoints corresponding to a given function name.
-  fname_bp_map get_breakpoint_list (const octave_value_list& fname_list);
-
-  bool have_breakpoints (void) { return (! m_bp_set.empty ()); }
+    // Should we enter debugging for this particular error identifier?
+    bool debug_on_err (const std::string& id)
+    {
+      return (m_errors_that_stop.empty () || m_errors_that_stop.count (id));
+    }
 
-  // Should we enter debugging for this particular error identifier?
-  bool debug_on_err (const std::string& id)
-  {
-    return (m_errors_that_stop.empty () || m_errors_that_stop.count (id));
-  }
+    // Should we enter debugging for this particular identifier in a try/catch?
+    bool debug_on_caught (const std::string& id)
+    {
+      return (m_caught_that_stop.empty () || m_caught_that_stop.count (id));
+    }
 
-  // Should we enter debugging for this particular identifier in a try/catch?
-  bool debug_on_caught (const std::string& id)
-  {
-    return (m_caught_that_stop.empty () || m_caught_that_stop.count (id));
-  }
+    // Should we enter debugging for this particular warning identifier?
+    bool debug_on_warn (const std::string& id)
+    {
+      return (m_warnings_that_stop.empty () || m_warnings_that_stop.count (id));
+    }
 
-  // Should we enter debugging for this particular warning identifier?
-  bool debug_on_warn (const std::string& id)
-  {
-    return (m_warnings_that_stop.empty () || m_warnings_that_stop.count (id));
-  }
+    octave_map stop_on_err_warn_status (bool to_screen);
+
+    void dbstop_process_map_args (const octave_map& mv);
 
-  octave_map stop_on_err_warn_status (bool to_screen);
+    void dbclear_all_signals (void);
 
-  void dbstop_process_map_args (const octave_map& mv);
+    bool condition_valid (const std::string& cond);
 
-  void dbclear_all_signals (void);
-
-  bool condition_valid (const std::string& cond);
+    void parse_dbfunction_params (const char *who,
+                                  const octave_value_list& args,
+                                  std::string& fcn_name,
+                                  std::string& class_name,
+                                  bp_table::bp_lines& lines,
+                                  std::string& cond);
 
-  void parse_dbfunction_params (const char *who,
-                                const octave_value_list& args,
-                                std::string& fcn_name,
-                                std::string& class_name,
-                                bp_table::bp_lines& lines,
-                                std::string& cond);
+  private:
+
+    typedef std::set<std::string>::const_iterator const_bp_set_iterator;
+    typedef std::set<std::string>::iterator bp_set_iterator;
 
-private:
-
-  typedef std::set<std::string>::const_iterator const_bp_set_iterator;
-  typedef std::set<std::string>::iterator bp_set_iterator;
+    tree_evaluator& m_evaluator;
 
-  tree_evaluator& m_evaluator;
-
-  // Set of function (.m file) names containing at least one breakpoint.
-  std::set<std::string> m_bp_set;
+    // Set of function (.m file) names containing at least one breakpoint.
+    std::set<std::string> m_bp_set;
 
-  // Set of error and warning message IDs that cause us to stop
-  // *if* Vdebug_on_error / Vdebug_on_caught / Vdebug_on_warning is set.
-  // Empty means stop on any error / caught error / warning.
-  std::set<std::string> m_errors_that_stop;
-  std::set<std::string> m_caught_that_stop;
-  std::set<std::string> m_warnings_that_stop;
+    // Set of error and warning message IDs that cause us to stop
+    // *if* Vdebug_on_error / Vdebug_on_caught / Vdebug_on_warning is set.
+    // Empty means stop on any error / caught error / warning.
+    std::set<std::string> m_errors_that_stop;
+    std::set<std::string> m_caught_that_stop;
+    std::set<std::string> m_warnings_that_stop;
 
-  void set_stop_flag (const char *who, const std::string& condition,
-                      bool on_off);
+    void set_stop_flag (const char *who, const std::string& condition,
+                        bool on_off);
 
-  void process_id_list (const char *who, const std::string& condition,
-                        const octave_value_list& args,
-                        int nargin, int& pos, bool on_off,
-                        std::set<std::string>& id_list);
+    void process_id_list (const char *who, const std::string& condition,
+                          const octave_value_list& args,
+                          int nargin, int& pos, bool on_off,
+                          std::set<std::string>& id_list);
 
-  bool add_breakpoint_1 (octave_user_code *fcn, const std::string& fname,
-                         const bp_lines& line, const std::string& condition,
-                         bp_lines& retval);
+    bool add_breakpoint_1 (octave_user_code *fcn, const std::string& fname,
+                           const bp_lines& line, const std::string& condition,
+                           bp_lines& retval);
 
-  int remove_breakpoint_1 (octave_user_code *fcn, const std::string&,
-                           const bp_lines& lines);
+    int remove_breakpoint_1 (octave_user_code *fcn, const std::string&,
+                             const bp_lines& lines);
 
-  bp_lines remove_all_breakpoints_in_file_1 (octave_user_code *fcn,
-      const std::string& fname);
-};
+    bp_lines remove_all_breakpoints_in_file_1 (octave_user_code *fcn,
+                                               const std::string& fname);
+  };
 
 OCTAVE_END_NAMESPACE(octave)
 
--- a/libinterp/parse-tree/lex.h	Fri Dec 02 10:11:46 2022 -0500
+++ b/libinterp/parse-tree/lex.h	Fri Dec 02 10:12:40 2022 -0500
@@ -691,10 +691,6 @@
 
   void warn_deprecated_syntax (const std::string& msg);
 
-  void warn_deprecated_operator (const std::string& deprecated_op,
-                                 const std::string& recommended_op,
-                                 const std::string& version);
-
   void push_token (token *);
 
   token * current_token (void);
--- a/libinterp/parse-tree/lex.ll	Fri Dec 02 10:11:46 2022 -0500
+++ b/libinterp/parse-tree/lex.ll	Fri Dec 02 10:12:40 2022 -0500
@@ -183,28 +183,6 @@
      }                                                                  \
    while (0)
 
-#define CMD_OR_DEPRECATED_OP(PATTERN, REPLACEMENT, VERSION, TOK)        \
-   do                                                                   \
-     {                                                                  \
-       curr_lexer->lexer_debug (PATTERN);                               \
-                                                                        \
-       if (curr_lexer->looks_like_command_arg ())                       \
-         {                                                              \
-           yyless (0);                                                  \
-           curr_lexer->push_start_state (COMMAND_START);                \
-         }                                                              \
-       else                                                             \
-         {                                                              \
-           curr_lexer->warn_deprecated_operator (PATTERN, REPLACEMENT,  \
-                                                 #VERSION);             \
-           /* set COMPAT to true here to avoid warning about            \
-              compatibility since we've already warned about the        \
-              operator being deprecated.  */                            \
-           return curr_lexer->handle_op (TOK, false, true);             \
-         }                                                              \
-     }                                                                  \
-   while (0)
-
 #define CMD_OR_UNARY_OP(PATTERN, TOK, COMPAT)                           \
    do                                                                   \
      {                                                                  \
@@ -1088,28 +1066,6 @@
     curr_lexer->m_string_text += '\v';
   }
 
-<DQ_STRING_START>(\.\.\.){S}*{NL} {
-    curr_lexer->lexer_debug ("<DQ_STRING_START>(\\.\\.\\.){S}*{NL}");
-
-    /* FIXME: Remove support for '...' continuation in Octave 9 */
-    static const char *msg = "'...' continuations in double-quoted character strings were deprecated in version 7 and will not be allowed in a future version of Octave; please use '\\' instead";
-
-    curr_lexer->warn_deprecated_syntax (msg);
-
-    HANDLE_STRING_CONTINUATION;
-  }
-
-<DQ_STRING_START>\\{S}+{NL} {
-    curr_lexer->lexer_debug ("<DQ_STRING_START>\\\\{S}+{NL}");
-
-    /* FIXME: Remove support for WS after line continuation in Octave 9 */
-    static const char *msg = "whitespace after continuation markers in double-quoted character strings were deprecated in version 7 and will not be allowed in a future version of Octave";
-
-    curr_lexer->warn_deprecated_syntax (msg);
-
-    HANDLE_STRING_CONTINUATION;
-  }
-
 <DQ_STRING_START>\\{NL} {
     curr_lexer->lexer_debug ("<DQ_STRING_START>\\\\{NL}");
 
@@ -1302,17 +1258,6 @@
 // Deprecated C preprocessor style continuation markers.
 %}
 
-\\{S}*{NL} |
-\\{S}*{CCHAR}{ANY_EXCEPT_NL}*{NL} {
-    curr_lexer->lexer_debug ("\\\\{S}*{NL}|\\\\{S}*{CCHAR}{ANY_EXCEPT_NL}*{NL}");
-
-    /* FIXME: Remove support for '\\' line continuation in Octave 9 */
-    static const char *msg = "using continuation marker \\ outside of double quoted strings was deprecated in version 7 and will be removed from a future version of Octave, use ... instead";
-
-    curr_lexer->warn_deprecated_syntax (msg);
-
-    curr_lexer->handle_continuation ();
-  }
 
 %{
 // End of file.
@@ -1644,13 +1589,10 @@
 %}
 
 ":"   { CMD_OR_OP (":", ':', true); }
-".+"  { CMD_OR_DEPRECATED_OP (".+", "+", 7, '+'); }
-".-"  { CMD_OR_DEPRECATED_OP (".-", "-", 7, '-'); }
 ".*"  { CMD_OR_OP (".*", EMUL, true); }
 "./"  { CMD_OR_OP ("./", EDIV, true); }
 ".\\" { CMD_OR_OP (".\\", ELEFTDIV, true); }
 ".^"  { CMD_OR_OP (".^", EPOW, true); }
-".**" { CMD_OR_DEPRECATED_OP (".**", ".^", 7, EPOW); }
 "<="  { CMD_OR_OP ("<=", EXPR_LE, true); }
 "=="  { CMD_OR_OP ("==", EXPR_EQ, true); }
 "!="  { CMD_OR_OP ("!=", EXPR_NE, false); }
@@ -1680,7 +1622,6 @@
   }
 
 "^"   { CMD_OR_OP ("^", POW, true); }
-"**"  { CMD_OR_DEPRECATED_OP ("**", "^", 7, POW); }
 "&&"  { CMD_OR_OP ("&&", EXPR_AND_AND, true); }
 "||"  { CMD_OR_OP ("||", EXPR_OR_OR, true); }
 
@@ -1817,15 +1758,11 @@
 "*="   { CMD_OR_OP ("*=", MUL_EQ, false); }
 "/="   { CMD_OR_OP ("/=", DIV_EQ, false); }
 "\\="  { CMD_OR_OP ("\\=", LEFTDIV_EQ, false); }
-".+="  { CMD_OR_DEPRECATED_OP (".+=", "+=", 7, ADD_EQ); }
-".-="  { CMD_OR_DEPRECATED_OP (".-=", "-=", 7, SUB_EQ); }
 ".*="  { CMD_OR_OP (".*=", EMUL_EQ, false); }
 "./="  { CMD_OR_OP ("./=", EDIV_EQ, false); }
 ".\\=" { CMD_OR_OP (".\\=", ELEFTDIV_EQ, false); }
 "^="   { CMD_OR_OP ("^=", POW_EQ, false); }
-"**="  { CMD_OR_DEPRECATED_OP ("**=", "^=", 7, POW_EQ); }
 ".^="  { CMD_OR_OP (".^=", EPOW_EQ, false); }
-".**=" { CMD_OR_DEPRECATED_OP (".**=", ".^=", 7, EPOW_EQ); }
 "&="   { CMD_OR_OP ("&=", AND_EQ, false); }
 "|="   { CMD_OR_OP ("|=", OR_EQ, false); }
 
@@ -3667,16 +3604,6 @@
   }
 
   void
-  base_lexer::warn_deprecated_operator (const std::string& deprecated_op,
-                                        const std::string& recommended_op,
-                                        const std::string& version)
-  {
-    std::string msg = "the '" + deprecated_op + "' operator was deprecated in version " + version + " and will not be allowed in a future version of Octave; please use '" + recommended_op + "' instead";
-
-    warn_deprecated_syntax (msg);
-  }
-
-  void
   base_lexer::push_token (token *tok)
   {
     YYSTYPE *lval = yyget_lval (m_scanner);
--- a/libinterp/parse-tree/oct-lvalue.h	Fri Dec 02 10:11:46 2022 -0500
+++ b/libinterp/parse-tree/oct-lvalue.h	Fri Dec 02 10:12:40 2022 -0500
@@ -81,14 +81,6 @@
 
   void unary_op (octave_value::unary_op op);
 
-#if defined (OCTAVE_PROVIDE_DEPRECATED_SYMBOLS)
-  OCTAVE_DEPRECATED (7, "use 'octave_lvalue::unary_op' instead")
-  void do_unary_op (octave_value::unary_op op)
-  {
-    return unary_op (op);
-  }
-#endif
-
   octave_value value (void) const;
 
 private:
--- a/libinterp/parse-tree/pt-eval.cc	Fri Dec 02 10:11:46 2022 -0500
+++ b/libinterp/parse-tree/pt-eval.cc	Fri Dec 02 10:12:40 2022 -0500
@@ -75,616 +75,855 @@
 
 OCTAVE_BEGIN_NAMESPACE(octave)
 
-// Normal evaluator.
-
-class quit_debug_exception
-{
-public:
-
-  quit_debug_exception (bool all = false) : m_all (all) { }
-
-  quit_debug_exception (const quit_debug_exception&) = default;
-
-  quit_debug_exception& operator = (const quit_debug_exception&) = default;
-
-  ~quit_debug_exception (void) = default;
-
-  bool all (void) const { return m_all; }
-
-private:
-
-  bool m_all;
-};
-
-class debugger
-{
-public:
-
-  enum execution_mode
-  {
-    EX_NORMAL = 0,
-    EX_CONTINUE = 1,
-    EX_QUIT = 2,
-    EX_QUIT_ALL = 3
+  // Normal evaluator.
+
+  class quit_debug_exception
+  {
+  public:
+
+    quit_debug_exception (bool all = false) : m_all (all) { }
+
+    quit_debug_exception (const quit_debug_exception&) = default;
+
+    quit_debug_exception& operator = (const quit_debug_exception&) = default;
+
+    ~quit_debug_exception (void) = default;
+
+    bool all (void) const { return m_all; }
+
+  private:
+
+    bool m_all;
   };
 
-  debugger (interpreter& interp, std::size_t level)
-    : m_interpreter (interp), m_level (level),
-      m_execution_mode (EX_NORMAL), m_in_debug_repl (false)
-  { }
-
-  int server_loop (void);
-
-  void repl (const std::string& prompt = "debug> ");
-
-  bool in_debug_repl (void) const { return m_in_debug_repl; }
-
-  void dbcont (void) { m_execution_mode = EX_CONTINUE; }
-
-  void dbquit (bool all = false)
-  {
-    if (all)
-      m_execution_mode = EX_QUIT_ALL;
-    else
-      m_execution_mode = EX_QUIT;
-  }
-
-  bool quitting_debugger (void) const;
-
-private:
-
-  interpreter& m_interpreter;
-
-  std::size_t m_level;
-  execution_mode m_execution_mode;
-  bool m_in_debug_repl;
-};
-
-// FIXME: Could the debugger server_loop and repl functions be merged
-// with the corresponding tree_evaluator functions or do they need to
-// remain separate?  They perform nearly the same functions.
-
-int debugger::server_loop (void)
-{
-  // Process events from the event queue.
-
-  tree_evaluator& tw = m_interpreter.get_evaluator ();
-
-  void (tree_evaluator::*server_mode_fptr) (bool)
-    = &tree_evaluator::server_mode;
-  unwind_action act (server_mode_fptr, &tw, true);
-
-  int exit_status = 0;
-
-  do
-    {
-      if (m_execution_mode == EX_CONTINUE || tw.dbstep_flag ())
-        break;
-
-      if (quitting_debugger ())
-        break;
-
-      try
-        {
-          // FIXME: Should we call octave_quit in the octave::sleep
-          // and/or command_editor::run_event_hooks functions?
-
-          octave_quit ();
-
-          // FIXME: Running the event queue should be decoupled from
-          // the command_editor.
-
-          // FIXME: Is it OK to use command_editor::run_event_hooks
-          // here?  It may run more than one queued function per call,
-          // and it seems that the checks at the top of the loop
-          // probably need to be done after each individual event
-          // function is executed.  For now, maybe the simplest thing
-          // would be to pass a predicate function (lambda expression)
-          // to the command_editor::run_event_hooks and have it check
-          // that and break out of the eval loop(s) if the condition
-          // is met?
-
-          // FIXME: We should also use a condition variable to manage
-          // the execution of entries in the queue and eliminate the
-          // need for the busy-wait loop.
-
-          command_editor::run_event_hooks ();
-
-          release_unreferenced_dynamic_libraries ();
-
-          sleep (0.1);
-        }
-      catch (const interrupt_exception&)
-        {
-          octave_interrupt_state = 1;
-          m_interpreter.recover_from_exception ();
-
-          // Required newline when the user does Ctrl+C at the prompt.
-          if (m_interpreter.interactive ())
-            octave_stdout << "\n";
-        }
-      catch (const index_exception& e)
-        {
-          m_interpreter.recover_from_exception ();
-
-          std::cerr << "error: unhandled index exception: "
-                    << e.message () << " -- trying to return to prompt"
-                    << std::endl;
-        }
-      catch (const execution_exception& ee)
-        {
-          error_system& es = m_interpreter.get_error_system ();
-
-          es.save_exception (ee);
-          es.display_exception (ee);
-
-          if (m_interpreter.interactive ())
-            {
-              m_interpreter.recover_from_exception ();
-            }
-          else
-            {
-              // We should exit with a nonzero status.
-              exit_status = 1;
-              break;
-            }
-        }
-      catch (const quit_debug_exception& qde)
-        {
-          if (qde.all ())
-            throw;
-
-          // Continue in this debug level.
-        }
-      catch (const std::bad_alloc&)
-        {
-          m_interpreter.recover_from_exception ();
-
-          std::cerr << "error: out of memory -- trying to return to prompt"
-                    << std::endl;
-        }
-    }
-  while (exit_status == 0);
-
-  if (exit_status == EOF)
-    {
-      if (m_interpreter.interactive ())
-        octave_stdout << "\n";
-
-      exit_status = 0;
-    }
-
-  return exit_status;
-}
-
-void debugger::repl (const std::string& prompt_arg)
-{
-  unwind_protect frame;
-
-  frame.protect_var (m_in_debug_repl);
-  frame.protect_var (m_execution_mode);
-
-  m_in_debug_repl = true;
-
-  tree_evaluator& tw = m_interpreter.get_evaluator ();
-
-  bool silent = tw.quiet_breakpoint_flag (false);
-
-  frame.add (&tree_evaluator::restore_frame, &tw,
-             tw.current_call_stack_frame_number ());
-
-  tw.goto_frame (tw.debug_frame ());
-
-  octave_user_code *caller = tw.current_user_code ();
-  std::string fcn_file_nm, fcn_nm;
-
-  if (caller)
-    {
-      fcn_file_nm = caller->fcn_file_name ();
-      fcn_nm = fcn_file_nm.empty () ? caller->name () : fcn_file_nm;
-    }
-
-  int curr_debug_line = tw.current_line ();
-
-  std::ostringstream buf;
-
-  input_system& input_sys = m_interpreter.get_input_system ();
-
-  event_manager& evmgr = m_interpreter.get_event_manager ();
-
-  if (! fcn_nm.empty ())
-    {
-      if (input_sys.gud_mode ())
-        {
-          static char ctrl_z = 'Z' & 0x1f;
-
-          buf << ctrl_z << ctrl_z << fcn_nm << ':' << curr_debug_line;
-        }
-      else
-        {
-          // FIXME: we should come up with a clean way to detect
-          // that we are stopped on the no-op command that marks the
-          // end of a function or script.
-
-          if (! silent)
-            {
-              std::shared_ptr<stack_frame> frm = tw.current_user_frame ();
-
-              frm->display_stopped_in_message (buf);
-            }
-
-          evmgr.enter_debugger_event (fcn_nm, fcn_file_nm, curr_debug_line);
-
-          evmgr.set_workspace ();
-
-          frame.add (&event_manager::execute_in_debugger_event, &evmgr,
-                     fcn_nm, curr_debug_line);
-
-          if (! silent)
-            {
-              std::string line_buf;
-
-              if (caller)
-                line_buf = caller->get_code_line (curr_debug_line);
-
-              if (! line_buf.empty ())
-                buf << curr_debug_line << ": " << line_buf;
-            }
-        }
-    }
-
-  if (silent)
-    command_editor::erase_empty_line (true);
-
-  std::string stopped_in_msg = buf.str ();
-
-  if (m_interpreter.server_mode ())
-    {
-      if (! stopped_in_msg.empty ())
-        octave_stdout << stopped_in_msg << std::endl;
-
-      evmgr.push_event_queue ();
-
-      frame.add (&event_manager::pop_event_queue, &evmgr);
-
-      frame.add (&tree_evaluator::set_parser, &tw, tw.get_parser ());
-
-      std::shared_ptr<push_parser>
-      debug_parser (new push_parser (m_interpreter));
-
-      tw.set_parser (debug_parser);
-
-      server_loop ();
-    }
-  else
+  class debugger
+  {
+  public:
+
+    enum execution_mode
+      {
+        EX_NORMAL = 0,
+        EX_CONTINUE = 1,
+        EX_QUIT = 2,
+        EX_QUIT_ALL = 3
+      };
+
+    debugger (interpreter& interp, std::size_t level)
+      : m_interpreter (interp), m_level (level),
+        m_execution_mode (EX_NORMAL), m_in_debug_repl (false)
+    { }
+
+    int server_loop (void);
+
+    void repl (const std::string& prompt = "debug> ");
+
+    bool in_debug_repl (void) const { return m_in_debug_repl; }
+
+    void dbcont (void) { m_execution_mode = EX_CONTINUE; }
+
+    void dbquit (bool all = false)
     {
-      if (! stopped_in_msg.empty ())
-        std::cerr << stopped_in_msg << std::endl;
-
-      std::string tmp_prompt = prompt_arg;
-      if (m_level > 0)
-        tmp_prompt = "[" + std::to_string (m_level) + "]" + prompt_arg;
-
-      frame.add (&input_system::set_PS1, &input_sys, input_sys.PS1 ());
-      input_sys.PS1 (tmp_prompt);
-
-      if (! m_interpreter.interactive ())
-        {
-          void (interpreter::*interactive_fptr) (bool)
-            = &interpreter::interactive;
-          frame.add (interactive_fptr, &m_interpreter,
-                     m_interpreter.interactive ());
-
-          m_interpreter.interactive (true);
-
-          // FIXME: should debugging be possible in an embedded
-          // interpreter?
-
-          application *app = application::app ();
-
-          if (app)
-            {
-              void (application::*forced_interactive_fptr) (bool)
-                = &application::forced_interactive;
-              frame.add (forced_interactive_fptr, app,
-                         app->forced_interactive ());
-
-              app->forced_interactive (true);
-            }
-        }
-
-#if defined (OCTAVE_ENABLE_COMMAND_LINE_PUSH_PARSER)
-
-      input_reader reader (m_interpreter);
-
-      push_parser debug_parser (m_interpreter);
-
-#else
-
-      parser debug_parser (m_interpreter);
-
-#endif
-
-      error_system& es = m_interpreter.get_error_system ();
-
-      while (m_in_debug_repl)
-        {
-          if (m_execution_mode == EX_CONTINUE || tw.dbstep_flag ())
-            break;
-
-          if (quitting_debugger ())
-            break;
-
-          try
-            {
-              debug_parser.reset ();
-
-#if defined (OCTAVE_ENABLE_COMMAND_LINE_PUSH_PARSER)
-
-              int retval = 0;
-
-              std::string prompt
-                = command_editor::decode_prompt_string (tmp_prompt);
-
-              do
-                {
-                  bool eof = false;
-                  std::string input_line = reader.get_input (prompt, eof);
-
-                  if (eof)
-                    {
-                      retval = EOF;
-                      break;
-                    }
-
-                  retval = debug_parser.run (input_line, false);
-
-                  prompt = command_editor::decode_prompt_string (input_sys.PS2 ());
-                }
-              while (retval < 0);
-
-#else
-
-              int retval = debug_parser.run ();
-
-#endif
-              if (command_editor::interrupt (false))
-                {
-                  // Break regardless of m_execution_mode value.
-
-                  quitting_debugger ();
-
-                  break;
-                }
-              else
-                {
-                  if (retval == 0)
-                    {
-                      std::shared_ptr<tree_statement_list> stmt_list
-                        = debug_parser.statement_list ();
-
-                      if (stmt_list)
-                        stmt_list->accept (tw);
-
-                      if (octave_completion_matches_called)
-                        octave_completion_matches_called = false;
-
-                      // FIXME: the following statement is here because
-                      // the last command may have been a dbup, dbdown, or
-                      // dbstep command that changed the current debug
-                      // frame.  If so, we need to reset the current frame
-                      // for the call stack.  But is this right way to do
-                      // this job?  What if the statement list was
-                      // something like "dbup; dbstack"?  Will the call to
-                      // dbstack use the right frame?  If not, how can we
-                      // fix this problem?
-                      tw.goto_frame (tw.debug_frame ());
-                    }
-
-                  octave_quit ();
-                }
-            }
-          catch (const execution_exception& ee)
-            {
-              es.save_exception (ee);
-              es.display_exception (ee);
-
-              // Ignore errors when in debugging mode;
-              m_interpreter.recover_from_exception ();
-            }
-          catch (const quit_debug_exception& qde)
-            {
-              if (qde.all ())
-                throw;
-
-              // Continue in this debug level.
-            }
-        }
-    }
-}
-
-bool debugger::quitting_debugger (void) const
-{
-  if (m_execution_mode == EX_QUIT)
-    {
-      // If there is no enclosing debug level or the top-level
-      // repl is not active, handle dbquit the same as dbcont.
-
-      if (m_level > 0 || m_interpreter.server_mode ()
-          || m_interpreter.in_top_level_repl ())
-        throw quit_debug_exception ();
+      if (all)
+        m_execution_mode = EX_QUIT_ALL;
       else
-        return true;
+        m_execution_mode = EX_QUIT;
     }
 
-  if (m_execution_mode == EX_QUIT_ALL)
-    {
-      // If the top-level repl is not active, handle "dbquit all"
-      // the same as dbcont.
-
-      if (m_interpreter.server_mode () || m_interpreter.in_top_level_repl ())
-        throw quit_debug_exception (true);
-      else
-        return true;
-    }
-
-  return false;
-}
-
-bool tree_evaluator::at_top_level (void) const
-{
-  return m_call_stack.at_top_level ();
-}
-
-std::string
-tree_evaluator::mfilename (const std::string& opt) const
-{
-  std::string fname;
-
-  octave_user_code *fcn = m_call_stack.current_user_code ();
-
-  if (fcn)
-    {
-      fname = fcn->fcn_file_name ();
-
-      if (fname.empty ())
-        fname = fcn->name ();
-    }
-
-  if (opt == "fullpathext")
-    return fname;
-
-  std::size_t dpos = fname.rfind (sys::file_ops::dir_sep_char ());
-  std::size_t epos = fname.rfind ('.');
-
-  if (epos <= dpos+1)
-    epos = std::string::npos;
-
-  if (epos != std::string::npos)
-    fname = fname.substr (0, epos);
-
-  if (opt == "fullpath")
-    return fname;
-
-  if (dpos != std::string::npos)
-    fname = fname.substr (dpos+1);
-
-  return fname;
-}
-
-void tree_evaluator::parse_and_execute (const std::string& input,
-                                        bool& incomplete_parse)
-{
-  incomplete_parse = false;
-
-  unwind_protect_var<bool> upv (m_in_top_level_repl, true);
-
-  if (at_top_level ())
-    {
-      dbstep_flag (0);
-      reset_debug_state ();
-    }
-
-  // FIXME: OK to do this job here, or should it be in the functions
-  // that do the actual prompting?
-
-  // Update the time stamp for the "prompt" so that automatically
-  // finding modified files based on file modification times will
-  // work.  In the future, we may do something completely different to
-  // check for changes to files but for now, we rely on the prompt
-  // time stamp to limit the checks for file modification times.
-
-  Vlast_prompt_time.stamp ();
-
-  bool eof = false;
-
-  event_manager& evmgr = m_interpreter.get_event_manager ();
-
-  if (command_history::add (input))
-    evmgr.append_history (input);
-
-  m_exit_status = m_parser->run (input, eof);
-
-  if (m_exit_status == 0)
-    {
-      std::shared_ptr<tree_statement_list>
-      stmt_list = m_parser->statement_list ();
-
-      if (stmt_list)
-        {
-          command_editor::increment_current_command_number ();
-
-          eval (stmt_list, m_interpreter.interactive ());
-
-          evmgr.set_workspace ();
-        }
-      else if (m_parser->at_end_of_input ())
-        m_exit_status = EOF;
-    }
-  else
-    incomplete_parse = true;
-
-  // FIXME: Should we be checking m_exit_status or incomplete_parse or
-  // both here?  Could EOF have a value other than -1, and is there
-  // possible confusion between that state and the parser returning -1?
-
-  if (m_exit_status == -1)
-    m_exit_status = 0;
-  else
-    m_parser->reset ();
-
-  evmgr.pre_input_event ();
-}
-
-void tree_evaluator::get_line_and_eval (void)
-{
-  std::mutex mtx;
-  std::unique_lock<std::mutex> lock (mtx);
-  std::condition_variable cv;
-  bool incomplete_parse = false;
-  bool evaluation_pending = false;
-  bool exiting = false;
-
-  input_system& input_sys = m_interpreter.get_input_system ();
-  event_manager& evmgr = m_interpreter.get_event_manager ();
-
-  while (true)
-    {
-      // FIXME: Detect EOF?  Use readline?  If
-      // so, then we need to disable idle event loop hook function
-      // execution.
-
-      std::string ps = incomplete_parse ? input_sys.PS2 () : input_sys.PS1 ();
-
-      std::cout << command_editor::decode_prompt_string (ps);
-
-      std::string input;
-      std::getline (std::cin, input);
-
-      if (input.empty ())
-        continue;
-
-      incomplete_parse = false;
-      evaluation_pending = true;
-      exiting = false;
-
-      evmgr.post_event
-      ([&] (interpreter& interp)
+    bool quitting_debugger (void) const;
+
+  private:
+
+    interpreter& m_interpreter;
+
+    std::size_t m_level;
+    execution_mode m_execution_mode;
+    bool m_in_debug_repl;
+  };
+
+  // FIXME: Could the debugger server_loop and repl functions be merged
+  // with the corresponding tree_evaluator functions or do they need to
+  // remain separate?  They perform nearly the same functions.
+
+  int debugger::server_loop (void)
+  {
+    // Process events from the event queue.
+
+    tree_evaluator& tw = m_interpreter.get_evaluator ();
+
+    void (tree_evaluator::*server_mode_fptr) (bool)
+      = &tree_evaluator::server_mode;
+    unwind_action act (server_mode_fptr, &tw, true);
+
+    int exit_status = 0;
+
+    do
       {
-        // INTERPRETER THREAD
-
-        std::lock_guard<std::mutex> local_lock (mtx);
+        if (m_execution_mode == EX_CONTINUE || tw.dbstep_flag ())
+          break;
+
+        if (quitting_debugger ())
+          break;
 
         try
           {
-            interp.parse_and_execute (input, incomplete_parse);
+            // FIXME: Should we call octave_quit in the octave::sleep
+            // and/or command_editor::run_event_hooks functions?
+
+            octave_quit ();
+
+            // FIXME: Running the event queue should be decoupled from
+            // the command_editor.
+
+            // FIXME: Is it OK to use command_editor::run_event_hooks
+            // here?  It may run more than one queued function per call,
+            // and it seems that the checks at the top of the loop
+            // probably need to be done after each individual event
+            // function is executed.  For now, maybe the simplest thing
+            // would be to pass a predicate function (lambda expression)
+            // to the command_editor::run_event_hooks and have it check
+            // that and break out of the eval loop(s) if the condition
+            // is met?
+
+            // FIXME: We should also use a condition variable to manage
+            // the execution of entries in the queue and eliminate the
+            // need for the busy-wait loop.
+
+            command_editor::run_event_hooks ();
+
+            release_unreferenced_dynamic_libraries ();
+
+            sleep (0.1);
+          }
+        catch (const interrupt_exception&)
+          {
+            octave_interrupt_state = 1;
+            m_interpreter.recover_from_exception ();
+
+            // Required newline when the user does Ctrl+C at the prompt.
+            if (m_interpreter.interactive ())
+              octave_stdout << "\n";
+          }
+        catch (const index_exception& e)
+          {
+            m_interpreter.recover_from_exception ();
+
+            std::cerr << "error: unhandled index exception: "
+                      << e.message () << " -- trying to return to prompt"
+                      << std::endl;
+          }
+        catch (const execution_exception& ee)
+          {
+            error_system& es = m_interpreter.get_error_system ();
+
+            es.save_exception (ee);
+            es.display_exception (ee);
+
+            if (m_interpreter.interactive ())
+              {
+                m_interpreter.recover_from_exception ();
+              }
+            else
+              {
+                // We should exit with a nonzero status.
+                exit_status = 1;
+                break;
+              }
+          }
+        catch (const quit_debug_exception& qde)
+          {
+            if (qde.all ())
+              throw;
+
+            // Continue in this debug level.
+          }
+        catch (const std::bad_alloc&)
+          {
+            m_interpreter.recover_from_exception ();
+
+            std::cerr << "error: out of memory -- trying to return to prompt"
+                      << std::endl;
           }
-        catch (const exit_exception&)
+      }
+    while (exit_status == 0);
+
+    if (exit_status == EOF)
+      {
+        if (m_interpreter.interactive ())
+          octave_stdout << "\n";
+
+        exit_status = 0;
+      }
+
+    return exit_status;
+  }
+
+  void debugger::repl (const std::string& prompt_arg)
+  {
+    unwind_protect frame;
+
+    frame.protect_var (m_in_debug_repl);
+    frame.protect_var (m_execution_mode);
+
+    m_in_debug_repl = true;
+
+    tree_evaluator& tw = m_interpreter.get_evaluator ();
+
+    bool silent = tw.quiet_breakpoint_flag (false);
+
+    frame.add (&tree_evaluator::restore_frame, &tw,
+               tw.current_call_stack_frame_number ());
+
+    tw.goto_frame (tw.debug_frame ());
+
+    octave_user_code *caller = tw.current_user_code ();
+    std::string fcn_file_nm, fcn_nm;
+
+    if (caller)
+      {
+        fcn_file_nm = caller->fcn_file_name ();
+        fcn_nm = fcn_file_nm.empty () ? caller->name () : fcn_file_nm;
+      }
+
+    int curr_debug_line = tw.current_line ();
+
+    std::ostringstream buf;
+
+    input_system& input_sys = m_interpreter.get_input_system ();
+
+    event_manager& evmgr = m_interpreter.get_event_manager ();
+
+    if (! fcn_nm.empty ())
+      {
+        if (input_sys.gud_mode ())
+          {
+            static char ctrl_z = 'Z' & 0x1f;
+
+            buf << ctrl_z << ctrl_z << fcn_nm << ':' << curr_debug_line;
+          }
+        else
+          {
+            // FIXME: we should come up with a clean way to detect
+            // that we are stopped on the no-op command that marks the
+            // end of a function or script.
+
+            if (! silent)
+              {
+                std::shared_ptr<stack_frame> frm = tw.current_user_frame ();
+
+                frm->display_stopped_in_message (buf);
+              }
+
+            evmgr.enter_debugger_event (fcn_nm, fcn_file_nm, curr_debug_line);
+
+            evmgr.set_workspace ();
+
+            frame.add (&event_manager::execute_in_debugger_event, &evmgr,
+                       fcn_nm, curr_debug_line);
+
+            if (! silent)
+              {
+                std::string line_buf;
+
+                if (caller)
+                  line_buf = caller->get_code_line (curr_debug_line);
+
+                if (! line_buf.empty ())
+                  buf << curr_debug_line << ": " << line_buf;
+              }
+          }
+      }
+
+    if (silent)
+      command_editor::erase_empty_line (true);
+
+    std::string stopped_in_msg = buf.str ();
+
+    if (m_interpreter.server_mode ())
+      {
+        if (! stopped_in_msg.empty ())
+          octave_stdout << stopped_in_msg << std::endl;
+
+        evmgr.push_event_queue ();
+
+        frame.add (&event_manager::pop_event_queue, &evmgr);
+
+        frame.add (&tree_evaluator::set_parser, &tw, tw.get_parser ());
+
+        std::shared_ptr<push_parser>
+          debug_parser (new push_parser (m_interpreter));
+
+        tw.set_parser (debug_parser);
+
+        server_loop ();
+      }
+    else
+      {
+        if (! stopped_in_msg.empty ())
+          std::cerr << stopped_in_msg << std::endl;
+
+        std::string tmp_prompt = prompt_arg;
+        if (m_level > 0)
+          tmp_prompt = "[" + std::to_string (m_level) + "]" + prompt_arg;
+
+        frame.add (&input_system::set_PS1, &input_sys, input_sys.PS1 ());
+        input_sys.PS1 (tmp_prompt);
+
+        if (! m_interpreter.interactive ())
+          {
+            void (interpreter::*interactive_fptr) (bool)
+              = &interpreter::interactive;
+            frame.add (interactive_fptr, &m_interpreter,
+                       m_interpreter.interactive ());
+
+            m_interpreter.interactive (true);
+
+            // FIXME: should debugging be possible in an embedded
+            // interpreter?
+
+            application *app = application::app ();
+
+            if (app)
+              {
+                void (application::*forced_interactive_fptr) (bool)
+                  = &application::forced_interactive;
+                frame.add (forced_interactive_fptr, app,
+                           app->forced_interactive ());
+
+                app->forced_interactive (true);
+              }
+          }
+
+#if defined (OCTAVE_ENABLE_COMMAND_LINE_PUSH_PARSER)
+
+        input_reader reader (m_interpreter);
+
+        push_parser debug_parser (m_interpreter);
+
+#else
+
+        parser debug_parser (m_interpreter);
+
+#endif
+
+        error_system& es = m_interpreter.get_error_system ();
+
+        while (m_in_debug_repl)
           {
-            evaluation_pending = false;
-            exiting = true;
-            cv.notify_all ();
-            throw;
+            if (m_execution_mode == EX_CONTINUE || tw.dbstep_flag ())
+              break;
+
+            if (quitting_debugger ())
+              break;
+
+            try
+              {
+                debug_parser.reset ();
+
+#if defined (OCTAVE_ENABLE_COMMAND_LINE_PUSH_PARSER)
+
+                int retval = 0;
+
+                std::string prompt
+                  = command_editor::decode_prompt_string (tmp_prompt);
+
+                do
+                  {
+                    bool eof = false;
+                    std::string input_line = reader.get_input (prompt, eof);
+
+                    if (eof)
+                      {
+                        retval = EOF;
+                        break;
+                      }
+
+                    retval = debug_parser.run (input_line, false);
+
+                    prompt = command_editor::decode_prompt_string (input_sys.PS2 ());
+                  }
+                while (retval < 0);
+
+#else
+
+                int retval = debug_parser.run ();
+
+#endif
+                if (command_editor::interrupt (false))
+                  {
+                    // Break regardless of m_execution_mode value.
+
+                    quitting_debugger ();
+
+                    break;
+                  }
+                else
+                  {
+                    if (retval == 0)
+                      {
+                        std::shared_ptr<tree_statement_list> stmt_list
+                          = debug_parser.statement_list ();
+
+                        if (stmt_list)
+                          stmt_list->accept (tw);
+
+                        if (octave_completion_matches_called)
+                          octave_completion_matches_called = false;
+
+                        // FIXME: the following statement is here because
+                        // the last command may have been a dbup, dbdown, or
+                        // dbstep command that changed the current debug
+                        // frame.  If so, we need to reset the current frame
+                        // for the call stack.  But is this right way to do
+                        // this job?  What if the statement list was
+                        // something like "dbup; dbstack"?  Will the call to
+                        // dbstack use the right frame?  If not, how can we
+                        // fix this problem?
+                        tw.goto_frame (tw.debug_frame ());
+                      }
+
+                    octave_quit ();
+                  }
+              }
+            catch (const execution_exception& ee)
+              {
+                es.save_exception (ee);
+                es.display_exception (ee);
+
+                // Ignore errors when in debugging mode;
+                m_interpreter.recover_from_exception ();
+              }
+            catch (const quit_debug_exception& qde)
+              {
+                if (qde.all ())
+                  throw;
+
+                // Continue in this debug level.
+              }
+          }
+      }
+  }
+
+  bool debugger::quitting_debugger (void) const
+  {
+    if (m_execution_mode == EX_QUIT)
+      {
+        // If there is no enclosing debug level or the top-level
+        // repl is not active, handle dbquit the same as dbcont.
+
+        if (m_level > 0 || m_interpreter.server_mode ()
+            || m_interpreter.in_top_level_repl ())
+          throw quit_debug_exception ();
+        else
+          return true;
+      }
+
+    if (m_execution_mode == EX_QUIT_ALL)
+      {
+        // If the top-level repl is not active, handle "dbquit all"
+        // the same as dbcont.
+
+        if (m_interpreter.server_mode () || m_interpreter.in_top_level_repl ())
+          throw quit_debug_exception (true);
+        else
+          return true;
+      }
+
+    return false;
+  }
+
+  bool tree_evaluator::at_top_level (void) const
+  {
+    return m_call_stack.at_top_level ();
+  }
+
+  std::string
+  tree_evaluator::mfilename (const std::string& opt) const
+  {
+    std::string fname;
+
+    octave_user_code *fcn = m_call_stack.current_user_code ();
+
+    if (fcn)
+      {
+        fname = fcn->fcn_file_name ();
+
+        if (fname.empty ())
+          fname = fcn->name ();
+      }
+
+    if (opt == "fullpathext")
+      return fname;
+
+    std::size_t dpos = fname.rfind (sys::file_ops::dir_sep_char ());
+    std::size_t epos = fname.rfind ('.');
+
+    if (epos <= dpos+1)
+      epos = std::string::npos;
+
+    if (epos != std::string::npos)
+      fname = fname.substr (0, epos);
+
+    if (opt == "fullpath")
+      return fname;
+
+    if (dpos != std::string::npos)
+      fname = fname.substr (dpos+1);
+
+    return fname;
+  }
+
+  void tree_evaluator::parse_and_execute (const std::string& input,
+                                          bool& incomplete_parse)
+  {
+    incomplete_parse = false;
+
+    unwind_protect_var<bool> upv (m_in_top_level_repl, true);
+
+    if (at_top_level ())
+      {
+        dbstep_flag (0);
+        reset_debug_state ();
+      }
+
+    // FIXME: OK to do this job here, or should it be in the functions
+    // that do the actual prompting?
+
+    // Update the time stamp for the "prompt" so that automatically
+    // finding modified files based on file modification times will
+    // work.  In the future, we may do something completely different to
+    // check for changes to files but for now, we rely on the prompt
+    // time stamp to limit the checks for file modification times.
+
+    Vlast_prompt_time.stamp ();
+
+    bool eof = false;
+
+    event_manager& evmgr = m_interpreter.get_event_manager ();
+
+    if (command_history::add (input))
+      evmgr.append_history (input);
+
+    m_exit_status = m_parser->run (input, eof);
+
+    if (m_exit_status == 0)
+      {
+        std::shared_ptr<tree_statement_list>
+          stmt_list = m_parser->statement_list ();
+
+        if (stmt_list)
+          {
+            command_editor::increment_current_command_number ();
+
+            eval (stmt_list, m_interpreter.interactive ());
+
+            evmgr.set_workspace ();
+          }
+        else if (m_parser->at_end_of_input ())
+          m_exit_status = EOF;
+      }
+    else
+      incomplete_parse = true;
+
+    // FIXME: Should we be checking m_exit_status or incomplete_parse or
+    // both here?  Could EOF have a value other than -1, and is there
+    // possible confusion between that state and the parser returning -1?
+
+    if (m_exit_status == -1)
+      m_exit_status = 0;
+    else
+      m_parser->reset ();
+
+    evmgr.pre_input_event ();
+  }
+
+  void tree_evaluator::get_line_and_eval (void)
+  {
+    std::mutex mtx;
+    std::unique_lock<std::mutex> lock (mtx);
+    std::condition_variable cv;
+    bool incomplete_parse = false;
+    bool evaluation_pending = false;
+    bool exiting = false;
+
+    input_system& input_sys = m_interpreter.get_input_system ();
+    event_manager& evmgr = m_interpreter.get_event_manager ();
+
+    while (true)
+      {
+        // FIXME: Detect EOF?  Use readline?  If
+        // so, then we need to disable idle event loop hook function
+        // execution.
+
+        std::string ps = incomplete_parse ? input_sys.PS2 () : input_sys.PS1 ();
+
+        std::cout << command_editor::decode_prompt_string (ps);
+
+        std::string input;
+        std::getline (std::cin, input);
+
+        if (input.empty ())
+          continue;
+
+        incomplete_parse = false;
+        evaluation_pending = true;
+        exiting = false;
+
+        evmgr.post_event
+          ([&] (interpreter& interp)
+           {
+             // INTERPRETER THREAD
+
+             std::lock_guard<std::mutex> local_lock (mtx);
+
+             try
+               {
+                 interp.parse_and_execute (input, incomplete_parse);
+               }
+             catch (const exit_exception&)
+               {
+                 evaluation_pending = false;
+                 exiting = true;
+                 cv.notify_all ();
+                 throw;
+               }
+             catch (const execution_exception& ee)
+               {
+                 error_system& es = m_interpreter.get_error_system ();
+
+                 es.save_exception (ee);
+                 es.display_exception (ee);
+
+                 if (m_interpreter.interactive ())
+                   {
+                     m_interpreter.recover_from_exception ();
+                     m_parser->reset ();
+                     evaluation_pending = false;
+                     cv.notify_all ();
+                   }
+                 else
+                   {
+                     evaluation_pending = false;
+                     cv.notify_all ();
+                     throw exit_exception (1);
+                   }
+               }
+             catch (...)
+               {
+                 evaluation_pending = false;
+                 cv.notify_all ();
+                 throw;
+               }
+
+             evaluation_pending = false;
+             cv.notify_all ();
+           });
+
+        // Wait until evaluation is finished before prompting for input
+        // again.
+
+        cv.wait (lock, [&] { return ! evaluation_pending; });
+
+        if (exiting)
+          break;
+      }
+  }
+
+  int tree_evaluator::repl (void)
+  {
+    // The big loop.  Read, Eval, Print, Loop.  Normally user
+    // interaction at the command line in a terminal session, but we may
+    // also end up here when reading from a pipe or when stdin is
+    // connected to a file by the magic of input redirection.
+
+    int exit_status = 0;
+
+    // FIXME: should this choice be a command-line option?  Note that we
+    // intend that the push parser interface only be used for
+    // interactive sessions.
+
+#if defined (OCTAVE_ENABLE_COMMAND_LINE_PUSH_PARSER)
+    static bool use_command_line_push_parser = true;
+#else
+    static bool use_command_line_push_parser = false;
+#endif
+
+    // The following logic is written as it is to allow easy transition
+    // to setting USE_COMMAND_LINE_PUSH_PARSER at run time and to
+    // simplify the logic of the main loop below by using the same
+    // base_parser::run interface for both push and pull parsers.
+
+    std::shared_ptr<base_parser> repl_parser;
+
+    if (m_interpreter.interactive ())
+      {
+        if (use_command_line_push_parser)
+          {
+            push_parser *pp
+              = new push_parser (m_interpreter,
+                                 new input_reader (m_interpreter));
+
+            repl_parser = std::shared_ptr<base_parser> (pp);
+          }
+        else
+          {
+            parser *pp = new parser (new lexer (m_interpreter));
+            repl_parser = std::shared_ptr<base_parser> (pp);
+          }
+      }
+    else
+      {
+        parser *pp = new parser (new lexer (stdin, m_interpreter));
+        repl_parser = std::shared_ptr<base_parser> (pp);
+      }
+
+    do
+      {
+        try
+          {
+            unwind_protect_var<bool> upv (m_in_top_level_repl, true);
+
+            repl_parser->reset ();
+
+            if (at_top_level ())
+              {
+                dbstep_flag (0);
+                reset_debug_state ();
+              }
+
+            exit_status = repl_parser->run ();
+
+            if (exit_status == 0)
+              {
+                std::shared_ptr<tree_statement_list>
+                  stmt_list = repl_parser->statement_list ();
+
+                if (stmt_list)
+                  {
+                    command_editor::increment_current_command_number ();
+
+                    eval (stmt_list, m_interpreter.interactive ());
+                  }
+                else if (repl_parser->at_end_of_input ())
+                  {
+                    exit_status = EOF;
+                    break;
+                  }
+              }
+          }
+        catch (const interrupt_exception&)
+          {
+            m_interpreter.recover_from_exception ();
+
+            // Required newline when the user does Ctrl+C at the prompt.
+            if (m_interpreter.interactive ())
+              octave_stdout << "\n";
+          }
+        catch (const index_exception& ie)
+          {
+            m_interpreter.recover_from_exception ();
+
+            std::cerr << "error: unhandled index exception: "
+                      << ie.message () << " -- trying to return to prompt"
+                      << std::endl;
+          }
+        catch (const execution_exception& ee)
+          {
+            error_system& es = m_interpreter.get_error_system ();
+
+            es.save_exception (ee);
+            es.display_exception (ee);
+
+            if (m_interpreter.interactive ())
+              m_interpreter.recover_from_exception ();
+            else
+              {
+                // We should exit with a nonzero status.
+                exit_status = 1;
+                break;
+              }
+          }
+        catch (const quit_debug_exception&)
+          {
+            m_interpreter.recover_from_exception ();
+
+            // FIXME: Does anything else need to happen here?
+          }
+        catch (const std::bad_alloc&)
+          {
+            m_interpreter.recover_from_exception ();
+
+            std::cerr << "error: out of memory -- trying to return to prompt"
+                      << std::endl;
+          }
+      }
+    while (exit_status == 0);
+
+    if (exit_status == EOF)
+      {
+        if (m_interpreter.interactive ())
+          octave_stdout << "\n";
+
+        exit_status = 0;
+      }
+
+    return exit_status;
+  }
+
+  int tree_evaluator::server_loop (void)
+  {
+    // Process events from the event queue.
+
+    unwind_protect_var<bool> upv1 (m_server_mode, true);
+
+    m_exit_status = 0;
+
+    std::shared_ptr<push_parser> parser (new push_parser (m_interpreter));
+    unwind_protect_var<std::shared_ptr<push_parser>> upv2 (m_parser, parser);
+
+    // FIXME: We are currently resetting the parser after every call to
+    // recover_from_exception.  This action should probably be handled
+    // in a more consistent way, but resetting the parser in every call
+    // to interpreter::recover_from_exception appears to cause
+    // segfaults in the test suite.
+
+    do
+      {
+        try
+          {
+            // FIXME: Should we call octave_quit in the octave::sleep
+            // and/or command_editor::run_event_hooks functions?
+
+            octave_quit ();
+
+            // FIXME: Running the event queue should be decoupled from
+            // the command_editor.  We should also use a condition
+            // variable to manage the execution of entries in the queue
+            // and eliminate the need for the busy-wait loop.
+
+            command_editor::run_event_hooks ();
+
+            release_unreferenced_dynamic_libraries ();
+
+            sleep (0.1);
+          }
+        catch (const interrupt_exception&)
+          {
+            octave_interrupt_state = 1;
+            m_interpreter.recover_from_exception ();
+            m_parser->reset ();
+
+            // Required newline when the user does Ctrl+C at the prompt.
+            if (m_interpreter.interactive ())
+              octave_stdout << "\n";
+          }
+        catch (const index_exception& e)
+          {
+            m_interpreter.recover_from_exception ();
+            m_parser->reset ();
+
+            std::cerr << "error: unhandled index exception: "
+                      << e.message () << " -- trying to return to prompt"
+                      << std::endl;
           }
         catch (const execution_exception& ee)
           {
@@ -697,1133 +936,874 @@
               {
                 m_interpreter.recover_from_exception ();
                 m_parser->reset ();
-                evaluation_pending = false;
-                cv.notify_all ();
               }
             else
               {
-                evaluation_pending = false;
-                cv.notify_all ();
-                throw exit_exception (1);
+                // We should exit with a nonzero status.
+                m_exit_status = 1;
+                break;
               }
           }
-        catch (...)
+        catch (const quit_debug_exception&)
           {
-            evaluation_pending = false;
-            cv.notify_all ();
-            throw;
-          }
-
-        evaluation_pending = false;
-        cv.notify_all ();
-      });
-
-      // Wait until evaluation is finished before prompting for input
-      // again.
-
-      cv.wait (lock, [&] { return ! evaluation_pending; });
-
-      if (exiting)
-        break;
-    }
-}
-
-int tree_evaluator::repl (void)
-{
-  // The big loop.  Read, Eval, Print, Loop.  Normally user
-  // interaction at the command line in a terminal session, but we may
-  // also end up here when reading from a pipe or when stdin is
-  // connected to a file by the magic of input redirection.
-
-  int exit_status = 0;
-
-  // FIXME: should this choice be a command-line option?  Note that we
-  // intend that the push parser interface only be used for
-  // interactive sessions.
-
-#if defined (OCTAVE_ENABLE_COMMAND_LINE_PUSH_PARSER)
-  static bool use_command_line_push_parser = true;
-#else
-  static bool use_command_line_push_parser = false;
-#endif
-
-  // The following logic is written as it is to allow easy transition
-  // to setting USE_COMMAND_LINE_PUSH_PARSER at run time and to
-  // simplify the logic of the main loop below by using the same
-  // base_parser::run interface for both push and pull parsers.
-
-  std::shared_ptr<base_parser> repl_parser;
-
-  if (m_interpreter.interactive ())
-    {
-      if (use_command_line_push_parser)
-        {
-          push_parser *pp
-            = new push_parser (m_interpreter,
-                               new input_reader (m_interpreter));
-
-          repl_parser = std::shared_ptr<base_parser> (pp);
-        }
-      else
-        {
-          parser *pp = new parser (new lexer (m_interpreter));
-          repl_parser = std::shared_ptr<base_parser> (pp);
-        }
-    }
-  else
-    {
-      parser *pp = new parser (new lexer (stdin, m_interpreter));
-      repl_parser = std::shared_ptr<base_parser> (pp);
-    }
-
-  do
-    {
-      try
-        {
-          unwind_protect_var<bool> upv (m_in_top_level_repl, true);
-
-          repl_parser->reset ();
-
-          if (at_top_level ())
-            {
-              dbstep_flag (0);
-              reset_debug_state ();
-            }
-
-          exit_status = repl_parser->run ();
-
-          if (exit_status == 0)
-            {
-              std::shared_ptr<tree_statement_list>
-              stmt_list = repl_parser->statement_list ();
-
-              if (stmt_list)
-                {
-                  command_editor::increment_current_command_number ();
-
-                  eval (stmt_list, m_interpreter.interactive ());
-                }
-              else if (repl_parser->at_end_of_input ())
-                {
-                  exit_status = EOF;
-                  break;
-                }
-            }
-        }
-      catch (const interrupt_exception&)
-        {
-          m_interpreter.recover_from_exception ();
-
-          // Required newline when the user does Ctrl+C at the prompt.
-          if (m_interpreter.interactive ())
-            octave_stdout << "\n";
-        }
-      catch (const index_exception& ie)
-        {
-          m_interpreter.recover_from_exception ();
-
-          std::cerr << "error: unhandled index exception: "
-                    << ie.message () << " -- trying to return to prompt"
-                    << std::endl;
-        }
-      catch (const execution_exception& ee)
-        {
-          error_system& es = m_interpreter.get_error_system ();
-
-          es.save_exception (ee);
-          es.display_exception (ee);
-
-          if (m_interpreter.interactive ())
+            octave_interrupt_state = 1;
             m_interpreter.recover_from_exception ();
-          else
-            {
-              // We should exit with a nonzero status.
-              exit_status = 1;
-              break;
-            }
-        }
-      catch (const quit_debug_exception&)
-        {
-          m_interpreter.recover_from_exception ();
-
-          // FIXME: Does anything else need to happen here?
-        }
-      catch (const std::bad_alloc&)
-        {
-          m_interpreter.recover_from_exception ();
-
-          std::cerr << "error: out of memory -- trying to return to prompt"
-                    << std::endl;
-        }
-    }
-  while (exit_status == 0);
-
-  if (exit_status == EOF)
-    {
-      if (m_interpreter.interactive ())
-        octave_stdout << "\n";
-
-      exit_status = 0;
-    }
-
-  return exit_status;
-}
-
-int tree_evaluator::server_loop (void)
-{
-  // Process events from the event queue.
-
-  unwind_protect_var<bool> upv1 (m_server_mode, true);
-
-  m_exit_status = 0;
-
-  std::shared_ptr<push_parser> parser (new push_parser (m_interpreter));
-  unwind_protect_var<std::shared_ptr<push_parser>> upv2 (m_parser, parser);
-
-  // FIXME: We are currently resetting the parser after every call to
-  // recover_from_exception.  This action should probably be handled
-  // in a more consistent way, but resetting the parser in every call
-  // to interpreter::recover_from_exception appears to cause
-  // segfaults in the test suite.
-
-  do
-    {
-      try
-        {
-          // FIXME: Should we call octave_quit in the octave::sleep
-          // and/or command_editor::run_event_hooks functions?
-
-          octave_quit ();
-
-          // FIXME: Running the event queue should be decoupled from
-          // the command_editor.  We should also use a condition
-          // variable to manage the execution of entries in the queue
-          // and eliminate the need for the busy-wait loop.
-
-          command_editor::run_event_hooks ();
-
-          release_unreferenced_dynamic_libraries ();
-
-          sleep (0.1);
-        }
-      catch (const interrupt_exception&)
-        {
-          octave_interrupt_state = 1;
-          m_interpreter.recover_from_exception ();
-          m_parser->reset ();
-
-          // Required newline when the user does Ctrl+C at the prompt.
-          if (m_interpreter.interactive ())
-            octave_stdout << "\n";
-        }
-      catch (const index_exception& e)
-        {
-          m_interpreter.recover_from_exception ();
-          m_parser->reset ();
-
-          std::cerr << "error: unhandled index exception: "
-                    << e.message () << " -- trying to return to prompt"
-                    << std::endl;
-        }
-      catch (const execution_exception& ee)
-        {
-          error_system& es = m_interpreter.get_error_system ();
-
-          es.save_exception (ee);
-          es.display_exception (ee);
-
-          if (m_interpreter.interactive ())
-            {
-              m_interpreter.recover_from_exception ();
-              m_parser->reset ();
-            }
-          else
-            {
-              // We should exit with a nonzero status.
-              m_exit_status = 1;
-              break;
-            }
-        }
-      catch (const quit_debug_exception&)
-        {
-          octave_interrupt_state = 1;
-          m_interpreter.recover_from_exception ();
-          m_parser->reset ();
-        }
-      catch (const exit_exception& xe)
-        {
-          m_exit_status = xe.exit_status ();
-          break;
-        }
-      catch (const std::bad_alloc&)
-        {
-          m_interpreter.recover_from_exception ();
-          m_parser->reset ();
-
-          std::cerr << "error: out of memory -- trying to return to prompt"
-                    << std::endl;
-        }
-    }
-  while (m_exit_status == 0);
-
-  if (m_exit_status == EOF)
-    {
-      if (m_interpreter.interactive ())
-        octave_stdout << "\n";
-
-      m_exit_status = 0;
-    }
-
-  return m_exit_status;
-}
-
-void tree_evaluator::eval (std::shared_ptr<tree_statement_list>& stmt_list,
-                           bool interactive)
-{
-  try
-    {
-      stmt_list->accept (*this);
-
-      octave_quit ();
-
-      if (! interactive)
-        {
-          bool quit = (m_returning || m_breaking);
-
-          if (m_returning)
-            m_returning = 0;
-
-          if (m_breaking)
-            m_breaking--;
-
-          if (quit)
-            return;
-        }
-
-      if (octave_completion_matches_called)
-        octave_completion_matches_called = false;
-    }
-  catch (const quit_debug_exception&)
-    {
-      m_interpreter.recover_from_exception ();
-    }
-}
-
-octave_value_list
-tree_evaluator::eval_string (const std::string& eval_str, bool silent,
-                             int& parse_status, int nargout)
-{
-  octave_value_list retval;
-
-  parser eval_parser (eval_str, m_interpreter);
-
-  do
-    {
-      eval_parser.reset ();
-
-      // If we are looking at
-      //
-      //   val = eval ("code");
-      //
-      // then don't allow code to be parsed as a command.
-
-      if (nargout > 0)
-        eval_parser.disallow_command_syntax ();
-
-      parse_status = eval_parser.run ();
-
-      if (parse_status == 0)
-        {
-          std::shared_ptr<tree_statement_list> stmt_list
-            = eval_parser.statement_list ();
-
-          if (stmt_list)
-            {
-              tree_statement *stmt = nullptr;
-
-              if (stmt_list->length () == 1
-                  && (stmt = stmt_list->front ())
-                  && stmt->is_expression ())
-                {
-                  tree_expression *expr = stmt->expression ();
-
-                  if (silent)
-                    expr->set_print_flag (false);
-
-                  retval = expr->evaluate_n (*this, nargout);
-
-                  bool do_bind_ans = false;
-
-                  if (expr->is_identifier ())
-                    do_bind_ans = ! is_variable (expr);
-                  else
-                    do_bind_ans = ! expr->is_assignment_expression ();
-
-                  if (do_bind_ans && ! retval.empty ())
-                    bind_ans (retval(0), expr->print_result ());
-
-                  if (nargout == 0)
-                    retval = octave_value_list ();
-                }
-              else if (nargout == 0)
-                stmt_list->accept (*this);
-              else
-                error ("eval: invalid use of statement list");
-
-              if (returning () || breaking () || continuing ())
-                break;
-            }
-          else if (eval_parser.at_end_of_input ())
+            m_parser->reset ();
+          }
+        catch (const exit_exception& xe)
+          {
+            m_exit_status = xe.exit_status ();
             break;
-        }
-    }
-  while (parse_status == 0);
-
-  return retval;
-}
-
-octave_value tree_evaluator::eval_string (const std::string& eval_str,
-    bool silent, int& parse_status)
-{
-  octave_value retval;
-
-  octave_value_list tmp = eval_string (eval_str, silent, parse_status, 1);
-
-  if (! tmp.empty ())
-    retval = tmp(0);
-
-  return retval;
-}
-
-octave_value_list tree_evaluator::eval_string (const octave_value& arg,
-    bool silent, int& parse_status,
-    int nargout)
-{
-  std::string s = arg.xstring_value ("eval: expecting string argument");
-
-  return eval_string (s, silent, parse_status, nargout);
-}
-
-octave_value_list tree_evaluator::eval (const std::string& try_code,
-                                        int nargout)
-{
-  int parse_status = 0;
-
-  return eval_string (try_code, nargout > 0, parse_status, nargout);
-}
-
-octave_value_list tree_evaluator::eval (const std::string& try_code,
-                                        const std::string& catch_code,
-                                        int nargout)
-{
-  octave_value_list retval;
-
-  error_system& es = m_interpreter.get_error_system ();
-
-  int parse_status = 0;
-
-  bool execution_error = false;
-
-  octave_value_list tmp;
-
-  try
-    {
-      tmp = eval_string (try_code, nargout > 0, parse_status, nargout);
-    }
-  catch (const execution_exception& ee)
-    {
-      es.save_exception (ee);
-      m_interpreter.recover_from_exception ();
-
-      execution_error = true;
-    }
-
-  if (parse_status != 0 || execution_error)
-    {
-      tmp = eval_string (catch_code, nargout > 0, parse_status, nargout);
-
-      retval = (nargout > 0) ? tmp : octave_value_list ();
-    }
-  else
-    {
-      if (nargout > 0)
-        retval = tmp;
-
-      // FIXME: we should really be rethrowing whatever
-      // exception occurred, not just throwing an
-      // execution exception.
-      if (execution_error)
-        throw execution_exception ();
-    }
-
-  return retval;
-}
-
-octave_value_list tree_evaluator::evalin (const std::string& context,
-    const std::string& try_code,
-    int nargout)
-{
-  unwind_action act ([=] (std::size_t frm)
-  {
-    m_call_stack.restore_frame (frm);
-  }, m_call_stack.current_frame ());
-
-  if (context == "caller")
-    m_call_stack.goto_caller_frame ();
-  else if (context == "base")
-    m_call_stack.goto_base_frame ();
-  else
-    error (R"(evalin: CONTEXT must be "caller" or "base")");
-
-  int parse_status = 0;
-
-  return eval_string (try_code, nargout > 0, parse_status, nargout);
-}
-
-octave_value_list tree_evaluator::evalin (const std::string& context,
-    const std::string& try_code,
-    const std::string& catch_code,
-    int nargout)
-{
-  octave_value_list retval;
-
-  unwind_action act1 ([=] (std::size_t frm)
-  {
-    m_call_stack.restore_frame (frm);
-  }, m_call_stack.current_frame ());
-
-  if (context == "caller")
-    m_call_stack.goto_caller_frame ();
-  else if (context == "base")
-    m_call_stack.goto_base_frame ();
-  else
-    error (R"(evalin: CONTEXT must be "caller" or "base")");
-
-  error_system& es = m_interpreter.get_error_system ();
-
-  int parse_status = 0;
-
-  bool execution_error = false;
-
-  octave_value_list tmp;
-
-  try
-    {
-      tmp = eval_string (try_code, nargout > 0, parse_status, nargout);
-    }
-  catch (const execution_exception& ee)
-    {
-      es.save_exception (ee);
-      m_interpreter.recover_from_exception ();
-
-      execution_error = true;
-    }
-
-  if (parse_status != 0 || execution_error)
-    {
-      tmp = eval_string (catch_code, nargout > 0, parse_status, nargout);
-
-      retval = (nargout > 0) ? tmp : octave_value_list ();
-    }
-  else
-    {
-      if (nargout > 0)
-        retval = tmp;
-
-      // FIXME: we should really be rethrowing whatever
-      // exception occurred, not just throwing an
-      // execution exception.
-      if (execution_error)
-        throw execution_exception ();
-    }
-
-  return retval;
-}
-
-void
-tree_evaluator::visit_anon_fcn_handle (tree_anon_fcn_handle&)
-{
-  panic_impossible ();
-}
-
-void
-tree_evaluator::visit_argument_list (tree_argument_list&)
-{
-  panic_impossible ();
-}
-
-void
-tree_evaluator::visit_arguments_block (tree_arguments_block&)
-{
-  warning ("function arguments validation blocks are not supported; INCORRECT RESULTS ARE POSSIBLE");
-}
-
-void
-tree_evaluator::visit_args_block_attribute_list (tree_args_block_attribute_list&)
-{
-  panic_impossible ();
-}
-
-void
-tree_evaluator::visit_args_block_validation_list (tree_args_block_validation_list&)
-{
-  panic_impossible ();
-}
-
-void
-tree_evaluator::visit_arg_validation (tree_arg_validation&)
-{
-  panic_impossible ();
-}
-
-void
-tree_evaluator::visit_arg_size_spec (tree_arg_size_spec&)
-{
-  panic_impossible ();
-}
-
-void
-tree_evaluator::visit_arg_validation_fcns (tree_arg_validation_fcns&)
-{
-  panic_impossible ();
-}
-
-void
-tree_evaluator::visit_binary_expression (tree_binary_expression&)
-{
-  panic_impossible ();
-}
-
-void
-tree_evaluator::visit_boolean_expression (tree_boolean_expression&)
-{
-  panic_impossible ();
-}
-
-void
-tree_evaluator::visit_compound_binary_expression (tree_compound_binary_expression&)
-{
-  panic_impossible ();
-}
-
-void
-tree_evaluator::visit_break_command (tree_break_command& cmd)
-{
-  if (m_echo_state)
-    {
-      int line = cmd.line ();
-      if (line < 0)
-        line = 1;
-      echo_code (line);
-      m_echo_file_pos = line + 1;
-    }
-
-  if (m_debug_mode)
-    do_breakpoint (cmd.is_active_breakpoint (*this));
-
-  if (m_in_loop_command)
-    m_breaking = 1;
-  else
-    error ("break must appear in a loop in the same file as loop command");
-}
-
-void
-tree_evaluator::visit_colon_expression (tree_colon_expression&)
-{
-  panic_impossible ();
-}
-
-void
-tree_evaluator::visit_continue_command (tree_continue_command& cmd)
-{
-  if (m_echo_state)
-    {
-      int line = cmd.line ();
-      if (line < 0)
-        line = 1;
-      echo_code (line);
-      m_echo_file_pos = line + 1;
-    }
-
-  if (m_debug_mode)
-    do_breakpoint (cmd.is_active_breakpoint (*this));
-
-  if (m_in_loop_command)
-    m_continuing = 1;
-}
-
-bool
-tree_evaluator::statement_printing_enabled (void)
-{
-  return ! (m_silent_functions && (m_statement_context == SC_FUNCTION
-                                   || m_statement_context == SC_SCRIPT));
-}
-
-void
-tree_evaluator::reset_debug_state (void)
-{
-  m_debug_mode = (m_bp_table.have_breakpoints ()
-                  || m_dbstep_flag != 0
-                  || m_break_on_next_stmt
-                  || in_debug_repl ());
-}
-
-void
-tree_evaluator::reset_debug_state (bool mode)
-{
-  m_debug_mode = mode;
-}
-
-void
-tree_evaluator::enter_debugger (const std::string& prompt)
-{
-  unwind_protect frame;
-
-  frame.add (command_history::ignore_entries,
-             command_history::ignoring_entries ());
-
-  command_history::ignore_entries (false);
-
-  frame.add (&call_stack::restore_frame, &m_call_stack,
-             m_call_stack.current_frame ());
-
-  // Don't allow errors or warnings at the debug prompt to push us
-  // into deeper levels of debugging.
-
-  error_system& es = m_interpreter.get_error_system ();
-
-  frame.add (&error_system::set_debug_on_error, &es, es.debug_on_error ());
-
-  frame.add (&error_system::set_debug_on_warning, &es,
-             es.debug_on_warning ());
-
-  es.debug_on_error (false);
-  es.debug_on_warning (false);
-
-  // Go up to the nearest user code frame.
-
-  m_debug_frame = m_call_stack.dbupdown (0);
-
-  // FIXME: probably we just want to print one line, not the
-  // entire statement, which might span many lines...
-  //
-  // tree_print_code tpc (octave_stdout);
-  // stmt.accept (tpc);
-
-  debugger *dbgr = new debugger (m_interpreter, m_debugger_stack.size ());
-
-  m_debugger_stack.push (dbgr);
-
-  frame.add ([=] (void)
-  {
-    delete m_debugger_stack.top ();
-    m_debugger_stack.pop ();
-    reset_debug_state ();
-  });
-
-  dbgr->repl (prompt);
-}
-
-void
-tree_evaluator::keyboard (const std::string& prompt)
-{
-  enter_debugger (prompt);
-}
-
-void
-tree_evaluator::dbupdown (int n, bool verbose)
-{
-  m_debug_frame = m_call_stack.dbupdown (n, verbose);
-}
-
-Matrix
-tree_evaluator::ignored_fcn_outputs (void) const
-{
-  Matrix retval;
-
-  const std::list<octave_lvalue> *lvalues = m_lvalue_list;
-
-  if (! lvalues)
+          }
+        catch (const std::bad_alloc&)
+          {
+            m_interpreter.recover_from_exception ();
+            m_parser->reset ();
+
+            std::cerr << "error: out of memory -- trying to return to prompt"
+                      << std::endl;
+          }
+      }
+    while (m_exit_status == 0);
+
+    if (m_exit_status == EOF)
+      {
+        if (m_interpreter.interactive ())
+          octave_stdout << "\n";
+
+        m_exit_status = 0;
+      }
+
+    return m_exit_status;
+  }
+
+  void tree_evaluator::eval (std::shared_ptr<tree_statement_list>& stmt_list,
+                             bool interactive)
+  {
+    try
+      {
+        stmt_list->accept (*this);
+
+        octave_quit ();
+
+        if (! interactive)
+          {
+            bool quit = (m_returning || m_breaking);
+
+            if (m_returning)
+              m_returning = 0;
+
+            if (m_breaking)
+              m_breaking--;
+
+            if (quit)
+              return;
+          }
+
+        if (octave_completion_matches_called)
+          octave_completion_matches_called = false;
+      }
+    catch (const quit_debug_exception&)
+      {
+        m_interpreter.recover_from_exception ();
+      }
+  }
+
+  octave_value_list
+  tree_evaluator::eval_string (const std::string& eval_str, bool silent,
+                               int& parse_status, int nargout)
+  {
+    octave_value_list retval;
+
+    parser eval_parser (eval_str, m_interpreter);
+
+    do
+      {
+        eval_parser.reset ();
+
+        // If we are looking at
+        //
+        //   val = eval ("code");
+        //
+        // then don't allow code to be parsed as a command.
+
+        if (nargout > 0)
+          eval_parser.disallow_command_syntax ();
+
+        parse_status = eval_parser.run ();
+
+        if (parse_status == 0)
+          {
+            std::shared_ptr<tree_statement_list> stmt_list
+              = eval_parser.statement_list ();
+
+            if (stmt_list)
+              {
+                tree_statement *stmt = nullptr;
+
+                if (stmt_list->length () == 1
+                    && (stmt = stmt_list->front ())
+                    && stmt->is_expression ())
+                  {
+                    tree_expression *expr = stmt->expression ();
+
+                    if (silent)
+                      expr->set_print_flag (false);
+
+                    retval = expr->evaluate_n (*this, nargout);
+
+                    bool do_bind_ans = false;
+
+                    if (expr->is_identifier ())
+                      do_bind_ans = ! is_variable (expr);
+                    else
+                      do_bind_ans = ! expr->is_assignment_expression ();
+
+                    if (do_bind_ans && ! retval.empty ())
+                      bind_ans (retval(0), expr->print_result ());
+
+                    if (nargout == 0)
+                      retval = octave_value_list ();
+                  }
+                else if (nargout == 0)
+                  stmt_list->accept (*this);
+                else
+                  error ("eval: invalid use of statement list");
+
+                if (returning () || breaking () || continuing ())
+                  break;
+              }
+            else if (eval_parser.at_end_of_input ())
+              break;
+          }
+      }
+    while (parse_status == 0);
+
+    return retval;
+  }
+
+  octave_value tree_evaluator::eval_string (const std::string& eval_str,
+                                            bool silent, int& parse_status)
+  {
+    octave_value retval;
+
+    octave_value_list tmp = eval_string (eval_str, silent, parse_status, 1);
+
+    if (! tmp.empty ())
+      retval = tmp(0);
+
+    return retval;
+  }
+
+  octave_value_list tree_evaluator::eval_string (const octave_value& arg,
+                                                 bool silent, int& parse_status,
+                                                 int nargout)
+  {
+    std::string s = arg.xstring_value ("eval: expecting string argument");
+
+    return eval_string (s, silent, parse_status, nargout);
+  }
+
+  octave_value_list tree_evaluator::eval (const std::string& try_code,
+                                          int nargout)
+  {
+    int parse_status = 0;
+
+    return eval_string (try_code, nargout > 0, parse_status, nargout);
+  }
+
+  octave_value_list tree_evaluator::eval (const std::string& try_code,
+                                          const std::string& catch_code,
+                                          int nargout)
+  {
+    octave_value_list retval;
+
+    error_system& es = m_interpreter.get_error_system ();
+
+    int parse_status = 0;
+
+    bool execution_error = false;
+
+    octave_value_list tmp;
+
+    try
+      {
+        tmp = eval_string (try_code, nargout > 0, parse_status, nargout);
+      }
+    catch (const execution_exception& ee)
+      {
+        es.save_exception (ee);
+        m_interpreter.recover_from_exception ();
+
+        execution_error = true;
+      }
+
+    if (parse_status != 0 || execution_error)
+      {
+        tmp = eval_string (catch_code, nargout > 0, parse_status, nargout);
+
+        retval = (nargout > 0) ? tmp : octave_value_list ();
+      }
+    else
+      {
+        if (nargout > 0)
+          retval = tmp;
+
+        // FIXME: we should really be rethrowing whatever
+        // exception occurred, not just throwing an
+        // execution exception.
+        if (execution_error)
+          throw execution_exception ();
+      }
+
+    return retval;
+  }
+
+  octave_value_list tree_evaluator::evalin (const std::string& context,
+                                            const std::string& try_code,
+                                            int nargout)
+  {
+    unwind_action act ([=] (std::size_t frm)
+                       {
+                         m_call_stack.restore_frame (frm);
+                       }, m_call_stack.current_frame ());
+
+    if (context == "caller")
+      m_call_stack.goto_caller_frame ();
+    else if (context == "base")
+      m_call_stack.goto_base_frame ();
+    else
+      error (R"(evalin: CONTEXT must be "caller" or "base")");
+
+    int parse_status = 0;
+
+    return eval_string (try_code, nargout > 0, parse_status, nargout);
+  }
+
+  octave_value_list tree_evaluator::evalin (const std::string& context,
+                                            const std::string& try_code,
+                                            const std::string& catch_code,
+                                            int nargout)
+  {
+    octave_value_list retval;
+
+    unwind_action act1 ([=] (std::size_t frm)
+                        {
+                          m_call_stack.restore_frame (frm);
+                        }, m_call_stack.current_frame ());
+
+    if (context == "caller")
+      m_call_stack.goto_caller_frame ();
+    else if (context == "base")
+      m_call_stack.goto_base_frame ();
+    else
+      error (R"(evalin: CONTEXT must be "caller" or "base")");
+
+    error_system& es = m_interpreter.get_error_system ();
+
+    int parse_status = 0;
+
+    bool execution_error = false;
+
+    octave_value_list tmp;
+
+    try
+      {
+        tmp = eval_string (try_code, nargout > 0, parse_status, nargout);
+      }
+    catch (const execution_exception& ee)
+      {
+        es.save_exception (ee);
+        m_interpreter.recover_from_exception ();
+
+        execution_error = true;
+      }
+
+    if (parse_status != 0 || execution_error)
+      {
+        tmp = eval_string (catch_code, nargout > 0, parse_status, nargout);
+
+        retval = (nargout > 0) ? tmp : octave_value_list ();
+      }
+    else
+      {
+        if (nargout > 0)
+          retval = tmp;
+
+        // FIXME: we should really be rethrowing whatever
+        // exception occurred, not just throwing an
+        // execution exception.
+        if (execution_error)
+          throw execution_exception ();
+      }
+
     return retval;
-
-  octave_idx_type nbh = 0;
-
-  for (const auto& lval : *lvalues)
-    nbh += lval.is_black_hole ();
-
-  if (nbh > 0)
-    {
-      retval.resize (1, nbh);
-
-      octave_idx_type k = 0;
-      octave_idx_type l = 0;
-
-      for (const auto& lval : *lvalues)
-        {
-          if (lval.is_black_hole ())
-            retval(l++) = k+1;
-
-          k += lval.numel ();
-        }
-    }
-
-  return retval;
-}
-
-// If NAME is an operator (like "+", "-", ...), convert it to the
-// corresponding function name ("plus", "minus", ...).
-
-static std::string
-get_operator_function_name (const std::string& name)
-{
-  // Bow to the god of compatibility.
-
-  // FIXME: it seems ugly to put this here, but there is no single
-  // function in the parser that converts from the operator name to
-  // the corresponding function name.  At least try to do it without N
-  // string compares.
-
-  // FIXME: .+, .-, **, and .** are deprecated but still need to be
-  // handled here until they are removed.
-
-  std::size_t len = name.length ();
-
-  if (len == 3 && name == ".**")
-    // deprecated
-    return "power";
-  else if (len == 2)
-    {
-      if (name[0] == '.')
-        {
-          switch (name[1])
-            {
-            case '\'':
-              return "transpose";
-
-            case '+':
-              // deprecated
-              return "plus";
-
-            case '-':
-              // deprecated
-              return "minus";
-
-            case '*':
-              return "times";
-
-            case '/':
-              return "rdivide";
-
-            case '^':
-              return "power";
-
-            case '\\':
-              return "ldivide";
-
-            default:
-              break;
-            }
-        }
-      else if (name[1] == '=')
-        {
-          switch (name[0])
-            {
-            case '<':
-              return "le";
-
-            case '=':
-              return "eq";
-
-            case '>':
-              return "ge";
-
-            case '~':
-            case '!':
-              return "ne";
-
-            default:
-              break;
-            }
-        }
-      else if (name == "**")
-        // deprecated
-        return "mpower";
-    }
-  else if (len == 1)
-    {
-      switch (name[0])
-        {
-        case '~':
-        case '!':
-          return "not";
-
-        case '\'':
-          return "ctranspose";
-
-        case '+':
-          return "plus";
-
-        case '-':
-          return "minus";
-
-        case '*':
-          return "mtimes";
-
-        case '/':
-          return "mrdivide";
-
-        case '^':
-          return "mpower";
-
-        case '\\':
-          return "mldivide";
-
-        case '<':
-          return "lt";
-
-        case '>':
-          return "gt";
-
-        case '&':
-          return "and";
-
-        case '|':
-          return "or";
-
-        default:
-          break;
-        }
-    }
-
-  return name;
-}
-
-// Creates a function handle that takes into account the context,
-// finding local, nested, private, or sub functions.
-
-octave_value
-tree_evaluator::make_fcn_handle (const std::string& name)
-{
-  octave_value retval;
-
-  // The str2func function can create a function handle with the name
-  // of an operator (for example, "+").  If so, it is converted to the
-  // name of the corresponding function ("+" -> "plus") and we create
-  // a simple function handle using that name.
-
-  std::string fcn_name = get_operator_function_name (name);
-
-  // If FCN_NAME is different from NAME, then NAME is an operator.  As
-  // of version 2020a, Matlab apparently uses the function name
-  // corresponding to the operator to search for private and local
-  // functions in the current scope but not(!) nested functions.
-
-  bool name_is_operator = fcn_name != name;
-
-  std::size_t pos = fcn_name.find ('.');
-
-  if (pos != std::string::npos)
-    {
-      // Recognize (some of?  which ones?) the following cases
-      // and create something other than a simple function handle?
-      // Should we just be checking for the last two when the first
-      // element of the dot-separated list is an object?  If so, then
-      // should this syntax be limited to a dot-separated list with
-      // exactly two elements?
-      //
-      //   object . method
-      //   object . static-method
-      //
-      // Code to do that duplicates some of simple_fcn_handle::call.
-
-      // Only accept expressions that contain one '.' separator.
-
-      // FIXME: The logic here is a bit complicated.  Is there a good
-      // way to simplify it?
-
-      std::string meth_nm = fcn_name.substr (pos+1);
-
-      if (meth_nm.find ('.') == std::string::npos)
-        {
-          std::string obj_nm = fcn_name.substr (0, pos);
-
-          // If obj_nm is an object in the current scope with a
-          // method named meth_nm, create a classsimple handle.
-
-          octave_value object = varval (obj_nm);
-
-          if (object.is_defined () && object.is_classdef_object ())
-            {
-              octave_classdef *cdef = object.classdef_object_value ();
-
-              if (cdef)
-                {
-                  std::string class_nm = cdef->class_name ();
-
-                  cdef_object cdef_obj = cdef->get_object ();
-
-                  cdef_class cls = cdef_obj.get_class ();
-
-                  cdef_method meth = cls.find_method (meth_nm);
-
-                  if (meth.ok ())
-                    {
-                      // If the method we found is static, create a
-                      // new function name from the class name and
-                      // method name and create a simple function
-                      // handle below.  Otherwise, create a class
-                      // simple function handle.
-
-                      if (meth.is_static ())
-                        fcn_name = class_nm + '.' + meth_nm;
-                      else
-                        {
-                          octave_value meth_fcn = meth.get_function ();
-
-                          octave_fcn_handle *fh
-                            = new octave_fcn_handle (object, meth_fcn,
-                                                     class_nm, meth_nm);
-
-                          return octave_value (fh);
-                        }
-                    }
-                }
-            }
-        }
-
-      // We didn't match anything above, so create handle to SIMPLE
-      // package function or static class method.  Function resolution
-      // is performed when the handle is used.
-
-      return octave_value (new octave_fcn_handle (fcn_name));
-    }
-
-  // If the function name refers to a sub/local/private function or a
-  // class method/constructor, create scoped function handle that is
-  // bound to that function.  Use the same precedence list as
-  // fcn_info::find but limit search to the following types of
-  // functions:
-  //
-  //   nested functions (and subfunctions)
-  //   local functions in the current file
-  //   private function
-  //   class method
-  //
-  // For anything else we create a simple function handle that will be
-  // resolved dynamically in the scope where it is evaluated.
-
-  symbol_scope curr_scope = get_current_scope ();
-
-  symbol_table& symtab = m_interpreter.get_symbol_table ();
-
-  if (curr_scope)
-    {
-      octave_value ov_fcn
-        = symtab.find_scoped_function (fcn_name, curr_scope);
-
-      // If name is operator, we are in Fstr2func, so skip the stack
-      // frame for that function.
-
-      bool skip_first = name_is_operator;
-      octave_function *curr_fcn = current_function (skip_first);
-
-      if (ov_fcn.is_defined ())
-        {
-          octave_function *fcn = ov_fcn.function_value ();
-
-          if (fcn->is_nested_function ())
-            {
-              if (! name_is_operator)
-                {
-                  // Get current stack frame and return handle to nested
-                  // function.
-
-                  std::shared_ptr<stack_frame> frame
-                    = m_call_stack.get_current_stack_frame ();
-
-                  // If we are creating a handle to the current
-                  // function or a handle to a sibling function (i.e.,
-                  // not a child of the current function), then use
-                  // the calling stack frame as the context instead of
-                  // the current stack frame.
-
-                  // FIXME:  Do we need both checks here or is it
-                  // sufficient to check that the parent of curr_fcn
-                  // is the same as the parent of fcn?  Is there any
-                  // case where curr_fcn could be nullptr, or does
-                  // that indicate an internal error of some kind?
-
-                  if (curr_fcn
-                      && (fcn_name == curr_fcn->name ()
-                          || fcn->parent_fcn_name () == curr_fcn->parent_fcn_name ()))
-                    frame = frame->access_link ();
-
-                  octave_fcn_handle *fh
-                    = new octave_fcn_handle (ov_fcn, fcn_name, frame);
-
-                  return octave_value (fh);
-                }
-            }
-          else if (fcn->is_subfunction ()
-                   /* || fcn->is_localfunction () */
-                   || fcn->is_private_function ())
-            {
-              // Create handle to SCOPED function (sub/local function
-              // or private function).
-
-              std::list<std::string> parentage = fcn->parent_fcn_names ();
-
-              octave_fcn_handle *fh
-                = new octave_fcn_handle (ov_fcn, fcn_name, parentage);
-
-              return octave_value (fh);
-            }
-        }
-
-      if (curr_fcn && (curr_fcn->is_class_method ()
-                       || curr_fcn->is_class_constructor ()))
-        {
-          std::string dispatch_class = curr_fcn->dispatch_class ();
-
-          octave_value ov_meth
-            = symtab.find_method (fcn_name, dispatch_class);
-
-          if (ov_meth.is_defined ())
-            {
-              octave_function *fcn = ov_meth.function_value ();
-
-              // FIXME: do we need to check that it is a method of
-              // dispatch_class, or is it sufficient to just check
-              // that it is a method?
-
-              if (fcn->is_class_method ())
-                {
-                  // Create CLASSSIMPLE handle to method but don't
-                  // bind to the method.  Lookup will be done later.
-
-                  octave_fcn_handle *fh
-                    = new octave_fcn_handle (dispatch_class, fcn_name);
-
-                  return octave_value (fh);
-                }
-            }
-        }
-    }
-
-  octave_value ov_fcn = symtab.find_user_function (fcn_name);
-
-  // Create handle to SIMPLE function.  If the function is not found
-  // now, then we will look for it again when the handle is used.
-
-  return octave_value (new octave_fcn_handle (ov_fcn, fcn_name));
-}
+  }
+
+  void
+  tree_evaluator::visit_anon_fcn_handle (tree_anon_fcn_handle&)
+  {
+    panic_impossible ();
+  }
+
+  void
+  tree_evaluator::visit_argument_list (tree_argument_list&)
+  {
+    panic_impossible ();
+  }
+
+  void
+  tree_evaluator::visit_arguments_block (tree_arguments_block&)
+  {
+    warning ("function arguments validation blocks are not supported; INCORRECT RESULTS ARE POSSIBLE");
+  }
+
+  void
+  tree_evaluator::visit_args_block_attribute_list (tree_args_block_attribute_list&)
+  {
+    panic_impossible ();
+  }
+
+  void
+  tree_evaluator::visit_args_block_validation_list (tree_args_block_validation_list&)
+  {
+    panic_impossible ();
+  }
+
+  void
+  tree_evaluator::visit_arg_validation (tree_arg_validation&)
+  {
+    panic_impossible ();
+  }
+
+  void
+  tree_evaluator::visit_arg_size_spec (tree_arg_size_spec&)
+  {
+    panic_impossible ();
+  }
+
+  void
+  tree_evaluator::visit_arg_validation_fcns (tree_arg_validation_fcns&)
+  {
+    panic_impossible ();
+  }
+
+  void
+  tree_evaluator::visit_binary_expression (tree_binary_expression&)
+  {
+    panic_impossible ();
+  }
+
+  void
+  tree_evaluator::visit_boolean_expression (tree_boolean_expression&)
+  {
+    panic_impossible ();
+  }
+
+  void
+  tree_evaluator::visit_compound_binary_expression (tree_compound_binary_expression&)
+  {
+    panic_impossible ();
+  }
+
+  void
+  tree_evaluator::visit_break_command (tree_break_command& cmd)
+  {
+    if (m_echo_state)
+      {
+        int line = cmd.line ();
+        if (line < 0)
+          line = 1;
+        echo_code (line);
+        m_echo_file_pos = line + 1;
+      }
+
+    if (m_debug_mode)
+      do_breakpoint (cmd.is_active_breakpoint (*this));
+
+    if (m_in_loop_command)
+      m_breaking = 1;
+    else
+      error ("break must appear in a loop in the same file as loop command");
+  }
+
+  void
+  tree_evaluator::visit_colon_expression (tree_colon_expression&)
+  {
+    panic_impossible ();
+  }
+
+  void
+  tree_evaluator::visit_continue_command (tree_continue_command& cmd)
+  {
+    if (m_echo_state)
+      {
+        int line = cmd.line ();
+        if (line < 0)
+          line = 1;
+        echo_code (line);
+        m_echo_file_pos = line + 1;
+      }
+
+    if (m_debug_mode)
+      do_breakpoint (cmd.is_active_breakpoint (*this));
+
+    if (m_in_loop_command)
+      m_continuing = 1;
+  }
+
+  bool
+  tree_evaluator::statement_printing_enabled (void)
+  {
+    return ! (m_silent_functions && (m_statement_context == SC_FUNCTION
+                                     || m_statement_context == SC_SCRIPT));
+  }
+
+  void
+  tree_evaluator::reset_debug_state (void)
+  {
+    m_debug_mode = (m_bp_table.have_breakpoints ()
+                    || m_dbstep_flag != 0
+                    || m_break_on_next_stmt
+                    || in_debug_repl ());
+  }
+
+  void
+  tree_evaluator::reset_debug_state (bool mode)
+  {
+    m_debug_mode = mode;
+  }
+
+  void
+  tree_evaluator::enter_debugger (const std::string& prompt)
+  {
+    unwind_protect frame;
+
+    frame.add (command_history::ignore_entries,
+               command_history::ignoring_entries ());
+
+    command_history::ignore_entries (false);
+
+    frame.add (&call_stack::restore_frame, &m_call_stack,
+               m_call_stack.current_frame ());
+
+    // Don't allow errors or warnings at the debug prompt to push us
+    // into deeper levels of debugging.
+
+    error_system& es = m_interpreter.get_error_system ();
+
+    frame.add (&error_system::set_debug_on_error, &es, es.debug_on_error ());
+
+    frame.add (&error_system::set_debug_on_warning, &es,
+               es.debug_on_warning ());
+
+    es.debug_on_error (false);
+    es.debug_on_warning (false);
+
+    // Go up to the nearest user code frame.
+
+    m_debug_frame = m_call_stack.dbupdown (0);
+
+    // FIXME: probably we just want to print one line, not the
+    // entire statement, which might span many lines...
+    //
+    // tree_print_code tpc (octave_stdout);
+    // stmt.accept (tpc);
+
+    debugger *dbgr = new debugger (m_interpreter, m_debugger_stack.size ());
+
+    m_debugger_stack.push (dbgr);
+
+    frame.add ([=] (void)
+               {
+                 delete m_debugger_stack.top ();
+                 m_debugger_stack.pop ();
+                 reset_debug_state ();
+               });
+
+    dbgr->repl (prompt);
+  }
+
+  void
+  tree_evaluator::keyboard (const std::string& prompt)
+  {
+    enter_debugger (prompt);
+  }
+
+  void
+  tree_evaluator::dbupdown (int n, bool verbose)
+  {
+    m_debug_frame = m_call_stack.dbupdown (n, verbose);
+  }
+
+  Matrix
+  tree_evaluator::ignored_fcn_outputs (void) const
+  {
+    Matrix retval;
+
+    const std::list<octave_lvalue> *lvalues = m_lvalue_list;
+
+    if (! lvalues)
+      return retval;
+
+    octave_idx_type nbh = 0;
+
+    for (const auto& lval : *lvalues)
+      nbh += lval.is_black_hole ();
+
+    if (nbh > 0)
+      {
+        retval.resize (1, nbh);
+
+        octave_idx_type k = 0;
+        octave_idx_type l = 0;
+
+        for (const auto& lval : *lvalues)
+          {
+            if (lval.is_black_hole ())
+              retval(l++) = k+1;
+
+            k += lval.numel ();
+          }
+      }
+
+    return retval;
+  }
+
+  // If NAME is an operator (like "+", "-", ...), convert it to the
+  // corresponding function name ("plus", "minus", ...).
+
+  static std::string
+  get_operator_function_name (const std::string& name)
+  {
+    // Bow to the god of compatibility.
+
+    // FIXME: it seems ugly to put this here, but there is no single
+    // function in the parser that converts from the operator name to
+    // the corresponding function name.  At least try to do it without N
+    // string compares.
+
+    std::size_t len = name.length ();
+
+    if (len == 2)
+      {
+        if (name[0] == '.')
+          {
+            switch (name[1])
+              {
+              case '\'':
+                return "transpose";
+
+              case '*':
+                return "times";
+
+              case '/':
+                return "rdivide";
+
+              case '^':
+                return "power";
+
+              case '\\':
+                return "ldivide";
+
+              default:
+                break;
+              }
+          }
+        else if (name[1] == '=')
+          {
+            switch (name[0])
+              {
+              case '<':
+                return "le";
+
+              case '=':
+                return "eq";
+
+              case '>':
+                return "ge";
+
+              case '~':
+              case '!':
+                return "ne";
+
+              default:
+                break;
+              }
+          }
+      }
+    else if (len == 1)
+      {
+        switch (name[0])
+          {
+          case '~':
+          case '!':
+            return "not";
+
+          case '\'':
+            return "ctranspose";
+
+          case '+':
+            return "plus";
+
+          case '-':
+            return "minus";
+
+          case '*':
+            return "mtimes";
+
+          case '/':
+            return "mrdivide";
+
+          case '^':
+            return "mpower";
+
+          case '\\':
+            return "mldivide";
+
+          case '<':
+            return "lt";
+
+          case '>':
+            return "gt";
+
+          case '&':
+            return "and";
+
+          case '|':
+            return "or";
+
+          default:
+            break;
+          }
+      }
+
+    return name;
+  }
+
+  // Creates a function handle that takes into account the context,
+  // finding local, nested, private, or sub functions.
+
+  octave_value
+  tree_evaluator::make_fcn_handle (const std::string& name)
+  {
+    octave_value retval;
+
+    // The str2func function can create a function handle with the name
+    // of an operator (for example, "+").  If so, it is converted to the
+    // name of the corresponding function ("+" -> "plus") and we create
+    // a simple function handle using that name.
+
+    std::string fcn_name = get_operator_function_name (name);
+
+    // If FCN_NAME is different from NAME, then NAME is an operator.  As
+    // of version 2020a, Matlab apparently uses the function name
+    // corresponding to the operator to search for private and local
+    // functions in the current scope but not(!) nested functions.
+
+    bool name_is_operator = fcn_name != name;
+
+    std::size_t pos = fcn_name.find ('.');
+
+    if (pos != std::string::npos)
+      {
+        // Recognize (some of?  which ones?) the following cases
+        // and create something other than a simple function handle?
+        // Should we just be checking for the last two when the first
+        // element of the dot-separated list is an object?  If so, then
+        // should this syntax be limited to a dot-separated list with
+        // exactly two elements?
+        //
+        //   object . method
+        //   object . static-method
+        //
+        // Code to do that duplicates some of simple_fcn_handle::call.
+
+        // Only accept expressions that contain one '.' separator.
+
+        // FIXME: The logic here is a bit complicated.  Is there a good
+        // way to simplify it?
+
+        std::string meth_nm = fcn_name.substr (pos+1);
+
+        if (meth_nm.find ('.') == std::string::npos)
+          {
+            std::string obj_nm = fcn_name.substr (0, pos);
+
+            // If obj_nm is an object in the current scope with a
+            // method named meth_nm, create a classsimple handle.
+
+            octave_value object = varval (obj_nm);
+
+            if (object.is_defined () && object.is_classdef_object ())
+              {
+                octave_classdef *cdef = object.classdef_object_value ();
+
+                if (cdef)
+                  {
+                    std::string class_nm = cdef->class_name ();
+
+                    cdef_object cdef_obj = cdef->get_object ();
+
+                    cdef_class cls = cdef_obj.get_class ();
+
+                    cdef_method meth = cls.find_method (meth_nm);
+
+                    if (meth.ok ())
+                      {
+                        // If the method we found is static, create a
+                        // new function name from the class name and
+                        // method name and create a simple function
+                        // handle below.  Otherwise, create a class
+                        // simple function handle.
+
+                        if (meth.is_static ())
+                          fcn_name = class_nm + '.' + meth_nm;
+                        else
+                          {
+                            octave_value meth_fcn = meth.get_function ();
+
+                            octave_fcn_handle *fh
+                              = new octave_fcn_handle (object, meth_fcn,
+                                                       class_nm, meth_nm);
+
+                            return octave_value (fh);
+                          }
+                      }
+                  }
+              }
+          }
+
+        // We didn't match anything above, so create handle to SIMPLE
+        // package function or static class method.  Function resolution
+        // is performed when the handle is used.
+
+        return octave_value (new octave_fcn_handle (fcn_name));
+      }
+
+    // If the function name refers to a sub/local/private function or a
+    // class method/constructor, create scoped function handle that is
+    // bound to that function.  Use the same precedence list as
+    // fcn_info::find but limit search to the following types of
+    // functions:
+    //
+    //   nested functions (and subfunctions)
+    //   local functions in the current file
+    //   private function
+    //   class method
+    //
+    // For anything else we create a simple function handle that will be
+    // resolved dynamically in the scope where it is evaluated.
+
+    symbol_scope curr_scope = get_current_scope ();
+
+    symbol_table& symtab = m_interpreter.get_symbol_table ();
+
+    if (curr_scope)
+      {
+        octave_value ov_fcn
+          = symtab.find_scoped_function (fcn_name, curr_scope);
+
+        // If name is operator, we are in Fstr2func, so skip the stack
+        // frame for that function.
+
+        bool skip_first = name_is_operator;
+        octave_function *curr_fcn = current_function (skip_first);
+
+        if (ov_fcn.is_defined ())
+          {
+            octave_function *fcn = ov_fcn.function_value ();
+
+            if (fcn->is_nested_function ())
+              {
+                if (! name_is_operator)
+                  {
+                    // Get current stack frame and return handle to nested
+                    // function.
+
+                    std::shared_ptr<stack_frame> frame
+                      = m_call_stack.get_current_stack_frame ();
+
+                    // If we are creating a handle to the current
+                    // function or a handle to a sibling function (i.e.,
+                    // not a child of the current function), then use
+                    // the calling stack frame as the context instead of
+                    // the current stack frame.
+
+                    // FIXME:  Do we need both checks here or is it
+                    // sufficient to check that the parent of curr_fcn
+                    // is the same as the parent of fcn?  Is there any
+                    // case where curr_fcn could be nullptr, or does
+                    // that indicate an internal error of some kind?
+
+                    if (curr_fcn
+                        && (fcn_name == curr_fcn->name ()
+                            || fcn->parent_fcn_name () == curr_fcn->parent_fcn_name ()))
+                      frame = frame->access_link ();
+
+                    octave_fcn_handle *fh
+                      = new octave_fcn_handle (ov_fcn, fcn_name, frame);
+
+                    return octave_value (fh);
+                  }
+              }
+            else if (fcn->is_subfunction ()
+                     /* || fcn->is_localfunction () */
+                     || fcn->is_private_function ())
+              {
+                // Create handle to SCOPED function (sub/local function
+                // or private function).
+
+                std::list<std::string> parentage = fcn->parent_fcn_names ();
+
+                octave_fcn_handle *fh
+                  = new octave_fcn_handle (ov_fcn, fcn_name, parentage);
+
+                return octave_value (fh);
+              }
+          }
+
+        if (curr_fcn && (curr_fcn->is_class_method ()
+                         || curr_fcn->is_class_constructor ()))
+          {
+            std::string dispatch_class = curr_fcn->dispatch_class ();
+
+            octave_value ov_meth
+              = symtab.find_method (fcn_name, dispatch_class);
+
+            if (ov_meth.is_defined ())
+              {
+                octave_function *fcn = ov_meth.function_value ();
+
+                // FIXME: do we need to check that it is a method of
+                // dispatch_class, or is it sufficient to just check
+                // that it is a method?
+
+                if (fcn->is_class_method ())
+                  {
+                    // Create CLASSSIMPLE handle to method but don't
+                    // bind to the method.  Lookup will be done later.
+
+                    octave_fcn_handle *fh
+                      = new octave_fcn_handle (dispatch_class, fcn_name);
+
+                    return octave_value (fh);
+                  }
+              }
+          }
+      }
+
+    octave_value ov_fcn = symtab.find_user_function (fcn_name);
+
+    // Create handle to SIMPLE function.  If the function is not found
+    // now, then we will look for it again when the handle is used.
+
+    return octave_value (new octave_fcn_handle (ov_fcn, fcn_name));
+  }
 
 /*
 %!test
-%! x = {".**", "power";
-%!      ".'", "transpose";
-%!      ".+", "plus";
-%!      ".-", "minus";
+%! x = {".'", "transpose";
 %!      ".*", "times";
 %!      "./", "rdivide";
 %!      ".^", "power";
@@ -1833,7 +1813,6 @@
 %!      ">=", "ge";
 %!      "!=", "ne";
 %!      "~=", "ne";
-%!      "**", "mpower";
 %!      "~", "not";
 %!      "!", "not";
 %!      "\'", "ctranspose";
@@ -1852,401 +1831,401 @@
 %! endfor
 */
 
-octave_value
-tree_evaluator::evaluate (tree_decl_elt *elt)
-{
-  // Do not allow functions to return null values.
-
-  tree_identifier *id = elt->ident ();
-
-  return id ? id->evaluate (*this).storable_value () : octave_value ();
-}
-
-bool
-tree_evaluator::is_variable (const std::string& name) const
-{
-  std::shared_ptr<stack_frame> frame
-    = m_call_stack.get_current_stack_frame ();
-
-  return frame->is_variable (name);
-}
-
-bool
-tree_evaluator::is_local_variable (const std::string& name) const
-{
-  std::shared_ptr<stack_frame> frame
-    = m_call_stack.get_current_stack_frame ();
-
-  return frame->is_local_variable (name);
-}
-
-bool
-tree_evaluator::is_variable (const tree_expression *expr) const
-{
-  if (expr->is_identifier ())
-    {
-      const tree_identifier *id
-        = dynamic_cast<const tree_identifier *> (expr);
-
-      if (id->is_black_hole ())
-        return false;
-
-      return is_variable (id->symbol ());
-    }
-
-  return false;
-}
-
-bool
-tree_evaluator::is_defined (const tree_expression *expr) const
-{
-  if (expr->is_identifier ())
-    {
-      const tree_identifier *id
-        = dynamic_cast<const tree_identifier *> (expr);
-
-      return is_defined (id->symbol ());
-    }
-
-  return false;
-}
-
-bool
-tree_evaluator::is_variable (const symbol_record& sym) const
-{
-  std::shared_ptr<stack_frame> frame
-    = m_call_stack.get_current_stack_frame ();
-
-  return frame->is_variable (sym);
-}
-
-bool
-tree_evaluator::is_defined (const symbol_record& sym) const
-{
-  std::shared_ptr<stack_frame> frame
-    = m_call_stack.get_current_stack_frame ();
-
-  return frame->is_defined (sym);
-}
-
-bool tree_evaluator::is_global (const std::string& name) const
-{
-  std::shared_ptr<stack_frame> frame
-    = m_call_stack.get_current_stack_frame ();
-
-  return frame->is_global (name);
-}
-
-octave_value
-tree_evaluator::varval (const symbol_record& sym) const
-{
-  std::shared_ptr<stack_frame> frame
-    = m_call_stack.get_current_stack_frame ();
-
-  return frame->varval (sym);
-}
-
-octave_value
-tree_evaluator::varval (const std::string& name) const
-{
-  std::shared_ptr<stack_frame> frame
-    = m_call_stack.get_current_stack_frame ();
-
-  return frame->varval (name);
-}
-
-void tree_evaluator::install_variable (const std::string& name,
-                                       const octave_value& value,
-                                       bool global)
-{
-  std::shared_ptr<stack_frame> frame
-    = m_call_stack.get_current_stack_frame ();
-
-  return frame->install_variable (name, value, global);
-}
-
-octave_value
-tree_evaluator::global_varval (const std::string& name) const
-{
-  return m_call_stack.global_varval (name);
-}
-
-octave_value&
-tree_evaluator::global_varref (const std::string& name)
-{
-  return m_call_stack.global_varref (name);
-}
-
-void
-tree_evaluator::global_assign (const std::string& name,
-                               const octave_value& val)
-{
-  m_call_stack.global_varref (name) = val;
-}
-
-octave_value
-tree_evaluator::top_level_varval (const std::string& name) const
-{
-  return m_call_stack.get_top_level_value (name);
-}
-
-void
-tree_evaluator::top_level_assign (const std::string& name,
-                                  const octave_value& val)
-{
-  m_call_stack.set_top_level_value (name, val);
-}
-
-void
-tree_evaluator::assign (const std::string& name, const octave_value& val)
-{
-  std::shared_ptr<stack_frame> frame
-    = m_call_stack.get_current_stack_frame ();
-
-  frame->assign (name, val);
-}
-
-void
-tree_evaluator::assignin (const std::string& context,
-                          const std::string& name, const octave_value& val)
-{
-  // FIXME: Can this be done without an unwind-protect frame, simply
-  // by getting a reference to the caller or base stack frame and
-  // calling assign on that?
-
-  unwind_action act ([=] (std::size_t frm)
-  {
-    m_call_stack.restore_frame (frm);
-  }, m_call_stack.current_frame ());
-
-  if (context == "caller")
-    m_call_stack.goto_caller_frame ();
-  else if (context == "base")
-    m_call_stack.goto_base_frame ();
-  else
-    error (R"(assignin: CONTEXT must be "caller" or "base")");
-
-  if (valid_identifier (name))
-    {
-      // Put the check here so that we don't slow down assignments
-      // generally.  Any that go through Octave's parser should have
-      // already been checked.
-
-      if (iskeyword (name))
-        error ("assignin: invalid assignment to keyword '%s'",
-               name.c_str ());
-
-      assign (name, val);
-    }
-  else
-    error ("assignin: invalid variable name '%s'", name.c_str ());
-}
-
-void
-tree_evaluator::source_file (const std::string& file_name,
-                             const std::string& context,
-                             bool verbose, bool require_file)
-{
-  // Map from absolute name of script file to recursion level.  We
-  // use a map instead of simply placing a limit on recursion in the
-  // source_file function so that two mutually recursive scripts
-  // written as
-  //
-  //   foo1.m:
-  //   ------
-  //   foo2
-  //
-  //   foo2.m:
-  //   ------
-  //   foo1
-  //
-  // and called with
-  //
-  //   foo1
-  //
-  // (for example) will behave the same if they are written as
-  //
-  //   foo1.m:
-  //   ------
-  //   source ("foo2.m")
-  //
-  //   foo2.m:
-  //   ------
-  //   source ("foo1.m")
-  //
-  // and called with
-  //
-  //   source ("foo1.m")
-  //
-  // (for example).
-
-  static std::map<std::string, int> source_call_depth;
-
-  std::string file_full_name
-    = sys::file_ops::tilde_expand (file_name);
-
-  std::size_t pos
-    = file_full_name.find_last_of (sys::file_ops::dir_sep_str ());
-
-  std::string dir_name = file_full_name.substr (0, pos);
-
-  file_full_name = sys::env::make_absolute (file_full_name);
-
-  unwind_protect frame;
-
-  if (source_call_depth.find (file_full_name) == source_call_depth.end ())
-    source_call_depth[file_full_name] = -1;
-
-  frame.protect_var (source_call_depth[file_full_name]);
-
-  source_call_depth[file_full_name]++;
-
-  if (source_call_depth[file_full_name] >= max_recursion_depth ())
-    error ("max_recursion_depth exceeded");
-
-  if (! context.empty ())
-    {
-      frame.add (&call_stack::restore_frame, &m_call_stack,
-                 m_call_stack.current_frame ());
-
-      if (context == "caller")
-        m_call_stack.goto_caller_frame ();
-      else if (context == "base")
-        m_call_stack.goto_base_frame ();
-      else
-        error (R"(source: CONTEXT must be "caller" or "base")");
-    }
-
-  // Find symbol name that would be in symbol_table, if it were loaded.
-  std::size_t dir_end
-    = file_name.find_last_of (sys::file_ops::dir_sep_chars ());
-  dir_end = (dir_end == std::string::npos) ? 0 : dir_end + 1;
-
-  std::size_t extension = file_name.find_last_of ('.');
-  if (extension == std::string::npos)
-    extension = file_name.length ();
-
-  std::string symbol = file_name.substr (dir_end, extension - dir_end);
-  std::string full_name = sys::canonicalize_file_name (file_name);
-
-  // Check if this file is already loaded (or in the path)
-  symbol_table& symtab = m_interpreter.get_symbol_table ();
-  octave_value ov_code = symtab.fcn_table_find (symbol);
-
-  // For compatibility with Matlab, accept both scripts and
-  // functions.
-
-  if (ov_code.is_user_code ())
-    {
-      octave_user_code *code = ov_code.user_code_value ();
-
-      if (! code
-          || (sys::canonicalize_file_name (code->fcn_file_name ())
-              != full_name))
-        {
-          // Wrong file, so load it below.
-          ov_code = octave_value ();
-        }
-    }
-  else
-    {
-      // Not a script, so load it below.
-      ov_code = octave_value ();
-    }
-
-  // If no symbol of this name, or the symbol is for a different
-  // file, load.
-
-  if (ov_code.is_undefined ())
-    {
-      try
-        {
-          ov_code = parse_fcn_file (m_interpreter, file_full_name,
-                                    file_name, dir_name, "", "",
-                                    require_file, true, false, false);
-        }
-      catch (execution_exception& ee)
-        {
-          error (ee, "source: error sourcing file '%s'",
-                 file_full_name.c_str ());
-        }
-    }
-
-  // Return or error if we don't have a valid script or function.
-
-  if (ov_code.is_undefined ())
-    return;
-
-  if (! ov_code.is_user_code ())
-    error ("source: %s is not a script", full_name.c_str ());
-
-  if (verbose)
-    {
-      octave_stdout << "executing commands from " << full_name << " ... ";
-      octave_stdout.flush ();
-    }
-
-  octave_user_code *code = ov_code.user_code_value ();
-
-  code->call (*this, 0, octave_value_list ());
-
-  if (verbose)
-    octave_stdout << "done." << std::endl;
-}
-
-void
-tree_evaluator::set_auto_fcn_var (stack_frame::auto_var_type avt,
-                                  const octave_value& val)
-{
-  m_call_stack.set_auto_fcn_var (avt, val);
-}
-
-octave_value
-tree_evaluator::get_auto_fcn_var (stack_frame::auto_var_type avt) const
-{
-  return m_call_stack.get_auto_fcn_var (avt);
-}
-
-void
-tree_evaluator::define_parameter_list_from_arg_vector
-(tree_parameter_list *param_list, const octave_value_list& args)
-{
-  if (! param_list || param_list->varargs_only ())
-    return;
-
-  int i = -1;
-
-  for (tree_decl_elt *elt : *param_list)
-    {
-      i++;
-
-      octave_lvalue ref = elt->lvalue (*this);
-
-      if (i < args.length ())
-        {
-          if (args(i).is_defined () && args(i).is_magic_colon ())
-            {
-              if (! eval_decl_elt (elt))
-                error ("no default value for argument %d", i+1);
-            }
-          else
-            ref.define (args(i));
-        }
-      else
-        eval_decl_elt (elt);
-    }
-}
-
-void
-tree_evaluator::undefine_parameter_list (tree_parameter_list *param_list)
-{
-  for (tree_decl_elt *elt : *param_list)
-    {
-      octave_lvalue ref = elt->lvalue (*this);
-
-      ref.assign (octave_value::op_asn_eq, octave_value ());
-    }
-}
+  octave_value
+  tree_evaluator::evaluate (tree_decl_elt *elt)
+  {
+    // Do not allow functions to return null values.
+
+    tree_identifier *id = elt->ident ();
+
+    return id ? id->evaluate (*this).storable_value () : octave_value ();
+  }
+
+  bool
+  tree_evaluator::is_variable (const std::string& name) const
+  {
+    std::shared_ptr<stack_frame> frame
+      = m_call_stack.get_current_stack_frame ();
+
+    return frame->is_variable (name);
+  }
+
+  bool
+  tree_evaluator::is_local_variable (const std::string& name) const
+  {
+    std::shared_ptr<stack_frame> frame
+      = m_call_stack.get_current_stack_frame ();
+
+    return frame->is_local_variable (name);
+  }
+
+  bool
+  tree_evaluator::is_variable (const tree_expression *expr) const
+  {
+    if (expr->is_identifier ())
+      {
+        const tree_identifier *id
+          = dynamic_cast<const tree_identifier *> (expr);
+
+        if (id->is_black_hole ())
+          return false;
+
+        return is_variable (id->symbol ());
+      }
+
+    return false;
+  }
+
+  bool
+  tree_evaluator::is_defined (const tree_expression *expr) const
+  {
+    if (expr->is_identifier ())
+      {
+        const tree_identifier *id
+          = dynamic_cast<const tree_identifier *> (expr);
+
+        return is_defined (id->symbol ());
+      }
+
+    return false;
+  }
+
+  bool
+  tree_evaluator::is_variable (const symbol_record& sym) const
+  {
+    std::shared_ptr<stack_frame> frame
+      = m_call_stack.get_current_stack_frame ();
+
+    return frame->is_variable (sym);
+  }
+
+  bool
+  tree_evaluator::is_defined (const symbol_record& sym) const
+  {
+    std::shared_ptr<stack_frame> frame
+      = m_call_stack.get_current_stack_frame ();
+
+    return frame->is_defined (sym);
+  }
+
+  bool tree_evaluator::is_global (const std::string& name) const
+  {
+    std::shared_ptr<stack_frame> frame
+      = m_call_stack.get_current_stack_frame ();
+
+    return frame->is_global (name);
+  }
+
+  octave_value
+  tree_evaluator::varval (const symbol_record& sym) const
+  {
+    std::shared_ptr<stack_frame> frame
+      = m_call_stack.get_current_stack_frame ();
+
+    return frame->varval (sym);
+  }
+
+  octave_value
+  tree_evaluator::varval (const std::string& name) const
+  {
+    std::shared_ptr<stack_frame> frame
+      = m_call_stack.get_current_stack_frame ();
+
+    return frame->varval (name);
+  }
+
+  void tree_evaluator::install_variable (const std::string& name,
+                                         const octave_value& value,
+                                         bool global)
+  {
+    std::shared_ptr<stack_frame> frame
+      = m_call_stack.get_current_stack_frame ();
+
+    return frame->install_variable (name, value, global);
+  }
+
+  octave_value
+  tree_evaluator::global_varval (const std::string& name) const
+  {
+    return m_call_stack.global_varval (name);
+  }
+
+  octave_value&
+  tree_evaluator::global_varref (const std::string& name)
+  {
+    return m_call_stack.global_varref (name);
+  }
+
+  void
+  tree_evaluator::global_assign (const std::string& name,
+                                 const octave_value& val)
+  {
+    m_call_stack.global_varref (name) = val;
+  }
+
+  octave_value
+  tree_evaluator::top_level_varval (const std::string& name) const
+  {
+    return m_call_stack.get_top_level_value (name);
+  }
+
+  void
+  tree_evaluator::top_level_assign (const std::string& name,
+                                    const octave_value& val)
+  {
+    m_call_stack.set_top_level_value (name, val);
+  }
+
+  void
+  tree_evaluator::assign (const std::string& name, const octave_value& val)
+  {
+    std::shared_ptr<stack_frame> frame
+      = m_call_stack.get_current_stack_frame ();
+
+    frame->assign (name, val);
+  }
+
+  void
+  tree_evaluator::assignin (const std::string& context,
+                            const std::string& name, const octave_value& val)
+  {
+    // FIXME: Can this be done without an unwind-protect frame, simply
+    // by getting a reference to the caller or base stack frame and
+    // calling assign on that?
+
+    unwind_action act ([=] (std::size_t frm)
+                       {
+                         m_call_stack.restore_frame (frm);
+                       }, m_call_stack.current_frame ());
+
+    if (context == "caller")
+      m_call_stack.goto_caller_frame ();
+    else if (context == "base")
+      m_call_stack.goto_base_frame ();
+    else
+      error (R"(assignin: CONTEXT must be "caller" or "base")");
+
+    if (valid_identifier (name))
+      {
+        // Put the check here so that we don't slow down assignments
+        // generally.  Any that go through Octave's parser should have
+        // already been checked.
+
+        if (iskeyword (name))
+          error ("assignin: invalid assignment to keyword '%s'",
+                 name.c_str ());
+
+        assign (name, val);
+      }
+    else
+      error ("assignin: invalid variable name '%s'", name.c_str ());
+  }
+
+  void
+  tree_evaluator::source_file (const std::string& file_name,
+                               const std::string& context,
+                               bool verbose, bool require_file)
+  {
+    // Map from absolute name of script file to recursion level.  We
+    // use a map instead of simply placing a limit on recursion in the
+    // source_file function so that two mutually recursive scripts
+    // written as
+    //
+    //   foo1.m:
+    //   ------
+    //   foo2
+    //
+    //   foo2.m:
+    //   ------
+    //   foo1
+    //
+    // and called with
+    //
+    //   foo1
+    //
+    // (for example) will behave the same if they are written as
+    //
+    //   foo1.m:
+    //   ------
+    //   source ("foo2.m")
+    //
+    //   foo2.m:
+    //   ------
+    //   source ("foo1.m")
+    //
+    // and called with
+    //
+    //   source ("foo1.m")
+    //
+    // (for example).
+
+    static std::map<std::string, int> source_call_depth;
+
+    std::string file_full_name
+      = sys::file_ops::tilde_expand (file_name);
+
+    std::size_t pos
+      = file_full_name.find_last_of (sys::file_ops::dir_sep_str ());
+
+    std::string dir_name = file_full_name.substr (0, pos);
+
+    file_full_name = sys::env::make_absolute (file_full_name);
+
+    unwind_protect frame;
+
+    if (source_call_depth.find (file_full_name) == source_call_depth.end ())
+      source_call_depth[file_full_name] = -1;
+
+    frame.protect_var (source_call_depth[file_full_name]);
+
+    source_call_depth[file_full_name]++;
+
+    if (source_call_depth[file_full_name] >= max_recursion_depth ())
+      error ("max_recursion_depth exceeded");
+
+    if (! context.empty ())
+      {
+        frame.add (&call_stack::restore_frame, &m_call_stack,
+                   m_call_stack.current_frame ());
+
+        if (context == "caller")
+          m_call_stack.goto_caller_frame ();
+        else if (context == "base")
+          m_call_stack.goto_base_frame ();
+        else
+          error (R"(source: CONTEXT must be "caller" or "base")");
+      }
+
+    // Find symbol name that would be in symbol_table, if it were loaded.
+    std::size_t dir_end
+      = file_name.find_last_of (sys::file_ops::dir_sep_chars ());
+    dir_end = (dir_end == std::string::npos) ? 0 : dir_end + 1;
+
+    std::size_t extension = file_name.find_last_of ('.');
+    if (extension == std::string::npos)
+      extension = file_name.length ();
+
+    std::string symbol = file_name.substr (dir_end, extension - dir_end);
+    std::string full_name = sys::canonicalize_file_name (file_name);
+
+    // Check if this file is already loaded (or in the path)
+    symbol_table& symtab = m_interpreter.get_symbol_table ();
+    octave_value ov_code = symtab.fcn_table_find (symbol);
+
+    // For compatibility with Matlab, accept both scripts and
+    // functions.
+
+    if (ov_code.is_user_code ())
+      {
+        octave_user_code *code = ov_code.user_code_value ();
+
+        if (! code
+            || (sys::canonicalize_file_name (code->fcn_file_name ())
+                != full_name))
+          {
+            // Wrong file, so load it below.
+            ov_code = octave_value ();
+          }
+      }
+    else
+      {
+        // Not a script, so load it below.
+        ov_code = octave_value ();
+      }
+
+    // If no symbol of this name, or the symbol is for a different
+    // file, load.
+
+    if (ov_code.is_undefined ())
+      {
+        try
+          {
+            ov_code = parse_fcn_file (m_interpreter, file_full_name,
+                                      file_name, dir_name, "", "",
+                                      require_file, true, false, false);
+          }
+        catch (execution_exception& ee)
+          {
+            error (ee, "source: error sourcing file '%s'",
+                   file_full_name.c_str ());
+          }
+      }
+
+    // Return or error if we don't have a valid script or function.
+
+    if (ov_code.is_undefined ())
+      return;
+
+    if (! ov_code.is_user_code ())
+      error ("source: %s is not a script", full_name.c_str ());
+
+    if (verbose)
+      {
+        octave_stdout << "executing commands from " << full_name << " ... ";
+        octave_stdout.flush ();
+      }
+
+    octave_user_code *code = ov_code.user_code_value ();
+
+    code->call (*this, 0, octave_value_list ());
+
+    if (verbose)
+      octave_stdout << "done." << std::endl;
+  }
+
+  void
+  tree_evaluator::set_auto_fcn_var (stack_frame::auto_var_type avt,
+                                    const octave_value& val)
+  {
+    m_call_stack.set_auto_fcn_var (avt, val);
+  }
+
+  octave_value
+  tree_evaluator::get_auto_fcn_var (stack_frame::auto_var_type avt) const
+  {
+    return m_call_stack.get_auto_fcn_var (avt);
+  }
+
+  void
+  tree_evaluator::define_parameter_list_from_arg_vector
+    (tree_parameter_list *param_list, const octave_value_list& args)
+  {
+    if (! param_list || param_list->varargs_only ())
+      return;
+
+    int i = -1;
+
+    for (tree_decl_elt *elt : *param_list)
+      {
+        i++;
+
+        octave_lvalue ref = elt->lvalue (*this);
+
+        if (i < args.length ())
+          {
+            if (args(i).is_defined () && args(i).is_magic_colon ())
+              {
+                if (! eval_decl_elt (elt))
+                  error ("no default value for argument %d", i+1);
+              }
+            else
+              ref.define (args(i));
+          }
+        else
+          eval_decl_elt (elt);
+      }
+  }
+
+  void
+  tree_evaluator::undefine_parameter_list (tree_parameter_list *param_list)
+  {
+    for (tree_decl_elt *elt : *param_list)
+      {
+        octave_lvalue ref = elt->lvalue (*this);
+
+        ref.assign (octave_value::op_asn_eq, octave_value ());
+      }
+  }
 
 // END is documented in op-kw-docs.
 DEFMETHOD (end, interp, args, ,
@@ -2292,2989 +2271,2988 @@
 %! assert (x(minus (minus (end, 1), 1)), 8);
 */
 
-octave_value_list
-tree_evaluator::convert_to_const_vector (tree_argument_list *args)
-{
-  std::list<octave_value> arg_vals;
-
-  for (auto elt : *args)
-    {
-      // FIXME: is it possible for elt to be invalid?
-
-      if (! elt)
+  octave_value_list
+  tree_evaluator::convert_to_const_vector (tree_argument_list *args)
+  {
+    std::list<octave_value> arg_vals;
+
+    for (auto elt : *args)
+      {
+        // FIXME: is it possible for elt to be invalid?
+
+        if (! elt)
+          break;
+
+        octave_value tmp = elt->evaluate (*this);
+
+        if (tmp.is_cs_list ())
+          {
+            octave_value_list tmp_ovl = tmp.list_value ();
+
+            for (octave_idx_type i = 0; i < tmp_ovl.length (); i++)
+              arg_vals.push_back (tmp_ovl(i));
+          }
+        else if (tmp.is_defined ())
+          arg_vals.push_back (tmp);
+      }
+
+    return octave_value_list (arg_vals);
+  }
+
+  octave_value_list
+  tree_evaluator::convert_return_list_to_const_vector
+    (tree_parameter_list *ret_list, int nargout, const Matrix& ignored_outputs,
+     const Cell& varargout)
+  {
+    octave_idx_type vlen = varargout.numel ();
+    int len = ret_list->length ();
+
+    // Special case.  Will do a shallow copy.
+    if (len == 0)
+      return varargout;
+    else
+      {
+        int i = 0;
+        int k = 0;
+        int num_ignored = ignored_outputs.numel ();
+        int ignored = num_ignored > 0 ? ignored_outputs(k) - 1 : -1;
+
+        if (nargout <= len)
+          {
+            int nout = nargout > 0 ? nargout : 1;
+            octave_value_list retval (nout);
+
+            for (tree_decl_elt *elt : *ret_list)
+              {
+                if (nargout == 0 && ! is_defined (elt->ident ()))
+                  break;
+
+                if (ignored >= 0 && i == ignored)
+                  {
+                    i++;
+                    k++;
+                    ignored = k < num_ignored ? ignored_outputs(k) - 1 : -1;
+                  }
+                else
+                  retval(i++) = evaluate (elt);
+
+                if (i == nout)
+                  break;
+              }
+
+            return retval;
+          }
+        else
+          {
+            octave_value_list retval (len + vlen);
+
+            for (tree_decl_elt *elt : *ret_list)
+              {
+                if (ignored >= 0 && i == ignored)
+                  {
+                    i++;
+                    k++;
+                    ignored = k < num_ignored ? ignored_outputs(k) - 1 : -1;
+                  }
+                else
+                  retval(i++) = evaluate (elt);
+              }
+
+            for (octave_idx_type j = 0; j < vlen; j++)
+              retval(i++) = varargout(j);
+
+            return retval;
+          }
+      }
+  }
+
+  bool
+  tree_evaluator::eval_decl_elt (tree_decl_elt *elt)
+  {
+    bool retval = false;
+
+    tree_identifier *id = elt->ident ();
+    tree_expression *expr = elt->expression ();
+
+    if (id && expr)
+      {
+        octave_lvalue ult = id->lvalue (*this);
+
+        octave_value init_val = expr->evaluate (*this);
+
+        ult.assign (octave_value::op_asn_eq, init_val);
+
+        retval = true;
+      }
+
+    return retval;
+  }
+
+  bool
+  tree_evaluator::switch_case_label_matches (tree_switch_case *expr,
+                                             const octave_value& val)
+  {
+    tree_expression *label = expr->case_label ();
+
+    octave_value label_value = label->evaluate (*this);
+
+    if (label_value.is_defined ())
+      {
+        if (label_value.iscell ())
+          {
+            Cell cell (label_value.cell_value ());
+
+            for (octave_idx_type i = 0; i < cell.rows (); i++)
+              {
+                for (octave_idx_type j = 0; j < cell.columns (); j++)
+                  {
+                    bool match = val.is_equal (cell(i,j));
+
+                    if (match)
+                      return true;
+                  }
+              }
+          }
+        else
+          return val.is_equal (label_value);
+      }
+
+    return false;
+  }
+
+  void tree_evaluator::push_stack_frame (const symbol_scope& scope)
+  {
+    m_call_stack.push (scope);
+  }
+
+  void tree_evaluator::push_stack_frame (octave_user_function *fcn,
+                                         const std::shared_ptr<stack_frame>& closure_frames)
+  {
+    m_call_stack.push (fcn, closure_frames);
+  }
+
+  void tree_evaluator::push_stack_frame (octave_user_function *fcn,
+                                         const stack_frame::local_vars_map& local_vars,
+                                         const std::shared_ptr<stack_frame>& closure_frames)
+  {
+    m_call_stack.push (fcn, local_vars, closure_frames);
+  }
+
+  void tree_evaluator::push_stack_frame (octave_user_script *script)
+  {
+    m_call_stack.push (script);
+  }
+
+  void tree_evaluator::push_stack_frame (octave_function *fcn)
+  {
+    m_call_stack.push (fcn);
+  }
+
+  void tree_evaluator::pop_stack_frame (void)
+  {
+    m_call_stack.pop ();
+  }
+
+  int tree_evaluator::current_line (void) const
+  {
+    return m_call_stack.current_line ();
+  }
+
+  int tree_evaluator::current_column (void) const
+  {
+    return m_call_stack.current_column ();
+  }
+
+  int tree_evaluator::debug_user_code_line (void) const
+  {
+    return m_call_stack.debug_user_code_line ();
+  }
+
+  int tree_evaluator::debug_user_code_column (void) const
+  {
+    return m_call_stack.debug_user_code_column ();
+  }
+
+  void tree_evaluator::debug_where (std::ostream& os) const
+  {
+    std::shared_ptr<stack_frame> frm = m_call_stack.current_user_frame ();
+
+    frm->display_stopped_in_message (os);
+  }
+
+  octave_user_code * tree_evaluator::current_user_code (void) const
+  {
+    return m_call_stack.current_user_code ();
+  }
+
+  unwind_protect * tree_evaluator::curr_fcn_unwind_protect_frame (void)
+  {
+    return m_call_stack.curr_fcn_unwind_protect_frame ();
+  }
+
+  octave_user_code * tree_evaluator::debug_user_code (void) const
+  {
+    return m_call_stack.debug_user_code ();
+  }
+
+  octave_function * tree_evaluator::current_function (bool skip_first) const
+  {
+    return m_call_stack.current_function (skip_first);
+  }
+
+  octave_function * tree_evaluator::caller_function (void) const
+  {
+    return m_call_stack.current_function (true);
+  }
+
+  bool tree_evaluator::goto_frame (std::size_t n, bool verbose)
+  {
+    return m_call_stack.goto_frame (n, verbose);
+  }
+
+  void tree_evaluator::goto_caller_frame (void)
+  {
+    m_call_stack.goto_caller_frame ();
+  }
+
+  void tree_evaluator::goto_base_frame (void)
+  {
+    m_call_stack.goto_base_frame ();
+  }
+
+  void tree_evaluator::restore_frame (std::size_t n)
+  {
+    return m_call_stack.restore_frame (n);
+  }
+
+  std::string tree_evaluator::get_dispatch_class (void) const
+  {
+    return m_call_stack.get_dispatch_class ();
+  }
+
+  void tree_evaluator::set_dispatch_class (const std::string& class_name)
+  {
+    m_call_stack.set_dispatch_class (class_name);
+  }
+
+  bool
+  tree_evaluator::is_class_method_executing (std::string& dclass) const
+  {
+    return m_call_stack.is_class_method_executing (dclass);
+  }
+
+  bool
+  tree_evaluator::is_class_constructor_executing (std::string& dclass) const
+  {
+    return m_call_stack.is_class_constructor_executing (dclass);
+  }
+
+  std::list<std::shared_ptr<stack_frame>>
+  tree_evaluator::backtrace_frames (octave_idx_type& curr_user_frame) const
+  {
+    return m_call_stack.backtrace_frames (curr_user_frame);
+  }
+
+  std::list<std::shared_ptr<stack_frame>>
+  tree_evaluator::backtrace_frames (void) const
+  {
+    return m_call_stack.backtrace_frames ();
+  }
+
+  std::list<frame_info>
+  tree_evaluator::backtrace_info (octave_idx_type& curr_user_frame,
+                                  bool print_subfn) const
+  {
+    return m_call_stack.backtrace_info (curr_user_frame, print_subfn);
+  }
+
+  std::list<frame_info> tree_evaluator::backtrace_info (void) const
+  {
+    return m_call_stack.backtrace_info ();
+  }
+
+  octave_map
+  tree_evaluator::backtrace (octave_idx_type& curr_user_frame,
+                             bool print_subfn) const
+  {
+    return m_call_stack.backtrace (curr_user_frame, print_subfn);
+  }
+
+  octave_map tree_evaluator::backtrace (void) const
+  {
+    return m_call_stack.backtrace ();
+  }
+
+  octave_map tree_evaluator::empty_backtrace (void) const
+  {
+    return m_call_stack.empty_backtrace ();
+  }
+
+  std::string tree_evaluator::backtrace_message (void) const
+  {
+    std::list<frame_info> frames = backtrace_info ();
+
+    std::ostringstream buf;
+
+    for (const auto& frm : frames)
+      {
+        buf << "    " << frm.fcn_name ();
+
+        int line = frm.line ();
+
+        if (line > 0)
+          {
+            buf << " at line " << line;
+
+            int column = frm.column ();
+
+            if (column > 0)
+              buf << " column " << column;
+
+            buf << "\n";
+          }
+      }
+
+    return buf.str ();
+  }
+
+  void tree_evaluator::push_dummy_scope (const std::string& name)
+  {
+    symbol_scope dummy_scope (name + "$dummy");
+
+    m_call_stack.push (dummy_scope);
+  }
+
+  void tree_evaluator::pop_scope (void)
+  {
+    m_call_stack.pop ();
+  }
+
+  symbol_scope tree_evaluator::get_top_scope (void) const
+  {
+    return m_call_stack.top_scope ();
+  }
+
+  symbol_scope tree_evaluator::get_current_scope (void) const
+  {
+    return m_call_stack.current_scope ();
+  }
+
+  void tree_evaluator::mlock (bool skip_first) const
+  {
+    octave_function *fcn = m_call_stack.current_function (skip_first);
+
+    if (! fcn)
+      error ("mlock: invalid use outside a function");
+
+    if (fcn->is_builtin_function ())
+      {
+        warning ("mlock: locking built-in function has no effect");
+        return;
+      }
+
+    fcn->lock ();
+  }
+
+  void tree_evaluator::munlock (bool skip_first) const
+  {
+    octave_function *fcn = m_call_stack.current_function (skip_first);
+
+    if (! fcn)
+      error ("munlock: invalid use outside a function");
+
+    if (fcn->is_builtin_function ())
+      {
+        warning ("munlock: unlocking built-in function has no effect");
+        return;
+      }
+
+    fcn->unlock ();
+  }
+
+  bool tree_evaluator::mislocked (bool skip_first) const
+  {
+    octave_function *fcn = m_call_stack.current_function (skip_first);
+
+    if (! fcn)
+      error ("mislocked: invalid use outside a function");
+
+    return fcn->islocked ();
+  }
+
+  octave_value
+  tree_evaluator::max_stack_depth (const octave_value_list& args, int nargout)
+  {
+    return m_call_stack.max_stack_depth (args, nargout);
+  }
+
+  void tree_evaluator::display_call_stack (void) const
+  {
+    m_call_stack.display ();
+  }
+
+  octave_value tree_evaluator::find (const std::string& name)
+  {
+    std::shared_ptr<stack_frame> frame
+      = m_call_stack.get_current_stack_frame ();
+
+    octave_value val = frame->varval (name);
+
+    if (val.is_defined ())
+      return val;
+
+    // Subfunction.  I think it only makes sense to check for
+    // subfunctions if we are currently executing a function defined
+    // from a .m file.
+
+    octave_value fcn = frame->find_subfunction (name);
+
+    if (fcn.is_defined ())
+      return fcn;
+
+    symbol_table& symtab = m_interpreter.get_symbol_table ();
+
+    return symtab.fcn_table_find (name, ovl ());
+  }
+
+  void tree_evaluator::clear_objects (void)
+  {
+    std::shared_ptr<stack_frame> frame
+      = m_call_stack.get_current_stack_frame ();
+
+    frame->clear_objects ();
+  }
+
+  void tree_evaluator::clear_variable (const std::string& name)
+  {
+    std::shared_ptr<stack_frame> frame
+      = m_call_stack.get_current_stack_frame ();
+
+    frame->clear_variable (name);
+  }
+
+  void tree_evaluator::clear_variable_pattern (const std::string& pattern)
+  {
+    std::shared_ptr<stack_frame> frame
+      = m_call_stack.get_current_stack_frame ();
+
+    frame->clear_variable_pattern (pattern);
+  }
+
+  void tree_evaluator::clear_variable_regexp (const std::string& pattern)
+  {
+    std::shared_ptr<stack_frame> frame
+      = m_call_stack.get_current_stack_frame ();
+
+    frame->clear_variable_regexp (pattern);
+  }
+
+  void tree_evaluator::clear_variables (void)
+  {
+    std::shared_ptr<stack_frame> frame
+      = m_call_stack.get_current_stack_frame ();
+
+    frame->clear_variables ();
+  }
+
+  void tree_evaluator::clear_global_variable (const std::string& name)
+  {
+    m_call_stack.clear_global_variable (name);
+  }
+
+  void
+  tree_evaluator::clear_global_variable_pattern (const std::string& pattern)
+  {
+    m_call_stack.clear_global_variable_pattern (pattern);
+  }
+
+  void tree_evaluator::clear_global_variable_regexp(const std::string& pattern)
+  {
+    m_call_stack.clear_global_variable_regexp (pattern);
+  }
+
+  void tree_evaluator::clear_global_variables (void)
+  {
+    m_call_stack.clear_global_variables ();
+  }
+
+  void tree_evaluator::clear_all (bool force)
+  {
+    // FIXME: should this also clear objects?
+
+    clear_variables ();
+    clear_global_variables ();
+
+    symbol_table& symtab = m_interpreter.get_symbol_table ();
+
+    symtab.clear_functions (force);
+  }
+
+  void tree_evaluator::clear_symbol (const std::string& name)
+  {
+    // FIXME: are we supposed to do both here?
+
+    clear_variable (name);
+
+    symbol_table& symtab = m_interpreter.get_symbol_table ();
+
+    symtab.clear_function (name);
+  }
+
+  void tree_evaluator::clear_symbol_pattern (const std::string& pattern)
+  {
+    // FIXME: are we supposed to do both here?
+
+    clear_variable_pattern (pattern);
+
+    symbol_table& symtab = m_interpreter.get_symbol_table ();
+
+    symtab.clear_function_pattern (pattern);
+  }
+
+  void tree_evaluator::clear_symbol_regexp (const std::string& pattern)
+  {
+    // FIXME: are we supposed to do both here?
+
+    clear_variable_regexp (pattern);
+
+    symbol_table& symtab = m_interpreter.get_symbol_table ();
+
+    symtab.clear_function_regexp (pattern);
+  }
+
+  std::list<std::string> tree_evaluator::global_variable_names (void) const
+  {
+    return m_call_stack.global_variable_names ();
+  }
+
+  std::list<std::string> tree_evaluator::top_level_variable_names (void) const
+  {
+    return m_call_stack.top_level_variable_names ();
+  }
+
+  std::list<std::string> tree_evaluator::variable_names (void) const
+  {
+    return m_call_stack.variable_names ();
+  }
+
+  // Return a pointer to the user-defined function FNAME.  If FNAME is empty,
+  // search backward for the first user-defined function in the
+  // current call stack.
+
+  octave_user_code *
+  tree_evaluator::get_user_code (const std::string& fname,
+                                 const std::string& class_name)
+  {
+    octave_user_code *user_code = nullptr;
+
+    if (fname.empty ())
+      user_code = m_call_stack.debug_user_code ();
+    else
+      {
+        std::string name = fname;
+
+        if (sys::file_ops::dir_sep_char () != '/' && name[0] == '@')
+          {
+            auto beg = name.begin () + 2;  // never have @/method
+            auto end = name.end () - 1;    // never have trailing '/'
+            std::replace (beg, end, '/', sys::file_ops::dir_sep_char ());
+          }
+
+        std::size_t name_len = name.length ();
+
+        if (name_len > 2 && name.substr (name_len-2) == ".m")
+          name = name.substr (0, name_len-2);
+
+        if (name.empty ())
+          return nullptr;
+
+        symbol_table& symtab = m_interpreter.get_symbol_table ();
+
+        octave_value fcn;
+        std::size_t p2 = std::string::npos;
+
+        if (name[0] == '@')
+          {
+            std::size_t p1 = name.find (sys::file_ops::dir_sep_char (), 1);
+
+            if (p1 == std::string::npos)
+              return nullptr;
+
+            std::string dispatch_type = name.substr (1, p1-1);
+
+            p2 = name.find ('>', p1);
+
+            std::string method = name.substr (p1+1, p2-1);
+
+            fcn = symtab.find_method (method, dispatch_type);
+          }
+        else if (! class_name.empty ())
+          {
+            cdef_manager& cdm = m_interpreter.get_cdef_manager ();
+
+            fcn = cdm.find_method (class_name, name);
+
+            // If there is no classdef method, then try legacy classes.
+            if (fcn.is_undefined ())
+              fcn = symtab.find_method (name, class_name);
+          }
+        else
+          {
+            p2 = name.find ('>');
+
+            std::string main_fcn = name.substr (0, p2);
+
+            fcn = symtab.find_function (main_fcn);
+          }
+
+        // List of function names sub1>sub2>...
+        std::string subfuns;
+
+        if (p2 != std::string::npos)
+          subfuns = name.substr (p2+1);
+
+        if (fcn.is_defined () && fcn.is_user_code ())
+          user_code = fcn.user_code_value ();
+
+        if (! user_code || subfuns.empty ())
+          return user_code;
+
+        fcn = user_code->find_subfunction (subfuns);
+
+        if (fcn.is_undefined ())
+          return nullptr;
+
+        user_code = fcn.user_code_value ();
+      }
+
+    return user_code;
+  }
+
+  std::string
+  tree_evaluator::current_function_name (bool skip_first) const
+  {
+    octave_function *curfcn = m_call_stack.current_function (skip_first);
+
+    if (curfcn)
+      return curfcn->name ();
+
+    return "";
+  }
+
+  bool
+  tree_evaluator::in_user_code (void) const
+  {
+    return m_call_stack.current_user_code () != nullptr;
+  }
+
+  void
+  tree_evaluator::visit_decl_command (tree_decl_command& cmd)
+  {
+    if (m_echo_state)
+      {
+        int line = cmd.line ();
+        if (line < 0)
+          line = 1;
+        echo_code (line);
+        m_echo_file_pos = line + 1;
+      }
+
+    if (m_debug_mode)
+      do_breakpoint (cmd.is_active_breakpoint (*this));
+
+    // FIXME: tree_decl_init_list is not derived from tree, so should it
+    // really have an accept method?
+
+    tree_decl_init_list *init_list = cmd.initializer_list ();
+
+    if (init_list)
+      init_list->accept (*this);
+  }
+
+  void
+  tree_evaluator::visit_decl_elt (tree_decl_elt& elt)
+  {
+    tree_identifier *id = elt.ident ();
+
+    if (id)
+      {
+        if (elt.is_global ())
+          m_call_stack.make_global (id->symbol ());
+        else if (elt.is_persistent ())
+          m_call_stack.make_persistent (id->symbol ());
+        else
+          error ("declaration list element not global or persistent");
+
+        octave_lvalue ult = id->lvalue (*this);
+
+        if (ult.is_undefined ())
+          {
+            tree_expression *expr = elt.expression ();
+
+            octave_value init_val;
+
+            if (expr)
+              init_val = expr->evaluate (*this);
+            else
+              init_val = Matrix ();
+
+            ult.assign (octave_value::op_asn_eq, init_val);
+          }
+      }
+  }
+
+  template <typename T>
+  void
+  tree_evaluator::execute_range_loop (const range<T>& rng, int line,
+                                      octave_lvalue& ult,
+                                      tree_statement_list *loop_body)
+  {
+    octave_idx_type steps = rng.numel ();
+
+    if (math::isinf (rng.limit ()))
+      warning_with_id ("Octave:infinite-loop",
+                       "FOR loop limit is infinite, will stop after %"
+                       OCTAVE_IDX_TYPE_FORMAT " steps", steps);
+
+    for (octave_idx_type i = 0; i < steps; i++)
+      {
+        if (m_echo_state)
+          m_echo_file_pos = line;
+
+        octave_value val (rng.elem (i));
+
+        ult.assign (octave_value::op_asn_eq, val);
+
+        if (loop_body)
+          loop_body->accept (*this);
+
+        if (quit_loop_now ())
+          break;
+      }
+  }
+
+  void
+  tree_evaluator::visit_simple_for_command (tree_simple_for_command& cmd)
+  {
+    int line = cmd.line ();
+    if (line < 0)
+      line = 1;
+
+    if (m_echo_state)
+      {
+        echo_code (line);
+        line++;
+      }
+
+    if (m_debug_mode)
+      do_breakpoint (cmd.is_active_breakpoint (*this));
+
+    // FIXME: need to handle PARFOR loops here using cmd.in_parallel ()
+    // and cmd.maxproc_expr ();
+
+    unwind_protect_var<bool> upv (m_in_loop_command, true);
+
+    tree_expression *expr = cmd.control_expr ();
+
+    octave_value rhs = expr->evaluate (*this);
+
+    if (rhs.is_undefined ())
+      return;
+
+    tree_expression *lhs = cmd.left_hand_side ();
+
+    octave_lvalue ult = lhs->lvalue (*this);
+
+    tree_statement_list *loop_body = cmd.body ();
+
+    if (rhs.is_range ())
+      {
+        // FIXME: is there a better way to dispatch here?
+
+        if (rhs.is_double_type ())
+          {
+            execute_range_loop (rhs.range_value (), line, ult, loop_body);
+            return;
+          }
+
+        // For now, disable all but range<double>.
+
+#if 0
+        if (rhs.is_int64_type ())
+          {
+            execute_range_loop (rhs.int64_range_value (), line, ult, loop_body);
+            return;
+          }
+
+        if (rhs.is_uint64_type ())
+          {
+            execute_range_loop (rhs.uint64_range_value (), line, ult, loop_body);
+            return;
+          }
+
+        if (rhs.is_int32_type ())
+          {
+            execute_range_loop (rhs.int32_range_value (), line, ult, loop_body);
+            return;
+          }
+
+        if (rhs.is_uint32_type ())
+          {
+            execute_range_loop (rhs.uint32_range_value (), line, ult, loop_body);
+            return;
+          }
+
+        if (rhs.is_int16_type ())
+          {
+            execute_range_loop (rhs.int16_range_value (), line, ult, loop_body);
+            return;
+          }
+
+        if (rhs.is_uint16_type ())
+          {
+            execute_range_loop (rhs.uint16_range_value (), line, ult, loop_body);
+            return;
+          }
+
+        if (rhs.is_int8_type ())
+          {
+            execute_range_loop (rhs.int8_range_value (), line, ult, loop_body);
+            return;
+          }
+
+        if (rhs.is_uint8_type ())
+          {
+            execute_range_loop (rhs.uint8_range_value (), line, ult, loop_body);
+            return;
+          }
+
+        if (rhs.is_single_type ())
+          {
+            execute_range_loop (rhs.float_range_value (), line, ult, loop_body);
+            return;
+          }
+#endif
+      }
+
+    if (rhs.is_scalar_type ())
+      {
+        if (m_echo_state)
+          m_echo_file_pos = line;
+
+        ult.assign (octave_value::op_asn_eq, rhs);
+
+        if (loop_body)
+          loop_body->accept (*this);
+
+        // Maybe decrement break and continue states.
+        quit_loop_now ();
+
+        return;
+      }
+
+    // Also handle any range types not explicitly handled above, though
+    // not as efficiently as the specialized code above.
+
+    if (rhs.is_range () || rhs.is_matrix_type () || rhs.iscell ()
+        || rhs.is_string () || rhs.isstruct ())
+      {
+        // A matrix or cell is reshaped to 2 dimensions and iterated by
+        // columns.
+
+        dim_vector dv = rhs.dims ().redim (2);
+
+        octave_idx_type nrows = dv(0);
+        octave_idx_type steps = dv(1);
+
+        octave_value arg = rhs;
+        if (rhs.ndims () > 2)
+          arg = arg.reshape (dv);
+
+        if (nrows > 0 && steps > 0)
+          {
+            octave_value_list idx;
+            octave_idx_type iidx;
+
+            // for row vectors, use single index to speed things up.
+            if (nrows == 1)
+              {
+                idx.resize (1);
+                iidx = 0;
+              }
+            else
+              {
+                idx.resize (2);
+                idx(0) = octave_value::magic_colon_t;
+                iidx = 1;
+              }
+
+            for (octave_idx_type i = 1; i <= steps; i++)
+              {
+                if (m_echo_state)
+                  m_echo_file_pos = line;
+
+                // index_op expects one-based indices.
+                idx(iidx) = i;
+                octave_value val = arg.index_op (idx);
+
+                ult.assign (octave_value::op_asn_eq, val);
+
+                if (loop_body)
+                  loop_body->accept (*this);
+
+                if (quit_loop_now ())
+                  break;
+              }
+          }
+        else
+          {
+            // Handle empty cases, while still assigning to loop var.
+            ult.assign (octave_value::op_asn_eq, arg);
+          }
+
+        return;
+      }
+
+    error ("invalid type in for loop expression near line %d, column %d",
+           cmd.line (), cmd.column ());
+  }
+
+  void
+  tree_evaluator::visit_complex_for_command (tree_complex_for_command& cmd)
+  {
+    int line = cmd.line ();
+    if (line < 0)
+      line = 1;
+
+    if (m_echo_state)
+      {
+        echo_code (line);
+        line++;
+      }
+
+    if (m_debug_mode)
+      do_breakpoint (cmd.is_active_breakpoint (*this));
+
+    unwind_protect_var<bool> upv (m_in_loop_command, true);
+
+    tree_expression *expr = cmd.control_expr ();
+
+    octave_value rhs = expr->evaluate (*this);
+
+    if (rhs.is_undefined ())
+      return;
+
+    if (! rhs.isstruct ())
+      error ("in statement 'for [X, Y] = VAL', VAL must be a structure");
+
+    // Cycle through structure elements.  First element of id_list
+    // is set to value and the second is set to the name of the
+    // structure element.
+
+    tree_argument_list *lhs = cmd.left_hand_side ();
+
+    auto p = lhs->begin ();
+
+    tree_expression *elt = *p++;
+
+    octave_lvalue val_ref = elt->lvalue (*this);
+
+    elt = *p;
+
+    octave_lvalue key_ref = elt->lvalue (*this);
+
+    const octave_map tmp_val = rhs.map_value ();
+
+    tree_statement_list *loop_body = cmd.body ();
+
+    string_vector keys = tmp_val.keys ();
+
+    octave_idx_type nel = keys.numel ();
+
+    for (octave_idx_type i = 0; i < nel; i++)
+      {
+        if (m_echo_state)
+          m_echo_file_pos = line;
+
+        std::string key = keys[i];
+
+        const Cell val_lst = tmp_val.contents (key);
+
+        octave_idx_type n = val_lst.numel ();
+
+        octave_value val = (n == 1) ? val_lst(0) : octave_value (val_lst);
+
+        val_ref.assign (octave_value::op_asn_eq, val);
+        key_ref.assign (octave_value::op_asn_eq, key);
+
+        if (loop_body)
+          loop_body->accept (*this);
+
+        if (quit_loop_now ())
+          break;
+      }
+  }
+
+  void tree_evaluator::visit_spmd_command (tree_spmd_command& cmd)
+  {
+    // For now, we just execute the commands serially.
+
+    tree_statement_list *body = cmd.body ();
+
+    if (body)
+      body->accept (*this);
+  }
+
+  octave_value
+  tree_evaluator::evaluate_anon_fcn_handle (tree_anon_fcn_handle& afh)
+  {
+    // FIXME: should CMD_LIST be limited to a single expression?
+    // I think that is what Matlab does.
+
+    symbol_scope new_scope;
+    symbol_scope scope = afh.scope ();
+    if (scope)
+      new_scope = scope.dup ();
+
+    tree_parameter_list *param_list = afh.parameter_list ();
+    tree_parameter_list *param_list_dup
+      = param_list ? param_list->dup (new_scope) : nullptr;
+
+    tree_parameter_list *ret_list = nullptr;
+
+    tree_statement_list *stmt_list = nullptr;
+
+    symbol_scope parent_scope = get_current_scope ();
+
+    new_scope.set_parent (parent_scope);
+    new_scope.set_primary_parent (parent_scope);
+
+    tree_expression *expr = afh.expression ();
+    if (expr)
+      {
+        tree_expression *expr_dup = expr->dup (new_scope);
+        tree_statement *stmt = new tree_statement (expr_dup, nullptr);
+        stmt_list = new tree_statement_list (stmt);
+      }
+
+    tree_anon_scopes anon_fcn_ctx (afh);
+
+    std::set<std::string> free_vars = anon_fcn_ctx.free_variables ();
+
+    stack_frame::local_vars_map local_vars;
+
+    std::shared_ptr<stack_frame> frame
+      = m_call_stack.get_current_stack_frame ();
+
+    for (auto& name : free_vars)
+      {
+        octave_value val = frame->varval (name);
+
+        if (val.is_defined ())
+          local_vars[name] = val;
+      }
+
+    octave_user_function *af
+      = new octave_user_function (new_scope, param_list_dup, ret_list,
+                                  stmt_list);
+
+    octave_function *curr_fcn = m_call_stack.current_function ();
+
+    bool is_nested = false;
+
+    if (curr_fcn)
+      {
+        // FIXME: maybe it would be better to just stash curr_fcn
+        // instead of individual bits of info about it?
+
+        // An anonymous function defined inside another nested function
+        // or parent of a nested function also behaves like a nested
+        // function.
+
+        if (curr_fcn->is_parent_function () || curr_fcn->is_nested_function ())
+          {
+            is_nested = true;
+            af->mark_as_nested_function ();
+            new_scope.set_nesting_depth (parent_scope.nesting_depth () + 1);
+          }
+
+        af->stash_dir_name (curr_fcn->dir_name ());
+
+        new_scope.cache_fcn_file_name (curr_fcn->fcn_file_name ());
+        new_scope.cache_dir_name (curr_fcn->dir_name ());
+
+        // The following is needed so that class method dispatch works
+        // properly for anonymous functions that wrap class methods.
+
+        if (curr_fcn->is_class_method () || curr_fcn->is_class_constructor ())
+          af->stash_dispatch_class (curr_fcn->dispatch_class ());
+
+        af->stash_fcn_file_name (curr_fcn->fcn_file_name ());
+      }
+
+    af->mark_as_anonymous_function ();
+
+    octave_value ov_fcn (af);
+
+    return (is_nested
+            ? octave_value (new octave_fcn_handle (ov_fcn, local_vars, frame))
+            : octave_value (new octave_fcn_handle (ov_fcn, local_vars)));
+  }
+
+  octave_value_list
+  tree_evaluator::execute_builtin_function (octave_builtin& builtin_function,
+                                            int nargout,
+                                            const octave_value_list& args)
+  {
+    octave_value_list retval;
+
+    if (args.has_magic_colon ())
+      error ("invalid use of colon in function argument list");
+
+    profiler::enter<octave_builtin> block (m_profiler, builtin_function);
+
+    octave_builtin::fcn fcn = builtin_function.function ();
+
+    if (fcn)
+      retval = (*fcn) (args, nargout);
+    else
+      {
+        octave_builtin::meth meth = builtin_function.method ();
+
+        retval = (*meth) (m_interpreter, args, nargout);
+      }
+
+    // Do not allow null values to be returned from functions.
+    // FIXME: perhaps true builtins should be allowed?
+
+    retval.make_storable_values ();
+
+    // Fix the case of a single undefined value.
+    // This happens when a compiled function uses
+    //
+    //   octave_value retval;
+    //
+    // instead of
+    //
+    //   octave_value_list retval;
+    //
+    // the idiom is very common, so we solve that here.
+
+    if (retval.length () == 1 && retval.xelem (0).is_undefined ())
+      retval.clear ();
+
+    return retval;
+  }
+
+  octave_value_list
+  tree_evaluator::execute_mex_function (octave_mex_function& mex_function,
+                                        int nargout,
+                                        const octave_value_list& args)
+  {
+    octave_value_list retval;
+
+    if (args.has_magic_colon ())
+      error ("invalid use of colon in function argument list");
+
+    profiler::enter<octave_mex_function> block (m_profiler, mex_function);
+
+    retval = call_mex (mex_function, args, nargout);
+
+    return retval;
+  }
+
+  octave_value_list
+  tree_evaluator::execute_user_script (octave_user_script& user_script,
+                                       int nargout,
+                                       const octave_value_list& args)
+  {
+    octave_value_list retval;
+
+    std::string file_name = user_script.fcn_file_name ();
+
+    if (args.length () != 0 || nargout != 0)
+      error ("invalid call to script %s", file_name.c_str ());
+
+    tree_statement_list *cmd_list = user_script.body ();
+
+    if (! cmd_list)
+      return retval;
+
+    // FIXME: Maybe this check belongs in the places where we push a new
+    // stack frame?  Or in the call_stack push method itself?
+
+    if (m_call_stack.size () >= static_cast<std::size_t> (m_max_recursion_depth))
+      error ("max_recursion_depth exceeded");
+
+    unwind_protect_var<stmt_list_type> upv (m_statement_context, SC_SCRIPT);
+
+    profiler::enter<octave_user_script> block (m_profiler, user_script);
+
+    if (echo ())
+      push_echo_state (tree_evaluator::ECHO_SCRIPTS, file_name);
+
+    // FIXME: Should we be using tree_evaluator::eval here?
+
+    cmd_list->accept (*this);
+
+    if (m_returning)
+      m_returning = 0;
+
+    if (m_breaking)
+      m_breaking--;
+
+    return retval;
+  }
+
+  void
+  tree_evaluator::visit_octave_user_script (octave_user_script&)
+  {
+    // ??
+    panic_impossible ();
+  }
+
+  octave_value_list
+  tree_evaluator::execute_user_function (octave_user_function& user_function,
+                                         int nargout,
+                                         const octave_value_list& xargs)
+  {
+    octave_value_list retval;
+
+    // If this function is a classdef constructor, extract the first input
+    // argument, which must be the partially constructed object instance.
+
+    octave_value_list args (xargs);
+    octave_value_list ret_args;
+
+    int nargin = args.length ();
+
+    if (user_function.is_classdef_constructor ())
+      {
+        if (nargin > 0)
+          {
+            ret_args = args.slice (0, 1, true);
+            --nargin;
+            args = args.slice (1, nargin, true);
+          }
+        else
+          panic_impossible ();
+      }
+
+    // FIXME: this probably shouldn't be a double-precision matrix.
+    Matrix ignored_outputs = ignored_fcn_outputs ();
+
+    tree_parameter_list *param_list = user_function.parameter_list ();
+
+    bool takes_varargs = false;
+    int max_inputs = 0;
+
+    if (param_list)
+      {
+        takes_varargs = param_list->takes_varargs ();
+        max_inputs = param_list->length ();
+      }
+
+    if (! takes_varargs && nargin > max_inputs)
+      {
+        std::string name = user_function.name ();
+
+        if (name.empty ())
+          name = "@<anonymous>";
+
+        error_with_id ("Octave:invalid-fun-call",
+                       "%s: function called with too many inputs",
+                       name.c_str ());
+      }
+
+    define_parameter_list_from_arg_vector (param_list, args);
+
+    tree_parameter_list *ret_list = user_function.return_list ();
+
+    if (ret_list && ! ret_list->takes_varargs ())
+      {
+        int max_outputs = ret_list->length ();
+
+        if (nargout > max_outputs)
+          {
+            std::string name = user_function.name ();
+
+            error_with_id ("Octave:invalid-fun-call",
+                           "%s: function called with too many outputs",
+                           name.c_str ());
+          }
+      }
+
+    bind_auto_fcn_vars (xargs.name_tags (), ignored_outputs, nargin,
+                        nargout, user_function.takes_varargs (),
+                        user_function.all_va_args (args));
+
+    // For classdef constructor, pre-populate the output arguments
+    // with the pre-initialized object instance, extracted above.
+
+    if (user_function.is_classdef_constructor ())
+      {
+        if (! ret_list)
+          error ("%s: invalid classdef constructor, no output argument defined",
+                 user_function.dispatch_class ().c_str ());
+
+        define_parameter_list_from_arg_vector (ret_list, ret_args);
+      }
+
+    // FIXME: Maybe this check belongs in the places where we push a
+    // new stack frame?  Or in the call_stack push method itself?
+
+    if (m_call_stack.size () >= static_cast<std::size_t> (m_max_recursion_depth))
+      error ("max_recursion_depth exceeded");
+
+    unwind_action act2 ([&user_function] () {
+                          user_function.restore_warning_states ();
+                        });
+
+    // Evaluate the commands that make up the function.
+
+    unwind_protect_var<stmt_list_type> upv (m_statement_context, SC_FUNCTION);
+
+    tree_statement_list *cmd_list = user_function.body ();
+
+    if (cmd_list)
+      {
+        profiler::enter<octave_user_function>
+          block (m_profiler, user_function);
+
+        if (echo ())
+          push_echo_state (tree_evaluator::ECHO_FUNCTIONS,
+                           user_function.fcn_file_name ());
+
+        if (user_function.is_special_expr ())
+          {
+            panic_if (cmd_list->length () != 1);
+
+            tree_statement *stmt = cmd_list->front ();
+
+            tree_expression *expr = stmt->expression ();
+
+            if (expr)
+              {
+                m_call_stack.set_location (stmt->line (), stmt->column ());
+
+                retval = expr->evaluate_n (*this, nargout);
+              }
+          }
+        else
+          cmd_list->accept (*this);
+
+        if (m_returning)
+          m_returning = 0;
+
+        if (m_breaking)
+          m_breaking--;
+      }
+
+    // Copy return values out.
+
+    if (ret_list && ! user_function.is_special_expr ())
+      {
+        Cell varargout;
+
+        if (ret_list->takes_varargs ())
+          {
+            octave_value varargout_varval = varval ("varargout");
+
+            if (varargout_varval.is_defined ())
+              varargout = varargout_varval.xcell_value ("varargout must be a cell array object");
+          }
+
+        retval = convert_return_list_to_const_vector (ret_list, nargout,
+                                                      ignored_outputs,
+                                                      varargout);
+      }
+
+    return retval;
+  }
+
+  void
+  tree_evaluator::visit_octave_user_function (octave_user_function&)
+  {
+    // ??
+    panic_impossible ();
+  }
+
+  void
+  tree_evaluator::visit_octave_user_function_header (octave_user_function&)
+  {
+    panic_impossible ();
+  }
+
+  void
+  tree_evaluator::visit_octave_user_function_trailer (octave_user_function&)
+  {
+    panic_impossible ();
+  }
+
+  void
+  tree_evaluator::visit_function_def (tree_function_def& cmd)
+  {
+    octave_value fcn = cmd.function ();
+
+    octave_function *f = fcn.function_value ();
+
+    if (f)
+      {
+        std::string nm = f->name ();
+
+        symbol_table& symtab = m_interpreter.get_symbol_table ();
+
+        symtab.install_cmdline_function (nm, fcn);
+
+        // Make sure that any variable with the same name as the new
+        // function is cleared.
+
+        assign (nm);
+      }
+  }
+
+  void
+  tree_evaluator::visit_identifier (tree_identifier&)
+  {
+    panic_impossible ();
+  }
+
+  void
+  tree_evaluator::visit_if_clause (tree_if_clause&)
+  {
+    panic_impossible ();
+  }
+
+  void
+  tree_evaluator::visit_if_command (tree_if_command& cmd)
+  {
+    if (m_echo_state)
+      {
+        int line = cmd.line ();
+        if (line < 0)
+          line = 1;
+        echo_code (line);
+        m_echo_file_pos = line + 1;
+      }
+
+    // FIXME: tree_if_command_list is not derived from tree, so should it
+    // really have an accept method?
+
+    tree_if_command_list *lst = cmd.cmd_list ();
+
+    if (lst)
+      lst->accept (*this);
+  }
+
+  void
+  tree_evaluator::visit_if_command_list (tree_if_command_list& lst)
+  {
+    for (tree_if_clause *tic : lst)
+      {
+        tree_expression *expr = tic->condition ();
+
+        if (! (in_debug_repl ()
+               && m_call_stack.current_frame () == m_debug_frame))
+          m_call_stack.set_location (tic->line (), tic->column ());
+
+        if (m_debug_mode && ! tic->is_else_clause ())
+          do_breakpoint (tic->is_active_breakpoint (*this));
+
+        if (tic->is_else_clause () || is_logically_true (expr, "if"))
+          {
+            tree_statement_list *stmt_lst = tic->commands ();
+
+            if (stmt_lst)
+              stmt_lst->accept (*this);
+
+            break;
+          }
+      }
+  }
+
+  void
+  tree_evaluator::visit_index_expression (tree_index_expression&)
+  {
+    panic_impossible ();
+  }
+
+  void
+  tree_evaluator::visit_matrix (tree_matrix&)
+  {
+    panic_impossible ();
+  }
+
+  void
+  tree_evaluator::visit_cell (tree_cell&)
+  {
+    panic_impossible ();
+  }
+
+  void
+  tree_evaluator::visit_multi_assignment (tree_multi_assignment&)
+  {
+    panic_impossible ();
+  }
+
+  void
+  tree_evaluator::visit_no_op_command (tree_no_op_command& cmd)
+  {
+    if (m_echo_state)
+      {
+        int line = cmd.line ();
+        if (line < 0)
+          line = 1;
+        echo_code (line);
+        m_echo_file_pos = line + 1;
+      }
+
+    if (m_debug_mode && cmd.is_end_of_fcn_or_script ())
+      do_breakpoint (cmd.is_active_breakpoint (*this), true);
+  }
+
+  void
+  tree_evaluator::visit_constant (tree_constant&)
+  {
+    panic_impossible ();
+  }
+
+  void
+  tree_evaluator::visit_fcn_handle (tree_fcn_handle&)
+  {
+    panic_impossible ();
+  }
+
+  void
+  tree_evaluator::visit_parameter_list (tree_parameter_list&)
+  {
+    panic_impossible ();
+  }
+
+  void
+  tree_evaluator::visit_postfix_expression (tree_postfix_expression&)
+  {
+    panic_impossible ();
+  }
+
+  void
+  tree_evaluator::visit_prefix_expression (tree_prefix_expression&)
+  {
+    panic_impossible ();
+  }
+
+  void
+  tree_evaluator::visit_return_command (tree_return_command& cmd)
+  {
+    if (m_echo_state)
+      {
+        int line = cmd.line ();
+        if (line < 0)
+          line = 1;
+        echo_code (line);
+        m_echo_file_pos = line + 1;
+      }
+
+    if (m_debug_mode)
+      do_breakpoint (cmd.is_active_breakpoint (*this));
+
+    // Act like dbcont.
+
+    if (in_debug_repl () && m_call_stack.current_frame () == m_debug_frame)
+      dbcont ();
+    else if (m_statement_context == SC_FUNCTION
+             || m_statement_context == SC_SCRIPT
+             || m_in_loop_command)
+      m_returning = 1;
+  }
+
+  void
+  tree_evaluator::visit_simple_assignment (tree_simple_assignment&)
+  {
+    panic_impossible ();
+  }
+
+  void
+  tree_evaluator::visit_statement (tree_statement& stmt)
+  {
+    tree_command *cmd = stmt.command ();
+    tree_expression *expr = stmt.expression ();
+
+    if (cmd || expr)
+      {
+        if (! (in_debug_repl ()
+               && m_call_stack.current_frame () == m_debug_frame))
+          m_call_stack.set_location (stmt.line (), stmt.column ());
+
+        try
+          {
+            if (cmd)
+              {
+                unwind_protect_var<const std::list<octave_lvalue> *>
+                  upv (m_lvalue_list, nullptr);
+
+                cmd->accept (*this);
+              }
+            else
+              {
+                if (m_echo_state)
+                  {
+                    int line = stmt.line ();
+                    if (line < 0)
+                      line = 1;
+                    echo_code (line);
+                    m_echo_file_pos = line + 1;
+                  }
+
+                if (m_debug_mode)
+                  do_breakpoint (expr->is_active_breakpoint (*this));
+
+                // FIXME: maybe all of this should be packaged in
+                // one virtual function that returns a flag saying whether
+                // or not the expression will take care of binding ans and
+                // printing the result.
+
+                // FIXME: it seems that we should just have to
+                // evaluate the expression and that should take care of
+                // everything, binding ans as necessary?
+
+                octave_value tmp_result = expr->evaluate (*this, 0);
+
+                if (tmp_result.is_defined ())
+                  {
+                    bool do_bind_ans = false;
+
+                    if (expr->is_identifier ())
+                      do_bind_ans = ! is_variable (expr);
+                    else
+                      do_bind_ans = ! expr->is_assignment_expression ();
+
+                    if (do_bind_ans)
+                      bind_ans (tmp_result, expr->print_result ()
+                                && statement_printing_enabled ());
+                  }
+              }
+          }
+        catch (const std::bad_alloc&)
+          {
+            // FIXME: We want to use error_with_id here so that give users
+            // control over this error message but error_with_id will
+            // require some memory allocations.  Is there anything we can
+            // do to make those more likely to succeed?
+
+            error_with_id ("Octave:bad-alloc",
+                           "out of memory or dimension too large for Octave's index type");
+          }
+        catch (const interrupt_exception&)
+          {
+            // If we are debugging, then continue with next statement.
+            // Otherwise, jump out of here.
+
+            if (m_debug_mode)
+              m_interpreter.recover_from_exception ();
+            else
+              throw;
+          }
+        catch (const execution_exception& ee)
+          {
+            error_system& es = m_interpreter.get_error_system ();
+
+            if ((m_interpreter.interactive ()
+                 || application::forced_interactive ())
+                && ((es.debug_on_error ()
+                     && m_bp_table.debug_on_err (es.last_error_id ()))
+                    || (es.debug_on_caught ()
+                        && m_bp_table.debug_on_caught (es.last_error_id ())))
+                && in_user_code ())
+              {
+                es.save_exception (ee);
+                es.display_exception (ee);
+
+                enter_debugger ();
+
+                // It doesn't make sense to continue execution after an
+                // error occurs so force the debugger to quit all debug
+                // levels and return the the top prompt.
+
+                throw quit_debug_exception (true);
+              }
+            else
+              throw;
+          }
+      }
+  }
+
+  void
+  tree_evaluator::visit_statement_list (tree_statement_list& lst)
+  {
+    // FIXME: commented out along with else clause below.
+    // static octave_value_list empty_list;
+
+    auto p = lst.begin ();
+
+    if (p != lst.end ())
+      {
+        while (true)
+          {
+            tree_statement *elt = *p++;
+
+            if (! elt)
+              error ("invalid statement found in statement list!");
+
+            octave_quit ();
+
+            elt->accept (*this);
+
+            if (m_breaking || m_continuing)
+              break;
+
+            if (m_returning)
+              break;
+
+            if (p == lst.end ())
+              break;
+            else
+              {
+                // Clear previous values before next statement is
+                // evaluated so that we aren't holding an extra
+                // reference to a value that may be used next.  For
+                // example, in code like this:
+                //
+                //   X = rand (N);  # refcount for X should be 1
+                //                  # after this statement
+                //
+                //   X(idx) = val;  # no extra copy of X should be
+                //                  # needed, but we will be faked
+                //                  # out if retval is not cleared
+                //                  # between statements here
+
+                //              result_values = empty_list;
+              }
+          }
+      }
+  }
+
+  void
+  tree_evaluator::visit_switch_case (tree_switch_case&)
+  {
+    panic_impossible ();
+  }
+
+  void
+  tree_evaluator::visit_switch_case_list (tree_switch_case_list&)
+  {
+    panic_impossible ();
+  }
+
+  void
+  tree_evaluator::visit_switch_command (tree_switch_command& cmd)
+  {
+    if (m_echo_state)
+      {
+        int line = cmd.line ();
+        if (line < 0)
+          line = 1;
+        echo_code (line);
+        m_echo_file_pos = line + 1;
+      }
+
+    if (m_debug_mode)
+      do_breakpoint (cmd.is_active_breakpoint (*this));
+
+    tree_expression *expr = cmd.switch_value ();
+
+    if (! expr)
+      error ("missing value in switch command near line %d, column %d",
+             cmd.line (), cmd.column ());
+
+    octave_value val = expr->evaluate (*this);
+
+    tree_switch_case_list *lst = cmd.case_list ();
+
+    if (lst)
+      {
+        for (tree_switch_case *t : *lst)
+          {
+            if (t->is_default_case () || switch_case_label_matches (t, val))
+              {
+                tree_statement_list *stmt_lst = t->commands ();
+
+                if (stmt_lst)
+                  stmt_lst->accept (*this);
+
+                break;
+              }
+          }
+      }
+  }
+
+  void
+  tree_evaluator::visit_try_catch_command (tree_try_catch_command& cmd)
+  {
+    if (m_echo_state)
+      {
+        int line = cmd.line ();
+        if (line < 0)
+          line = 1;
+        echo_code (line);
+        m_echo_file_pos = line + 1;
+      }
+
+    bool execution_error = false;
+    octave_scalar_map err_map;
+
+    tree_statement_list *try_code = cmd.body ();
+
+    if (try_code)
+      {
+        // unwind frame before catch block
+
+        unwind_protect frame;
+
+        interpreter_try (frame);
+
+        // The catch code is *not* added to unwind_protect stack; it
+        // doesn't need to be run on interrupts.
+
+        try
+          {
+            try_code->accept (*this);
+          }
+        catch (const execution_exception& ee)
+          {
+            execution_error = true;
+
+            error_system& es = m_interpreter.get_error_system ();
+
+            es.save_exception (ee);
+
+            err_map.assign ("message", es.last_error_message ());
+            err_map.assign ("identifier", es.last_error_id ());
+            err_map.assign ("stack", es.last_error_stack ());
+
+            m_interpreter.recover_from_exception ();
+          }
+
+        // Actions attached to unwind_protect frame will run here, prior
+        // to executing the catch block.
+      }
+
+    if (execution_error)
+      {
+        tree_statement_list *catch_code = cmd.cleanup ();
+
+        if (catch_code)
+          {
+            tree_identifier *expr_id = cmd.identifier ();
+
+            if (expr_id)
+              {
+                octave_lvalue ult = expr_id->lvalue (*this);
+
+                ult.assign (octave_value::op_asn_eq, err_map);
+              }
+
+            // perform actual "catch" block
+            catch_code->accept (*this);
+          }
+      }
+  }
+
+  void
+  tree_evaluator::do_unwind_protect_cleanup_code (tree_statement_list *list)
+  {
+    unwind_protect frame;
+
+    frame.protect_var (octave_interrupt_state);
+    octave_interrupt_state = 0;
+
+    // We want to preserve the last location info for possible
+    // backtracking.
+
+    frame.add (&call_stack::set_line, &m_call_stack,
+               m_call_stack.current_line ());
+
+    frame.add (&call_stack::set_column, &m_call_stack,
+               m_call_stack.current_column ());
+
+    // Similarly, if we have seen a return or break statement, allow all
+    // the cleanup code to run before returning or handling the break.
+    // We don't have to worry about continue statements because they can
+    // only occur in loops.
+
+    frame.protect_var (m_returning);
+    m_returning = 0;
+
+    frame.protect_var (m_breaking);
+    m_breaking = 0;
+
+    try
+      {
+        if (list)
+          list->accept (*this);
+      }
+    catch (const execution_exception& ee)
+      {
+        error_system& es = m_interpreter.get_error_system ();
+
+        es.save_exception (ee);
+        m_interpreter.recover_from_exception ();
+
+        if (m_breaking || m_returning)
+          frame.discard (2);
+        else
+          frame.run (2);
+
+        frame.discard (2);
+
+        throw;
+      }
+
+    // The unwind_protects are popped off the stack in the reverse of
+    // the order they are pushed on.
+
+    // FIXME: these statements say that if we see a break or
+    // return statement in the cleanup block, that we want to use the
+    // new value of the breaking or returning flag instead of restoring
+    // the previous value.  Is that the right thing to do?  I think so.
+    // Consider the case of
+    //
+    //   function foo ()
+    //     unwind_protect
+    //       fprintf (stderr, "1: this should always be executed\n");
+    //       break;
+    //       fprintf (stderr, "1: this should never be executed\n");
+    //     unwind_protect_cleanup
+    //       fprintf (stderr, "2: this should always be executed\n");
+    //       return;
+    //       fprintf (stderr, "2: this should never be executed\n");
+    //     end_unwind_protect
+    //   endfunction
+    //
+    // If we reset the value of the breaking flag, both the returning
+    // flag and the breaking flag will be set, and we shouldn't have
+    // both.  So, use the most recent one.  If there is no return or
+    // break in the cleanup block, the values should be reset to
+    // whatever they were when the cleanup block was entered.
+
+    if (m_breaking || m_returning)
+      frame.discard (2);
+    else
+      frame.run (2);
+  }
+
+  void
+  tree_evaluator::visit_unwind_protect_command (tree_unwind_protect_command& cmd)
+  {
+    if (m_echo_state)
+      {
+        int line = cmd.line ();
+        if (line < 0)
+          line = 1;
+        echo_code (line);
+        m_echo_file_pos = line + 1;
+      }
+
+    tree_statement_list *cleanup_code = cmd.cleanup ();
+
+    tree_statement_list *unwind_protect_code = cmd.body ();
+
+    if (unwind_protect_code)
+      {
+        try
+          {
+            unwind_protect_code->accept (*this);
+          }
+        catch (const execution_exception& ee)
+          {
+            error_system& es = m_interpreter.get_error_system ();
+
+            // FIXME: Maybe we should be able to temporarily set the
+            // interpreter's exception handling state to something "safe"
+            // while the cleanup block runs instead of just resetting it
+            // here?
+            es.save_exception (ee);
+            m_interpreter.recover_from_exception ();
+
+            // Run the cleanup code on exceptions, so that it is run even
+            // in case of interrupt or out-of-memory.
+            do_unwind_protect_cleanup_code (cleanup_code);
+
+            // If an error occurs inside the cleanup code, a new
+            // exception will be thrown instead of the original.
+            throw;
+          }
+        catch (const interrupt_exception&)
+          {
+            // The comments above apply here as well.
+            m_interpreter.recover_from_exception ();
+            do_unwind_protect_cleanup_code (cleanup_code);
+            throw;
+          }
+
+        // Also execute the unwind_protect_cleanump code if the
+        // unwind_protect block runs without error.
+        do_unwind_protect_cleanup_code (cleanup_code);
+      }
+  }
+
+  void
+  tree_evaluator::visit_while_command (tree_while_command& cmd)
+  {
+    int line = cmd.line ();
+    if (line < 0)
+      line = 1;
+
+    if (m_echo_state)
+      {
+        echo_code (line);
+        line++;
+      }
+
+    unwind_protect_var<bool> upv (m_in_loop_command, true);
+
+    tree_expression *expr = cmd.condition ();
+
+    if (! expr)
+      panic_impossible ();
+
+    for (;;)
+      {
+        if (m_echo_state)
+          m_echo_file_pos = line;
+
+        if (m_debug_mode)
+          do_breakpoint (cmd.is_active_breakpoint (*this));
+
+        if (is_logically_true (expr, "while"))
+          {
+            tree_statement_list *loop_body = cmd.body ();
+
+            if (loop_body)
+              loop_body->accept (*this);
+
+            if (quit_loop_now ())
+              break;
+          }
+        else
+          break;
+      }
+  }
+
+  void
+  tree_evaluator::visit_do_until_command (tree_do_until_command& cmd)
+  {
+    int line = cmd.line ();
+    if (line < 0)
+      line = 1;
+
+    if (m_echo_state)
+      {
+        echo_code (line);
+        line++;
+      }
+
+    unwind_protect_var<bool> upv (m_in_loop_command, true);
+
+    tree_expression *expr = cmd.condition ();
+
+    if (! expr)
+      panic_impossible ();
+
+    for (;;)
+      {
+        if (m_echo_state)
+          m_echo_file_pos = line;
+
+        tree_statement_list *loop_body = cmd.body ();
+
+        if (loop_body)
+          loop_body->accept (*this);
+
+        if (quit_loop_now ())
+          break;
+
+        if (m_debug_mode)
+          do_breakpoint (cmd.is_active_breakpoint (*this));
+
+        if (is_logically_true (expr, "do-until"))
+          break;
+      }
+  }
+
+  void
+  tree_evaluator::visit_superclass_ref (tree_superclass_ref&)
+  {
+    panic_impossible ();
+  }
+
+  void
+  tree_evaluator::visit_metaclass_query (tree_metaclass_query&)
+  {
+    panic_impossible ();
+  }
+
+  void tree_evaluator::bind_ans (const octave_value& val, bool print)
+  {
+    static std::string ans = "ans";
+
+    if (val.is_defined ())
+      {
+        if (val.is_cs_list ())
+          {
+            octave_value_list lst = val.list_value ();
+
+            for (octave_idx_type i = 0; i < lst.length (); i++)
+              bind_ans (lst(i), print);
+          }
+        else
+          {
+            // FIXME: Maybe assign could also return the assigned value,
+            // just for convenience?
+
+            assign (ans, val);
+
+            if (print)
+              {
+                // Use varval instead of displaying VAL directly so that
+                // we get the right type and value for things like
+                // magic_int values that may mutate when stored.
+
+                octave_value_list args = ovl (varval (ans));
+                args.stash_name_tags (string_vector (ans));
+                feval ("display", args);
+              }
+          }
+      }
+  }
+
+  void
+  tree_evaluator::do_breakpoint (tree_statement& stmt)
+  {
+    do_breakpoint (stmt.is_active_breakpoint (*this),
+                   stmt.is_end_of_fcn_or_script ());
+  }
+
+  void
+  tree_evaluator::do_breakpoint (bool is_breakpoint,
+                                 bool is_end_of_fcn_or_script)
+  {
+    bool break_on_this_statement = false;
+
+    if (is_breakpoint)
+      break_on_this_statement = true;
+    else if (m_dbstep_flag > 0)
+      {
+        if (m_call_stack.current_frame () == m_debug_frame)
+          {
+            if (m_dbstep_flag == 1 || is_end_of_fcn_or_script)
+              {
+                // We get here if we are doing a "dbstep" or a "dbstep N" and
+                // the count has reached 1 so that we must stop and return to
+                // debug prompt.  Alternatively, "dbstep N" has been used but
+                // the end of the frame has been reached so we stop at the last
+                // line and return to prompt.
+
+                break_on_this_statement = true;
+              }
+            else
+              {
+                // Executing "dbstep N".  Decrease N by one and continue.
+
+                m_dbstep_flag--;
+              }
+
+          }
+        else if (m_dbstep_flag == 1
+                 && m_call_stack.current_frame () < m_debug_frame)
+          {
+            // We stepped out from the end of a function.
+
+            m_debug_frame = m_call_stack.current_frame ();
+
+            break_on_this_statement = true;
+          }
+      }
+    else if (m_dbstep_flag == -1)
+      {
+        // We get here if we are doing a "dbstep in".
+
+        break_on_this_statement = true;
+
+        m_debug_frame = m_call_stack.current_frame ();
+      }
+    else if (m_dbstep_flag == -2)
+      {
+        // We get here if we are doing a "dbstep out".  Check for end of
+        // function and whether the current frame is the same as the
+        // cached value because we want to step out from the frame where
+        // "dbstep out" was evaluated, not from any functions called from
+        // that frame.
+
+        if (is_end_of_fcn_or_script
+            && m_call_stack.current_frame () == m_debug_frame)
+          m_dbstep_flag = -1;
+      }
+
+    if (! break_on_this_statement)
+      break_on_this_statement = m_break_on_next_stmt;
+
+    m_break_on_next_stmt = false;
+
+    if (break_on_this_statement)
+      {
+        m_dbstep_flag = 0;
+
+        enter_debugger ();
+      }
+  }
+
+  bool
+  tree_evaluator::is_logically_true (tree_expression *expr,
+                                     const char *warn_for)
+  {
+    bool expr_value = false;
+
+    m_call_stack.set_location (expr->line (), expr->column ());
+
+    octave_value t1 = expr->evaluate (*this);
+
+    if (t1.is_defined ())
+      return t1.is_true ();
+    else
+      error ("%s: undefined value used in conditional expression", warn_for);
+
+    return expr_value;
+  }
+
+  octave_value
+  tree_evaluator::max_recursion_depth (const octave_value_list& args,
+                                       int nargout)
+  {
+    return set_internal_variable (m_max_recursion_depth, args, nargout,
+                                  "max_recursion_depth", 0);
+  }
+
+  symbol_info_list
+  tree_evaluator::glob_symbol_info (const std::string& pattern) const
+  {
+    return m_call_stack.glob_symbol_info (pattern);
+  }
+
+  symbol_info_list
+  tree_evaluator::regexp_symbol_info (const std::string& pattern) const
+  {
+    return m_call_stack.regexp_symbol_info (pattern);
+  }
+
+  symbol_info_list
+  tree_evaluator::get_symbol_info (void)
+  {
+    return m_call_stack.get_symbol_info ();
+  }
+
+  symbol_info_list
+  tree_evaluator::top_scope_symbol_info (void) const
+  {
+    return m_call_stack.top_scope_symbol_info ();
+  }
+
+  octave_map tree_evaluator::get_autoload_map (void) const
+  {
+    Cell fcn_names (dim_vector (m_autoload_map.size (), 1));
+    Cell file_names (dim_vector (m_autoload_map.size (), 1));
+
+    octave_idx_type i = 0;
+    for (const auto& fcn_fname : m_autoload_map)
+      {
+        fcn_names(i) = fcn_fname.first;
+        file_names(i) = fcn_fname.second;
+
+        i++;
+      }
+
+    octave_map m;
+
+    m.assign ("function", fcn_names);
+    m.assign ("file", file_names);
+
+    return m;
+  }
+
+  std::string tree_evaluator::lookup_autoload (const std::string& nm) const
+  {
+    std::string retval;
+
+    auto p = m_autoload_map.find (nm);
+
+    if (p != m_autoload_map.end ())
+      {
+        load_path& lp = m_interpreter.get_load_path ();
+
+        retval = lp.find_file (p->second);
+      }
+
+    return retval;
+  }
+
+  std::list<std::string> tree_evaluator::autoloaded_functions (void) const
+  {
+    std::list<std::string> names;
+
+    for (const auto& fcn_fname : m_autoload_map)
+      names.push_back (fcn_fname.first);
+
+    return names;
+  }
+
+  std::list<std::string>
+  tree_evaluator::reverse_lookup_autoload (const std::string& nm) const
+  {
+    std::list<std::string> names;
+
+    for (const auto& fcn_fname : m_autoload_map)
+      if (nm == fcn_fname.second)
+        names.push_back (fcn_fname.first);
+
+    return names;
+  }
+
+  void tree_evaluator::add_autoload (const std::string& fcn,
+                                     const std::string& nm)
+  {
+    std::string file_name = check_autoload_file (nm);
+
+    m_autoload_map[fcn] = file_name;
+  }
+
+  void tree_evaluator::remove_autoload (const std::string& fcn,
+                                        const std::string& nm)
+  {
+    check_autoload_file (nm);
+
+    // Remove function from symbol table and autoload map.
+    symbol_table& symtab = m_interpreter.get_symbol_table ();
+
+    symtab.clear_dld_function (fcn);
+
+    m_autoload_map.erase (fcn);
+  }
+
+  octave_value
+  tree_evaluator::whos_line_format (const octave_value_list& args, int nargout)
+  {
+    return set_internal_variable (m_whos_line_format, args, nargout,
+                                  "whos_line_format");
+  }
+
+  octave_value
+  tree_evaluator::silent_functions (const octave_value_list& args, int nargout)
+  {
+    return set_internal_variable (m_silent_functions, args, nargout,
+                                  "silent_functions");
+  }
+
+  octave_value
+  tree_evaluator::string_fill_char (const octave_value_list& args, int nargout)
+  {
+    return set_internal_variable (m_string_fill_char, args, nargout,
+                                  "string_fill_char");
+  }
+
+  // Final step of processing an indexing error.  Add the name of the
+  // variable being indexed, if any, then issue an error.  (Will this also
+  // be needed by pt-lvalue, which calls subsref?)
+
+  void tree_evaluator::final_index_error (index_exception& ie,
+                                          const tree_expression *expr)
+  {
+    std::string extra_message;
+
+    if (is_variable (expr))
+      {
+        std::string var = expr->name ();
+
+        ie.set_var (var);
+
+        symbol_table& symtab = m_interpreter.get_symbol_table ();
+
+        octave_value fcn = symtab.find_function (var);
+
+        if (fcn.is_function ())
+          {
+            octave_function *fp = fcn.function_value ();
+
+            if (fp && fp->name () == var)
+              extra_message
+                = " (note: variable '" + var + "' shadows function)";
+          }
+      }
+
+    std::string msg = ie.message () + extra_message;
+
+    error_with_id (ie.err_id (), "%s", msg.c_str ());
+  }
+
+  octave_value
+  tree_evaluator::do_who (int argc, const string_vector& argv,
+                          bool return_list, bool verbose)
+  {
+    return m_call_stack.do_who (argc, argv, return_list, verbose);
+  }
+
+  octave_value_list
+  tree_evaluator::make_value_list (tree_argument_list *args,
+                                   const string_vector& arg_nm)
+  {
+    octave_value_list retval;
+
+    if (args)
+      {
+        unwind_protect_var<const std::list<octave_lvalue> *>
+          upv (m_lvalue_list, nullptr);
+
+        int len = args->length ();
+
+        unwind_protect_var<int> upv2 (m_index_position);
+        unwind_protect_var<int> upv3 (m_num_indices);
+
+        m_num_indices = len;
+
+        std::list<octave_value> arg_vals;
+
+        int k = 0;
+
+        for (auto elt : *args)
+          {
+            // FIXME: is it possible for elt to be invalid?
+
+            if (! elt)
+              break;
+
+            m_index_position = k++;
+
+            octave_value tmp = elt->evaluate (*this);
+
+            if (tmp.is_cs_list ())
+              {
+                octave_value_list tmp_ovl = tmp.list_value ();
+
+                for (octave_idx_type i = 0; i < tmp_ovl.length (); i++)
+                  arg_vals.push_back (tmp_ovl(i));
+              }
+            else if (tmp.is_defined ())
+              arg_vals.push_back (tmp);
+          }
+
+        retval = octave_value_list (arg_vals);
+      }
+
+    octave_idx_type n = retval.length ();
+
+    if (n > 0)
+      retval.stash_name_tags (arg_nm);
+
+    return retval;
+  }
+
+  std::list<octave_lvalue>
+  tree_evaluator::make_lvalue_list (tree_argument_list *lhs)
+  {
+    std::list<octave_lvalue> retval;
+
+    for (tree_expression *elt : *lhs)
+      retval.push_back (elt->lvalue (*this));
+
+    return retval;
+  }
+
+  void
+  tree_evaluator::push_echo_state (int type, const std::string& file_name,
+                                   int pos)
+  {
+    unwind_protect *frame = m_call_stack.curr_fcn_unwind_protect_frame ();
+
+    if (frame)
+      {
+        push_echo_state_cleanup (*frame);
+
+        set_echo_state (type, file_name, pos);
+      }
+  }
+
+  void
+  tree_evaluator::set_echo_state (int type, const std::string& file_name,
+                                  int pos)
+  {
+    m_echo_state = echo_this_file (file_name, type);
+    m_echo_file_name = file_name;
+    m_echo_file_pos = pos;
+  }
+
+  void
+  tree_evaluator::uwp_set_echo_state (bool state, const std::string& file_name,
+                                      int pos)
+  {
+    m_echo_state = state;
+    m_echo_file_name = file_name;
+    m_echo_file_pos = pos;
+  }
+
+  void
+  tree_evaluator::maybe_set_echo_state (void)
+  {
+    octave_function *caller = caller_function ();
+
+    if (caller && caller->is_user_code ())
+      {
+        octave_user_code *fcn = dynamic_cast<octave_user_code *> (caller);
+
+        int type = fcn->is_user_function () ? ECHO_FUNCTIONS : ECHO_SCRIPTS;
+
+        std::string file_name = fcn->fcn_file_name ();
+
+        // We want the line where "echo" was called, not the line number
+        // stored in the stack frame that was created for the echo
+        // function (that will always be -1).
+
+        int pos = m_call_stack.current_user_code_line ();
+
+        if (pos < 0)
+          pos = 1;
+
+        set_echo_state (type, file_name, pos);
+      }
+  }
+
+  void
+  tree_evaluator::push_echo_state_cleanup (unwind_protect& frame)
+  {
+    frame.add (&tree_evaluator::uwp_set_echo_state, this,
+               m_echo_state, m_echo_file_name, m_echo_file_pos);
+  }
+
+  bool tree_evaluator::maybe_push_echo_state_cleanup (void)
+  {
+    // This function is expected to be called from ECHO, which would be
+    // the top of the call stack.  If the caller of ECHO is a
+    // user-defined function or script, then set up unwind-protect
+    // elements to restore echo state.
+
+    unwind_protect *frame = m_call_stack.curr_fcn_unwind_protect_frame ();
+
+    if (frame)
+      {
+        push_echo_state_cleanup (*frame);
+        return true;
+      }
+
+    return false;
+  }
+
+
+  octave_value
+  tree_evaluator::echo (const octave_value_list& args, int)
+  {
+    bool cleanup_pushed = maybe_push_echo_state_cleanup ();
+
+    string_vector argv = args.make_argv ();
+
+    switch (args.length ())
+      {
+      case 0:
+        if ((m_echo & ECHO_SCRIPTS) || (m_echo & ECHO_FUNCTIONS))
+          {
+            m_echo = ECHO_OFF;
+            m_echo_files.clear ();
+          }
+        else
+          m_echo = ECHO_SCRIPTS;
         break;
 
-      octave_value tmp = elt->evaluate (*this);
-
-      if (tmp.is_cs_list ())
+      case 1:
         {
-          octave_value_list tmp_ovl = tmp.list_value ();
-
-          for (octave_idx_type i = 0; i < tmp_ovl.length (); i++)
-            arg_vals.push_back (tmp_ovl(i));
-        }
-      else if (tmp.is_defined ())
-        arg_vals.push_back (tmp);
-    }
-
-  return octave_value_list (arg_vals);
-}
-
-octave_value_list
-tree_evaluator::convert_return_list_to_const_vector
-(tree_parameter_list *ret_list, int nargout, const Matrix& ignored_outputs,
- const Cell& varargout)
-{
-  octave_idx_type vlen = varargout.numel ();
-  int len = ret_list->length ();
-
-  // Special case.  Will do a shallow copy.
-  if (len == 0)
-    return varargout;
-  else
-    {
-      int i = 0;
-      int k = 0;
-      int num_ignored = ignored_outputs.numel ();
-      int ignored = num_ignored > 0 ? ignored_outputs(k) - 1 : -1;
-
-      if (nargout <= len)
-        {
-          int nout = nargout > 0 ? nargout : 1;
-          octave_value_list retval (nout);
-
-          for (tree_decl_elt *elt : *ret_list)
+          std::string arg0 = argv[0];
+
+          if (arg0 == "on")
+            m_echo = ECHO_SCRIPTS;
+          else if (arg0 == "off")
+            m_echo = ECHO_OFF;
+          else
             {
-              if (nargout == 0 && ! is_defined (elt->ident ()))
-                break;
-
-              if (ignored >= 0 && i == ignored)
+              std::string file = fcn_file_in_path (arg0);
+              file = sys::env::make_absolute (file);
+
+              if (file.empty ())
+                error ("echo: no such file %s", arg0.c_str ());
+
+              if (m_echo & ECHO_ALL)
                 {
-                  i++;
-                  k++;
-                  ignored = k < num_ignored ? ignored_outputs(k) - 1 : -1;
+                  // Echo is enabled for all functions, so turn it off
+                  // for this one.
+
+                  m_echo_files[file] = false;
                 }
               else
-                retval(i++) = evaluate (elt);
-
-              if (i == nout)
-                break;
-            }
-
-          return retval;
-        }
-      else
-        {
-          octave_value_list retval (len + vlen);
-
-          for (tree_decl_elt *elt : *ret_list)
-            {
-              if (ignored >= 0 && i == ignored)
                 {
-                  i++;
-                  k++;
-                  ignored = k < num_ignored ? ignored_outputs(k) - 1 : -1;
-                }
-              else
-                retval(i++) = evaluate (elt);
-            }
-
-          for (octave_idx_type j = 0; j < vlen; j++)
-            retval(i++) = varargout(j);
-
-          return retval;
-        }
-    }
-}
-
-bool
-tree_evaluator::eval_decl_elt (tree_decl_elt *elt)
-{
-  bool retval = false;
-
-  tree_identifier *id = elt->ident ();
-  tree_expression *expr = elt->expression ();
-
-  if (id && expr)
-    {
-      octave_lvalue ult = id->lvalue (*this);
-
-      octave_value init_val = expr->evaluate (*this);
-
-      ult.assign (octave_value::op_asn_eq, init_val);
-
-      retval = true;
-    }
-
-  return retval;
-}
-
-bool
-tree_evaluator::switch_case_label_matches (tree_switch_case *expr,
-    const octave_value& val)
-{
-  tree_expression *label = expr->case_label ();
-
-  octave_value label_value = label->evaluate (*this);
-
-  if (label_value.is_defined ())
-    {
-      if (label_value.iscell ())
-        {
-          Cell cell (label_value.cell_value ());
-
-          for (octave_idx_type i = 0; i < cell.rows (); i++)
-            {
-              for (octave_idx_type j = 0; j < cell.columns (); j++)
-                {
-                  bool match = val.is_equal (cell(i, j));
-
-                  if (match)
-                    return true;
+                  // Echo may be enabled for specific functions.
+
+                  auto p = m_echo_files.find (file);
+
+                  if (p == m_echo_files.end ())
+                    {
+                      // Not this one, so enable it.
+
+                      m_echo |= ECHO_FUNCTIONS;
+                      m_echo_files[file] = true;
+                    }
+                  else
+                    {
+                      // This one is already in the list.  Flip the
+                      // status for it.
+
+                      p->second = ! p->second;
+                    }
                 }
             }
         }
-      else
-        return val.is_equal (label_value);
-    }
-
-  return false;
-}
-
-void tree_evaluator::push_stack_frame (const symbol_scope& scope)
-{
-  m_call_stack.push (scope);
-}
-
-void tree_evaluator::push_stack_frame (octave_user_function *fcn,
-                                       const std::shared_ptr<stack_frame>& closure_frames)
-{
-  m_call_stack.push (fcn, closure_frames);
-}
-
-void tree_evaluator::push_stack_frame (octave_user_function *fcn,
-                                       const stack_frame::local_vars_map& local_vars,
-                                       const std::shared_ptr<stack_frame>& closure_frames)
-{
-  m_call_stack.push (fcn, local_vars, closure_frames);
-}
-
-void tree_evaluator::push_stack_frame (octave_user_script *script)
-{
-  m_call_stack.push (script);
-}
-
-void tree_evaluator::push_stack_frame (octave_function *fcn)
-{
-  m_call_stack.push (fcn);
-}
-
-void tree_evaluator::pop_stack_frame (void)
-{
-  m_call_stack.pop ();
-}
-
-int tree_evaluator::current_line (void) const
-{
-  return m_call_stack.current_line ();
-}
-
-int tree_evaluator::current_column (void) const
-{
-  return m_call_stack.current_column ();
-}
-
-int tree_evaluator::debug_user_code_line (void) const
-{
-  return m_call_stack.debug_user_code_line ();
-}
-
-int tree_evaluator::debug_user_code_column (void) const
-{
-  return m_call_stack.debug_user_code_column ();
-}
-
-void tree_evaluator::debug_where (std::ostream& os) const
-{
-  std::shared_ptr<stack_frame> frm = m_call_stack.current_user_frame ();
-
-  frm->display_stopped_in_message (os);
-}
-
-octave_user_code *tree_evaluator::current_user_code (void) const
-{
-  return m_call_stack.current_user_code ();
-}
-
-unwind_protect *tree_evaluator::curr_fcn_unwind_protect_frame (void)
-{
-  return m_call_stack.curr_fcn_unwind_protect_frame ();
-}
-
-octave_user_code *tree_evaluator::debug_user_code (void) const
-{
-  return m_call_stack.debug_user_code ();
-}
-
-octave_function *tree_evaluator::current_function (bool skip_first) const
-{
-  return m_call_stack.current_function (skip_first);
-}
-
-octave_function *tree_evaluator::caller_function (void) const
-{
-  return m_call_stack.current_function (true);
-}
-
-bool tree_evaluator::goto_frame (std::size_t n, bool verbose)
-{
-  return m_call_stack.goto_frame (n, verbose);
-}
-
-void tree_evaluator::goto_caller_frame (void)
-{
-  m_call_stack.goto_caller_frame ();
-}
-
-void tree_evaluator::goto_base_frame (void)
-{
-  m_call_stack.goto_base_frame ();
-}
-
-void tree_evaluator::restore_frame (std::size_t n)
-{
-  return m_call_stack.restore_frame (n);
-}
-
-std::string tree_evaluator::get_dispatch_class (void) const
-{
-  return m_call_stack.get_dispatch_class ();
-}
-
-void tree_evaluator::set_dispatch_class (const std::string& class_name)
-{
-  m_call_stack.set_dispatch_class (class_name);
-}
-
-bool
-tree_evaluator::is_class_method_executing (std::string& dclass) const
-{
-  return m_call_stack.is_class_method_executing (dclass);
-}
-
-bool
-tree_evaluator::is_class_constructor_executing (std::string& dclass) const
-{
-  return m_call_stack.is_class_constructor_executing (dclass);
-}
-
-std::list<std::shared_ptr<stack_frame>>
-                                     tree_evaluator::backtrace_frames (octave_idx_type& curr_user_frame) const
-{
-  return m_call_stack.backtrace_frames (curr_user_frame);
-}
-
-std::list<std::shared_ptr<stack_frame>>
-                                     tree_evaluator::backtrace_frames (void) const
-{
-  return m_call_stack.backtrace_frames ();
-}
-
-std::list<frame_info>
-tree_evaluator::backtrace_info (octave_idx_type& curr_user_frame,
-                                bool print_subfn) const
-{
-  return m_call_stack.backtrace_info (curr_user_frame, print_subfn);
-}
-
-std::list<frame_info> tree_evaluator::backtrace_info (void) const
-{
-  return m_call_stack.backtrace_info ();
-}
-
-octave_map
-tree_evaluator::backtrace (octave_idx_type& curr_user_frame,
-                           bool print_subfn) const
-{
-  return m_call_stack.backtrace (curr_user_frame, print_subfn);
-}
-
-octave_map tree_evaluator::backtrace (void) const
-{
-  return m_call_stack.backtrace ();
-}
-
-octave_map tree_evaluator::empty_backtrace (void) const
-{
-  return m_call_stack.empty_backtrace ();
-}
-
-std::string tree_evaluator::backtrace_message (void) const
-{
-  std::list<frame_info> frames = backtrace_info ();
-
-  std::ostringstream buf;
-
-  for (const auto& frm : frames)
-    {
-      buf << "    " << frm.fcn_name ();
-
-      int line = frm.line ();
-
-      if (line > 0)
+        break;
+
+      case 2:
         {
-          buf << " at line " << line;
-
-          int column = frm.column ();
-
-          if (column > 0)
-            buf << " column " << column;
-
-          buf << "\n";
-        }
-    }
-
-  return buf.str ();
-}
-
-void tree_evaluator::push_dummy_scope (const std::string& name)
-{
-  symbol_scope dummy_scope (name + "$dummy");
-
-  m_call_stack.push (dummy_scope);
-}
-
-void tree_evaluator::pop_scope (void)
-{
-  m_call_stack.pop ();
-}
-
-symbol_scope tree_evaluator::get_top_scope (void) const
-{
-  return m_call_stack.top_scope ();
-}
-
-symbol_scope tree_evaluator::get_current_scope (void) const
-{
-  return m_call_stack.current_scope ();
-}
-
-void tree_evaluator::mlock (bool skip_first) const
-{
-  octave_function *fcn = m_call_stack.current_function (skip_first);
-
-  if (! fcn)
-    error ("mlock: invalid use outside a function");
-
-  if (fcn->is_builtin_function ())
-    {
-      warning ("mlock: locking built-in function has no effect");
-      return;
-    }
-
-  fcn->lock ();
-}
-
-void tree_evaluator::munlock (bool skip_first) const
-{
-  octave_function *fcn = m_call_stack.current_function (skip_first);
-
-  if (! fcn)
-    error ("munlock: invalid use outside a function");
-
-  if (fcn->is_builtin_function ())
-    {
-      warning ("munlock: unlocking built-in function has no effect");
-      return;
-    }
-
-  fcn->unlock ();
-}
-
-bool tree_evaluator::mislocked (bool skip_first) const
-{
-  octave_function *fcn = m_call_stack.current_function (skip_first);
-
-  if (! fcn)
-    error ("mislocked: invalid use outside a function");
-
-  return fcn->islocked ();
-}
-
-octave_value
-tree_evaluator::max_stack_depth (const octave_value_list& args, int nargout)
-{
-  return m_call_stack.max_stack_depth (args, nargout);
-}
-
-void tree_evaluator::display_call_stack (void) const
-{
-  m_call_stack.display ();
-}
-
-octave_value tree_evaluator::find (const std::string& name)
-{
-  std::shared_ptr<stack_frame> frame
-    = m_call_stack.get_current_stack_frame ();
-
-  octave_value val = frame->varval (name);
-
-  if (val.is_defined ())
-    return val;
-
-  // Subfunction.  I think it only makes sense to check for
-  // subfunctions if we are currently executing a function defined
-  // from a .m file.
-
-  octave_value fcn = frame->find_subfunction (name);
-
-  if (fcn.is_defined ())
-    return fcn;
-
-  symbol_table& symtab = m_interpreter.get_symbol_table ();
-
-  return symtab.fcn_table_find (name, ovl ());
-}
-
-void tree_evaluator::clear_objects (void)
-{
-  std::shared_ptr<stack_frame> frame
-    = m_call_stack.get_current_stack_frame ();
-
-  frame->clear_objects ();
-}
-
-void tree_evaluator::clear_variable (const std::string& name)
-{
-  std::shared_ptr<stack_frame> frame
-    = m_call_stack.get_current_stack_frame ();
-
-  frame->clear_variable (name);
-}
-
-void tree_evaluator::clear_variable_pattern (const std::string& pattern)
-{
-  std::shared_ptr<stack_frame> frame
-    = m_call_stack.get_current_stack_frame ();
-
-  frame->clear_variable_pattern (pattern);
-}
-
-void tree_evaluator::clear_variable_regexp (const std::string& pattern)
-{
-  std::shared_ptr<stack_frame> frame
-    = m_call_stack.get_current_stack_frame ();
-
-  frame->clear_variable_regexp (pattern);
-}
-
-void tree_evaluator::clear_variables (void)
-{
-  std::shared_ptr<stack_frame> frame
-    = m_call_stack.get_current_stack_frame ();
-
-  frame->clear_variables ();
-}
-
-void tree_evaluator::clear_global_variable (const std::string& name)
-{
-  m_call_stack.clear_global_variable (name);
-}
-
-void
-tree_evaluator::clear_global_variable_pattern (const std::string& pattern)
-{
-  m_call_stack.clear_global_variable_pattern (pattern);
-}
-
-void tree_evaluator::clear_global_variable_regexp(const std::string& pattern)
-{
-  m_call_stack.clear_global_variable_regexp (pattern);
-}
-
-void tree_evaluator::clear_global_variables (void)
-{
-  m_call_stack.clear_global_variables ();
-}
-
-void tree_evaluator::clear_all (bool force)
-{
-  // FIXME: should this also clear objects?
-
-  clear_variables ();
-  clear_global_variables ();
-
-  symbol_table& symtab = m_interpreter.get_symbol_table ();
-
-  symtab.clear_functions (force);
-}
-
-void tree_evaluator::clear_symbol (const std::string& name)
-{
-  // FIXME: are we supposed to do both here?
-
-  clear_variable (name);
-
-  symbol_table& symtab = m_interpreter.get_symbol_table ();
-
-  symtab.clear_function (name);
-}
-
-void tree_evaluator::clear_symbol_pattern (const std::string& pattern)
-{
-  // FIXME: are we supposed to do both here?
-
-  clear_variable_pattern (pattern);
-
-  symbol_table& symtab = m_interpreter.get_symbol_table ();
-
-  symtab.clear_function_pattern (pattern);
-}
-
-void tree_evaluator::clear_symbol_regexp (const std::string& pattern)
-{
-  // FIXME: are we supposed to do both here?
-
-  clear_variable_regexp (pattern);
-
-  symbol_table& symtab = m_interpreter.get_symbol_table ();
-
-  symtab.clear_function_regexp (pattern);
-}
-
-std::list<std::string> tree_evaluator::global_variable_names (void) const
-{
-  return m_call_stack.global_variable_names ();
-}
-
-std::list<std::string> tree_evaluator::top_level_variable_names (void) const
-{
-  return m_call_stack.top_level_variable_names ();
-}
-
-std::list<std::string> tree_evaluator::variable_names (void) const
-{
-  return m_call_stack.variable_names ();
-}
-
-// Return a pointer to the user-defined function FNAME.  If FNAME is empty,
-// search backward for the first user-defined function in the
-// current call stack.
-
-octave_user_code *
-tree_evaluator::get_user_code (const std::string& fname,
-                               const std::string& class_name)
-{
-  octave_user_code *user_code = nullptr;
-
-  if (fname.empty ())
-    user_code = m_call_stack.debug_user_code ();
-  else
-    {
-      std::string name = fname;
-
-      if (sys::file_ops::dir_sep_char () != '/' && name[0] == '@')
-        {
-          auto beg = name.begin () + 2;  // never have @/method
-          auto end = name.end () - 1;    // never have trailing '/'
-          std::replace (beg, end, '/', sys::file_ops::dir_sep_char ());
-        }
-
-      std::size_t name_len = name.length ();
-
-      if (name_len > 2 && name.substr (name_len-2) == ".m")
-        name = name.substr (0, name_len-2);
-
-      if (name.empty ())
-        return nullptr;
-
-      symbol_table& symtab = m_interpreter.get_symbol_table ();
-
-      octave_value fcn;
-      std::size_t p2 = std::string::npos;
-
-      if (name[0] == '@')
-        {
-          std::size_t p1 = name.find (sys::file_ops::dir_sep_char (), 1);
-
-          if (p1 == std::string::npos)
-            return nullptr;
-
-          std::string dispatch_type = name.substr (1, p1-1);
-
-          p2 = name.find ('>', p1);
-
-          std::string method = name.substr (p1+1, p2-1);
-
-          fcn = symtab.find_method (method, dispatch_type);
-        }
-      else if (! class_name.empty ())
-        {
-          cdef_manager& cdm = m_interpreter.get_cdef_manager ();
-
-          fcn = cdm.find_method (class_name, name);
-
-          // If there is no classdef method, then try legacy classes.
-          if (fcn.is_undefined ())
-            fcn = symtab.find_method (name, class_name);
-        }
-      else
-        {
-          p2 = name.find ('>');
-
-          std::string main_fcn = name.substr (0, p2);
-
-          fcn = symtab.find_function (main_fcn);
-        }
-
-      // List of function names sub1>sub2>...
-      std::string subfuns;
-
-      if (p2 != std::string::npos)
-        subfuns = name.substr (p2+1);
-
-      if (fcn.is_defined () && fcn.is_user_code ())
-        user_code = fcn.user_code_value ();
-
-      if (! user_code || subfuns.empty ())
-        return user_code;
-
-      fcn = user_code->find_subfunction (subfuns);
-
-      if (fcn.is_undefined ())
-        return nullptr;
-
-      user_code = fcn.user_code_value ();
-    }
-
-  return user_code;
-}
-
-std::string
-tree_evaluator::current_function_name (bool skip_first) const
-{
-  octave_function *curfcn = m_call_stack.current_function (skip_first);
-
-  if (curfcn)
-    return curfcn->name ();
-
-  return "";
-}
-
-bool
-tree_evaluator::in_user_code (void) const
-{
-  return m_call_stack.current_user_code () != nullptr;
-}
-
-void
-tree_evaluator::visit_decl_command (tree_decl_command& cmd)
-{
-  if (m_echo_state)
-    {
-      int line = cmd.line ();
-      if (line < 0)
-        line = 1;
-      echo_code (line);
-      m_echo_file_pos = line + 1;
-    }
-
-  if (m_debug_mode)
-    do_breakpoint (cmd.is_active_breakpoint (*this));
-
-  // FIXME: tree_decl_init_list is not derived from tree, so should it
-  // really have an accept method?
-
-  tree_decl_init_list *init_list = cmd.initializer_list ();
-
-  if (init_list)
-    init_list->accept (*this);
-}
-
-void
-tree_evaluator::visit_decl_elt (tree_decl_elt& elt)
-{
-  tree_identifier *id = elt.ident ();
-
-  if (id)
-    {
-      if (elt.is_global ())
-        m_call_stack.make_global (id->symbol ());
-      else if (elt.is_persistent ())
-        m_call_stack.make_persistent (id->symbol ());
-      else
-        error ("declaration list element not global or persistent");
-
-      octave_lvalue ult = id->lvalue (*this);
-
-      if (ult.is_undefined ())
-        {
-          tree_expression *expr = elt.expression ();
-
-          octave_value init_val;
-
-          if (expr)
-            init_val = expr->evaluate (*this);
-          else
-            init_val = Matrix ();
-
-          ult.assign (octave_value::op_asn_eq, init_val);
-        }
-    }
-}
-
-template <typename T>
-void
-tree_evaluator::execute_range_loop (const range<T>& rng, int line,
-                                    octave_lvalue& ult,
-                                    tree_statement_list *loop_body)
-{
-  octave_idx_type steps = rng.numel ();
-
-  if (math::isinf (rng.limit ()))
-    warning_with_id ("Octave:infinite-loop",
-                     "FOR loop limit is infinite, will stop after %"
-                     OCTAVE_IDX_TYPE_FORMAT " steps", steps);
-
-  for (octave_idx_type i = 0; i < steps; i++)
-    {
-      if (m_echo_state)
-        m_echo_file_pos = line;
-
-      octave_value val (rng.elem (i));
-
-      ult.assign (octave_value::op_asn_eq, val);
-
-      if (loop_body)
-        loop_body->accept (*this);
-
-      if (quit_loop_now ())
-        break;
-    }
-}
-
-void
-tree_evaluator::visit_simple_for_command (tree_simple_for_command& cmd)
-{
-  int line = cmd.line ();
-  if (line < 0)
-    line = 1;
-
-  if (m_echo_state)
-    {
-      echo_code (line);
-      line++;
-    }
-
-  if (m_debug_mode)
-    do_breakpoint (cmd.is_active_breakpoint (*this));
-
-  // FIXME: need to handle PARFOR loops here using cmd.in_parallel ()
-  // and cmd.maxproc_expr ();
-
-  unwind_protect_var<bool> upv (m_in_loop_command, true);
-
-  tree_expression *expr = cmd.control_expr ();
-
-  octave_value rhs = expr->evaluate (*this);
-
-  if (rhs.is_undefined ())
-    return;
-
-  tree_expression *lhs = cmd.left_hand_side ();
-
-  octave_lvalue ult = lhs->lvalue (*this);
-
-  tree_statement_list *loop_body = cmd.body ();
-
-  if (rhs.is_range ())
-    {
-      // FIXME: is there a better way to dispatch here?
-
-      if (rhs.is_double_type ())
-        {
-          execute_range_loop (rhs.range_value (), line, ult, loop_body);
-          return;
-        }
-
-      // For now, disable all but range<double>.
-
-#if 0
-      if (rhs.is_int64_type ())
-        {
-          execute_range_loop (rhs.int64_range_value (), line, ult, loop_body);
-          return;
-        }
-
-      if (rhs.is_uint64_type ())
-        {
-          execute_range_loop (rhs.uint64_range_value (), line, ult, loop_body);
-          return;
-        }
-
-      if (rhs.is_int32_type ())
-        {
-          execute_range_loop (rhs.int32_range_value (), line, ult, loop_body);
-          return;
-        }
-
-      if (rhs.is_uint32_type ())
-        {
-          execute_range_loop (rhs.uint32_range_value (), line, ult, loop_body);
-          return;
-        }
-
-      if (rhs.is_int16_type ())
-        {
-          execute_range_loop (rhs.int16_range_value (), line, ult, loop_body);
-          return;
-        }
-
-      if (rhs.is_uint16_type ())
-        {
-          execute_range_loop (rhs.uint16_range_value (), line, ult, loop_body);
-          return;
-        }
-
-      if (rhs.is_int8_type ())
-        {
-          execute_range_loop (rhs.int8_range_value (), line, ult, loop_body);
-          return;
-        }
-
-      if (rhs.is_uint8_type ())
-        {
-          execute_range_loop (rhs.uint8_range_value (), line, ult, loop_body);
-          return;
-        }
-
-      if (rhs.is_single_type ())
-        {
-          execute_range_loop (rhs.float_range_value (), line, ult, loop_body);
-          return;
-        }
-#endif
-    }
-
-  if (rhs.is_scalar_type ())
-    {
-      if (m_echo_state)
-        m_echo_file_pos = line;
-
-      ult.assign (octave_value::op_asn_eq, rhs);
-
-      if (loop_body)
-        loop_body->accept (*this);
-
-      // Maybe decrement break and continue states.
-      quit_loop_now ();
-
-      return;
-    }
-
-  // Also handle any range types not explicitly handled above, though
-  // not as efficiently as the specialized code above.
-
-  if (rhs.is_range () || rhs.is_matrix_type () || rhs.iscell ()
-      || rhs.is_string () || rhs.isstruct ())
-    {
-      // A matrix or cell is reshaped to 2 dimensions and iterated by
-      // columns.
-
-      dim_vector dv = rhs.dims ().redim (2);
-
-      octave_idx_type nrows = dv(0);
-      octave_idx_type steps = dv(1);
-
-      octave_value arg = rhs;
-      if (rhs.ndims () > 2)
-        arg = arg.reshape (dv);
-
-      if (nrows > 0 && steps > 0)
-        {
-          octave_value_list idx;
-          octave_idx_type iidx;
-
-          // for row vectors, use single index to speed things up.
-          if (nrows == 1)
+          std::string arg0 = argv[0];
+          std::string arg1 = argv[1];
+
+          if (arg1 == "on" || arg1 == "off")
+            std::swap (arg0, arg1);
+
+          if (arg0 == "on")
             {
-              idx.resize (1);
-              iidx = 0;
+              if (arg1 == "all")
+                {
+                  m_echo = (ECHO_SCRIPTS | ECHO_FUNCTIONS | ECHO_ALL);
+                  m_echo_files.clear ();
+                }
+              else
+                {
+                  std::string file = fcn_file_in_path (arg1);
+                  file = sys::env::make_absolute (file);
+
+                  if (file.empty ())
+                    error ("echo: no such file %s", arg1.c_str ());
+
+                  m_echo |= ECHO_FUNCTIONS;
+                  m_echo_files[file] = true;
+                }
+            }
+          else if (arg0 == "off")
+            {
+              if (arg1 == "all")
+                {
+                  m_echo = ECHO_OFF;
+                  m_echo_files.clear ();
+                }
+              else
+                {
+                  std::string file = fcn_file_in_path (arg1);
+                  file = sys::env::make_absolute (file);
+
+                  if (file.empty ())
+                    error ("echo: no such file %s", arg1.c_str ());
+
+                  m_echo_files[file] = false;
+                }
             }
           else
-            {
-              idx.resize (2);
-              idx(0) = octave_value::magic_colon_t;
-              iidx = 1;
-            }
-
-          for (octave_idx_type i = 1; i <= steps; i++)
-            {
-              if (m_echo_state)
-                m_echo_file_pos = line;
-
-              // index_op expects one-based indices.
-              idx(iidx) = i;
-              octave_value val = arg.index_op (idx);
-
-              ult.assign (octave_value::op_asn_eq, val);
-
-              if (loop_body)
-                loop_body->accept (*this);
-
-              if (quit_loop_now ())
-                break;
-            }
-        }
-      else
-        {
-          // Handle empty cases, while still assigning to loop var.
-          ult.assign (octave_value::op_asn_eq, arg);
-        }
-
-      return;
-    }
-
-  error ("invalid type in for loop expression near line %d, column %d",
-         cmd.line (), cmd.column ());
-}
-
-void
-tree_evaluator::visit_complex_for_command (tree_complex_for_command& cmd)
-{
-  int line = cmd.line ();
-  if (line < 0)
-    line = 1;
-
-  if (m_echo_state)
-    {
-      echo_code (line);
-      line++;
-    }
-
-  if (m_debug_mode)
-    do_breakpoint (cmd.is_active_breakpoint (*this));
-
-  unwind_protect_var<bool> upv (m_in_loop_command, true);
-
-  tree_expression *expr = cmd.control_expr ();
-
-  octave_value rhs = expr->evaluate (*this);
-
-  if (rhs.is_undefined ())
-    return;
-
-  if (! rhs.isstruct ())
-    error ("in statement 'for [X, Y] = VAL', VAL must be a structure");
-
-  // Cycle through structure elements.  First element of id_list
-  // is set to value and the second is set to the name of the
-  // structure element.
-
-  tree_argument_list *lhs = cmd.left_hand_side ();
-
-  auto p = lhs->begin ();
-
-  tree_expression *elt = *p++;
-
-  octave_lvalue val_ref = elt->lvalue (*this);
-
-  elt = *p;
-
-  octave_lvalue key_ref = elt->lvalue (*this);
-
-  const octave_map tmp_val = rhs.map_value ();
-
-  tree_statement_list *loop_body = cmd.body ();
-
-  string_vector keys = tmp_val.keys ();
-
-  octave_idx_type nel = keys.numel ();
-
-  for (octave_idx_type i = 0; i < nel; i++)
-    {
-      if (m_echo_state)
-        m_echo_file_pos = line;
-
-      std::string key = keys[i];
-
-      const Cell val_lst = tmp_val.contents (key);
-
-      octave_idx_type n = val_lst.numel ();
-
-      octave_value val = (n == 1) ? val_lst(0) : octave_value (val_lst);
-
-      val_ref.assign (octave_value::op_asn_eq, val);
-      key_ref.assign (octave_value::op_asn_eq, key);
-
-      if (loop_body)
-        loop_body->accept (*this);
-
-      if (quit_loop_now ())
-        break;
-    }
-}
-
-void tree_evaluator::visit_spmd_command (tree_spmd_command& cmd)
-{
-  // For now, we just execute the commands serially.
-
-  tree_statement_list *body = cmd.body ();
-
-  if (body)
-    body->accept (*this);
-}
-
-octave_value
-tree_evaluator::evaluate_anon_fcn_handle (tree_anon_fcn_handle& afh)
-{
-  // FIXME: should CMD_LIST be limited to a single expression?
-  // I think that is what Matlab does.
-
-  symbol_scope new_scope;
-  symbol_scope scope = afh.scope ();
-  if (scope)
-    new_scope = scope.dup ();
-
-  tree_parameter_list *param_list = afh.parameter_list ();
-  tree_parameter_list *param_list_dup
-    = param_list ? param_list->dup (new_scope) : nullptr;
-
-  tree_parameter_list *ret_list = nullptr;
-
-  tree_statement_list *stmt_list = nullptr;
-
-  symbol_scope parent_scope = get_current_scope ();
-
-  new_scope.set_parent (parent_scope);
-  new_scope.set_primary_parent (parent_scope);
-
-  tree_expression *expr = afh.expression ();
-  if (expr)
-    {
-      tree_expression *expr_dup = expr->dup (new_scope);
-      tree_statement *stmt = new tree_statement (expr_dup, nullptr);
-      stmt_list = new tree_statement_list (stmt);
-    }
-
-  tree_anon_scopes anon_fcn_ctx (afh);
-
-  std::set<std::string> free_vars = anon_fcn_ctx.free_variables ();
-
-  stack_frame::local_vars_map local_vars;
-
-  std::shared_ptr<stack_frame> frame
-    = m_call_stack.get_current_stack_frame ();
-
-  for (auto& name : free_vars)
-    {
-      octave_value val = frame->varval (name);
-
-      if (val.is_defined ())
-        local_vars[name] = val;
-    }
-
-  octave_user_function *af
-    = new octave_user_function (new_scope, param_list_dup, ret_list,
-                                stmt_list);
-
-  octave_function *curr_fcn = m_call_stack.current_function ();
-
-  bool is_nested = false;
-
-  if (curr_fcn)
-    {
-      // FIXME: maybe it would be better to just stash curr_fcn
-      // instead of individual bits of info about it?
-
-      // An anonymous function defined inside another nested function
-      // or parent of a nested function also behaves like a nested
-      // function.
-
-      if (curr_fcn->is_parent_function () || curr_fcn->is_nested_function ())
-        {
-          is_nested = true;
-          af->mark_as_nested_function ();
-          new_scope.set_nesting_depth (parent_scope.nesting_depth () + 1);
-        }
-
-      af->stash_dir_name (curr_fcn->dir_name ());
-
-      new_scope.cache_fcn_file_name (curr_fcn->fcn_file_name ());
-      new_scope.cache_dir_name (curr_fcn->dir_name ());
-
-      // The following is needed so that class method dispatch works
-      // properly for anonymous functions that wrap class methods.
-
-      if (curr_fcn->is_class_method () || curr_fcn->is_class_constructor ())
-        af->stash_dispatch_class (curr_fcn->dispatch_class ());
-
-      af->stash_fcn_file_name (curr_fcn->fcn_file_name ());
-    }
-
-  af->mark_as_anonymous_function ();
-
-  octave_value ov_fcn (af);
-
-  return (is_nested
-          ? octave_value (new octave_fcn_handle (ov_fcn, local_vars, frame))
-          : octave_value (new octave_fcn_handle (ov_fcn, local_vars)));
-}
-
-octave_value_list
-tree_evaluator::execute_builtin_function (octave_builtin& builtin_function,
-    int nargout,
-    const octave_value_list& args)
-{
-  octave_value_list retval;
-
-  if (args.has_magic_colon ())
-    error ("invalid use of colon in function argument list");
-
-  profiler::enter<octave_builtin> block (m_profiler, builtin_function);
-
-  octave_builtin::fcn fcn = builtin_function.function ();
-
-  if (fcn)
-    retval = (*fcn) (args, nargout);
-  else
-    {
-      octave_builtin::meth meth = builtin_function.method ();
-
-      retval = (*meth) (m_interpreter, args, nargout);
-    }
-
-  // Do not allow null values to be returned from functions.
-  // FIXME: perhaps true builtins should be allowed?
-
-  retval.make_storable_values ();
-
-  // Fix the case of a single undefined value.
-  // This happens when a compiled function uses
-  //
-  //   octave_value retval;
-  //
-  // instead of
-  //
-  //   octave_value_list retval;
-  //
-  // the idiom is very common, so we solve that here.
-
-  if (retval.length () == 1 && retval.xelem (0).is_undefined ())
-    retval.clear ();
-
-  return retval;
-}
-
-octave_value_list
-tree_evaluator::execute_mex_function (octave_mex_function& mex_function,
-                                      int nargout,
-                                      const octave_value_list& args)
-{
-  octave_value_list retval;
-
-  if (args.has_magic_colon ())
-    error ("invalid use of colon in function argument list");
-
-  profiler::enter<octave_mex_function> block (m_profiler, mex_function);
-
-  retval = call_mex (mex_function, args, nargout);
-
-  return retval;
-}
-
-octave_value_list
-tree_evaluator::execute_user_script (octave_user_script& user_script,
-                                     int nargout,
-                                     const octave_value_list& args)
-{
-  octave_value_list retval;
-
-  std::string file_name = user_script.fcn_file_name ();
-
-  if (args.length () != 0 || nargout != 0)
-    error ("invalid call to script %s", file_name.c_str ());
-
-  tree_statement_list *cmd_list = user_script.body ();
-
-  if (! cmd_list)
-    return retval;
-
-  // FIXME: Maybe this check belongs in the places where we push a new
-  // stack frame?  Or in the call_stack push method itself?
-
-  if (m_call_stack.size () >= static_cast<std::size_t> (m_max_recursion_depth))
-    error ("max_recursion_depth exceeded");
-
-  unwind_protect_var<stmt_list_type> upv (m_statement_context, SC_SCRIPT);
-
-  profiler::enter<octave_user_script> block (m_profiler, user_script);
-
-  if (echo ())
-    push_echo_state (tree_evaluator::ECHO_SCRIPTS, file_name);
-
-  // FIXME: Should we be using tree_evaluator::eval here?
-
-  cmd_list->accept (*this);
-
-  if (m_returning)
-    m_returning = 0;
-
-  if (m_breaking)
-    m_breaking--;
-
-  return retval;
-}
-
-void
-tree_evaluator::visit_octave_user_script (octave_user_script&)
-{
-  // ??
-  panic_impossible ();
-}
-
-octave_value_list
-tree_evaluator::execute_user_function (octave_user_function& user_function,
-                                       int nargout,
-                                       const octave_value_list& xargs)
-{
-  octave_value_list retval;
-
-  // If this function is a classdef constructor, extract the first input
-  // argument, which must be the partially constructed object instance.
-
-  octave_value_list args (xargs);
-  octave_value_list ret_args;
-
-  int nargin = args.length ();
-
-  if (user_function.is_classdef_constructor ())
-    {
-      if (nargin > 0)
-        {
-          ret_args = args.slice (0, 1, true);
-          --nargin;
-          args = args.slice (1, nargin, true);
-        }
-      else
-        panic_impossible ();
-    }
-
-  // FIXME: this probably shouldn't be a double-precision matrix.
-  Matrix ignored_outputs = ignored_fcn_outputs ();
-
-  tree_parameter_list *param_list = user_function.parameter_list ();
-
-  bool takes_varargs = false;
-  int max_inputs = 0;
-
-  if (param_list)
-    {
-      takes_varargs = param_list->takes_varargs ();
-      max_inputs = param_list->length ();
-    }
-
-  if (! takes_varargs && nargin > max_inputs)
-    {
-      std::string name = user_function.name ();
-
-      if (name.empty ())
-        name = "@<anonymous>";
-
-      error_with_id ("Octave:invalid-fun-call",
-                     "%s: function called with too many inputs",
-                     name.c_str ());
-    }
-
-  define_parameter_list_from_arg_vector (param_list, args);
-
-  tree_parameter_list *ret_list = user_function.return_list ();
-
-  if (ret_list && ! ret_list->takes_varargs ())
-    {
-      int max_outputs = ret_list->length ();
-
-      if (nargout > max_outputs)
-        {
-          std::string name = user_function.name ();
-
-          error_with_id ("Octave:invalid-fun-call",
-                         "%s: function called with too many outputs",
-                         name.c_str ());
-        }
-    }
-
-  bind_auto_fcn_vars (xargs.name_tags (), ignored_outputs, nargin,
-                      nargout, user_function.takes_varargs (),
-                      user_function.all_va_args (args));
-
-  // For classdef constructor, pre-populate the output arguments
-  // with the pre-initialized object instance, extracted above.
-
-  if (user_function.is_classdef_constructor ())
-    {
-      if (! ret_list)
-        error ("%s: invalid classdef constructor, no output argument defined",
-               user_function.dispatch_class ().c_str ());
-
-      define_parameter_list_from_arg_vector (ret_list, ret_args);
-    }
-
-  // FIXME: Maybe this check belongs in the places where we push a
-  // new stack frame?  Or in the call_stack push method itself?
-
-  if (m_call_stack.size () >= static_cast<std::size_t> (m_max_recursion_depth))
-    error ("max_recursion_depth exceeded");
-
-  unwind_action act2 ([&user_function] ()
-  {
-    user_function.restore_warning_states ();
-  });
-
-  // Evaluate the commands that make up the function.
-
-  unwind_protect_var<stmt_list_type> upv (m_statement_context, SC_FUNCTION);
-
-  tree_statement_list *cmd_list = user_function.body ();
-
-  if (cmd_list)
-    {
-      profiler::enter<octave_user_function>
-      block (m_profiler, user_function);
-
-      if (echo ())
-        push_echo_state (tree_evaluator::ECHO_FUNCTIONS,
-                         user_function.fcn_file_name ());
-
-      if (user_function.is_special_expr ())
-        {
-          panic_if (cmd_list->length () != 1);
-
-          tree_statement *stmt = cmd_list->front ();
-
-          tree_expression *expr = stmt->expression ();
-
-          if (expr)
-            {
-              m_call_stack.set_location (stmt->line (), stmt->column ());
-
-              retval = expr->evaluate_n (*this, nargout);
-            }
-        }
-      else
-        cmd_list->accept (*this);
-
-      if (m_returning)
-        m_returning = 0;
-
-      if (m_breaking)
-        m_breaking--;
-    }
-
-  // Copy return values out.
-
-  if (ret_list && ! user_function.is_special_expr ())
-    {
-      Cell varargout;
-
-      if (ret_list->takes_varargs ())
-        {
-          octave_value varargout_varval = varval ("varargout");
-
-          if (varargout_varval.is_defined ())
-            varargout = varargout_varval.xcell_value ("varargout must be a cell array object");
-        }
-
-      retval = convert_return_list_to_const_vector (ret_list, nargout,
-               ignored_outputs,
-               varargout);
-    }
-
-  return retval;
-}
-
-void
-tree_evaluator::visit_octave_user_function (octave_user_function&)
-{
-  // ??
-  panic_impossible ();
-}
-
-void
-tree_evaluator::visit_octave_user_function_header (octave_user_function&)
-{
-  panic_impossible ();
-}
-
-void
-tree_evaluator::visit_octave_user_function_trailer (octave_user_function&)
-{
-  panic_impossible ();
-}
-
-void
-tree_evaluator::visit_function_def (tree_function_def& cmd)
-{
-  octave_value fcn = cmd.function ();
-
-  octave_function *f = fcn.function_value ();
-
-  if (f)
-    {
-      std::string nm = f->name ();
-
-      symbol_table& symtab = m_interpreter.get_symbol_table ();
-
-      symtab.install_cmdline_function (nm, fcn);
-
-      // Make sure that any variable with the same name as the new
-      // function is cleared.
-
-      assign (nm);
-    }
-}
-
-void
-tree_evaluator::visit_identifier (tree_identifier&)
-{
-  panic_impossible ();
-}
-
-void
-tree_evaluator::visit_if_clause (tree_if_clause&)
-{
-  panic_impossible ();
-}
-
-void
-tree_evaluator::visit_if_command (tree_if_command& cmd)
-{
-  if (m_echo_state)
-    {
-      int line = cmd.line ();
-      if (line < 0)
-        line = 1;
-      echo_code (line);
-      m_echo_file_pos = line + 1;
-    }
-
-  // FIXME: tree_if_command_list is not derived from tree, so should it
-  // really have an accept method?
-
-  tree_if_command_list *lst = cmd.cmd_list ();
-
-  if (lst)
-    lst->accept (*this);
-}
-
-void
-tree_evaluator::visit_if_command_list (tree_if_command_list& lst)
-{
-  for (tree_if_clause *tic : lst)
-    {
-      tree_expression *expr = tic->condition ();
-
-      if (! (in_debug_repl ()
-             && m_call_stack.current_frame () == m_debug_frame))
-        m_call_stack.set_location (tic->line (), tic->column ());
-
-      if (m_debug_mode && ! tic->is_else_clause ())
-        do_breakpoint (tic->is_active_breakpoint (*this));
-
-      if (tic->is_else_clause () || is_logically_true (expr, "if"))
-        {
-          tree_statement_list *stmt_lst = tic->commands ();
-
-          if (stmt_lst)
-            stmt_lst->accept (*this);
-
-          break;
-        }
-    }
-}
-
-void
-tree_evaluator::visit_index_expression (tree_index_expression&)
-{
-  panic_impossible ();
-}
-
-void
-tree_evaluator::visit_matrix (tree_matrix&)
-{
-  panic_impossible ();
-}
-
-void
-tree_evaluator::visit_cell (tree_cell&)
-{
-  panic_impossible ();
-}
-
-void
-tree_evaluator::visit_multi_assignment (tree_multi_assignment&)
-{
-  panic_impossible ();
-}
-
-void
-tree_evaluator::visit_no_op_command (tree_no_op_command& cmd)
-{
-  if (m_echo_state)
-    {
-      int line = cmd.line ();
-      if (line < 0)
-        line = 1;
-      echo_code (line);
-      m_echo_file_pos = line + 1;
-    }
-
-  if (m_debug_mode && cmd.is_end_of_fcn_or_script ())
-    do_breakpoint (cmd.is_active_breakpoint (*this), true);
-}
-
-void
-tree_evaluator::visit_constant (tree_constant&)
-{
-  panic_impossible ();
-}
-
-void
-tree_evaluator::visit_fcn_handle (tree_fcn_handle&)
-{
-  panic_impossible ();
-}
-
-void
-tree_evaluator::visit_parameter_list (tree_parameter_list&)
-{
-  panic_impossible ();
-}
-
-void
-tree_evaluator::visit_postfix_expression (tree_postfix_expression&)
-{
-  panic_impossible ();
-}
-
-void
-tree_evaluator::visit_prefix_expression (tree_prefix_expression&)
-{
-  panic_impossible ();
-}
-
-void
-tree_evaluator::visit_return_command (tree_return_command& cmd)
-{
-  if (m_echo_state)
-    {
-      int line = cmd.line ();
-      if (line < 0)
-        line = 1;
-      echo_code (line);
-      m_echo_file_pos = line + 1;
-    }
-
-  if (m_debug_mode)
-    do_breakpoint (cmd.is_active_breakpoint (*this));
-
-  // Act like dbcont.
-
-  if (in_debug_repl () && m_call_stack.current_frame () == m_debug_frame)
-    dbcont ();
-  else if (m_statement_context == SC_FUNCTION
-           || m_statement_context == SC_SCRIPT
-           || m_in_loop_command)
-    m_returning = 1;
-}
-
-void
-tree_evaluator::visit_simple_assignment (tree_simple_assignment&)
-{
-  panic_impossible ();
-}
-
-void
-tree_evaluator::visit_statement (tree_statement& stmt)
-{
-  tree_command *cmd = stmt.command ();
-  tree_expression *expr = stmt.expression ();
-
-  if (cmd || expr)
-    {
-      if (! (in_debug_repl ()
-             && m_call_stack.current_frame () == m_debug_frame))
-        m_call_stack.set_location (stmt.line (), stmt.column ());
-
-      try
-        {
-          if (cmd)
-            {
-              unwind_protect_var<const std::list<octave_lvalue> *>
-              upv (m_lvalue_list, nullptr);
-
-              cmd->accept (*this);
-            }
-          else
-            {
-              if (m_echo_state)
-                {
-                  int line = stmt.line ();
-                  if (line < 0)
-                    line = 1;
-                  echo_code (line);
-                  m_echo_file_pos = line + 1;
-                }
-
-              if (m_debug_mode)
-                do_breakpoint (expr->is_active_breakpoint (*this));
-
-              // FIXME: maybe all of this should be packaged in
-              // one virtual function that returns a flag saying whether
-              // or not the expression will take care of binding ans and
-              // printing the result.
-
-              // FIXME: it seems that we should just have to
-              // evaluate the expression and that should take care of
-              // everything, binding ans as necessary?
-
-              octave_value tmp_result = expr->evaluate (*this, 0);
-
-              if (tmp_result.is_defined ())
-                {
-                  bool do_bind_ans = false;
-
-                  if (expr->is_identifier ())
-                    do_bind_ans = ! is_variable (expr);
-                  else
-                    do_bind_ans = ! expr->is_assignment_expression ();
-
-                  if (do_bind_ans)
-                    bind_ans (tmp_result, expr->print_result ()
-                              && statement_printing_enabled ());
-                }
-            }
-        }
-      catch (const std::bad_alloc&)
-        {
-          // FIXME: We want to use error_with_id here so that give users
-          // control over this error message but error_with_id will
-          // require some memory allocations.  Is there anything we can
-          // do to make those more likely to succeed?
-
-          error_with_id ("Octave:bad-alloc",
-                         "out of memory or dimension too large for Octave's index type");
-        }
-      catch (const interrupt_exception&)
-        {
-          // If we are debugging, then continue with next statement.
-          // Otherwise, jump out of here.
-
-          if (m_debug_mode)
-            m_interpreter.recover_from_exception ();
-          else
-            throw;
-        }
-      catch (const execution_exception& ee)
-        {
-          error_system& es = m_interpreter.get_error_system ();
-
-          if ((m_interpreter.interactive ()
-               || application::forced_interactive ())
-              && ((es.debug_on_error ()
-                   && m_bp_table.debug_on_err (es.last_error_id ()))
-                  || (es.debug_on_caught ()
-                      && m_bp_table.debug_on_caught (es.last_error_id ())))
-              && in_user_code ())
-            {
-              es.save_exception (ee);
-              es.display_exception (ee);
-
-              enter_debugger ();
-
-              // It doesn't make sense to continue execution after an
-              // error occurs so force the debugger to quit all debug
-              // levels and return the the top prompt.
-
-              throw quit_debug_exception (true);
-            }
-          else
-            throw;
-        }
-    }
-}
-
-void
-tree_evaluator::visit_statement_list (tree_statement_list& lst)
-{
-  // FIXME: commented out along with else clause below.
-  // static octave_value_list empty_list;
-
-  auto p = lst.begin ();
-
-  if (p != lst.end ())
-    {
-      while (true)
-        {
-          tree_statement *elt = *p++;
-
-          if (! elt)
-            error ("invalid statement found in statement list!");
-
-          octave_quit ();
-
-          elt->accept (*this);
-
-          if (m_breaking || m_continuing)
-            break;
-
-          if (m_returning)
-            break;
-
-          if (p == lst.end ())
-            break;
-          else
-            {
-              // Clear previous values before next statement is
-              // evaluated so that we aren't holding an extra
-              // reference to a value that may be used next.  For
-              // example, in code like this:
-              //
-              //   X = rand (N);  # refcount for X should be 1
-              //                  # after this statement
-              //
-              //   X(idx) = val;  # no extra copy of X should be
-              //                  # needed, but we will be faked
-              //                  # out if retval is not cleared
-              //                  # between statements here
-
-              //              result_values = empty_list;
-            }
+            print_usage ();
         }
-    }
-}
-
-void
-tree_evaluator::visit_switch_case (tree_switch_case&)
-{
-  panic_impossible ();
-}
-
-void
-tree_evaluator::visit_switch_case_list (tree_switch_case_list&)
-{
-  panic_impossible ();
-}
-
-void
-tree_evaluator::visit_switch_command (tree_switch_command& cmd)
-{
-  if (m_echo_state)
-    {
-      int line = cmd.line ();
-      if (line < 0)
-        line = 1;
-      echo_code (line);
-      m_echo_file_pos = line + 1;
-    }
-
-  if (m_debug_mode)
-    do_breakpoint (cmd.is_active_breakpoint (*this));
-
-  tree_expression *expr = cmd.switch_value ();
-
-  if (! expr)
-    error ("missing value in switch command near line %d, column %d",
-           cmd.line (), cmd.column ());
-
-  octave_value val = expr->evaluate (*this);
-
-  tree_switch_case_list *lst = cmd.case_list ();
-
-  if (lst)
-    {
-      for (tree_switch_case *t : *lst)
-        {
-          if (t->is_default_case () || switch_case_label_matches (t, val))
-            {
-              tree_statement_list *stmt_lst = t->commands ();
-
-              if (stmt_lst)
-                stmt_lst->accept (*this);
-
-              break;
-            }
-        }
-    }
-}
-
-void
-tree_evaluator::visit_try_catch_command (tree_try_catch_command& cmd)
-{
-  if (m_echo_state)
-    {
-      int line = cmd.line ();
-      if (line < 0)
-        line = 1;
-      echo_code (line);
-      m_echo_file_pos = line + 1;
-    }
-
-  bool execution_error = false;
-  octave_scalar_map err_map;
-
-  tree_statement_list *try_code = cmd.body ();
-
-  if (try_code)
-    {
-      // unwind frame before catch block
-
-      unwind_protect frame;
-
-      interpreter_try (frame);
-
-      // The catch code is *not* added to unwind_protect stack; it
-      // doesn't need to be run on interrupts.
-
-      try
-        {
-          try_code->accept (*this);
-        }
-      catch (const execution_exception& ee)
-        {
-          execution_error = true;
-
-          error_system& es = m_interpreter.get_error_system ();
-
-          es.save_exception (ee);
-
-          err_map.assign ("message", es.last_error_message ());
-          err_map.assign ("identifier", es.last_error_id ());
-          err_map.assign ("stack", es.last_error_stack ());
-
-          m_interpreter.recover_from_exception ();
-        }
-
-      // Actions attached to unwind_protect frame will run here, prior
-      // to executing the catch block.
-    }
-
-  if (execution_error)
-    {
-      tree_statement_list *catch_code = cmd.cleanup ();
-
-      if (catch_code)
-        {
-          tree_identifier *expr_id = cmd.identifier ();
-
-          if (expr_id)
-            {
-              octave_lvalue ult = expr_id->lvalue (*this);
-
-              ult.assign (octave_value::op_asn_eq, err_map);
-            }
-
-          // perform actual "catch" block
-          catch_code->accept (*this);
-        }
-    }
-}
-
-void
-tree_evaluator::do_unwind_protect_cleanup_code (tree_statement_list *list)
-{
-  unwind_protect frame;
-
-  frame.protect_var (octave_interrupt_state);
-  octave_interrupt_state = 0;
-
-  // We want to preserve the last location info for possible
-  // backtracking.
-
-  frame.add (&call_stack::set_line, &m_call_stack,
-             m_call_stack.current_line ());
-
-  frame.add (&call_stack::set_column, &m_call_stack,
-             m_call_stack.current_column ());
-
-  // Similarly, if we have seen a return or break statement, allow all
-  // the cleanup code to run before returning or handling the break.
-  // We don't have to worry about continue statements because they can
-  // only occur in loops.
-
-  frame.protect_var (m_returning);
-  m_returning = 0;
-
-  frame.protect_var (m_breaking);
-  m_breaking = 0;
-
-  try
-    {
-      if (list)
-        list->accept (*this);
-    }
-  catch (const execution_exception& ee)
-    {
-      error_system& es = m_interpreter.get_error_system ();
-
-      es.save_exception (ee);
-      m_interpreter.recover_from_exception ();
-
-      if (m_breaking || m_returning)
-        frame.discard (2);
-      else
-        frame.run (2);
-
-      frame.discard (2);
-
-      throw;
-    }
-
-  // The unwind_protects are popped off the stack in the reverse of
-  // the order they are pushed on.
-
-  // FIXME: these statements say that if we see a break or
-  // return statement in the cleanup block, that we want to use the
-  // new value of the breaking or returning flag instead of restoring
-  // the previous value.  Is that the right thing to do?  I think so.
-  // Consider the case of
-  //
-  //   function foo ()
-  //     unwind_protect
-  //       fprintf (stderr, "1: this should always be executed\n");
-  //       break;
-  //       fprintf (stderr, "1: this should never be executed\n");
-  //     unwind_protect_cleanup
-  //       fprintf (stderr, "2: this should always be executed\n");
-  //       return;
-  //       fprintf (stderr, "2: this should never be executed\n");
-  //     end_unwind_protect
-  //   endfunction
-  //
-  // If we reset the value of the breaking flag, both the returning
-  // flag and the breaking flag will be set, and we shouldn't have
-  // both.  So, use the most recent one.  If there is no return or
-  // break in the cleanup block, the values should be reset to
-  // whatever they were when the cleanup block was entered.
-
-  if (m_breaking || m_returning)
-    frame.discard (2);
-  else
-    frame.run (2);
-}
-
-void
-tree_evaluator::visit_unwind_protect_command (tree_unwind_protect_command& cmd)
-{
-  if (m_echo_state)
-    {
-      int line = cmd.line ();
-      if (line < 0)
-        line = 1;
-      echo_code (line);
-      m_echo_file_pos = line + 1;
-    }
-
-  tree_statement_list *cleanup_code = cmd.cleanup ();
-
-  tree_statement_list *unwind_protect_code = cmd.body ();
-
-  if (unwind_protect_code)
-    {
-      try
-        {
-          unwind_protect_code->accept (*this);
-        }
-      catch (const execution_exception& ee)
-        {
-          error_system& es = m_interpreter.get_error_system ();
-
-          // FIXME: Maybe we should be able to temporarily set the
-          // interpreter's exception handling state to something "safe"
-          // while the cleanup block runs instead of just resetting it
-          // here?
-          es.save_exception (ee);
-          m_interpreter.recover_from_exception ();
-
-          // Run the cleanup code on exceptions, so that it is run even
-          // in case of interrupt or out-of-memory.
-          do_unwind_protect_cleanup_code (cleanup_code);
-
-          // If an error occurs inside the cleanup code, a new
-          // exception will be thrown instead of the original.
-          throw;
-        }
-      catch (const interrupt_exception&)
-        {
-          // The comments above apply here as well.
-          m_interpreter.recover_from_exception ();
-          do_unwind_protect_cleanup_code (cleanup_code);
-          throw;
-        }
-
-      // Also execute the unwind_protect_cleanump code if the
-      // unwind_protect block runs without error.
-      do_unwind_protect_cleanup_code (cleanup_code);
-    }
-}
-
-void
-tree_evaluator::visit_while_command (tree_while_command& cmd)
-{
-  int line = cmd.line ();
-  if (line < 0)
-    line = 1;
-
-  if (m_echo_state)
-    {
-      echo_code (line);
-      line++;
-    }
-
-  unwind_protect_var<bool> upv (m_in_loop_command, true);
-
-  tree_expression *expr = cmd.condition ();
-
-  if (! expr)
-    panic_impossible ();
-
-  for (;;)
-    {
-      if (m_echo_state)
-        m_echo_file_pos = line;
-
-      if (m_debug_mode)
-        do_breakpoint (cmd.is_active_breakpoint (*this));
-
-      if (is_logically_true (expr, "while"))
-        {
-          tree_statement_list *loop_body = cmd.body ();
-
-          if (loop_body)
-            loop_body->accept (*this);
-
-          if (quit_loop_now ())
-            break;
-        }
-      else
         break;
-    }
-}
-
-void
-tree_evaluator::visit_do_until_command (tree_do_until_command& cmd)
-{
-  int line = cmd.line ();
-  if (line < 0)
-    line = 1;
-
-  if (m_echo_state)
-    {
-      echo_code (line);
-      line++;
-    }
-
-  unwind_protect_var<bool> upv (m_in_loop_command, true);
-
-  tree_expression *expr = cmd.condition ();
-
-  if (! expr)
-    panic_impossible ();
-
-  for (;;)
-    {
-      if (m_echo_state)
-        m_echo_file_pos = line;
-
-      tree_statement_list *loop_body = cmd.body ();
-
-      if (loop_body)
-        loop_body->accept (*this);
-
-      if (quit_loop_now ())
-        break;
-
-      if (m_debug_mode)
-        do_breakpoint (cmd.is_active_breakpoint (*this));
-
-      if (is_logically_true (expr, "do-until"))
+
+      default:
+        print_usage ();
         break;
-    }
-}
-
-void
-tree_evaluator::visit_superclass_ref (tree_superclass_ref&)
-{
-  panic_impossible ();
-}
-
-void
-tree_evaluator::visit_metaclass_query (tree_metaclass_query&)
-{
-  panic_impossible ();
-}
-
-void tree_evaluator::bind_ans (const octave_value& val, bool print)
-{
-  static std::string ans = "ans";
-
-  if (val.is_defined ())
-    {
-      if (val.is_cs_list ())
-        {
-          octave_value_list lst = val.list_value ();
-
-          for (octave_idx_type i = 0; i < lst.length (); i++)
-            bind_ans (lst(i), print);
-        }
-      else
-        {
-          // FIXME: Maybe assign could also return the assigned value,
-          // just for convenience?
-
-          assign (ans, val);
-
-          if (print)
-            {
-              // Use varval instead of displaying VAL directly so that
-              // we get the right type and value for things like
-              // magic_int values that may mutate when stored.
-
-              octave_value_list args = ovl (varval (ans));
-              args.stash_name_tags (string_vector (ans));
-              feval ("display", args);
-            }
-        }
-    }
-}
-
-void
-tree_evaluator::do_breakpoint (tree_statement& stmt)
-{
-  do_breakpoint (stmt.is_active_breakpoint (*this),
-                 stmt.is_end_of_fcn_or_script ());
-}
-
-void
-tree_evaluator::do_breakpoint (bool is_breakpoint,
-                               bool is_end_of_fcn_or_script)
-{
-  bool break_on_this_statement = false;
-
-  if (is_breakpoint)
-    break_on_this_statement = true;
-  else if (m_dbstep_flag > 0)
-    {
-      if (m_call_stack.current_frame () == m_debug_frame)
-        {
-          if (m_dbstep_flag == 1 || is_end_of_fcn_or_script)
-            {
-              // We get here if we are doing a "dbstep" or a "dbstep N" and
-              // the count has reached 1 so that we must stop and return to
-              // debug prompt.  Alternatively, "dbstep N" has been used but
-              // the end of the frame has been reached so we stop at the last
-              // line and return to prompt.
-
-              break_on_this_statement = true;
-            }
-          else
-            {
-              // Executing "dbstep N".  Decrease N by one and continue.
-
-              m_dbstep_flag--;
-            }
-
-        }
-      else if (m_dbstep_flag == 1
-               && m_call_stack.current_frame () < m_debug_frame)
-        {
-          // We stepped out from the end of a function.
-
-          m_debug_frame = m_call_stack.current_frame ();
-
-          break_on_this_statement = true;
-        }
-    }
-  else if (m_dbstep_flag == -1)
-    {
-      // We get here if we are doing a "dbstep in".
-
-      break_on_this_statement = true;
-
-      m_debug_frame = m_call_stack.current_frame ();
-    }
-  else if (m_dbstep_flag == -2)
-    {
-      // We get here if we are doing a "dbstep out".  Check for end of
-      // function and whether the current frame is the same as the
-      // cached value because we want to step out from the frame where
-      // "dbstep out" was evaluated, not from any functions called from
-      // that frame.
-
-      if (is_end_of_fcn_or_script
-          && m_call_stack.current_frame () == m_debug_frame)
-        m_dbstep_flag = -1;
-    }
-
-  if (! break_on_this_statement)
-    break_on_this_statement = m_break_on_next_stmt;
-
-  m_break_on_next_stmt = false;
-
-  if (break_on_this_statement)
-    {
-      m_dbstep_flag = 0;
-
-      enter_debugger ();
-    }
-}
-
-bool
-tree_evaluator::is_logically_true (tree_expression *expr,
-                                   const char *warn_for)
-{
-  bool expr_value = false;
-
-  m_call_stack.set_location (expr->line (), expr->column ());
-
-  octave_value t1 = expr->evaluate (*this);
-
-  if (t1.is_defined ())
-    return t1.is_true ();
-  else
-    error ("%s: undefined value used in conditional expression", warn_for);
-
-  return expr_value;
-}
-
-octave_value
-tree_evaluator::max_recursion_depth (const octave_value_list& args,
-                                     int nargout)
-{
-  return set_internal_variable (m_max_recursion_depth, args, nargout,
-                                "max_recursion_depth", 0);
-}
-
-symbol_info_list
-tree_evaluator::glob_symbol_info (const std::string& pattern) const
-{
-  return m_call_stack.glob_symbol_info (pattern);
-}
-
-symbol_info_list
-tree_evaluator::regexp_symbol_info (const std::string& pattern) const
-{
-  return m_call_stack.regexp_symbol_info (pattern);
-}
-
-symbol_info_list
-tree_evaluator::get_symbol_info (void)
-{
-  return m_call_stack.get_symbol_info ();
-}
-
-symbol_info_list
-tree_evaluator::top_scope_symbol_info (void) const
-{
-  return m_call_stack.top_scope_symbol_info ();
-}
-
-octave_map tree_evaluator::get_autoload_map (void) const
-{
-  Cell fcn_names (dim_vector (m_autoload_map.size (), 1));
-  Cell file_names (dim_vector (m_autoload_map.size (), 1));
-
-  octave_idx_type i = 0;
-  for (const auto& fcn_fname : m_autoload_map)
-    {
-      fcn_names(i) = fcn_fname.first;
-      file_names(i) = fcn_fname.second;
-
-      i++;
-    }
-
-  octave_map m;
-
-  m.assign ("function", fcn_names);
-  m.assign ("file", file_names);
-
-  return m;
-}
-
-std::string tree_evaluator::lookup_autoload (const std::string& nm) const
-{
-  std::string retval;
-
-  auto p = m_autoload_map.find (nm);
-
-  if (p != m_autoload_map.end ())
-    {
-      load_path& lp = m_interpreter.get_load_path ();
-
-      retval = lp.find_file (p->second);
-    }
-
-  return retval;
-}
-
-std::list<std::string> tree_evaluator::autoloaded_functions (void) const
-{
-  std::list<std::string> names;
-
-  for (const auto& fcn_fname : m_autoload_map)
-    names.push_back (fcn_fname.first);
-
-  return names;
-}
-
-std::list<std::string>
-tree_evaluator::reverse_lookup_autoload (const std::string& nm) const
-{
-  std::list<std::string> names;
-
-  for (const auto& fcn_fname : m_autoload_map)
-    if (nm == fcn_fname.second)
-      names.push_back (fcn_fname.first);
-
-  return names;
-}
-
-void tree_evaluator::add_autoload (const std::string& fcn,
-                                   const std::string& nm)
-{
-  std::string file_name = check_autoload_file (nm);
-
-  m_autoload_map[fcn] = file_name;
-}
-
-void tree_evaluator::remove_autoload (const std::string& fcn,
-                                      const std::string& nm)
-{
-  check_autoload_file (nm);
-
-  // Remove function from symbol table and autoload map.
-  symbol_table& symtab = m_interpreter.get_symbol_table ();
-
-  symtab.clear_dld_function (fcn);
-
-  m_autoload_map.erase (fcn);
-}
-
-octave_value
-tree_evaluator::whos_line_format (const octave_value_list& args, int nargout)
-{
-  return set_internal_variable (m_whos_line_format, args, nargout,
-                                "whos_line_format");
-}
-
-octave_value
-tree_evaluator::silent_functions (const octave_value_list& args, int nargout)
-{
-  return set_internal_variable (m_silent_functions, args, nargout,
-                                "silent_functions");
-}
-
-octave_value
-tree_evaluator::string_fill_char (const octave_value_list& args, int nargout)
-{
-  return set_internal_variable (m_string_fill_char, args, nargout,
-                                "string_fill_char");
-}
-
-// Final step of processing an indexing error.  Add the name of the
-// variable being indexed, if any, then issue an error.  (Will this also
-// be needed by pt-lvalue, which calls subsref?)
-
-void tree_evaluator::final_index_error (index_exception& ie,
-                                        const tree_expression *expr)
-{
-  std::string extra_message;
-
-  if (is_variable (expr))
-    {
-      std::string var = expr->name ();
-
-      ie.set_var (var);
-
-      symbol_table& symtab = m_interpreter.get_symbol_table ();
-
-      octave_value fcn = symtab.find_function (var);
-
-      if (fcn.is_function ())
-        {
-          octave_function *fp = fcn.function_value ();
-
-          if (fp && fp->name () == var)
-            extra_message
-              = " (note: variable '" + var + "' shadows function)";
-        }
-    }
-
-  std::string msg = ie.message () + extra_message;
-
-  error_with_id (ie.err_id (), "%s", msg.c_str ());
-}
-
-octave_value
-tree_evaluator::do_who (int argc, const string_vector& argv,
-                        bool return_list, bool verbose)
-{
-  return m_call_stack.do_who (argc, argv, return_list, verbose);
-}
-
-octave_value_list
-tree_evaluator::make_value_list (tree_argument_list *args,
-                                 const string_vector& arg_nm)
-{
-  octave_value_list retval;
-
-  if (args)
-    {
-      unwind_protect_var<const std::list<octave_lvalue> *>
-      upv (m_lvalue_list, nullptr);
-
-      int len = args->length ();
-
-      unwind_protect_var<int> upv2 (m_index_position);
-      unwind_protect_var<int> upv3 (m_num_indices);
-
-      m_num_indices = len;
-
-      std::list<octave_value> arg_vals;
-
-      int k = 0;
-
-      for (auto elt : *args)
-        {
-          // FIXME: is it possible for elt to be invalid?
-
-          if (! elt)
-            break;
-
-          m_index_position = k++;
-
-          octave_value tmp = elt->evaluate (*this);
-
-          if (tmp.is_cs_list ())
-            {
-              octave_value_list tmp_ovl = tmp.list_value ();
-
-              for (octave_idx_type i = 0; i < tmp_ovl.length (); i++)
-                arg_vals.push_back (tmp_ovl(i));
-            }
-          else if (tmp.is_defined ())
-            arg_vals.push_back (tmp);
-        }
-
-      retval = octave_value_list (arg_vals);
-    }
-
-  octave_idx_type n = retval.length ();
-
-  if (n > 0)
-    retval.stash_name_tags (arg_nm);
-
-  return retval;
-}
-
-std::list<octave_lvalue>
-tree_evaluator::make_lvalue_list (tree_argument_list *lhs)
-{
-  std::list<octave_lvalue> retval;
-
-  for (tree_expression *elt : *lhs)
-    retval.push_back (elt->lvalue (*this));
-
-  return retval;
-}
-
-void
-tree_evaluator::push_echo_state (int type, const std::string& file_name,
-                                 int pos)
-{
-  unwind_protect *frame = m_call_stack.curr_fcn_unwind_protect_frame ();
-
-  if (frame)
-    {
-      push_echo_state_cleanup (*frame);
-
-      set_echo_state (type, file_name, pos);
-    }
-}
-
-void
-tree_evaluator::set_echo_state (int type, const std::string& file_name,
-                                int pos)
-{
-  m_echo_state = echo_this_file (file_name, type);
-  m_echo_file_name = file_name;
-  m_echo_file_pos = pos;
-}
-
-void
-tree_evaluator::uwp_set_echo_state (bool state, const std::string& file_name,
-                                    int pos)
-{
-  m_echo_state = state;
-  m_echo_file_name = file_name;
-  m_echo_file_pos = pos;
-}
-
-void
-tree_evaluator::maybe_set_echo_state (void)
-{
-  octave_function *caller = caller_function ();
-
-  if (caller && caller->is_user_code ())
-    {
-      octave_user_code *fcn = dynamic_cast<octave_user_code *> (caller);
-
-      int type = fcn->is_user_function () ? ECHO_FUNCTIONS : ECHO_SCRIPTS;
-
-      std::string file_name = fcn->fcn_file_name ();
-
-      // We want the line where "echo" was called, not the line number
-      // stored in the stack frame that was created for the echo
-      // function (that will always be -1).
-
-      int pos = m_call_stack.current_user_code_line ();
-
-      if (pos < 0)
-        pos = 1;
-
-      set_echo_state (type, file_name, pos);
-    }
-}
-
-void
-tree_evaluator::push_echo_state_cleanup (unwind_protect& frame)
-{
-  frame.add (&tree_evaluator::uwp_set_echo_state, this,
-             m_echo_state, m_echo_file_name, m_echo_file_pos);
-}
-
-bool tree_evaluator::maybe_push_echo_state_cleanup (void)
-{
-  // This function is expected to be called from ECHO, which would be
-  // the top of the call stack.  If the caller of ECHO is a
-  // user-defined function or script, then set up unwind-protect
-  // elements to restore echo state.
-
-  unwind_protect *frame = m_call_stack.curr_fcn_unwind_protect_frame ();
-
-  if (frame)
-    {
-      push_echo_state_cleanup (*frame);
-      return true;
-    }
-
-  return false;
-}
-
-
-octave_value
-tree_evaluator::echo (const octave_value_list& args, int)
-{
-  bool cleanup_pushed = maybe_push_echo_state_cleanup ();
-
-  string_vector argv = args.make_argv ();
-
-  switch (args.length ())
-    {
-    case 0:
-      if ((m_echo & ECHO_SCRIPTS) || (m_echo & ECHO_FUNCTIONS))
-        {
-          m_echo = ECHO_OFF;
-          m_echo_files.clear ();
-        }
-      else
-        m_echo = ECHO_SCRIPTS;
-      break;
-
-    case 1:
+      }
+
+    if (cleanup_pushed)
+      maybe_set_echo_state ();
+
+    return octave_value ();
+  }
+
+  bool tree_evaluator::in_debug_repl (void) const
+  {
+    return (m_debugger_stack.empty ()
+            ? false : m_debugger_stack.top()->in_debug_repl ());
+  }
+
+  void tree_evaluator::dbcont (void)
+  {
+    if (! m_debugger_stack.empty ())
+      m_debugger_stack.top()->dbcont ();
+  }
+
+  void tree_evaluator::dbquit (bool all)
+  {
+    if (! m_debugger_stack.empty ())
+      m_debugger_stack.top()->dbquit (all);
+  }
+
+  static octave_value end_value (const octave_value& value,
+                                 octave_idx_type index_position,
+                                 octave_idx_type num_indices)
+  {
+    dim_vector dv = value.dims ();
+    int ndims = dv.ndims ();
+
+    if (num_indices < ndims)
       {
-        std::string arg0 = argv[0];
-
-        if (arg0 == "on")
-          m_echo = ECHO_SCRIPTS;
-        else if (arg0 == "off")
-          m_echo = ECHO_OFF;
+        for (int i = num_indices; i < ndims; i++)
+          dv(num_indices-1) *= dv(i);
+
+        if (num_indices == 1)
+          {
+            ndims = 2;
+            dv.resize (ndims);
+            dv(1) = 1;
+          }
         else
           {
-            std::string file = fcn_file_in_path (arg0);
-            file = sys::env::make_absolute (file);
-
-            if (file.empty ())
-              error ("echo: no such file %s", arg0.c_str ());
-
-            if (m_echo & ECHO_ALL)
-              {
-                // Echo is enabled for all functions, so turn it off
-                // for this one.
-
-                m_echo_files[file] = false;
-              }
-            else
+            ndims = num_indices;
+            dv.resize (ndims);
+          }
+      }
+
+    return (index_position < ndims
+            ? octave_value (dv(index_position)) : octave_value (1.0));
+  }
+
+  octave_value_list
+  tree_evaluator::evaluate_end_expression (const octave_value_list& args)
+  {
+    int nargin = args.length ();
+
+    if (nargin != 0 && nargin != 3)
+      print_usage ();
+
+    if (nargin == 3)
+      {
+        octave_idx_type index_position
+          = args(1).xidx_type_value ("end: K must be integer value");
+
+        if (index_position < 1)
+          error ("end: K must be greater than zero");
+
+        octave_idx_type num_indices
+          = args(2).xidx_type_value ("end: N must be integer value");
+
+        if (num_indices < 1)
+          error ("end: N must be greater than zero");
+
+        return end_value (args(0), index_position-1, num_indices);
+      }
+
+    // If m_indexed_object is undefined, then this use of 'end' is
+    // either appearing in a function call argument list or in an
+    // attempt to index an undefined symbol.  There seems to be no
+    // reasonable way to provide a better error message.  So just fail
+    // with an invalid use message.  See bug #58830.
+
+    if (m_indexed_object.is_undefined ())
+      error ("invalid use of 'end': may only be used to index existing value");
+
+    octave_value expr_result;
+
+    if (m_index_list.empty ())
+      expr_result = m_indexed_object;
+    else
+      {
+        try
+          {
+            // When evaluating "end" with no arguments, we should have
+            // been called from the built-in Fend function that appears
+            // in the context of an argument list.  Fend will be
+            // evaluated in its own stack frame.  But we need to
+            // evaluate the partial expression that the special "end"
+            // token applies to in the calling stack frame.
+
+            unwind_action act ([=] (std::size_t frm)
+                               {
+                                 m_call_stack.restore_frame (frm);
+                               }, m_call_stack.current_frame ());
+
+            std::size_t n = m_call_stack.find_current_user_frame ();
+            m_call_stack.goto_frame (n);
+
+            // End is only valid inside argument lists used for
+            // indexing.  The dispatch class is set by the function that
+            // evaluates the argument list.
+
+            // Silently ignore extra output values.
+
+            octave_value_list tmp
+              = m_indexed_object.subsref (m_index_type, m_index_list, 1);
+
+            expr_result = tmp.length () ? tmp(0) : octave_value ();
+
+            if (expr_result.is_cs_list ())
+              err_indexed_cs_list ();
+          }
+        catch (const index_exception&)
+          {
+            error ("error evaluating partial expression for END");
+          }
+      }
+
+    if (expr_result.isobject ())
+      {
+        // FIXME: is there a better way to lookup and execute a method
+        // that handles all the details like setting the dispatch class
+        // appropriately?
+
+        std::string dispatch_class = expr_result.class_name ();
+
+        symbol_table& symtab = m_interpreter.get_symbol_table ();
+
+        octave_value meth = symtab.find_method ("end", dispatch_class);
+
+        if (meth.is_defined ())
+          return m_interpreter.feval
+            (meth, ovl (expr_result, m_index_position+1, m_num_indices), 1);
+      }
+
+    return end_value (expr_result, m_index_position, m_num_indices);
+  }
+
+  octave_value
+  tree_evaluator::PS4 (const octave_value_list& args, int nargout)
+  {
+    return set_internal_variable (m_PS4, args, nargout, "PS4");
+  }
+
+  bool tree_evaluator::echo_this_file (const std::string& file, int type) const
+  {
+    if ((type & m_echo) == ECHO_SCRIPTS)
+      {
+        // Asking about scripts and echo is enabled for them.
+        return true;
+      }
+
+    if ((type & m_echo) == ECHO_FUNCTIONS)
+      {
+        // Asking about functions and echo is enabled for functions.
+        // Now, which ones?
+
+        auto p = m_echo_files.find (file);
+
+        if (m_echo & ECHO_ALL)
+          {
+            // Return true ulness echo was turned off for a specific
+            // file.
+
+            return (p == m_echo_files.end () || p->second);
+          }
+        else
+          {
+            // Return true if echo is specifically enabled for this file.
+
+            return p != m_echo_files.end () && p->second;
+          }
+      }
+
+    return false;
+  }
+
+  void tree_evaluator::echo_code (int line)
+  {
+    std::string prefix = command_editor::decode_prompt_string (m_PS4);
+
+    octave_function *curr_fcn = m_call_stack.current_function ();
+
+    if (curr_fcn && curr_fcn->is_user_code ())
+      {
+        octave_user_code *code = dynamic_cast<octave_user_code *> (curr_fcn);
+
+        int num_lines = line - m_echo_file_pos + 1;
+
+        std::deque<std::string> lines
+          = code->get_code_lines (m_echo_file_pos, num_lines);
+
+        for (auto& elt : lines)
+          octave_stdout << prefix << elt << std::endl;
+      }
+  }
+
+  // Decide if it's time to quit a for or while loop.
+  bool tree_evaluator::quit_loop_now (void)
+  {
+    octave_quit ();
+
+    // Maybe handle 'continue N' someday...
+
+    if (m_continuing)
+      m_continuing--;
+
+    bool quit = (m_returning || m_breaking || m_continuing);
+
+    if (m_breaking)
+      m_breaking--;
+
+    return quit;
+  }
+
+  void tree_evaluator::bind_auto_fcn_vars (const string_vector& arg_names,
+                                           const Matrix& ignored_outputs,
+                                           int nargin, int nargout,
+                                           bool takes_varargs,
+                                           const octave_value_list& va_args)
+  {
+    set_auto_fcn_var (stack_frame::ARG_NAMES, Cell (arg_names));
+    set_auto_fcn_var (stack_frame::IGNORED, ignored_outputs);
+    set_auto_fcn_var (stack_frame::NARGIN, nargin);
+    set_auto_fcn_var (stack_frame::NARGOUT, nargout);
+    set_auto_fcn_var (stack_frame::SAVED_WARNING_STATES, octave_value ());
+
+    if (takes_varargs)
+      assign ("varargin", va_args.cell_value ());
+  }
+
+  std::string
+  tree_evaluator::check_autoload_file (const std::string& nm) const
+  {
+    if (sys::env::absolute_pathname (nm))
+      return nm;
+
+    std::string full_name = nm;
+
+    octave_user_code *fcn = m_call_stack.current_user_code ();
+
+    bool found = false;
+
+    if (fcn)
+      {
+        std::string fname = fcn->fcn_file_name ();
+
+        if (! fname.empty ())
+          {
+            fname = sys::env::make_absolute (fname);
+            fname = fname.substr (0, fname.find_last_of (sys::file_ops::dir_sep_str ()) + 1);
+
+            sys::file_stat fs (fname + nm);
+
+            if (fs.exists ())
               {
-                // Echo may be enabled for specific functions.
-
-                auto p = m_echo_files.find (file);
-
-                if (p == m_echo_files.end ())
-                  {
-                    // Not this one, so enable it.
-
-                    m_echo |= ECHO_FUNCTIONS;
-                    m_echo_files[file] = true;
-                  }
-                else
-                  {
-                    // This one is already in the list.  Flip the
-                    // status for it.
-
-                    p->second = ! p->second;
-                  }
+                full_name = fname + nm;
+                found = true;
               }
           }
       }
-      break;
-
-    case 2:
-      {
-        std::string arg0 = argv[0];
-        std::string arg1 = argv[1];
-
-        if (arg1 == "on" || arg1 == "off")
-          std::swap (arg0, arg1);
-
-        if (arg0 == "on")
-          {
-            if (arg1 == "all")
-              {
-                m_echo = (ECHO_SCRIPTS | ECHO_FUNCTIONS | ECHO_ALL);
-                m_echo_files.clear ();
-              }
-            else
-              {
-                std::string file = fcn_file_in_path (arg1);
-                file = sys::env::make_absolute (file);
-
-                if (file.empty ())
-                  error ("echo: no such file %s", arg1.c_str ());
-
-                m_echo |= ECHO_FUNCTIONS;
-                m_echo_files[file] = true;
-              }
-          }
-        else if (arg0 == "off")
-          {
-            if (arg1 == "all")
-              {
-                m_echo = ECHO_OFF;
-                m_echo_files.clear ();
-              }
-            else
-              {
-                std::string file = fcn_file_in_path (arg1);
-                file = sys::env::make_absolute (file);
-
-                if (file.empty ())
-                  error ("echo: no such file %s", arg1.c_str ());
-
-                m_echo_files[file] = false;
-              }
-          }
-        else
-          print_usage ();
-      }
-      break;
-
-    default:
-      print_usage ();
-      break;
-    }
-
-  if (cleanup_pushed)
-    maybe_set_echo_state ();
-
-  return octave_value ();
-}
-
-bool tree_evaluator::in_debug_repl (void) const
-{
-  return (m_debugger_stack.empty ()
-          ? false : m_debugger_stack.top()->in_debug_repl ());
-}
-
-void tree_evaluator::dbcont (void)
-{
-  if (! m_debugger_stack.empty ())
-    m_debugger_stack.top()->dbcont ();
-}
-
-void tree_evaluator::dbquit (bool all)
-{
-  if (! m_debugger_stack.empty ())
-    m_debugger_stack.top()->dbquit (all);
-}
-
-static octave_value end_value (const octave_value& value,
-                               octave_idx_type index_position,
-                               octave_idx_type num_indices)
-{
-  dim_vector dv = value.dims ();
-  int ndims = dv.ndims ();
-
-  if (num_indices < ndims)
-    {
-      for (int i = num_indices; i < ndims; i++)
-        dv(num_indices-1) *= dv(i);
-
-      if (num_indices == 1)
-        {
-          ndims = 2;
-          dv.resize (ndims);
-          dv(1) = 1;
-        }
-      else
-        {
-          ndims = num_indices;
-          dv.resize (ndims);
-        }
-    }
-
-  return (index_position < ndims
-          ? octave_value (dv(index_position)) : octave_value (1.0));
-}
-
-octave_value_list
-tree_evaluator::evaluate_end_expression (const octave_value_list& args)
-{
-  int nargin = args.length ();
-
-  if (nargin != 0 && nargin != 3)
-    print_usage ();
-
-  if (nargin == 3)
-    {
-      octave_idx_type index_position
-        = args(1).xidx_type_value ("end: K must be integer value");
-
-      if (index_position < 1)
-        error ("end: K must be greater than zero");
-
-      octave_idx_type num_indices
-        = args(2).xidx_type_value ("end: N must be integer value");
-
-      if (num_indices < 1)
-        error ("end: N must be greater than zero");
-
-      return end_value (args(0), index_position-1, num_indices);
-    }
-
-  // If m_indexed_object is undefined, then this use of 'end' is
-  // either appearing in a function call argument list or in an
-  // attempt to index an undefined symbol.  There seems to be no
-  // reasonable way to provide a better error message.  So just fail
-  // with an invalid use message.  See bug #58830.
-
-  if (m_indexed_object.is_undefined ())
-    error ("invalid use of 'end': may only be used to index existing value");
-
-  octave_value expr_result;
-
-  if (m_index_list.empty ())
-    expr_result = m_indexed_object;
-  else
-    {
-      try
-        {
-          // When evaluating "end" with no arguments, we should have
-          // been called from the built-in Fend function that appears
-          // in the context of an argument list.  Fend will be
-          // evaluated in its own stack frame.  But we need to
-          // evaluate the partial expression that the special "end"
-          // token applies to in the calling stack frame.
-
-          unwind_action act ([=] (std::size_t frm)
-          {
-            m_call_stack.restore_frame (frm);
-          }, m_call_stack.current_frame ());
-
-          std::size_t n = m_call_stack.find_current_user_frame ();
-          m_call_stack.goto_frame (n);
-
-          // End is only valid inside argument lists used for
-          // indexing.  The dispatch class is set by the function that
-          // evaluates the argument list.
-
-          // Silently ignore extra output values.
-
-          octave_value_list tmp
-            = m_indexed_object.subsref (m_index_type, m_index_list, 1);
-
-          expr_result = tmp.length () ? tmp(0) : octave_value ();
-
-          if (expr_result.is_cs_list ())
-            err_indexed_cs_list ();
-        }
-      catch (const index_exception&)
-        {
-          error ("error evaluating partial expression for END");
-        }
-    }
-
-  if (expr_result.isobject ())
-    {
-      // FIXME: is there a better way to lookup and execute a method
-      // that handles all the details like setting the dispatch class
-      // appropriately?
-
-      std::string dispatch_class = expr_result.class_name ();
-
-      symbol_table& symtab = m_interpreter.get_symbol_table ();
-
-      octave_value meth = symtab.find_method ("end", dispatch_class);
-
-      if (meth.is_defined ())
-        return m_interpreter.feval
-               (meth, ovl (expr_result, m_index_position+1, m_num_indices), 1);
-    }
-
-  return end_value (expr_result, m_index_position, m_num_indices);
-}
-
-octave_value
-tree_evaluator::PS4 (const octave_value_list& args, int nargout)
-{
-  return set_internal_variable (m_PS4, args, nargout, "PS4");
-}
-
-bool tree_evaluator::echo_this_file (const std::string& file, int type) const
-{
-  if ((type & m_echo) == ECHO_SCRIPTS)
-    {
-      // Asking about scripts and echo is enabled for them.
-      return true;
-    }
-
-  if ((type & m_echo) == ECHO_FUNCTIONS)
-    {
-      // Asking about functions and echo is enabled for functions.
-      // Now, which ones?
-
-      auto p = m_echo_files.find (file);
-
-      if (m_echo & ECHO_ALL)
-        {
-          // Return true ulness echo was turned off for a specific
-          // file.
-
-          return (p == m_echo_files.end () || p->second);
-        }
-      else
-        {
-          // Return true if echo is specifically enabled for this file.
-
-          return p != m_echo_files.end () && p->second;
-        }
-    }
-
-  return false;
-}
-
-void tree_evaluator::echo_code (int line)
-{
-  std::string prefix = command_editor::decode_prompt_string (m_PS4);
-
-  octave_function *curr_fcn = m_call_stack.current_function ();
-
-  if (curr_fcn && curr_fcn->is_user_code ())
-    {
-      octave_user_code *code = dynamic_cast<octave_user_code *> (curr_fcn);
-
-      int num_lines = line - m_echo_file_pos + 1;
-
-      std::deque<std::string> lines
-        = code->get_code_lines (m_echo_file_pos, num_lines);
-
-      for (auto& elt : lines)
-        octave_stdout << prefix << elt << std::endl;
-    }
-}
-
-// Decide if it's time to quit a for or while loop.
-bool tree_evaluator::quit_loop_now (void)
-{
-  octave_quit ();
-
-  // Maybe handle 'continue N' someday...
-
-  if (m_continuing)
-    m_continuing--;
-
-  bool quit = (m_returning || m_breaking || m_continuing);
-
-  if (m_breaking)
-    m_breaking--;
-
-  return quit;
-}
-
-void tree_evaluator::bind_auto_fcn_vars (const string_vector& arg_names,
-    const Matrix& ignored_outputs,
-    int nargin, int nargout,
-    bool takes_varargs,
-    const octave_value_list& va_args)
-{
-  set_auto_fcn_var (stack_frame::ARG_NAMES, Cell (arg_names));
-  set_auto_fcn_var (stack_frame::IGNORED, ignored_outputs);
-  set_auto_fcn_var (stack_frame::NARGIN, nargin);
-  set_auto_fcn_var (stack_frame::NARGOUT, nargout);
-  set_auto_fcn_var (stack_frame::SAVED_WARNING_STATES, octave_value ());
-
-  if (takes_varargs)
-    assign ("varargin", va_args.cell_value ());
-}
-
-std::string
-tree_evaluator::check_autoload_file (const std::string& nm) const
-{
-  if (sys::env::absolute_pathname (nm))
-    return nm;
-
-  std::string full_name = nm;
-
-  octave_user_code *fcn = m_call_stack.current_user_code ();
-
-  bool found = false;
-
-  if (fcn)
-    {
-      std::string fname = fcn->fcn_file_name ();
-
-      if (! fname.empty ())
-        {
-          fname = sys::env::make_absolute (fname);
-          fname = fname.substr (0, fname.find_last_of (sys::file_ops::dir_sep_str ()) + 1);
-
-          sys::file_stat fs (fname + nm);
-
-          if (fs.exists ())
-            {
-              full_name = fname + nm;
-              found = true;
-            }
-        }
-    }
-
-  if (! found)
-    warning_with_id ("Octave:autoload-relative-file-name",
-                     "autoload: '%s' is not an absolute filename",
-                     nm.c_str ());
-
-  return full_name;
-}
+
+    if (! found)
+      warning_with_id ("Octave:autoload-relative-file-name",
+                       "autoload: '%s' is not an absolute filename",
+                       nm.c_str ());
+
+    return full_name;
+  }
 
 DEFMETHOD (max_recursion_depth, interp, args, nargout,
            doc: /* -*- texinfo -*-
--- a/liboctave/array/Array.h	Fri Dec 02 10:11:46 2022 -0500
+++ b/liboctave/array/Array.h	Fri Dec 02 10:12:40 2022 -0500
@@ -663,12 +663,6 @@
   OCTARRAY_OVERRIDABLE_FUNC_API const T * data (void) const
   { return m_slice_data; }
 
-#if defined (OCTAVE_PROVIDE_DEPRECATED_SYMBOLS)
-  OCTAVE_DEPRECATED (7, "for read-only access, use 'data' method instead")
-  OCTARRAY_OVERRIDABLE_FUNC_API const T * fortran_vec (void) const
-  { return data (); }
-#endif
-
   OCTARRAY_API T * fortran_vec (void);
 
   OCTARRAY_OVERRIDABLE_FUNC_API bool is_shared (void)
--- a/liboctave/array/DiagArray2.h	Fri Dec 02 10:11:46 2022 -0500
+++ b/liboctave/array/DiagArray2.h	Fri Dec 02 10:12:40 2022 -0500
@@ -168,11 +168,6 @@
 
   const T * data (void) const { return Array<T>::data (); }
 
-#if defined (OCTAVE_PROVIDE_DEPRECATED_SYMBOLS)
-  OCTAVE_DEPRECATED (7, "for read-only access, use 'data' method instead")
-  const T * fortran_vec (void) const { return Array<T>::data (); }
-#endif
-
   T * fortran_vec (void) { return Array<T>::fortran_vec (); }
 
   void print_info (std::ostream& os, const std::string& prefix) const
--- a/liboctave/array/Range.cc	Fri Dec 02 10:11:46 2022 -0500
+++ b/liboctave/array/Range.cc	Fri Dec 02 10:12:40 2022 -0500
@@ -453,553 +453,3 @@
 }
 
 OCTAVE_END_NAMESPACE(octave)
-
-bool
-Range::all_elements_are_ints (void) const
-{
-  // If the base and increment are ints, the final value in the range will also
-  // be an integer, even if the limit is not.  If there is one or fewer
-  // elements only the base needs to be an integer.
-
-  return (! (octave::math::isnan (m_base) || octave::math::isnan (m_inc))
-          && (octave::math::nint_big (m_base) == m_base || m_numel < 1)
-          && (octave::math::nint_big (m_inc) == m_inc || m_numel <= 1));
-}
-
-octave_idx_type
-Range::nnz (void) const
-{
-  octave_idx_type retval = 0;
-
-  if (! isempty ())
-    {
-      if ((m_base > 0.0 && m_limit > 0.0) || (m_base < 0.0 && m_limit < 0.0))
-        {
-          // All elements have the same sign, hence there are no zeros.
-          retval = m_numel;
-        }
-      else if (m_inc != 0.0)
-        {
-          if (m_base == 0.0 || m_limit == 0.0)
-            // Exactly one zero at beginning or end of range.
-            retval = m_numel - 1;
-          else if ((m_base / m_inc) != std::floor (m_base / m_inc))
-            // Range crosses negative/positive without hitting zero.
-            retval = m_numel;
-          else
-            // Range crosses negative/positive and hits zero.
-            retval = m_numel - 1;
-        }
-      else
-        {
-          // All elements are equal (m_inc = 0) but not positive or negative,
-          // therefore all elements are zero.
-          retval = 0;
-        }
-    }
-
-  return retval;
-}
-
-Matrix
-Range::matrix_value (void) const
-{
-  Matrix retval (1, m_numel);
-
-  if (m_numel > 0)
-    {
-      // The first element must always be *exactly* the base.
-      // E.g, -0 would otherwise become +0 in the loop (-0 + 0*increment).
-      retval(0) = m_base;
-
-      double b = m_base;
-      double increment = m_inc;
-      for (octave_idx_type i = 1; i < m_numel - 1; i++)
-        retval.xelem (i) = b + i * increment;
-
-      retval.xelem (m_numel - 1) = m_limit;
-    }
-
-  return retval;
-}
-
-double
-Range::checkelem (octave_idx_type i) const
-{
-  if (i < 0 || i >= m_numel)
-    octave::err_index_out_of_range (2, 2, i+1, m_numel, dims ());
-
-  if (i == 0)
-    return m_base;
-  else if (i < m_numel - 1)
-    return m_base + i * m_inc;
-  else
-    return m_limit;
-}
-
-double
-Range::checkelem (octave_idx_type i, octave_idx_type j) const
-{
-  // Ranges are *always* row vectors.
-  if (i != 0)
-    octave::err_index_out_of_range (1, 1, i+1, m_numel, dims ());
-
-  return checkelem (j);
-}
-
-double
-Range::elem (octave_idx_type i) const
-{
-  if (i == 0)
-    return m_base;
-  else if (i < m_numel - 1)
-    return m_base + i * m_inc;
-  else
-    return m_limit;
-}
-
-Array<double>
-Range::index (const octave::idx_vector& idx) const
-{
-  Array<double> retval;
-
-  octave_idx_type n = m_numel;
-
-  if (idx.is_colon ())
-    {
-      retval = matrix_value ().reshape (dim_vector (m_numel, 1));
-    }
-  else
-    {
-      if (idx.extent (n) != n)
-        octave::err_index_out_of_range (1, 1, idx.extent (n), n, dims ()); // throws
-
-      dim_vector idx_dims = idx.orig_dimensions ();
-      octave_idx_type idx_len = idx.length (n);
-
-      // taken from Array.cc.
-      if (n != 1 && idx_dims.isvector ())
-        idx_dims = dim_vector (1, idx_len);
-
-      retval.clear (idx_dims);
-
-      // Loop over all values in IDX, executing the lambda expression
-      // for each index value.
-
-      double *array = retval.fortran_vec ();
-
-      idx.loop (n, [=, &array] (idx_vector i)
-      {
-        if (i == 0)
-          *array++ = m_base;
-        else if (i < m_numel - 1)
-          *array++ = m_base + i * m_inc;
-        else
-          *array++ = m_limit;
-      });
-    }
-
-  return retval;
-}
-
-// NOTE: max and min only return useful values if numel > 0.
-//       do_minmax_body() in max.cc avoids calling Range::min/max if numel == 0.
-
-double
-Range::min (void) const
-{
-  double retval = 0.0;
-  if (m_numel > 0)
-    {
-      if (m_inc > 0)
-        retval = m_base;
-      else
-        {
-          retval = m_base + (m_numel - 1) * m_inc;
-
-          // Require '<=' test.  See note in max ().
-          if (retval <= m_limit)
-            retval = m_limit;
-        }
-
-    }
-  return retval;
-}
-
-double
-Range::max (void) const
-{
-  double retval = 0.0;
-  if (m_numel > 0)
-    {
-      if (m_inc > 0)
-        {
-          retval = m_base + (m_numel - 1) * m_inc;
-
-          // On some machines (x86 with extended precision floating point
-          // arithmetic, for example) it is possible that we can overshoot the
-          // limit by approximately the machine precision even though we were
-          // very careful in our calculation of the number of elements.
-          // Therefore, we clip the result to the limit if it overshoots.
-          // The test also includes equality (>= m_limit) to have expressions
-          // such as -5:1:-0 result in a -0 endpoint.
-          if (retval >= m_limit)
-            retval = m_limit;
-        }
-      else
-        retval = m_base;
-    }
-  return retval;
-}
-
-void
-Range::sort_internal (bool ascending)
-{
-  if ((ascending && m_base > m_limit && m_inc < 0.0)
-      || (! ascending && m_base < m_limit && m_inc > 0.0))
-    {
-      std::swap (m_base, m_limit);
-      m_inc = -m_inc;
-    }
-}
-
-void
-Range::sort_internal (Array<octave_idx_type>& sidx, bool ascending)
-{
-  octave_idx_type nel = numel ();
-
-  sidx.resize (dim_vector (1, nel));
-
-  octave_idx_type *psidx = sidx.fortran_vec ();
-
-  bool reverse = false;
-
-  if ((ascending && m_base > m_limit && m_inc < 0.0)
-      || (! ascending && m_base < m_limit && m_inc > 0.0))
-    {
-      std::swap (m_base, m_limit);
-      m_inc = -m_inc;
-      reverse = true;
-    }
-
-  octave_idx_type tmp = (reverse ? nel - 1 : 0);
-  octave_idx_type stp = (reverse ? -1 : 1);
-
-  for (octave_idx_type i = 0; i < nel; i++, tmp += stp)
-    psidx[i] = tmp;
-}
-
-Matrix
-Range::diag (octave_idx_type k) const
-{
-  return matrix_value ().diag (k);
-}
-
-Range
-Range::sort (octave_idx_type dim, sortmode mode) const
-{
-  Range retval = *this;
-
-  if (dim == 1)
-    {
-      if (mode == ASCENDING)
-        retval.sort_internal (true);
-      else if (mode == DESCENDING)
-        retval.sort_internal (false);
-    }
-  else if (dim != 0)
-    (*current_liboctave_error_handler) ("Range::sort: invalid dimension");
-
-  return retval;
-}
-
-Range
-Range::sort (Array<octave_idx_type>& sidx, octave_idx_type dim,
-             sortmode mode) const
-{
-  Range retval = *this;
-
-  if (dim == 1)
-    {
-      if (mode == ASCENDING)
-        retval.sort_internal (sidx, true);
-      else if (mode == DESCENDING)
-        retval.sort_internal (sidx, false);
-    }
-  else if (dim != 0)
-    (*current_liboctave_error_handler) ("Range::sort: invalid dimension");
-
-  return retval;
-}
-
-sortmode
-Range::issorted (sortmode mode) const
-{
-  if (m_numel > 1 && m_inc > 0)
-    mode = (mode == DESCENDING) ? UNSORTED : ASCENDING;
-  else if (m_numel > 1 && m_inc < 0)
-    mode = (mode == ASCENDING) ? UNSORTED : DESCENDING;
-  else
-    mode = (mode == UNSORTED) ? ASCENDING : mode;
-
-  return mode;
-}
-
-void
-Range::set_base (double b)
-{
-  if (m_base != b)
-    {
-      m_base = b;
-
-      init ();
-    }
-}
-
-void
-Range::set_limit (double l)
-{
-  if (m_limit != l)
-    {
-      m_limit = l;
-
-      init ();
-    }
-}
-
-void
-Range::set_inc (double i)
-{
-  if (m_inc != i)
-    {
-      m_inc = i;
-
-      init ();
-    }
-}
-
-std::ostream&
-operator << (std::ostream& os, const Range& a)
-{
-  double b = a.base ();
-  double increment = a.increment ();
-  octave_idx_type nel = a.numel ();
-
-  if (nel > 1)
-    {
-      // First element must be the base *exactly* (e.g., -0).
-      os << b << ' ';
-      for (octave_idx_type i = 1; i < nel-1; i++)
-        os << b + i * increment << ' ';
-    }
-
-  // Print out the last element exactly, rather than a calculated last element.
-  os << a.m_limit << "\n";
-
-  return os;
-}
-
-std::istream&
-operator >> (std::istream& is, Range& a)
-{
-  is >> a.m_base;
-  if (is)
-    {
-      double tmp_limit;
-      is >> tmp_limit;
-
-      if (is)
-        is >> a.m_inc;
-
-      // Clip the m_limit to the true limit, rebuild numel, clear cache
-      a.set_limit (tmp_limit);
-    }
-
-  return is;
-}
-
-// DEPRECATED in Octave 7.
-Range operator - (const Range& r)
-{
-  return Range (-r.base (), -r.limit (), -r.increment (), r.numel ());
-}
-
-// DEPRECATED in Octave 7.
-Range operator + (double x, const Range& r)
-{
-  return Range (x + r.base (), x + r.limit (), r.increment (), r.numel ());
-}
-
-// DEPRECATED in Octave 7.
-Range operator + (const Range& r, double x)
-{
-  return Range (r.base () + x, r.limit () + x, r.increment (), r.numel ());
-}
-
-// DEPRECATED in Octave 7.
-Range operator - (double x, const Range& r)
-{
-  return Range (x - r.base (), x - r.limit (), -r.increment (), r.numel ());
-}
-
-// DEPRECATED in Octave 7.
-Range operator - (const Range& r, double x)
-{
-  return Range (r.base () - x, r.limit () - x, r.increment (), r.numel ());
-}
-
-// DEPRECATED in Octave 7.
-Range operator * (double x, const Range& r)
-{
-  return Range (x * r.base (), x * r.limit (), x * r.increment (), r.numel ());
-}
-
-// DEPRECATED in Octave 7.
-Range operator * (const Range& r, double x)
-{
-  return Range (r.base () * x, r.limit () * x, r.increment () * x, r.numel ());
-}
-
-// C  See Knuth, Art Of Computer Programming, Vol. 1, Problem 1.2.4-5.
-// C
-// C===Tolerant FLOOR function.
-// C
-// C    X  -  is given as a Double Precision argument to be operated on.
-// C          It is assumed that X is represented with M mantissa bits.
-// C    CT -  is   given   as   a   Comparison   Tolerance   such   that
-// C          0.LT.CT.LE.3-SQRT(5)/2. If the relative difference between
-// C          X and A whole number is  less  than  CT,  then  TFLOOR  is
-// C          returned   as   this   whole   number.   By  treating  the
-// C          floating-point numbers as a finite ordered set  note  that
-// C          the  heuristic  EPS=2.**(-(M-1))   and   CT=3*EPS   causes
-// C          arguments  of  TFLOOR/TCEIL to be treated as whole numbers
-// C          if they are  exactly  whole  numbers  or  are  immediately
-// C          adjacent to whole number representations.  Since EPS,  the
-// C          "distance"  between  floating-point  numbers  on  the unit
-// C          interval, and M, the number of bits in X'S mantissa, exist
-// C          on  every  floating-point   computer,   TFLOOR/TCEIL   are
-// C          consistently definable on every floating-point computer.
-// C
-// C          For more information see the following references:
-// C    (1) P. E. Hagerty, "More On Fuzzy Floor And Ceiling," APL  QUOTE
-// C        QUAD 8(4):20-24, June 1978. Note that TFLOOR=FL5.
-// C    (2) L. M. Breed, "Definitions For Fuzzy Floor And Ceiling",  APL
-// C        QUOTE QUAD 8(3):16-23, March 1978. This paper cites FL1 through
-// C        FL5, the history of five years of evolutionary development of
-// C        FL5 - the seven lines of code below - by open collaboration
-// C        and corroboration of the mathematical-computing community.
-// C
-// C  Penn State University Center for Academic Computing
-// C  H. D. Knoble - August, 1978.
-
-static inline double
-tfloor (double x, double ct)
-{
-// C---------FLOOR(X) is the largest integer algebraically less than
-// C         or equal to X; that is, the unfuzzy FLOOR function.
-
-//  DINT (X) = X - DMOD (X, 1.0);
-//  FLOOR (X) = DINT (X) - DMOD (2.0 + DSIGN (1.0, X), 3.0);
-
-// C---------Hagerty's FL5 function follows...
-
-  double q = 1.0;
-
-  if (x < 0.0)
-    q = 1.0 - ct;
-
-  double rmax = q / (2.0 - ct);
-
-  double t1 = 1.0 + std::floor (x);
-  t1 = (ct / q) * (t1 < 0.0 ? -t1 : t1);
-  t1 = (rmax < t1 ? rmax : t1);
-  t1 = (ct > t1 ? ct : t1);
-  t1 = std::floor (x + t1);
-
-  if (x <= 0.0 || (t1 - x) < rmax)
-    return t1;
-  else
-    return t1 - 1.0;
-}
-
-static inline bool
-teq (double u, double v,
-     double ct = 3.0 * std::numeric_limits<double>::epsilon ())
-{
-  double tu = std::abs (u);
-  double tv = std::abs (v);
-
-  return std::abs (u - v) < ((tu > tv ? tu : tv) * ct);
-}
-
-octave_idx_type
-Range::numel_internal (void) const
-{
-  octave_idx_type retval = -1;
-
-  if (! octave::math::isfinite (m_base) || ! octave::math::isfinite (m_inc)
-      || octave::math::isnan (m_limit))
-    retval = -2;
-  else if (octave::math::isinf (m_limit)
-           && ((m_inc > 0 && m_limit > 0)
-               || (m_inc < 0 && m_limit < 0)))
-    retval = std::numeric_limits<octave_idx_type>::max () - 1;
-  else if (m_inc == 0
-           || (m_limit > m_base && m_inc < 0)
-           || (m_limit < m_base && m_inc > 0))
-    {
-      retval = 0;
-    }
-  else
-    {
-      double ct = 3.0 * std::numeric_limits<double>::epsilon ();
-
-      double tmp = tfloor ((m_limit - m_base + m_inc) / m_inc, ct);
-
-      octave_idx_type n_elt = (tmp > 0.0
-                               ? static_cast<octave_idx_type> (tmp) : 0);
-
-      // If the final element that we would compute for the range is equal to
-      // the limit of the range, or is an adjacent floating point number,
-      // accept it.  Otherwise, try a range with one fewer element.  If that
-      // fails, try again with one more element.
-      //
-      // I'm not sure this is very good, but it seems to work better than just
-      // using tfloor as above.  For example, without it, the expression
-      // 1.8:0.05:1.9 fails to produce the expected result of [1.8, 1.85, 1.9].
-
-      if (! teq (m_base + (n_elt - 1) * m_inc, m_limit))
-        {
-          if (teq (m_base + (n_elt - 2) * m_inc, m_limit))
-            n_elt--;
-          else if (teq (m_base + n_elt * m_inc, m_limit))
-            n_elt++;
-        }
-
-      retval = ((n_elt < std::numeric_limits<octave_idx_type>::max ())
-                ? n_elt : -1);
-    }
-
-  return retval;
-}
-
-double
-Range::limit_internal (void) const
-{
-  double new_limit = m_inc > 0 ? max () : min ();
-
-  // If result must be an integer then force the new_limit to be one.
-  if (all_elements_are_ints ())
-    new_limit = std::round (new_limit);
-
-  return new_limit;
-}
-
-void
-Range::init (void)
-{
-  m_numel = numel_internal ();
-
-  if (! octave::math::isinf (m_limit))
-    m_limit = limit_internal ();
-}
--- a/liboctave/array/Range.h	Fri Dec 02 10:11:46 2022 -0500
+++ b/liboctave/array/Range.h	Fri Dec 02 10:12:40 2022 -0500
@@ -40,550 +40,360 @@
 
 OCTAVE_BEGIN_NAMESPACE(octave)
 
-// For now, only define for floating point types.  However, we only
-// need range<float> as a temporary local variable in make_float_range
-// in ov.cc.
-
-template <typename T>
-class
-range<T, typename std::enable_if<std::is_floating_point<T>::value>::type>
-{
-public:
-
-  range (void)
-    : m_base (0), m_increment (0), m_limit (0), m_final (0), m_numel (0),
-      m_reverse (false)
-  { }
-
-  // LIMIT is an upper limit and may be outside the range of actual
-  // values.  For floating point ranges, we perform a tolerant check
-  // to attempt to capture limit in the set of values if it is "close"
-  // to the value of base + a multiple of the increment.
-
-  range (const T& base, const T& increment, const T& limit,
-         bool reverse = false)
-    : m_base (base), m_increment (increment), m_limit (limit),
-      m_final (), m_numel (), m_reverse (reverse)
-  {
-    init ();
-  }
-
-  range (const T& base, const T& limit)
-    : m_base (base), m_increment (1), m_limit (limit), m_final (), m_numel (),
-      m_reverse (false)
-  {
-    init ();
-  }
+  // For now, only define for floating point types.  However, we only
+  // need range<float> as a temporary local variable in make_float_range
+  // in ov.cc.
 
-  // Allow conversion from (presumably) properly constructed Range
-  // objects.  The values of base, limit, increment, and numel must be
-  // consistent.
-
-  // FIXME: Actually check that base, limit, increment, and numel are
-  // consistent?
-
-  range (const T& base, const T& increment, const T& limit,
-         octave_idx_type numel, bool reverse = false)
-    : m_base (base), m_increment (increment), m_limit (limit),
-      m_final (limit), m_numel (numel), m_reverse (reverse)
-  { }
-
-  // We don't use a constructor for this because it will conflict with
-  // range<T> (base, limit, increment) when T is octave_idx_type.
-
-  static range<T> make_n_element_range (const T& base, const T& increment,
-                                        octave_idx_type numel,
-                                        bool reverse = false)
-  {
-    // We could just make this constructor public, but it allows
-    // inconsistent ranges to be constructed.  And it is probably much
-    // clearer to see "make_n_element_range" instead of puzzling over the
-    // purpose of this strange constructor form.
-
-    T final_val = (reverse ? base - (numel - 1) * increment
-                   : base + (numel - 1) * increment);
-
-    return range<T> (base, increment, final_val, numel, reverse);
-  }
-
-  range (const range<T>& r)
-    : m_base (r.m_base), m_increment (r.m_increment),
-      m_limit (r.m_limit), m_final (r.m_final),
-      m_numel (r.m_numel), m_reverse (r.m_reverse)
-  { }
-
-  range<T>& operator = (const range<T>& r)
+  template <typename T>
+  class
+  range<T, typename std::enable_if<std::is_floating_point<T>::value>::type>
   {
-    if (this != &r)
-      {
-        m_base = r.m_base;
-        m_increment = r.m_increment;
-        m_limit = r.m_limit;
-        m_final = r.m_final;
-        m_numel = r.m_numel;
-        m_reverse = r.m_reverse;
-      }
+  public:
+
+    range (void)
+      : m_base (0), m_increment (0), m_limit (0), m_final (0), m_numel (0),
+        m_reverse (false)
+    { }
+
+    // LIMIT is an upper limit and may be outside the range of actual
+    // values.  For floating point ranges, we perform a tolerant check
+    // to attempt to capture limit in the set of values if it is "close"
+    // to the value of base + a multiple of the increment.
 
-    return *this;
-  }
-
-  ~range (void) = default;
+    range (const T& base, const T& increment, const T& limit,
+           bool reverse = false)
+      : m_base (base), m_increment (increment), m_limit (limit),
+        m_final (), m_numel (), m_reverse (reverse)
+    {
+      init ();
+    }
 
-  T base (void) const { return m_base; }
-  T increment (void) const { return m_increment; }
-  T limit (void) const { return m_limit; }
-  bool reverse (void) const { return m_reverse; }
+    range (const T& base, const T& limit)
+      : m_base (base), m_increment (1), m_limit (limit), m_final (), m_numel (),
+        m_reverse (false)
+    {
+      init ();
+    }
+
+    // Allow conversion from (presumably) properly constructed Range
+    // objects.  The values of base, limit, increment, and numel must be
+    // consistent.
 
-  T final_value (void) const { return m_final; }
+    // FIXME: Actually check that base, limit, increment, and numel are
+    // consistent?
 
-  T min (void) const
-  {
-    return (m_numel > 0
-            ? ((m_reverse ? m_increment > T (0)
-                : m_increment > T (0)) ? base () : final_value ())
-            : T (0));
-  }
+    range (const T& base, const T& increment, const T& limit,
+           octave_idx_type numel, bool reverse = false)
+      : m_base (base), m_increment (increment), m_limit (limit),
+        m_final (limit), m_numel (numel), m_reverse (reverse)
+    { }
+
+    // We don't use a constructor for this because it will conflict with
+    // range<T> (base, limit, increment) when T is octave_idx_type.
 
-  T max (void) const
-  {
-    return (m_numel > 0
-            ? ((m_reverse ? m_increment < T (0)
-                : m_increment > T (0)) ? final_value () : base ())
-            : T (0));
-  }
+    static range<T> make_n_element_range (const T& base, const T& increment,
+                                          octave_idx_type numel,
+                                          bool reverse = false)
+    {
+      // We could just make this constructor public, but it allows
+      // inconsistent ranges to be constructed.  And it is probably much
+      // clearer to see "make_n_element_range" instead of puzzling over the
+      // purpose of this strange constructor form.
 
-  octave_idx_type numel (void) const { return m_numel; }
+      T final_val = (reverse ? base - (numel - 1) * increment
+                             : base + (numel - 1) * increment);
+
+      return range<T> (base, increment, final_val, numel, reverse);
+    }
+
+    range (const range<T>& r)
+      : m_base (r.m_base), m_increment (r.m_increment),
+        m_limit (r.m_limit), m_final (r.m_final),
+        m_numel (r.m_numel), m_reverse (r.m_reverse)
+    { }
 
-  // To support things like "for i = 1:Inf; ...; end" that are
-  // required for Matlab compatibility, creation of a range object
-  // like 1:Inf is allowed with m_numel set to
-  // numeric_limits<octave_idx_type>::max().  However, it is not
-  // possible to store these ranges.  The following function allows
-  // us to easily distinguish ranges with an infinite number of
-  // elements.  There are specializations for double and float.
+    range<T>& operator = (const range<T>& r)
+    {
+      if (this != &r)
+        {
+          m_base = r.m_base;
+          m_increment = r.m_increment;
+          m_limit = r.m_limit;
+          m_final = r.m_final;
+          m_numel = r.m_numel;
+          m_reverse = r.m_reverse;
+        }
 
-  bool is_storable (void) const { return true; }
+      return *this;
+    }
+
+    ~range (void) = default;
 
-  dim_vector dims (void) const { return dim_vector (1, m_numel); }
+    T base (void) const { return m_base; }
+    T increment (void) const { return m_increment; }
+    T limit (void) const { return m_limit; }
+    bool reverse (void) const { return m_reverse; }
 
-  octave_idx_type rows (void) const { return 1; }
+    T final_value (void) const { return m_final; }
 
-  octave_idx_type cols (void) const { return numel (); }
-  octave_idx_type columns (void) const { return numel (); }
+    T min (void) const
+    {
+      return (m_numel > 0
+              ? ((m_reverse ? m_increment > T (0)
+                            : m_increment > T (0)) ? base () : final_value ())
+              : T (0));
+    }
 
-  bool isempty (void) const { return numel () == 0; }
+    T max (void) const
+    {
+      return (m_numel > 0
+              ? ((m_reverse ? m_increment < T (0)
+                            : m_increment > T (0)) ? final_value () : base ())
+              : T (0));
+    }
 
-  bool all_elements_are_ints (void) const { return true; }
+    octave_idx_type numel (void) const { return m_numel; }
 
-  sortmode issorted (sortmode mode = ASCENDING) const
-  {
-    if (m_numel > 1 && (m_reverse ? m_increment < T (0)
-                        : m_increment > T (0)))
-      mode = ((mode == DESCENDING) ? UNSORTED : ASCENDING);
-    else if (m_numel > 1 && (m_reverse ? m_increment > T (0)
-                             : m_increment < T (0)))
-      mode = ((mode == ASCENDING) ? UNSORTED : DESCENDING);
-    else
-      mode = ((mode == UNSORTED) ? ASCENDING : mode);
+    // To support things like "for i = 1:Inf; ...; end" that are
+    // required for Matlab compatibility, creation of a range object
+    // like 1:Inf is allowed with m_numel set to
+    // numeric_limits<octave_idx_type>::max().  However, it is not
+    // possible to store these ranges.  The following function allows
+    // us to easily distinguish ranges with an infinite number of
+    // elements.  There are specializations for double and float.
+
+    bool is_storable (void) const { return true; }
+
+    dim_vector dims (void) const { return dim_vector (1, m_numel); }
+
+    octave_idx_type rows (void) const { return 1; }
+
+    octave_idx_type cols (void) const { return numel (); }
+    octave_idx_type columns (void) const { return numel (); }
+
+    bool isempty (void) const { return numel () == 0; }
+
+    bool all_elements_are_ints (void) const { return true; }
 
-    return mode;
-  }
-
-  OCTAVE_API octave_idx_type nnz (void) const;
+    sortmode issorted (sortmode mode = ASCENDING) const
+    {
+      if (m_numel > 1 && (m_reverse ? m_increment < T (0)
+                                    : m_increment > T (0)))
+        mode = ((mode == DESCENDING) ? UNSORTED : ASCENDING);
+      else if (m_numel > 1 && (m_reverse ? m_increment > T (0)
+                                         : m_increment < T (0)))
+        mode = ((mode == ASCENDING) ? UNSORTED : DESCENDING);
+      else
+        mode = ((mode == UNSORTED) ? ASCENDING : mode);
 
-  // Support for single-index subscripting, without generating matrix cache.
+      return mode;
+    }
+
+    OCTAVE_API octave_idx_type nnz (void) const;
 
-  T checkelem (octave_idx_type i) const
-  {
-    if (i < 0 || i >= m_numel)
-      err_index_out_of_range (2, 2, i+1, m_numel, dims ());
+    // Support for single-index subscripting, without generating matrix cache.
+
+    T checkelem (octave_idx_type i) const
+    {
+      if (i < 0 || i >= m_numel)
+        err_index_out_of_range (2, 2, i+1, m_numel, dims ());
 
-    if (i == 0)
-      // Required for proper NaN handling.
-      return (m_numel == 1 ? final_value () : m_base);
-    else if (i < m_numel - 1)
-      return (m_reverse ? m_base + T (i) * m_increment
-              : m_base + T (i) * m_increment);
-    else
-      return final_value ();
-  }
+      if (i == 0)
+        // Required for proper NaN handling.
+        return (m_numel == 1 ? final_value () : m_base);
+      else if (i < m_numel - 1)
+        return (m_reverse ? m_base + T (i) * m_increment
+                          : m_base + T (i) * m_increment);
+      else
+        return final_value ();
+    }
 
-  T checkelem (octave_idx_type i, octave_idx_type j) const
-  {
-    // Ranges are *always* row vectors.
-    if (i != 0)
-      err_index_out_of_range (1, 1, i+1, m_numel, dims ());
+    T checkelem (octave_idx_type i, octave_idx_type j) const
+    {
+      // Ranges are *always* row vectors.
+      if (i != 0)
+        err_index_out_of_range (1, 1, i+1, m_numel, dims ());
 
-    return checkelem (j);
-  }
+      return checkelem (j);
+    }
 
-  T elem (octave_idx_type i) const
-  {
-    if (i == 0)
-      // Required for proper NaN handling.
-      return (m_numel == 1 ? final_value () : m_base);
-    else if (i < m_numel - 1)
-      return (m_reverse ? m_base - T (i) * m_increment
-              : m_base + T (i) * m_increment);
-    else
-      return final_value ();
-  }
+    T elem (octave_idx_type i) const
+    {
+      if (i == 0)
+        // Required for proper NaN handling.
+        return (m_numel == 1 ? final_value () : m_base);
+      else if (i < m_numel - 1)
+        return (m_reverse ? m_base - T (i) * m_increment
+                          : m_base + T (i) * m_increment);
+      else
+        return final_value ();
+    }
 
-  T elem (octave_idx_type /* i */, octave_idx_type j) const
-  {
-    return elem (j);
-  }
+    T elem (octave_idx_type /* i */, octave_idx_type j) const
+    {
+      return elem (j);
+    }
 
-  T operator () (octave_idx_type i) const
-  {
-    return elem (i);
-  }
+    T operator () (octave_idx_type i) const
+    {
+      return elem (i);
+    }
 
-  T operator () (octave_idx_type i, octave_idx_type j) const
-  {
-    return elem (i, j);
-  }
+    T operator () (octave_idx_type i, octave_idx_type j) const
+    {
+      return elem (i, j);
+    }
 
-  Array<T> index (const idx_vector& idx) const
-  {
-    Array<T> retval;
+    Array<T> index (const idx_vector& idx) const
+    {
+      Array<T> retval;
 
-    octave_idx_type n = m_numel;
+      octave_idx_type n = m_numel;
 
-    if (idx.is_colon ())
-      {
-        retval = array_value ().reshape (dim_vector (m_numel, 1));
-      }
-    else
-      {
-        if (idx.extent (n) != n)
-          err_index_out_of_range (1, 1, idx.extent (n), n, dims ());
+      if (idx.is_colon ())
+        {
+          retval = array_value ().reshape (dim_vector (m_numel, 1));
+        }
+      else
+        {
+          if (idx.extent (n) != n)
+            err_index_out_of_range (1, 1, idx.extent (n), n, dims ());
 
-        dim_vector idx_dims = idx.orig_dimensions ();
-        octave_idx_type idx_len = idx.length (n);
+          dim_vector idx_dims = idx.orig_dimensions ();
+          octave_idx_type idx_len = idx.length (n);
 
-        // taken from Array.cc.
-        if (n != 1 && idx_dims.isvector ())
-          idx_dims = dim_vector (1, idx_len);
+          // taken from Array.cc.
+          if (n != 1 && idx_dims.isvector ())
+            idx_dims = dim_vector (1, idx_len);
 
-        retval.clear (idx_dims);
+          retval.clear (idx_dims);
 
-        // Loop over all values in IDX, executing the lambda
-        // expression for each index value.
+          // Loop over all values in IDX, executing the lambda
+          // expression for each index value.
 
-        T *array = retval.fortran_vec ();
+          T *array = retval.fortran_vec ();
 
-        idx.loop (n, [=, &array] (octave_idx_type i)
-        {
-          if (i == 0)
-            // Required for proper NaN handling.
-            *array++ = (m_numel == 0 ? m_final : m_base);
-          else if (i < m_numel - 1)
-            *array++ = (m_reverse ? m_base - T (i) * m_increment
-                        : m_base + T (i) * m_increment);
-          else
-            *array++ = m_final;
-        });
-      }
+          idx.loop (n, [=, &array] (octave_idx_type i)
+          {
+            if (i == 0)
+              // Required for proper NaN handling.
+              *array++ = (m_numel == 0 ? m_final : m_base);
+            else if (i < m_numel - 1)
+              *array++ = (m_reverse ? m_base - T (i) * m_increment
+                                    : m_base + T (i) * m_increment);
+            else
+              *array++ = m_final;
+          });
+        }
 
-    return retval;
-  }
+      return retval;
+    }
 
-  Array<T> diag (octave_idx_type k) const
-  {
-    return array_value ().diag (k);
-  }
+    Array<T> diag (octave_idx_type k) const
+    {
+      return array_value ().diag (k);
+    }
 
-  Array<T> array_value (void) const
-  {
-    octave_idx_type nel = numel ();
+    Array<T> array_value (void) const
+    {
+      octave_idx_type nel = numel ();
 
-    Array<T> retval (dim_vector (1, nel));
+      Array<T> retval (dim_vector (1, nel));
 
-    if (nel == 1)
-      // Required for proper NaN handling.
-      retval(0) = final_value ();
-    else if (nel > 1)
-      {
-        // The first element must always be *exactly* the base.
-        // E.g, -0 would otherwise become +0 in the loop (-0 + 0*increment).
-        retval(0) = m_base;
+      if (nel == 1)
+        // Required for proper NaN handling.
+        retval(0) = final_value ();
+      else if (nel > 1)
+        {
+          // The first element must always be *exactly* the base.
+          // E.g, -0 would otherwise become +0 in the loop (-0 + 0*increment).
+          retval(0) = m_base;
 
-        if (m_reverse)
-          for (octave_idx_type i = 1; i < nel - 1; i++)
-            retval.xelem (i) = m_base - i * m_increment;
-        else
-          for (octave_idx_type i = 1; i < nel - 1; i++)
-            retval.xelem (i) = m_base + i * m_increment;
+          if (m_reverse)
+            for (octave_idx_type i = 1; i < nel - 1; i++)
+              retval.xelem (i) = m_base - i * m_increment;
+          else
+            for (octave_idx_type i = 1; i < nel - 1; i++)
+              retval.xelem (i) = m_base + i * m_increment;
 
-        retval.xelem (nel - 1) = final_value ();
-      }
+          retval.xelem (nel - 1) = final_value ();
+        }
 
-    return retval;
-  }
+      return retval;
+    }
 
-private:
+  private:
 
-  T m_base;
-  T m_increment;
-  T m_limit;
-  T m_final;
-  octave_idx_type m_numel;
-  bool m_reverse;
+    T m_base;
+    T m_increment;
+    T m_limit;
+    T m_final;
+    octave_idx_type m_numel;
+    bool m_reverse;
 
-  // Setting the number of elements to zero when the increment is zero
-  // is intentional and matches the behavior of Matlab's colon
-  // operator.
+    // Setting the number of elements to zero when the increment is zero
+    // is intentional and matches the behavior of Matlab's colon
+    // operator.
 
-  // These calculations are appropriate for integer ranges.  There are
-  // specializations for double and float.
+    // These calculations are appropriate for integer ranges.  There are
+    // specializations for double and float.
 
-  void init (void)
-  {
-    if (m_reverse)
-      {
-        m_numel = ((m_increment == T (0)
-                    || (m_limit > m_base && m_increment > T (0))
-                    || (m_limit < m_base && m_increment < T (0)))
-                   ? T (0)
-                   : (m_base - m_limit - m_increment) / m_increment);
+    void init (void)
+    {
+      if (m_reverse)
+        {
+          m_numel = ((m_increment == T (0)
+                      || (m_limit > m_base && m_increment > T (0))
+                      || (m_limit < m_base && m_increment < T (0)))
+                     ? T (0)
+                     : (m_base - m_limit - m_increment) / m_increment);
 
-        m_final = m_base - (m_numel - 1) * m_increment;
-      }
-    else
-      {
-        m_numel = ((m_increment == T (0)
-                    || (m_limit > m_base && m_increment < T (0))
-                    || (m_limit < m_base && m_increment > T (0)))
-                   ? T (0)
-                   : (m_limit - m_base + m_increment) / m_increment);
+          m_final = m_base - (m_numel - 1) * m_increment;
+        }
+      else
+        {
+          m_numel = ((m_increment == T (0)
+                      || (m_limit > m_base && m_increment < T (0))
+                      || (m_limit < m_base && m_increment > T (0)))
+                     ? T (0)
+                     : (m_limit - m_base + m_increment) / m_increment);
 
-        m_final = m_base + (m_numel - 1) * m_increment;
-      }
-  }
-};
+          m_final = m_base + (m_numel - 1) * m_increment;
+        }
+    }
+  };
 
-// Specializations defined externally.
+  // Specializations defined externally.
 
-template <> OCTAVE_API bool range<double>::all_elements_are_ints (void) const;
-template <> OCTAVE_API bool range<float>::all_elements_are_ints (void) const;
+  template <> OCTAVE_API bool range<double>::all_elements_are_ints (void) const;
+  template <> OCTAVE_API bool range<float>::all_elements_are_ints (void) const;
 
-template <> OCTAVE_API void range<double>::init (void);
-template <> OCTAVE_API void range<float>::init (void);
+  template <> OCTAVE_API void range<double>::init (void);
+  template <> OCTAVE_API void range<float>::init (void);
 
-// For now, only define for floating point types.  However, we only
-// need range<float> as a temporary local variable in make_float_range
-// in ov.cc.
+  // For now, only define for floating point types.  However, we only
+  // need range<float> as a temporary local variable in make_float_range
+  // in ov.cc.
 
 #if 0
 
-template <> OCTAVE_API void range<octave_int8>::init (void);
-template <> OCTAVE_API void range<octave_int16>::init (void);
-template <> OCTAVE_API void range<octave_int32>::init (void);
-template <> OCTAVE_API void range<octave_int64>::init (void);
-template <> OCTAVE_API void range<octave_uint8>::init (void);
-template <> OCTAVE_API void range<octave_uint16>::init (void);
-template <> OCTAVE_API void range<octave_uint32>::init (void);
-template <> OCTAVE_API void range<octave_uint64>::init (void);
+  template <> OCTAVE_API void range<octave_int8>::init (void);
+  template <> OCTAVE_API void range<octave_int16>::init (void);
+  template <> OCTAVE_API void range<octave_int32>::init (void);
+  template <> OCTAVE_API void range<octave_int64>::init (void);
+  template <> OCTAVE_API void range<octave_uint8>::init (void);
+  template <> OCTAVE_API void range<octave_uint16>::init (void);
+  template <> OCTAVE_API void range<octave_uint32>::init (void);
+  template <> OCTAVE_API void range<octave_uint64>::init (void);
 
 #endif
 
-template <> OCTAVE_API bool range<double>::is_storable (void) const;
-template <> OCTAVE_API bool range<float>::is_storable (void) const;
+  template <> OCTAVE_API bool range<double>::is_storable (void) const;
+  template <> OCTAVE_API bool range<float>::is_storable (void) const;
 
-template <> OCTAVE_API octave_idx_type range<double>::nnz (void) const;
-template <> OCTAVE_API octave_idx_type range<float>::nnz (void) const;
+  template <> OCTAVE_API octave_idx_type range<double>::nnz (void) const;
+  template <> OCTAVE_API octave_idx_type range<float>::nnz (void) const;
 
 OCTAVE_END_NAMESPACE(octave)
 
-class
-Range
-{
-public:
-
-  OCTAVE_DEPRECATED (7, "use the 'octave::range<double>' class instead")
-  Range (void)
-    : m_base (0), m_limit (0), m_inc (0), m_numel (0)
-  { }
-
-  // Assume range is already properly constructed, so just copy internal
-  // values.  However, we set LIMIT to the computed final value because
-  // that mimics the behavior of the other Range class constructors that
-  // reset limit to the computed final value.
-
-  OCTAVE_DEPRECATED (7, "use the 'octave::range<double>' class instead")
-  Range (const octave::range<double>& r)
-    : m_base (r.base ()), m_limit (r.final_value ()), m_inc (r.increment ()),
-      m_numel (r.numel ())
-  { }
-
-  Range (const Range& r) = default;
-
-  Range& operator = (const Range& r) = default;
-
-  ~Range (void) = default;
-
-  OCTAVE_DEPRECATED (7, "use the 'octave::range<double>' class instead")
-  Range (double b, double l)
-    : m_base (b), m_limit (l), m_inc (1), m_numel (numel_internal ())
-  {
-    if (! octave::math::isinf (m_limit))
-      m_limit = limit_internal ();
-  }
-
-  OCTAVE_DEPRECATED (7, "use the 'octave::range<double>' class instead")
-  Range (double b, double l, double i)
-    : m_base (b), m_limit (l), m_inc (i), m_numel (numel_internal ())
-  {
-    if (! octave::math::isinf (m_limit))
-      m_limit = limit_internal ();
-  }
-
-  // NOTE: The following constructor may be deprecated and removed after
-  // the arithmetic operators are removed.
-
-  // For operators' usage (to preserve element count) and to create
-  // constant row vectors (obsolete usage).
-
-  OCTAVE_DEPRECATED (7, "use the 'octave::range<double>' class instead")
-  Range (double b, double i, octave_idx_type n)
-    : m_base (b), m_limit (b + (n-1) * i), m_inc (i), m_numel (n)
-  {
-    if (! octave::math::isinf (m_limit))
-      m_limit = limit_internal ();
-  }
-
-  // The range has a finite number of elements.
-  bool ok (void) const
-  {
-    return (octave::math::isfinite (m_limit)
-            && (m_numel >= 0 || m_numel == -2));
-  }
-
-  double base (void) const { return m_base; }
-  double limit (void) const { return m_limit; }
-  double inc (void) const { return m_inc; }
-  double increment (void) const { return m_inc; }
-
-  // We adjust the limit to be the final value, so return that.  We
-  // could introduce a new variable to store the final value separately,
-  // but it seems like that would just add confusion.  If we changed
-  // the meaning of the limit function, we would change the behavior of
-  // programs that expect limit to be the final value instead of the
-  // value of the limit when the range was created.  This problem will
-  // be fixed with the new template range class.
-  double final_value (void) const { return m_limit; }
-
-  octave_idx_type numel (void) const { return m_numel; }
-
-  dim_vector dims (void) const { return dim_vector (1, m_numel); }
-
-  octave_idx_type rows (void) const { return 1; }
-
-  octave_idx_type cols (void) const { return numel (); }
-  octave_idx_type columns (void) const { return numel (); }
-
-  bool isempty (void) const { return numel () == 0; }
-
-  OCTAVE_API bool all_elements_are_ints (void) const;
-
-  OCTAVE_API Matrix matrix_value (void) const;
-
-  OCTAVE_API double min (void) const;
-  OCTAVE_API double max (void) const;
-
-  OCTAVE_API void sort_internal (bool ascending = true);
-  OCTAVE_API void sort_internal (Array<octave_idx_type>& sidx, bool ascending = true);
-
-  OCTAVE_API Matrix diag (octave_idx_type k = 0) const;
-
-  OCTAVE_API Range sort (octave_idx_type dim = 0, sortmode mode = ASCENDING) const;
-  OCTAVE_API Range sort (Array<octave_idx_type>& sidx, octave_idx_type dim = 0,
-                         sortmode mode = ASCENDING) const;
-
-  OCTAVE_API sortmode issorted (sortmode mode = ASCENDING) const;
-
-  OCTAVE_API octave_idx_type nnz (void) const;
-
-  // Support for single-index subscripting, without generating matrix cache.
-
-  OCTAVE_API double checkelem (octave_idx_type i) const;
-  OCTAVE_API double checkelem (octave_idx_type i, octave_idx_type j) const;
-
-  OCTAVE_API double elem (octave_idx_type i) const;
-  double elem (octave_idx_type /* i */, octave_idx_type j) const
-  { return elem (j); }
-
-  double operator () (octave_idx_type i) const { return elem (i); }
-  double operator () (octave_idx_type i, octave_idx_type j) const
-  { return elem (i, j); }
-
-  OCTAVE_API Array<double> index (const octave::idx_vector& i) const;
-
-  OCTAVE_API void set_base (double b);
-
-  OCTAVE_API void set_limit (double l);
-
-  OCTAVE_API void set_inc (double i);
-
-  friend OCTAVE_API std::ostream& operator << (std::ostream& os,
-                                               const Range& r);
-  friend OCTAVE_API std::istream& operator >> (std::istream& is, Range& r);
-
-  friend OCTAVE_API Range operator - (const Range& r);
-  friend OCTAVE_API Range operator + (double x, const Range& r);
-  friend OCTAVE_API Range operator + (const Range& r, double x);
-  friend OCTAVE_API Range operator - (double x, const Range& r);
-  friend OCTAVE_API Range operator - (const Range& r, double x);
-  friend OCTAVE_API Range operator * (double x, const Range& r);
-  friend OCTAVE_API Range operator * (const Range& r, double x);
-
-private:
-
-  double m_base;
-  double m_limit;
-  double m_inc;
-
-  octave_idx_type m_numel;
-
-  OCTAVE_API octave_idx_type numel_internal (void) const;
-
-  OCTAVE_API double limit_internal (void) const;
-
-  OCTAVE_API void init (void);
-
-protected:
-
-  // NOTE: The following constructor may be removed when the arithmetic
-  // operators are removed.
-
-  // For operators' usage (to allow all values to be set directly).
-  Range (double b, double l, double i, octave_idx_type n)
-    : m_base (b), m_limit (l), m_inc (i), m_numel (n)
-  { }
-};
-
-#if defined (OCTAVE_PROVIDE_DEPRECATED_SYMBOLS)
-OCTAVE_DEPRECATED (7, "arithmetic operations on Range objects are unreliable")
-extern OCTAVE_API Range operator - (const Range& r);
-
-OCTAVE_DEPRECATED (7, "arithmetic operations on Range objects are unreliable")
-extern OCTAVE_API Range operator + (double x, const Range& r);
-
-OCTAVE_DEPRECATED (7, "arithmetic operations on Range objects are unreliable")
-extern OCTAVE_API Range operator + (const Range& r, double x);
-
-OCTAVE_DEPRECATED (7, "arithmetic operations on Range objects are unreliable")
-extern OCTAVE_API Range operator - (double x, const Range& r);
-
-OCTAVE_DEPRECATED (7, "arithmetic operations on Range objects are unreliable")
-extern OCTAVE_API Range operator - (const Range& r, double x);
-
-OCTAVE_DEPRECATED (7, "arithmetic operations on Range objects are unreliable")
-extern OCTAVE_API Range operator * (double x, const Range& r);
-
-OCTAVE_DEPRECATED (7, "arithmetic operations on Range objects are unreliable")
-extern OCTAVE_API Range operator * (const Range& r, double x);
 #endif
-
-#endif
--- a/liboctave/numeric/CollocWt.h	Fri Dec 02 10:11:46 2022 -0500
+++ b/liboctave/numeric/CollocWt.h	Fri Dec 02 10:12:40 2022 -0500
@@ -209,9 +209,4 @@
 
 OCTAVE_END_NAMESPACE(octave)
 
-#if defined (OCTAVE_PROVIDE_DEPRECATED_SYMBOLS)
-OCTAVE_DEPRECATED (7, "use 'octave::CollocWt' instead")
-typedef octave::CollocWt CollocWt;
 #endif
-
-#endif
--- a/liboctave/numeric/oct-convn.h	Fri Dec 02 10:11:46 2022 -0500
+++ b/liboctave/numeric/oct-convn.h	Fri Dec 02 10:12:40 2022 -0500
@@ -158,152 +158,4 @@
 
 OCTAVE_END_NAMESPACE(octave)
 
-#if defined (OCTAVE_PROVIDE_DEPRECATED_SYMBOLS)
-OCTAVE_DEPRECATED (7, "use 'octave::convn' instead")
-inline NDArray
-convn (const NDArray& a, const NDArray& b, convn_type ct)
-{
-  return octave::convn (a, b, static_cast<octave::convn_type> (ct));
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::convn' instead")
-inline Matrix
-convn (const Matrix& a, const Matrix& b, convn_type ct)
-{
-  return octave::convn (a, b, octave::convert_enum (ct));
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::convn' instead")
-inline Matrix
-convn (const Matrix& a, const ColumnVector& c, const RowVector& r,
-       convn_type ct)
-{
-  return octave::convn (a, c, r, octave::convert_enum (ct));
-}
-
-// double complex X double real
-
-OCTAVE_DEPRECATED (7, "use 'octave::convn' instead")
-inline ComplexNDArray
-convn (const ComplexNDArray& a, const NDArray& b, convn_type ct)
-{
-  return octave::convn (a, b, octave::convert_enum (ct));
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::convn' instead")
-inline ComplexMatrix
-convn (const ComplexMatrix& a, const Matrix& b, convn_type ct)
-{
-  return octave::convn (a, b, octave::convert_enum (ct));
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::convn' instead")
-inline ComplexMatrix
-convn (const ComplexMatrix& a, const ColumnVector& c, const RowVector& r,
-       convn_type ct)
-{
-  return octave::convn (a, c, r, octave::convert_enum (ct));
-}
-
-// double complex X double complex
-
-OCTAVE_DEPRECATED (7, "use 'octave::convn' instead")
-inline ComplexNDArray
-convn (const ComplexNDArray& a, const ComplexNDArray& b, convn_type ct)
-{
-  return octave::convn (a, b, octave::convert_enum (ct));
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::convn' instead")
-inline ComplexMatrix
-convn (const ComplexMatrix& a, const ComplexMatrix& b, convn_type ct)
-{
-  return octave::convn (a, b, octave::convert_enum (ct));
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::convn' instead")
-inline ComplexMatrix
-convn (const ComplexMatrix& a, const ComplexColumnVector& c,
-       const ComplexRowVector& r, convn_type ct)
-{
-  return octave::convn (a, c, r, octave::convert_enum (ct));
-}
-
-// float real X float real
-
-OCTAVE_DEPRECATED (7, "use 'octave::convn' instead")
-inline FloatNDArray
-convn (const FloatNDArray& a, const FloatNDArray& b, convn_type ct)
-{
-  return octave::convn (a, b, octave::convert_enum (ct));
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::convn' instead")
-inline FloatMatrix
-convn (const FloatMatrix& a, const FloatMatrix& b, convn_type ct)
-{
-  return octave::convn (a, b, octave::convert_enum (ct));
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::convn' instead")
-inline FloatMatrix
-convn (const FloatMatrix& a, const FloatColumnVector& c,
-       const FloatRowVector& r, convn_type ct)
-{
-  return octave::convn (a, c, r, octave::convert_enum (ct));
-}
-
-// float complex X float real
-
-OCTAVE_DEPRECATED (7, "use 'octave::convn' instead")
-inline FloatComplexNDArray
-convn (const FloatComplexNDArray& a, const FloatNDArray& b,
-       convn_type ct)
-{
-  return octave::convn (a, b, octave::convert_enum (ct));
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::convn' instead")
-inline FloatComplexMatrix
-convn (const FloatComplexMatrix& a, const FloatMatrix& b,
-       convn_type ct)
-{
-  return octave::convn (a, b, octave::convert_enum (ct));
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::convn' instead")
-inline FloatComplexMatrix
-convn (const FloatComplexMatrix& a, const FloatColumnVector& c,
-       const FloatRowVector& r, convn_type ct)
-{
-  return octave::convn (a, c, r, octave::convert_enum (ct));
-}
-
-// float complex X float complex
-
-OCTAVE_DEPRECATED (7, "use 'octave::convn' instead")
-inline FloatComplexNDArray
-convn (const FloatComplexNDArray& a, const FloatComplexNDArray& b,
-       convn_type ct)
-{
-  return octave::convn (a, b, octave::convert_enum (ct));
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::convn' instead")
-inline FloatComplexMatrix
-convn (const FloatComplexMatrix& a, const FloatComplexMatrix& b,
-       convn_type ct)
-{
-  return octave::convn (a, b, octave::convert_enum (ct));
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::convn' instead")
-inline FloatComplexMatrix
-convn (const FloatComplexMatrix& a, const FloatComplexColumnVector& c,
-       const FloatComplexRowVector& r, convn_type ct)
-{
-  return octave::convn (a, c, r, octave::convert_enum (ct));
-}
 #endif
-
-#endif
--- a/liboctave/numeric/oct-norm.cc	Fri Dec 02 10:11:46 2022 -0500
+++ b/liboctave/numeric/oct-norm.cc	Fri Dec 02 10:12:40 2022 -0500
@@ -65,261 +65,261 @@
 
 OCTAVE_BEGIN_NAMESPACE(octave)
 
-// Theory: norm accumulator is an object that has an accum method able
-// to handle both real and complex element, and a cast operator
-// returning the intermediate norm.  Reference: Higham, N. "Estimating
-// the Matrix p-Norm." Numer. Math. 62, 539-555, 1992.
+  // Theory: norm accumulator is an object that has an accum method able
+  // to handle both real and complex element, and a cast operator
+  // returning the intermediate norm.  Reference: Higham, N. "Estimating
+  // the Matrix p-Norm." Numer. Math. 62, 539-555, 1992.
 
-// norm accumulator for the p-norm
-template <typename R>
-class norm_accumulator_p
-{
-public:
-  norm_accumulator_p () { } // we need this one for Array
-  norm_accumulator_p (R pp) : m_p(pp), m_scl(0), m_sum(1) { }
+  // norm accumulator for the p-norm
+  template <typename R>
+  class norm_accumulator_p
+  {
+  public:
+    norm_accumulator_p () { } // we need this one for Array
+    norm_accumulator_p (R pp) : m_p(pp), m_scl(0), m_sum(1) { }
 
-  template <typename U>
-  void accum (U val)
-  {
-    octave_quit ();
-    R t = std::abs (val);
-    if (m_scl == t) // we need this to handle Infs properly
-      m_sum += 1;
-    else if (m_scl < t)
-      {
-        m_sum *= std::pow (m_scl/t, m_p);
+    template <typename U>
+    void accum (U val)
+    {
+      octave_quit ();
+      R t = std::abs (val);
+      if (m_scl == t) // we need this to handle Infs properly
         m_sum += 1;
-        m_scl = t;
-      }
-    else if (t != 0)
-      m_sum += std::pow (t/m_scl, m_p);
-  }
+      else if (m_scl < t)
+        {
+          m_sum *= std::pow (m_scl/t, m_p);
+          m_sum += 1;
+          m_scl = t;
+        }
+      else if (t != 0)
+        m_sum += std::pow (t/m_scl, m_p);
+    }
+
+    operator R () { return m_scl * std::pow (m_sum, 1/m_p); }
 
-  operator R () { return m_scl * std::pow (m_sum, 1/m_p); }
+  private:
+    R m_p, m_scl, m_sum;
+  };
 
-private:
-  R m_p, m_scl, m_sum;
-};
+  // norm accumulator for the minus p-pseudonorm
+  template <typename R>
+  class norm_accumulator_mp
+  {
+  public:
+    norm_accumulator_mp () { } // we need this one for Array
+    norm_accumulator_mp (R pp) : m_p(pp), m_scl(0), m_sum(1) { }
 
-// norm accumulator for the minus p-pseudonorm
-template <typename R>
-class norm_accumulator_mp
-{
-public:
-  norm_accumulator_mp () { } // we need this one for Array
-  norm_accumulator_mp (R pp) : m_p(pp), m_scl(0), m_sum(1) { }
+    template <typename U>
+    void accum (U val)
+    {
+      octave_quit ();
+      R t = 1 / std::abs (val);
+      if (m_scl == t)
+        m_sum += 1;
+      else if (m_scl < t)
+        {
+          m_sum *= std::pow (m_scl/t, m_p);
+          m_sum += 1;
+          m_scl = t;
+        }
+      else if (t != 0)
+        m_sum += std::pow (t/m_scl, m_p);
+    }
 
-  template <typename U>
-  void accum (U val)
+    operator R () { return m_scl * std::pow (m_sum, -1/m_p); }
+
+  private:
+    R m_p, m_scl, m_sum;
+  };
+
+  // norm accumulator for the 2-norm (euclidean)
+  template <typename R>
+  class norm_accumulator_2
   {
-    octave_quit ();
-    R t = 1 / std::abs (val);
-    if (m_scl == t)
-      m_sum += 1;
-    else if (m_scl < t)
-      {
-        m_sum *= std::pow (m_scl/t, m_p);
+  public:
+    norm_accumulator_2 () : m_scl(0), m_sum(1) { }
+
+    void accum (R val)
+    {
+      R t = std::abs (val);
+      if (m_scl == t)
         m_sum += 1;
-        m_scl = t;
-      }
-    else if (t != 0)
-      m_sum += std::pow (t/m_scl, m_p);
-  }
+      else if (m_scl < t)
+        {
+          m_sum *= pow2 (m_scl/t);
+          m_sum += 1;
+          m_scl = t;
+        }
+      else if (t != 0)
+        m_sum += pow2 (t/m_scl);
+    }
 
-  operator R () { return m_scl * std::pow (m_sum, -1/m_p); }
+    void accum (std::complex<R> val)
+    {
+      accum (val.real ());
+      accum (val.imag ());
+    }
+
+    operator R () { return m_scl * std::sqrt (m_sum); }
+
+  private:
+    static inline R pow2 (R x) { return x*x; }
+
+    //--------
 
-private:
-  R m_p, m_scl, m_sum;
-};
+    R m_scl, m_sum;
+  };
 
-// norm accumulator for the 2-norm (euclidean)
-template <typename R>
-class norm_accumulator_2
-{
-public:
-  norm_accumulator_2 () : m_scl(0), m_sum(1) { }
+  // norm accumulator for the 1-norm (city metric)
+  template <typename R>
+  class norm_accumulator_1
+  {
+  public:
+    norm_accumulator_1 () : m_sum (0) { }
+    template <typename U>
+    void accum (U val)
+    {
+      m_sum += std::abs (val);
+    }
 
-  void accum (R val)
+    operator R () { return m_sum; }
+
+  private:
+    R m_sum;
+  };
+
+  // norm accumulator for the inf-norm (max metric)
+  template <typename R>
+  class norm_accumulator_inf
   {
-    R t = std::abs (val);
-    if (m_scl == t)
-      m_sum += 1;
-    else if (m_scl < t)
-      {
-        m_sum *= pow2 (m_scl/t);
-        m_sum += 1;
-        m_scl = t;
-      }
-    else if (t != 0)
-      m_sum += pow2 (t/m_scl);
-  }
+  public:
+    norm_accumulator_inf () : m_max (0) { }
+    template <typename U>
+    void accum (U val)
+    {
+      if (math::isnan (val))
+        m_max = numeric_limits<R>::NaN ();
+      else
+        m_max = std::max (m_max, std::abs (val));
+    }
+
+    operator R () { return m_max; }
 
-  void accum (std::complex<R> val)
+  private:
+    R m_max;
+  };
+
+  // norm accumulator for the -inf pseudonorm (min abs value)
+  template <typename R>
+  class norm_accumulator_minf
   {
-    accum (val.real ());
-    accum (val.imag ());
-  }
+  public:
+    norm_accumulator_minf () : m_min (numeric_limits<R>::Inf ()) { }
+    template <typename U>
+    void accum (U val)
+    {
+      if (math::isnan (val))
+        m_min = numeric_limits<R>::NaN ();
+      else
+        m_min = std::min (m_min, std::abs (val));
+    }
 
-  operator R () { return m_scl * std::sqrt (m_sum); }
-
-private:
-  static inline R pow2 (R x) { return x*x; }
+    operator R () { return m_min; }
 
-  //--------
-
-  R m_scl, m_sum;
-};
+  private:
+    R m_min;
+  };
 
-// norm accumulator for the 1-norm (city metric)
-template <typename R>
-class norm_accumulator_1
-{
-public:
-  norm_accumulator_1 () : m_sum (0) { }
-  template <typename U>
-  void accum (U val)
+  // norm accumulator for the 0-pseudonorm (hamming distance)
+  template <typename R>
+  class norm_accumulator_0
   {
-    m_sum += std::abs (val);
+  public:
+    norm_accumulator_0 () : m_num (0) { }
+    template <typename U>
+    void accum (U val)
+    {
+      if (val != static_cast<U> (0)) ++m_num;
+    }
+
+    operator R () { return m_num; }
+
+  private:
+    unsigned int m_num;
+  };
+
+  // OK, we're armed :) Now let's go for the fun
+
+  template <typename T, typename R, typename ACC>
+  inline void vector_norm (const Array<T>& v, R& res, ACC acc)
+  {
+    for (octave_idx_type i = 0; i < v.numel (); i++)
+      acc.accum (v(i));
+
+    res = acc;
   }
 
-  operator R () { return m_sum; }
-
-private:
-  R m_sum;
-};
+  // dense versions
+  template <typename T, typename R, typename ACC>
+  void column_norms (const MArray<T>& m, MArray<R>& res, ACC acc)
+  {
+    res = MArray<R> (dim_vector (1, m.columns ()));
+    for (octave_idx_type j = 0; j < m.columns (); j++)
+      {
+        ACC accj = acc;
+        for (octave_idx_type i = 0; i < m.rows (); i++)
+          accj.accum (m(i, j));
 
-// norm accumulator for the inf-norm (max metric)
-template <typename R>
-class norm_accumulator_inf
-{
-public:
-  norm_accumulator_inf () : m_max (0) { }
-  template <typename U>
-  void accum (U val)
-  {
-    if (math::isnan (val))
-      m_max = numeric_limits<R>::NaN ();
-    else
-      m_max = std::max (m_max, std::abs (val));
+        res.xelem (j) = accj;
+      }
   }
 
-  operator R () { return m_max; }
-
-private:
-  R m_max;
-};
-
-// norm accumulator for the -inf pseudonorm (min abs value)
-template <typename R>
-class norm_accumulator_minf
-{
-public:
-  norm_accumulator_minf () : m_min (numeric_limits<R>::Inf ()) { }
-  template <typename U>
-  void accum (U val)
+  template <typename T, typename R, typename ACC>
+  void row_norms (const MArray<T>& m, MArray<R>& res, ACC acc)
   {
-    if (math::isnan (val))
-      m_min = numeric_limits<R>::NaN ();
-    else
-      m_min = std::min (m_min, std::abs (val));
-  }
-
-  operator R () { return m_min; }
+    res = MArray<R> (dim_vector (m.rows (), 1));
+    std::vector<ACC> acci (m.rows (), acc);
+    for (octave_idx_type j = 0; j < m.columns (); j++)
+      {
+        for (octave_idx_type i = 0; i < m.rows (); i++)
+          acci[i].accum (m(i, j));
+      }
 
-private:
-  R m_min;
-};
-
-// norm accumulator for the 0-pseudonorm (hamming distance)
-template <typename R>
-class norm_accumulator_0
-{
-public:
-  norm_accumulator_0 () : m_num (0) { }
-  template <typename U>
-  void accum (U val)
-  {
-    if (val != static_cast<U> (0)) ++m_num;
+    for (octave_idx_type i = 0; i < m.rows (); i++)
+      res.xelem (i) = acci[i];
   }
 
-  operator R () { return m_num; }
-
-private:
-  unsigned int m_num;
-};
-
-// OK, we're armed :) Now let's go for the fun
-
-template <typename T, typename R, typename ACC>
-inline void vector_norm (const Array<T>& v, R& res, ACC acc)
-{
-  for (octave_idx_type i = 0; i < v.numel (); i++)
-    acc.accum (v(i));
+  // sparse versions
+  template <typename T, typename R, typename ACC>
+  void column_norms (const MSparse<T>& m, MArray<R>& res, ACC acc)
+  {
+    res = MArray<R> (dim_vector (1, m.columns ()));
+    for (octave_idx_type j = 0; j < m.columns (); j++)
+      {
+        ACC accj = acc;
+        for (octave_idx_type k = m.cidx (j); k < m.cidx (j+1); k++)
+          accj.accum (m.data (k));
 
-  res = acc;
-}
-
-// dense versions
-template <typename T, typename R, typename ACC>
-void column_norms (const MArray<T>& m, MArray<R>& res, ACC acc)
-{
-  res = MArray<R> (dim_vector (1, m.columns ()));
-  for (octave_idx_type j = 0; j < m.columns (); j++)
-    {
-      ACC accj = acc;
-      for (octave_idx_type i = 0; i < m.rows (); i++)
-        accj.accum (m(i, j));
-
-      res.xelem (j) = accj;
-    }
-}
+        res.xelem (j) = accj;
+      }
+  }
 
-template <typename T, typename R, typename ACC>
-void row_norms (const MArray<T>& m, MArray<R>& res, ACC acc)
-{
-  res = MArray<R> (dim_vector (m.rows (), 1));
-  std::vector<ACC> acci (m.rows (), acc);
-  for (octave_idx_type j = 0; j < m.columns (); j++)
-    {
-      for (octave_idx_type i = 0; i < m.rows (); i++)
-        acci[i].accum (m(i, j));
-    }
-
-  for (octave_idx_type i = 0; i < m.rows (); i++)
-    res.xelem (i) = acci[i];
-}
+  template <typename T, typename R, typename ACC>
+  void row_norms (const MSparse<T>& m, MArray<R>& res, ACC acc)
+  {
+    res = MArray<R> (dim_vector (m.rows (), 1));
+    std::vector<ACC> acci (m.rows (), acc);
+    for (octave_idx_type j = 0; j < m.columns (); j++)
+      {
+        for (octave_idx_type k = m.cidx (j); k < m.cidx (j+1); k++)
+          acci[m.ridx (k)].accum (m.data (k));
+      }
 
-// sparse versions
-template <typename T, typename R, typename ACC>
-void column_norms (const MSparse<T>& m, MArray<R>& res, ACC acc)
-{
-  res = MArray<R> (dim_vector (1, m.columns ()));
-  for (octave_idx_type j = 0; j < m.columns (); j++)
-    {
-      ACC accj = acc;
-      for (octave_idx_type k = m.cidx (j); k < m.cidx (j+1); k++)
-        accj.accum (m.data (k));
-
-      res.xelem (j) = accj;
-    }
-}
+    for (octave_idx_type i = 0; i < m.rows (); i++)
+      res.xelem (i) = acci[i];
+  }
 
-template <typename T, typename R, typename ACC>
-void row_norms (const MSparse<T>& m, MArray<R>& res, ACC acc)
-{
-  res = MArray<R> (dim_vector (m.rows (), 1));
-  std::vector<ACC> acci (m.rows (), acc);
-  for (octave_idx_type j = 0; j < m.columns (); j++)
-    {
-      for (octave_idx_type k = m.cidx (j); k < m.cidx (j+1); k++)
-        acci[m.ridx (k)].accum (m.data (k));
-    }
-
-  for (octave_idx_type i = 0; i < m.rows (); i++)
-    res.xelem (i) = acci[i];
-}
-
-// now the dispatchers
+  // now the dispatchers
 #define DEFINE_DISPATCHER(FCN_NAME, ARG_TYPE, RES_TYPE)         \
   template <typename T, typename R>                             \
   RES_TYPE FCN_NAME (const ARG_TYPE& v, R p)                    \
@@ -345,224 +345,216 @@
     return res;                                                 \
   }
 
-DEFINE_DISPATCHER (vector_norm, MArray<T>, R)
-DEFINE_DISPATCHER (column_norms, MArray<T>, MArray<R>)
-DEFINE_DISPATCHER (row_norms, MArray<T>, MArray<R>)
-DEFINE_DISPATCHER (column_norms, MSparse<T>, MArray<R>)
-DEFINE_DISPATCHER (row_norms, MSparse<T>, MArray<R>)
+  DEFINE_DISPATCHER (vector_norm, MArray<T>, R)
+  DEFINE_DISPATCHER (column_norms, MArray<T>, MArray<R>)
+  DEFINE_DISPATCHER (row_norms, MArray<T>, MArray<R>)
+  DEFINE_DISPATCHER (column_norms, MSparse<T>, MArray<R>)
+  DEFINE_DISPATCHER (row_norms, MSparse<T>, MArray<R>)
 
-// The approximate subproblem in Higham's method.  Find lambda and mu such
-// that norm ([lambda, mu], p) == 1 and norm (y*lambda + col*mu, p) is
-// maximized.
-// Real version.  As in Higham's paper.
-template <typename ColVectorT, typename R>
-static void
-higham_subp (const ColVectorT& y, const ColVectorT& col,
-             octave_idx_type nsamp, R p, R& lambda, R& mu)
-{
-  R nrm = 0;
-  for (octave_idx_type i = 0; i < nsamp; i++)
-    {
-      octave_quit ();
-      R fi = i * static_cast<R> (M_PI) / nsamp;
-      R lambda1 = cos (fi);
-      R mu1 = sin (fi);
-      R lmnr = std::pow (std::pow (std::abs (lambda1), p) +
-                         std::pow (std::abs (mu1), p), 1/p);
-      lambda1 /= lmnr; mu1 /= lmnr;
-      R nrm1 = vector_norm (lambda1 * y + mu1 * col, p);
-      if (nrm1 > nrm)
-        {
-          lambda = lambda1;
-          mu = mu1;
-          nrm = nrm1;
-        }
-    }
-}
+  // The approximate subproblem in Higham's method.  Find lambda and mu such
+  // that norm ([lambda, mu], p) == 1 and norm (y*lambda + col*mu, p) is
+  // maximized.
+  // Real version.  As in Higham's paper.
+  template <typename ColVectorT, typename R>
+  static void
+  higham_subp (const ColVectorT& y, const ColVectorT& col,
+               octave_idx_type nsamp, R p, R& lambda, R& mu)
+  {
+    R nrm = 0;
+    for (octave_idx_type i = 0; i < nsamp; i++)
+      {
+        octave_quit ();
+        R fi = i * static_cast<R> (M_PI) / nsamp;
+        R lambda1 = cos (fi);
+        R mu1 = sin (fi);
+        R lmnr = std::pow (std::pow (std::abs (lambda1), p) +
+                           std::pow (std::abs (mu1), p), 1/p);
+        lambda1 /= lmnr; mu1 /= lmnr;
+        R nrm1 = vector_norm (lambda1 * y + mu1 * col, p);
+        if (nrm1 > nrm)
+          {
+            lambda = lambda1;
+            mu = mu1;
+            nrm = nrm1;
+          }
+      }
+  }
 
-// Complex version.  Higham's paper does not deal with complex case, so we
-// use a simple extension.  First, guess the magnitudes as in real version,
-// then try to rotate lambda to improve further.
-template <typename ColVectorT, typename R>
-static void
-higham_subp (const ColVectorT& y, const ColVectorT& col,
-             octave_idx_type nsamp, R p,
-             std::complex<R>& lambda, std::complex<R>& mu)
-{
-  typedef std::complex<R> CR;
-  R nrm = 0;
-  lambda = 1.0;
-  CR lamcu = lambda / std::abs (lambda);
-  // Probe magnitudes
-  for (octave_idx_type i = 0; i < nsamp; i++)
-    {
-      octave_quit ();
-      R fi = i * static_cast<R> (M_PI) / nsamp;
-      R lambda1 = cos (fi);
-      R mu1 = sin (fi);
-      R lmnr = std::pow (std::pow (std::abs (lambda1), p) +
-                         std::pow (std::abs (mu1), p), 1/p);
-      lambda1 /= lmnr; mu1 /= lmnr;
-      R nrm1 = vector_norm (lambda1 * lamcu * y + mu1 * col, p);
-      if (nrm1 > nrm)
-        {
-          lambda = lambda1 * lamcu;
-          mu = mu1;
-          nrm = nrm1;
-        }
-    }
-  R lama = std::abs (lambda);
-  // Probe orientation
-  for (octave_idx_type i = 0; i < nsamp; i++)
-    {
-      octave_quit ();
-      R fi = i * static_cast<R> (M_PI) / nsamp;
-      lamcu = CR (cos (fi), sin (fi));
-      R nrm1 = vector_norm (lama * lamcu * y + mu * col, p);
-      if (nrm1 > nrm)
-        {
-          lambda = lama * lamcu;
-          nrm = nrm1;
-        }
-    }
-}
+  // Complex version.  Higham's paper does not deal with complex case, so we
+  // use a simple extension.  First, guess the magnitudes as in real version,
+  // then try to rotate lambda to improve further.
+  template <typename ColVectorT, typename R>
+  static void
+  higham_subp (const ColVectorT& y, const ColVectorT& col,
+               octave_idx_type nsamp, R p,
+               std::complex<R>& lambda, std::complex<R>& mu)
+  {
+    typedef std::complex<R> CR;
+    R nrm = 0;
+    lambda = 1.0;
+    CR lamcu = lambda / std::abs (lambda);
+    // Probe magnitudes
+    for (octave_idx_type i = 0; i < nsamp; i++)
+      {
+        octave_quit ();
+        R fi = i * static_cast<R> (M_PI) / nsamp;
+        R lambda1 = cos (fi);
+        R mu1 = sin (fi);
+        R lmnr = std::pow (std::pow (std::abs (lambda1), p) +
+                           std::pow (std::abs (mu1), p), 1/p);
+        lambda1 /= lmnr; mu1 /= lmnr;
+        R nrm1 = vector_norm (lambda1 * lamcu * y + mu1 * col, p);
+        if (nrm1 > nrm)
+          {
+            lambda = lambda1 * lamcu;
+            mu = mu1;
+            nrm = nrm1;
+          }
+      }
+    R lama = std::abs (lambda);
+    // Probe orientation
+    for (octave_idx_type i = 0; i < nsamp; i++)
+      {
+        octave_quit ();
+        R fi = i * static_cast<R> (M_PI) / nsamp;
+        lamcu = CR (cos (fi), sin (fi));
+        R nrm1 = vector_norm (lama * lamcu * y + mu * col, p);
+        if (nrm1 > nrm)
+          {
+            lambda = lama * lamcu;
+            nrm = nrm1;
+          }
+      }
+  }
 
-// the p-dual element (should work for both real and complex)
-template <typename T, typename R>
-inline T elem_dual_p (T x, R p)
-{
-  return math::signum (x) * std::pow (std::abs (x), p-1);
-}
+  // the p-dual element (should work for both real and complex)
+  template <typename T, typename R>
+  inline T elem_dual_p (T x, R p)
+  {
+    return math::signum (x) * std::pow (std::abs (x), p-1);
+  }
 
-// the VectorT is used for vectors, but actually it has to be
-// a Matrix type to allow all the operations.  For instance SparseMatrix
-// does not support multiplication with column/row vectors.
-// the dual vector
-template <typename VectorT, typename R>
-VectorT dual_p (const VectorT& x, R p, R q)
-{
-  VectorT res (x.dims ());
-  for (octave_idx_type i = 0; i < x.numel (); i++)
-    res.xelem (i) = elem_dual_p (x(i), p);
-  return res / vector_norm (res, q);
-}
+  // the VectorT is used for vectors, but actually it has to be
+  // a Matrix type to allow all the operations.  For instance SparseMatrix
+  // does not support multiplication with column/row vectors.
+  // the dual vector
+  template <typename VectorT, typename R>
+  VectorT dual_p (const VectorT& x, R p, R q)
+  {
+    VectorT res (x.dims ());
+    for (octave_idx_type i = 0; i < x.numel (); i++)
+      res.xelem (i) = elem_dual_p (x(i), p);
+    return res / vector_norm (res, q);
+  }
 
-// Higham's hybrid method
-template <typename MatrixT, typename VectorT, typename R>
-R higham (const MatrixT& m, R p, R tol, int maxiter,
-          VectorT& x)
-{
-  x.resize (m.columns (), 1);
-  // the OSE part
-  VectorT y(m.rows (), 1, 0), z(m.rows (), 1);
-  typedef typename VectorT::element_type RR;
-  RR lambda = 0;
-  RR mu = 1;
-  for (octave_idx_type k = 0; k < m.columns (); k++)
-    {
-      octave_quit ();
-      VectorT col (m.column (k));
-      if (k > 0)
-        higham_subp (y, col, 4*k, p, lambda, mu);
-      for (octave_idx_type i = 0; i < k; i++)
-        x(i) *= lambda;
-      x(k) = mu;
-      y = lambda * y + mu * col;
-    }
-
-  // the PM part
-  x = x / vector_norm (x, p);
-  R q = p/(p-1);
+  // Higham's hybrid method
+  template <typename MatrixT, typename VectorT, typename R>
+  R higham (const MatrixT& m, R p, R tol, int maxiter,
+            VectorT& x)
+  {
+    x.resize (m.columns (), 1);
+    // the OSE part
+    VectorT y(m.rows (), 1, 0), z(m.rows (), 1);
+    typedef typename VectorT::element_type RR;
+    RR lambda = 0;
+    RR mu = 1;
+    for (octave_idx_type k = 0; k < m.columns (); k++)
+      {
+        octave_quit ();
+        VectorT col (m.column (k));
+        if (k > 0)
+          higham_subp (y, col, 4*k, p, lambda, mu);
+        for (octave_idx_type i = 0; i < k; i++)
+          x(i) *= lambda;
+        x(k) = mu;
+        y = lambda * y + mu * col;
+      }
 
-  R gamma = 0, gamma1;
-  int iter = 0;
-  while (iter < maxiter)
-    {
-      octave_quit ();
-      y = m*x;
-      gamma1 = gamma;
-      gamma = vector_norm (y, p);
-      z = dual_p (y, p, q);
-      z = z.hermitian ();
-      z = z * m;
+    // the PM part
+    x = x / vector_norm (x, p);
+    R q = p/(p-1);
 
-      if (iter > 0 && (vector_norm (z, q) <= gamma
-                       || (gamma - gamma1) <= tol*gamma))
-        break;
+    R gamma = 0, gamma1;
+    int iter = 0;
+    while (iter < maxiter)
+      {
+        octave_quit ();
+        y = m*x;
+        gamma1 = gamma;
+        gamma = vector_norm (y, p);
+        z = dual_p (y, p, q);
+        z = z.hermitian ();
+        z = z * m;
 
-      z = z.hermitian ();
-      x = dual_p (z, q, p);
-      iter++;
-    }
+        if (iter > 0 && (vector_norm (z, q) <= gamma
+                         || (gamma - gamma1) <= tol*gamma))
+          break;
 
-  return gamma;
-}
+        z = z.hermitian ();
+        x = dual_p (z, q, p);
+        iter++;
+      }
 
-// derive column vector and SVD types
+    return gamma;
+  }
 
-static const char *p_less1_gripe = "xnorm: p must be >= 1";
+  // derive column vector and SVD types
 
-// Static constant to control the maximum number of iterations.  100 seems to
-// be a good value.  Eventually, we can provide a means to change this
-// constant from Octave.
-static int max_norm_iter = 100;
+  static const char *p_less1_gripe = "xnorm: p must be >= 1";
 
-// version with SVD for dense matrices
-template <typename MatrixT, typename VectorT, typename R>
-R svd_matrix_norm (const MatrixT& m, R p, VectorT)
-{
-  // NOTE: The octave:: namespace tags are needed for the following
-  // function calls until the deprecated inline functions are removed
-  // from oct-norm.h.
+  // Static constant to control the maximum number of iterations.  100 seems to
+  // be a good value.  Eventually, we can provide a means to change this
+  // constant from Octave.
+  static int max_norm_iter = 100;
 
-  R res = 0;
-  if (p == 2)
-    {
-      math::svd<MatrixT> fact (m, math::svd<MatrixT>::Type::sigma_only);
-      res = fact.singular_values () (0, 0);
-    }
-  else if (p == 1)
-    res = octave::xcolnorms (m, static_cast<R> (1)).max ();
-  else if (lo_ieee_isinf (p) && p > 1)
-    res = octave::xrownorms (m, static_cast<R> (1)).max ();
-  else if (p > 1)
-    {
-      VectorT x;
-      const R sqrteps = std::sqrt (std::numeric_limits<R>::epsilon ());
-      res = higham (m, p, sqrteps, max_norm_iter, x);
-    }
-  else
-    (*current_liboctave_error_handler) ("%s", p_less1_gripe);
-
-  return res;
-}
+  // version with SVD for dense matrices
+  template <typename MatrixT, typename VectorT, typename R>
+  R svd_matrix_norm (const MatrixT& m, R p, VectorT)
+  {
+    R res = 0;
+    if (p == 2)
+      {
+        math::svd<MatrixT> fact (m, math::svd<MatrixT>::Type::sigma_only);
+        res = fact.singular_values () (0, 0);
+      }
+    else if (p == 1)
+      res = xcolnorms (m, static_cast<R> (1)).max ();
+    else if (lo_ieee_isinf (p) && p > 1)
+      res = xrownorms (m, static_cast<R> (1)).max ();
+    else if (p > 1)
+      {
+        VectorT x;
+        const R sqrteps = std::sqrt (std::numeric_limits<R>::epsilon ());
+        res = higham (m, p, sqrteps, max_norm_iter, x);
+      }
+    else
+      (*current_liboctave_error_handler) ("%s", p_less1_gripe);
 
-// SVD-free version for sparse matrices
-template <typename MatrixT, typename VectorT, typename R>
-R matrix_norm (const MatrixT& m, R p, VectorT)
-{
-  // NOTE: The octave:: namespace tags are needed for the following
-  // function calls until the deprecated inline functions are removed
-  // from oct-norm.h.
+    return res;
+  }
 
-  R res = 0;
-  if (p == 1)
-    res = octave::xcolnorms (m, static_cast<R> (1)).max ();
-  else if (lo_ieee_isinf (p) && p > 1)
-    res = octave::xrownorms (m, static_cast<R> (1)).max ();
-  else if (p > 1)
-    {
-      VectorT x;
-      const R sqrteps = std::sqrt (std::numeric_limits<R>::epsilon ());
-      res = higham (m, p, sqrteps, max_norm_iter, x);
-    }
-  else
-    (*current_liboctave_error_handler) ("%s", p_less1_gripe);
+  // SVD-free version for sparse matrices
+  template <typename MatrixT, typename VectorT, typename R>
+  R matrix_norm (const MatrixT& m, R p, VectorT)
+  {
+    R res = 0;
+    if (p == 1)
+      res = xcolnorms (m, static_cast<R> (1)).max ();
+    else if (lo_ieee_isinf (p) && p > 1)
+      res = xrownorms (m, static_cast<R> (1)).max ();
+    else if (p > 1)
+      {
+        VectorT x;
+        const R sqrteps = std::sqrt (std::numeric_limits<R>::epsilon ());
+        res = higham (m, p, sqrteps, max_norm_iter, x);
+      }
+    else
+      (*current_liboctave_error_handler) ("%s", p_less1_gripe);
 
-  return res;
-}
+    return res;
+  }
 
-// and finally, here's what we've promised in the header file
+  // and finally, here's what we've promised in the header file
 
 #define DEFINE_XNORM_FCNS(PREFIX, RTYPE)                                \
   RTYPE xnorm (const PREFIX##ColumnVector& x, RTYPE p)                  \
@@ -582,21 +574,21 @@
     return vector_norm (x, static_cast<RTYPE> (2));                     \
   }
 
-DEFINE_XNORM_FCNS(, double)
-DEFINE_XNORM_FCNS(Complex, double)
-DEFINE_XNORM_FCNS(Float, float)
-DEFINE_XNORM_FCNS(FloatComplex, float)
+  DEFINE_XNORM_FCNS(, double)
+  DEFINE_XNORM_FCNS(Complex, double)
+  DEFINE_XNORM_FCNS(Float, float)
+  DEFINE_XNORM_FCNS(FloatComplex, float)
 
-// this is needed to avoid copying the sparse matrix for xfrobnorm
-template <typename T, typename R>
-inline void array_norm_2 (const T *v, octave_idx_type n, R& res)
-{
-  norm_accumulator_2<R> acc;
-  for (octave_idx_type i = 0; i < n; i++)
-    acc.accum (v[i]);
+  // this is needed to avoid copying the sparse matrix for xfrobnorm
+  template <typename T, typename R>
+  inline void array_norm_2 (const T *v, octave_idx_type n, R& res)
+  {
+    norm_accumulator_2<R> acc;
+    for (octave_idx_type i = 0; i < n; i++)
+      acc.accum (v[i]);
 
-  res = acc;
-}
+    res = acc;
+  }
 
 #define DEFINE_XNORM_SPARSE_FCNS(PREFIX, RTYPE)                 \
   RTYPE xnorm (const Sparse##PREFIX##Matrix& x, RTYPE p)        \
@@ -610,8 +602,8 @@
     return res;                                                 \
   }
 
-DEFINE_XNORM_SPARSE_FCNS(, double)
-DEFINE_XNORM_SPARSE_FCNS(Complex, double)
+  DEFINE_XNORM_SPARSE_FCNS(, double)
+  DEFINE_XNORM_SPARSE_FCNS(Complex, double)
 
 #define DEFINE_COLROW_NORM_FCNS(PREFIX, RPREFIX, RTYPE)         \
   RPREFIX##RowVector                                            \
@@ -625,12 +617,12 @@
     return row_norms (m, p);                                    \
   }                                                             \
 
-DEFINE_COLROW_NORM_FCNS(,, double)
-DEFINE_COLROW_NORM_FCNS(Complex,, double)
-DEFINE_COLROW_NORM_FCNS(Float, Float, float)
-DEFINE_COLROW_NORM_FCNS(FloatComplex, Float, float)
+  DEFINE_COLROW_NORM_FCNS(, , double)
+  DEFINE_COLROW_NORM_FCNS(Complex, , double)
+  DEFINE_COLROW_NORM_FCNS(Float, Float, float)
+  DEFINE_COLROW_NORM_FCNS(FloatComplex, Float, float)
 
-DEFINE_COLROW_NORM_FCNS(Sparse,, double)
-DEFINE_COLROW_NORM_FCNS(SparseComplex,, double)
+  DEFINE_COLROW_NORM_FCNS(Sparse, , double)
+  DEFINE_COLROW_NORM_FCNS(SparseComplex, , double)
 
 OCTAVE_END_NAMESPACE(octave)
--- a/liboctave/numeric/oct-norm.h	Fri Dec 02 10:11:46 2022 -0500
+++ b/liboctave/numeric/oct-norm.h	Fri Dec 02 10:12:40 2022 -0500
@@ -32,14 +32,6 @@
 
 #include "oct-cmplx.h"
 
-// The remaining includes can be removed when the deprecated functions
-// at the end of this file are removed.
-
-#include "dColVector.h"
-#include "dRowVector.h"
-#include "fColVector.h"
-#include "fRowVector.h"
-
 OCTAVE_BEGIN_NAMESPACE(octave)
 
 extern OCTAVE_API double xnorm (const ColumnVector&, double p = 2);
@@ -88,198 +80,4 @@
 
 OCTAVE_END_NAMESPACE(octave)
 
-#if defined (OCTAVE_PROVIDE_DEPRECATED_SYMBOLS)
-OCTAVE_DEPRECATED (7, "use 'octave::xnorm' instead")
-inline double xnorm (const ColumnVector& v, double p = 2)
-{
-  return octave::xnorm (v, p);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::xnorm' instead")
-inline double xnorm (const RowVector& v, double p = 2)
-{
-  return octave::xnorm (v, p);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::xnorm' instead")
-inline double xnorm (const Matrix& m, double p = 2)
-{
-  return octave::xnorm (m, p);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::xfrobnorm' instead")
-inline double xfrobnorm (const Matrix& m)
-{
-  return octave::xfrobnorm (m);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::xnorm' instead")
-inline double xnorm (const ComplexColumnVector& v, double p = 2)
-{
-  return octave::xnorm (v, p);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::xnorm' instead")
-inline double xnorm (const ComplexRowVector& v, double p = 2)
-{
-  return octave::xnorm (v, p);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::xnorm' instead")
-inline double xnorm (const ComplexMatrix& m, double p = 2)
-{
-  return octave::xnorm (m, p);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::xfrobnorm' instead")
-inline double xfrobnorm (const ComplexMatrix& m)
-{
-  return octave::xfrobnorm (m);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::xnorm' instead")
-inline float xnorm (const FloatColumnVector& v, float p = 2)
-{
-  return octave::xnorm (v, p);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::xnorm' instead")
-inline float xnorm (const FloatRowVector& v, float p = 2)
-{
-  return octave::xnorm (v, p);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::xnorm' instead")
-inline float xnorm (const FloatMatrix& m, float p = 2)
-{
-  return octave::xnorm (m, p);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::xfrobnorm' instead")
-inline float xfrobnorm (const FloatMatrix& m)
-{
-  return octave::xfrobnorm (m);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::xnorm' instead")
-inline float xnorm (const FloatComplexColumnVector& v, float p = 2)
-{
-  return octave::xnorm (v, p);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::xnorm' instead")
-inline float xnorm (const FloatComplexRowVector& v, float p = 2)
-{
-  return octave::xnorm (v, p);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::xnorm' instead")
-inline float xnorm (const FloatComplexMatrix& m, float p = 2)
-{
-  return octave::xnorm (m, p);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::xfrobnorm' instead")
-inline float xfrobnorm (const FloatComplexMatrix& m)
-{
-  return octave::xfrobnorm (m);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::xnorm' instead")
-inline double xnorm (const SparseMatrix& m, double p = 2)
-{
-  return octave::xnorm (m, p);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::xfrobnorm' instead")
-inline double xfrobnorm (const SparseMatrix& m)
-{
-  return octave::xfrobnorm (m);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::xnorm' instead")
-inline double xnorm (const SparseComplexMatrix& m, double p = 2)
-{
-  return octave::xnorm (m, p);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::xfrobnorm' instead")
-inline double xfrobnorm (const SparseComplexMatrix& m)
-{
-  return octave::xfrobnorm (m);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::xcolnorms' instead")
-inline RowVector xcolnorms (const Matrix& m, double p = 2)
-{
-  return octave::xcolnorms (m, p);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::xrownorms' instead")
-inline ColumnVector xrownorms (const Matrix& m, double p = 2)
-{
-  return octave::xrownorms (m, p);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::xcolnorms' instead")
-inline RowVector xcolnorms (const ComplexMatrix& m, double p = 2)
-{
-  return octave::xcolnorms (m, p);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::xrownorms' instead")
-inline ColumnVector xrownorms (const ComplexMatrix& m, double p = 2)
-{
-  return octave::xrownorms (m, p);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::xcolnorms' instead")
-inline FloatRowVector xcolnorms (const FloatMatrix& m, float p = 2)
-{
-  return octave::xcolnorms (m, p);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::xrownorms' instead")
-inline FloatColumnVector xrownorms (const FloatMatrix& m, float p = 2)
-{
-  return octave::xrownorms (m, p);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::xcolnorms' instead")
-inline FloatRowVector xcolnorms (const FloatComplexMatrix& m, float p = 2)
-{
-  return octave::xcolnorms (m, p);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::xrownorms' instead")
-inline FloatColumnVector xrownorms (const FloatComplexMatrix& m, float p = 2)
-{
-  return octave::xrownorms (m, p);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::xcolnorms' instead")
-inline RowVector xcolnorms (const SparseMatrix& m, double p = 2)
-{
-  return octave::xcolnorms (m, p);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::xrownorms' instead")
-inline ColumnVector xrownorms (const SparseMatrix& m, double p = 2)
-{
-  return octave::xrownorms (m, p);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::xcolnorms' instead")
-inline RowVector xcolnorms (const SparseComplexMatrix& m, double p = 2)
-{
-  return octave::xcolnorms (m, p);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::xrownorms' instead")
-inline ColumnVector xrownorms (const SparseComplexMatrix& m, double p = 2)
-{
-  return octave::xrownorms (m, p);
-}
 #endif
-
-#endif
--- a/liboctave/numeric/oct-spparms.h	Fri Dec 02 10:11:46 2022 -0500
+++ b/liboctave/numeric/oct-spparms.h	Fri Dec 02 10:12:40 2022 -0500
@@ -116,9 +116,4 @@
 
 OCTAVE_END_NAMESPACE(octave)
 
-#if defined (OCTAVE_PROVIDE_DEPRECATED_SYMBOLS)
-OCTAVE_DEPRECATED (7, "use 'octave::sparse_params' instead")
-typedef octave::sparse_params octave_sparse_params;
 #endif
-
-#endif
--- a/liboctave/util/lo-ieee.h	Fri Dec 02 10:11:46 2022 -0500
+++ b/liboctave/util/lo-ieee.h	Fri Dec 02 10:12:40 2022 -0500
@@ -156,17 +156,4 @@
 
 #endif
 
-#if defined (OCTAVE_PROVIDE_DEPRECATED_SYMBOLS)
-
-OCTAVE_DEPRECATED (7, "use '__lo_ieee_isfinite' instead")
-inline int __lo_ieee_finite (double x) { return __lo_ieee_isfinite (x); }
-
-OCTAVE_DEPRECATED (7, "use '__lo_ieee_float_isfinite' instead")
-inline int __lo_ieee_float_finite (float x)
-{ return __lo_ieee_float_isfinite (x); }
-
-#define lo_ieee_finite(x) lo_ieee_isfinite(x)
-
 #endif
-
-#endif
--- a/liboctave/util/lo-utils.cc	Fri Dec 02 10:11:46 2022 -0500
+++ b/liboctave/util/lo-utils.cc	Fri Dec 02 10:12:40 2022 -0500
@@ -47,473 +47,479 @@
 
 OCTAVE_BEGIN_NAMESPACE(octave)
 
-bool is_int_or_inf_or_nan (double x)
-{
-  return math::isnan (x) || math::x_nint (x) == x;
-}
+  bool is_int_or_inf_or_nan (double x)
+  {
+    return math::isnan (x) || math::x_nint (x) == x;
+  }
+
+  bool too_large_for_float (double x)
+  {
+    return (math::isfinite (x)
+            && fabs (x) > std::numeric_limits<float>::max ());
+  }
+
+  bool too_large_for_float (const Complex& x)
+  {
+    return (too_large_for_float (x.real ())
+            || too_large_for_float (x.imag ()));
+  }
+
+  bool is_int_or_inf_or_nan (float x)
+  {
+    return math::isnan (x) || math::x_nint (x) == x;
+  }
 
-bool too_large_for_float (double x)
-{
-  return (math::isfinite (x)
-          && fabs (x) > std::numeric_limits<float>::max ());
-}
+  // Save a string.
+
+  char * strsave (const char *s)
+  {
+    if (! s)
+      return nullptr;
 
-bool too_large_for_float (const Complex& x)
-{
-  return (too_large_for_float (x.real ())
-          || too_large_for_float (x.imag ()));
-}
+    int len = strlen (s);
+    char *tmp = new char [len+1];
+    tmp = strcpy (tmp, s);
+    return tmp;
+  }
+
+  std::string fgets (FILE *f)
+  {
+    bool eof;
+    return fgets (f, eof);
+  }
+
+  std::string fgets (FILE *f, bool& eof)
+  {
+    eof = false;
+
+    std::string retval;
 
-bool is_int_or_inf_or_nan (float x)
-{
-  return math::isnan (x) || math::x_nint (x) == x;
-}
+    int grow_size = 1024;
+    int max_size = grow_size;
+
+    char *buf = static_cast<char *> (std::malloc (max_size));
+    if (! buf)
+      (*current_liboctave_error_handler) ("octave_fgets: unable to malloc %d bytes", max_size);
 
-// Save a string.
+    char *bufptr = buf;
+    int len = 0;
 
-char * strsave (const char *s)
-{
-  if (! s)
-    return nullptr;
+    do
+      {
+        if (std::fgets (bufptr, grow_size, f))
+          {
+            len = strlen (bufptr);
 
-  int len = strlen (s);
-  char *tmp = new char [len+1];
-  tmp = strcpy (tmp, s);
-  return tmp;
-}
+            if (len == grow_size - 1)
+              {
+                int tmp = bufptr - buf + grow_size - 1;
+                grow_size *= 2;
+                max_size += grow_size;
+                auto tmpbuf = static_cast<char *> (std::realloc (buf, max_size));
+                if (! tmpbuf)
+                  {
+                    free (buf);
+                    (*current_liboctave_error_handler) ("octave_fgets: unable to realloc %d bytes", max_size);
+                  }
+                buf = tmpbuf;
+                bufptr = buf + tmp;
 
-std::string fgets (FILE *f)
-{
-  bool eof;
-  return fgets (f, eof);
-}
+                if (*(bufptr-1) == '\n')
+                  {
+                    *bufptr = '\0';
+                    retval = buf;
+                  }
+              }
+            else if (bufptr[len-1] != '\n')
+              {
+                bufptr[len++] = '\n';
+                bufptr[len] = '\0';
+                retval = buf;
+              }
+            else
+              retval = buf;
+          }
+        else
+          {
+            if (len == 0)
+              {
+                eof = true;
 
-std::string fgets (FILE *f, bool& eof)
-{
-  eof = false;
+                free (buf);
+
+                buf = nullptr;
+              }
+
+            break;
+          }
+      }
+    while (retval.empty ());
+
+    free (buf);
+
+    octave_quit ();
 
-  std::string retval;
+    return retval;
+  }
 
-  int grow_size = 1024;
-  int max_size = grow_size;
+  std::string fgetl (FILE *f)
+  {
+    bool eof;
+    return fgetl (f, eof);
+  }
+
+  std::string fgetl (FILE *f, bool& eof)
+  {
+    std::string retval = fgets (f, eof);
+
+    if (! retval.empty () && retval.back () == '\n')
+      retval.pop_back ();
 
-  char *buf = static_cast<char *> (std::malloc (max_size));
-  if (! buf)
-    (*current_liboctave_error_handler) ("octave_fgets: unable to malloc %d bytes", max_size);
+    return retval;
+  }
+
+  template <typename T>
+  T
+  read_value (std::istream& is)
+  {
+    T retval;
+    is >> retval;
+    return retval;
+  }
 
-  char *bufptr = buf;
-  int len = 0;
+  template OCTAVE_API bool read_value<bool> (std::istream& is);
+  template OCTAVE_API octave_int8 read_value<octave_int8> (std::istream& is);
+  template OCTAVE_API octave_int16 read_value<octave_int16> (std::istream& is);
+  template OCTAVE_API octave_int32 read_value<octave_int32> (std::istream& is);
+  template OCTAVE_API octave_int64 read_value<octave_int64> (std::istream& is);
+  template OCTAVE_API octave_uint8 read_value<octave_uint8> (std::istream& is);
+  template OCTAVE_API octave_uint16 read_value<octave_uint16> (std::istream& is);
+  template OCTAVE_API octave_uint32 read_value<octave_uint32> (std::istream& is);
+  template OCTAVE_API octave_uint64 read_value<octave_uint64> (std::istream& is);
 
-  do
-    {
-      if (std::fgets (bufptr, grow_size, f))
+  // Note that the caller is responsible for repositioning the stream on
+  // failure.
+
+  template <typename T>
+  T
+  read_inf_nan_na (std::istream& is, char c0)
+  {
+    T val = 0.0;
+
+    switch (c0)
+      {
+      case 'i': case 'I':
         {
-          len = strlen (bufptr);
-
-          if (len == grow_size - 1)
+          char c1 = is.get ();
+          if (c1 == 'n' || c1 == 'N')
             {
-              int tmp = bufptr - buf + grow_size - 1;
-              grow_size *= 2;
-              max_size += grow_size;
-              auto tmpbuf = static_cast<char *> (std::realloc (buf, max_size));
-              if (! tmpbuf)
+              char c2 = is.get ();
+              if (c2 == 'f' || c2 == 'F')
                 {
-                  free (buf);
-                  (*current_liboctave_error_handler) ("octave_fgets: unable to realloc %d bytes", max_size);
+                  val = std::numeric_limits<T>::infinity ();
+                  is.peek ();  // Potentially set EOF bit
                 }
-              buf = tmpbuf;
-              bufptr = buf + tmp;
+              else
+                is.setstate (std::ios::failbit);
+            }
+          else
+            is.setstate (std::ios::failbit);
+        }
+        break;
 
-              if (*(bufptr-1) == '\n')
+      case 'n': case 'N':
+        {
+          char c1 = is.get ();
+          if (c1 == 'a' || c1 == 'A')
+            {
+              char c2 = is.get ();
+              if (c2 == 'n' || c2 == 'N')
                 {
-                  *bufptr = '\0';
-                  retval = buf;
+                  val = std::numeric_limits<T>::quiet_NaN ();
+                  is.peek ();  // Potentially set EOF bit
+                }
+              else
+                {
+                  val = numeric_limits<T>::NA ();
+                  if (c2 != std::istream::traits_type::eof ())
+                    is.putback (c2);
+                  else
+                    is.clear (is.rdstate () & ~std::ios::failbit);
                 }
             }
-          else if (bufptr[len-1] != '\n')
-            {
-              bufptr[len++] = '\n';
-              bufptr[len] = '\0';
-              retval = buf;
-            }
           else
-            retval = buf;
+            is.setstate (std::ios::failbit);
         }
-      else
+        break;
+
+      default:
+        (*current_liboctave_error_handler)
+          ("read_inf_nan_na: invalid character '%c'", c0);
+      }
+
+    return val;
+  }
+
+  // Read a double value.  Discard any sign on NaN and NA.
+
+  template <typename T>
+  double
+  read_fp_value (std::istream& is)
+  {
+    T val = 0.0;
+
+    // FIXME: resetting stream position is likely to fail unless we are
+    //        reading from a file.
+    std::streampos pos = is.tellg ();
+
+    is >> std::ws;  // skip through whitespace and advance stream pointer
+
+    bool neg = false;
+    char c1 = is.get ();
+    switch (c1)
+      {
+      case '-':
+        neg = true;
+        OCTAVE_FALLTHROUGH;
+
+      case '+':
         {
-          if (len == 0)
+          char c2 = 0;
+          c2 = is.get ();
+          if (c2 == 'i' || c2 == 'I' || c2 == 'n' || c2 == 'N')
+            val = read_inf_nan_na<T> (is, c2);
+          else if (isspace (c2))
+            is.setstate (std::ios::failbit);
+          else
             {
-              eof = true;
-
-              free (buf);
-
-              buf = nullptr;
+              is.putback (c2);
+              is >> val;
             }
 
-          break;
+          if (neg && ! math::isnan (val) && ! is.fail ())
+            val = -val;
         }
-    }
-  while (retval.empty ());
-
-  free (buf);
-
-  octave_quit ();
-
-  return retval;
-}
+        break;
 
-std::string fgetl (FILE *f)
-{
-  bool eof;
-  return fgetl (f, eof);
-}
+      case 'i': case 'I':
+      case 'n': case 'N':
+        val = read_inf_nan_na<T> (is, c1);
+        break;
 
-std::string fgetl (FILE *f, bool& eof)
-{
-  std::string retval = fgets (f, eof);
-
-  if (! retval.empty () && retval.back () == '\n')
-    retval.pop_back ();
-
-  return retval;
-}
+      default:
+        is.putback (c1);
+        is >> val;
+        break;
+      }
 
-template <typename T>
-T
-read_value (std::istream& is)
-{
-  T retval;
-  is >> retval;
-  return retval;
-}
+    std::ios::iostate status = is.rdstate ();
+    if (status & std::ios::failbit)
+      {
+        // Convert MAX_VAL returned by C++ streams for very large numbers to Inf
+        if (val == std::numeric_limits<T>::max ())
+          {
+            if (neg)
+              val = -std::numeric_limits<T>::infinity ();
+            else
+              val = std::numeric_limits<T>::infinity ();
+            is.clear (status & ~std::ios::failbit);
+          }
+        else
+          {
+            // True error.
+            // Reset stream to original position, clear eof bit, pass status on.
+            is.clear ();
+            is.seekg (pos);
+            is.setstate (status & ~std::ios_base::eofbit);
+          }
+      }
 
-template OCTAVE_API bool read_value<bool> (std::istream& is);
-template OCTAVE_API octave_int8 read_value<octave_int8> (std::istream& is);
-template OCTAVE_API octave_int16 read_value<octave_int16> (std::istream& is);
-template OCTAVE_API octave_int32 read_value<octave_int32> (std::istream& is);
-template OCTAVE_API octave_int64 read_value<octave_int64> (std::istream& is);
-template OCTAVE_API octave_uint8 read_value<octave_uint8> (std::istream& is);
-template OCTAVE_API octave_uint16 read_value<octave_uint16> (std::istream& is);
-template OCTAVE_API octave_uint32 read_value<octave_uint32> (std::istream& is);
-template OCTAVE_API octave_uint64 read_value<octave_uint64> (std::istream& is);
+    return val;
+  }
 
-// Note that the caller is responsible for repositioning the stream on
-// failure.
+  template <typename T>
+  std::complex<T>
+  read_cx_fp_value (std::istream& is)
+  {
+    T re = 0.0;
+    T im = 0.0;
 
-template <typename T>
-T
-read_inf_nan_na (std::istream& is, char c0)
-{
-  T val = 0.0;
+    std::complex<T> cx = 0.0;
+
+    char ch = ' ';
 
-  switch (c0)
-    {
-    case 'i': case 'I':
+    while (isspace (ch))
+      ch = is.get ();
+
+    if (ch == '(')
       {
-        char c1 = is.get ();
-        if (c1 == 'n' || c1 == 'N')
+        re = read_value<T> (is);
+        ch = is.get ();
+
+        if (ch == ',')
           {
-            char c2 = is.get ();
-            if (c2 == 'f' || c2 == 'F')
-              val = std::numeric_limits<T>::infinity ();
+            im = read_value<T> (is);
+            ch = is.get ();
+
+            if (ch == ')')
+              cx = std::complex<T> (re, im);
             else
               is.setstate (std::ios::failbit);
           }
-        else
-          is.setstate (std::ios::failbit);
-      }
-      break;
-
-    case 'n': case 'N':
-      {
-        char c1 = is.get ();
-        if (c1 == 'a' || c1 == 'A')
-          {
-            char c2 = is.get ();
-            if (c2 == 'n' || c2 == 'N')
-              val = std::numeric_limits<T>::quiet_NaN ();
-            else
-              {
-                val = numeric_limits<T>::NA ();
-                if (c2 != std::istream::traits_type::eof ())
-                  is.putback (c2);
-                else
-                  is.clear (is.rdstate () & ~std::ios::failbit);
-              }
-          }
+        else if (ch == ')')
+          cx = re;
         else
           is.setstate (std::ios::failbit);
       }
-      break;
-
-    default:
-      (*current_liboctave_error_handler)
-        ("read_inf_nan_na: invalid character '%c'", c0);
-    }
-
-  return val;
-}
-
-// Read a double value.  Discard any sign on NaN and NA.
-
-template <typename T>
-double
-read_fp_value (std::istream& is)
-{
-  T val = 0.0;
-
-  // FIXME: resetting stream position is likely to fail unless we are
-  // reading from a file.
-  std::streampos pos = is.tellg ();
-
-  char c1 = ' ';
+    else
+      {
+        is.putback (ch);
+        cx = read_value<T> (is);
+      }
 
-  while (isspace (c1))
-    c1 = is.get ();
-
-  bool neg = false;
-
-  switch (c1)
-    {
-    case '-':
-      neg = true;
-      OCTAVE_FALLTHROUGH;
+    return cx;
+  }
 
-    case '+':
-      {
-        char c2 = 0;
-        c2 = is.get ();
-        if (c2 == 'i' || c2 == 'I' || c2 == 'n' || c2 == 'N')
-          val = read_inf_nan_na<T> (is, c2);
-        else
-          {
-            is.putback (c2);
-            is >> val;
-          }
+  // FIXME: Could we use traits and enable_if to avoid duplication in the
+  // following specializations?
 
-        if (neg && ! is.fail ())
-          val = -val;
-      }
-      break;
+  template <> OCTAVE_API double read_value (std::istream& is)
+  {
+    return read_fp_value<double> (is);
+  }
 
-    case 'i': case 'I':
-    case 'n': case 'N':
-      val = read_inf_nan_na<T> (is, c1);
-      break;
+  template <> OCTAVE_API Complex read_value (std::istream& is)
+  {
+    return read_cx_fp_value<double> (is);
+  }
 
-    default:
-      is.putback (c1);
-      is >> val;
-      break;
-    }
+  template <> OCTAVE_API float read_value (std::istream& is)
+  {
+    return read_fp_value<float> (is);
+  }
 
-  std::ios::iostate status = is.rdstate ();
-  if (status & std::ios::failbit)
-    {
-      // Convert MAX_VAL returned by C++ streams for very large numbers to Inf
-      if (val == std::numeric_limits<T>::max ())
-        {
-          if (neg)
-            val = -std::numeric_limits<T>::infinity ();
-          else
-            val = std::numeric_limits<T>::infinity ();
-          is.clear (status & ~std::ios::failbit);
-        }
-      else
-        {
-          // True error.  Reset stream to original position and pass status on.
-          is.clear ();
-          is.seekg (pos);
-          is.setstate (status);
-        }
-    }
-
-  return val;
-}
+  template <> OCTAVE_API FloatComplex read_value (std::istream& is)
+  {
+    return read_cx_fp_value<float> (is);
+  }
 
-template <typename T>
-std::complex<T>
-read_cx_fp_value (std::istream& is)
-{
-  T re = 0.0;
-  T im = 0.0;
-
-  std::complex<T> cx = 0.0;
-
-  char ch = ' ';
-
-  while (isspace (ch))
-    ch = is.get ();
-
-  if (ch == '(')
-    {
-      re = read_value<T> (is);
-      ch = is.get ();
-
-      if (ch == ',')
-        {
-          im = read_value<T> (is);
-          ch = is.get ();
+  template <typename T>
+  void
+  write_value (std::ostream& os, const T& value)
+  {
+    os << value;
+  }
 
-          if (ch == ')')
-            cx = std::complex<T> (re, im);
-          else
-            is.setstate (std::ios::failbit);
-        }
-      else if (ch == ')')
-        cx = re;
-      else
-        is.setstate (std::ios::failbit);
-    }
-  else
-    {
-      is.putback (ch);
-      cx = read_value<T> (is);
-    }
-
-  return cx;
-}
-
-// FIXME: Could we use traits and enable_if to avoid duplication in the
-// following specializations?
+  template OCTAVE_API void
+  write_value<bool> (std::ostream& os, const bool& value);
+  template OCTAVE_API void
+  write_value<octave_int8> (std::ostream& os, const octave_int8& value);
+  template OCTAVE_API void
+  write_value<octave_int16> (std::ostream& os, const octave_int16& value);
+  template OCTAVE_API void
+  write_value<octave_int32> (std::ostream& os, const octave_int32& value);
+  template OCTAVE_API void
+  write_value<octave_int64> (std::ostream& os, const octave_int64& value);
+  template OCTAVE_API void
+  write_value<octave_uint8> (std::ostream& os, const octave_uint8& value);
+  template OCTAVE_API void
+  write_value<octave_uint16> (std::ostream& os, const octave_uint16& value);
+  template OCTAVE_API void
+  write_value<octave_uint32> (std::ostream& os, const octave_uint32& value);
+  template OCTAVE_API void
+  write_value<octave_uint64> (std::ostream& os, const octave_uint64& value);
 
-template <> OCTAVE_API double read_value (std::istream& is)
-{
-                                          return read_fp_value<double> (is);
-}
-
-template <> OCTAVE_API Complex read_value (std::istream& is)
-{
-                                           return read_cx_fp_value<double> (is);
-}
+  // Note: precision is supposed to be managed outside of this function by
+  // setting stream parameters.
 
-template <> OCTAVE_API float read_value (std::istream& is)
-{
-                                         return read_fp_value<float> (is);
-}
-
-template <> OCTAVE_API FloatComplex read_value (std::istream& is)
-{
-                                                return read_cx_fp_value<float> (is);
-}
-
-template <typename T>
-void
-write_value (std::ostream& os, const T& value)
-{
-  os << value;
-}
+  template <> OCTAVE_API void
+  write_value (std::ostream& os, const double& value)
+  {
+    if (lo_ieee_is_NA (value))
+      os << "NA";
+    else if (lo_ieee_isnan (value))
+      os << "NaN";
+    else if (lo_ieee_isinf (value))
+      os << (value < 0 ? "-Inf" : "Inf");
+    else
+      os << value;
+  }
 
-template OCTAVE_API void
-write_value<bool> (std::ostream& os, const bool& value);
-template OCTAVE_API void
-write_value<octave_int8> (std::ostream& os, const octave_int8& value);
-template OCTAVE_API void
-write_value<octave_int16> (std::ostream& os, const octave_int16& value);
-template OCTAVE_API void
-write_value<octave_int32> (std::ostream& os, const octave_int32& value);
-template OCTAVE_API void
-write_value<octave_int64> (std::ostream& os, const octave_int64& value);
-template OCTAVE_API void
-write_value<octave_uint8> (std::ostream& os, const octave_uint8& value);
-template OCTAVE_API void
-write_value<octave_uint16> (std::ostream& os, const octave_uint16& value);
-template OCTAVE_API void
-write_value<octave_uint32> (std::ostream& os, const octave_uint32& value);
-template OCTAVE_API void
-write_value<octave_uint64> (std::ostream& os, const octave_uint64& value);
+  template <> OCTAVE_API void
+  write_value (std::ostream& os, const Complex& value)
+  {
+    os << '(';
+    write_value<double> (os, real (value));
+    os << ',';
+    write_value<double> (os, imag (value));
+    os << ')';
+  }
 
-// Note: precision is supposed to be managed outside of this function by
-// setting stream parameters.
-
-template <> OCTAVE_API void
-write_value (std::ostream& os, const double& value)
-{
-  if (lo_ieee_is_NA (value))
-    os << "NA";
-  else if (lo_ieee_isnan (value))
-    os << "NaN";
-  else if (lo_ieee_isinf (value))
-    os << (value < 0 ? "-Inf" : "Inf");
-  else
-    os << value;
-}
+  // Note: precision is supposed to be managed outside of this function by
+  // setting stream parameters.
 
-template <> OCTAVE_API void
-write_value (std::ostream& os, const Complex& value)
-{
-  os << '(';
-  write_value<double> (os, real (value));
-  os << ',';
-  write_value<double> (os, imag (value));
-  os << ')';
-}
-
-// Note: precision is supposed to be managed outside of this function by
-// setting stream parameters.
+  template <> OCTAVE_API void
+  write_value (std::ostream& os, const float& value)
+  {
+    if (lo_ieee_is_NA (value))
+      os << "NA";
+    else if (lo_ieee_isnan (value))
+      os << "NaN";
+    else if (lo_ieee_isinf (value))
+      os << (value < 0 ? "-Inf" : "Inf");
+    else
+      os << value;
+  }
 
-template <> OCTAVE_API void
-write_value (std::ostream& os, const float& value)
-{
-  if (lo_ieee_is_NA (value))
-    os << "NA";
-  else if (lo_ieee_isnan (value))
-    os << "NaN";
-  else if (lo_ieee_isinf (value))
-    os << (value < 0 ? "-Inf" : "Inf");
-  else
-    os << value;
-}
-
-template <> OCTAVE_API void
-write_value (std::ostream& os, const FloatComplex& value)
-{
-  os << '(';
-  write_value<float> (os, real (value));
-  os << ',';
-  write_value<float> (os, imag (value));
-  os << ')';
-}
+  template <> OCTAVE_API void
+  write_value (std::ostream& os, const FloatComplex& value)
+  {
+    os << '(';
+    write_value<float> (os, real (value));
+    os << ',';
+    write_value<float> (os, imag (value));
+    os << ')';
+  }
 
 OCTAVE_BEGIN_NAMESPACE(math)
 
-bool int_multiply_overflow (int a, int b, int *r)
-{
-  return octave_i_multiply_overflow_wrapper (a, b, r);
-}
+    bool int_multiply_overflow (int a, int b, int *r)
+    {
+      return octave_i_multiply_overflow_wrapper (a, b, r);
+    }
 
-bool int_multiply_overflow (long int a, long int b, long int *r)
-{
-  return octave_li_multiply_overflow_wrapper (a, b, r);
-}
+    bool int_multiply_overflow (long int a, long int b, long int *r)
+    {
+      return octave_li_multiply_overflow_wrapper (a, b, r);
+    }
 
 #if defined (OCTAVE_HAVE_LONG_LONG_INT)
-bool int_multiply_overflow (long long int a, long long int b,
-                            long long int *r)
-{
-  return octave_lli_multiply_overflow_wrapper (a, b, r);
-}
+    bool int_multiply_overflow (long long int a, long long int b,
+                                long long int *r)
+    {
+      return octave_lli_multiply_overflow_wrapper (a, b, r);
+    }
 #endif
 
-bool int_multiply_overflow (unsigned int a, unsigned int b,
-                            unsigned int *r)
-{
-  return octave_ui_multiply_overflow_wrapper (a, b, r);
-}
+    bool int_multiply_overflow (unsigned int a, unsigned int b,
+                                unsigned int *r)
+    {
+      return octave_ui_multiply_overflow_wrapper (a, b, r);
+    }
 
-bool int_multiply_overflow (unsigned long int a, unsigned long int b,
-                            unsigned long int *r)
-{
-  return octave_uli_multiply_overflow_wrapper (a, b, r);
-}
+    bool int_multiply_overflow (unsigned long int a, unsigned long int b,
+                                unsigned long int *r)
+    {
+      return octave_uli_multiply_overflow_wrapper (a, b, r);
+    }
 
 #if defined (OCTAVE_HAVE_UNSIGNED_LONG_LONG_INT)
-bool int_multiply_overflow (unsigned long long int a,
-                            unsigned long long int b,
-                            unsigned long long int *r)
-{
-  return octave_ulli_multiply_overflow_wrapper (a, b, r);
-}
+    bool int_multiply_overflow (unsigned long long int a,
+                                unsigned long long int b,
+                                unsigned long long int *r)
+    {
+      return octave_ulli_multiply_overflow_wrapper (a, b, r);
+    }
 #endif
 
 OCTAVE_END_NAMESPACE(math)
--- a/liboctave/util/lo-utils.h	Fri Dec 02 10:11:46 2022 -0500
+++ b/liboctave/util/lo-utils.h	Fri Dec 02 10:12:40 2022 -0500
@@ -137,146 +137,4 @@
 OCTAVE_END_NAMESPACE(math)
 OCTAVE_END_NAMESPACE(octave)
 
-#if defined (OCTAVE_PROVIDE_DEPRECATED_SYMBOLS)
-template <typename F, typename T, bool zero>
-OCTAVE_DEPRECATED (7, "use 'octave::any_all_test' instead")
-bool
-any_all_test (F fcn, const T *m, octave_idx_type len)
-{
-  return octave::any_all_test<F, T, zero> (fcn, m, len);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::is_int_or_inf_or_nan' instead")
-inline bool xis_int_or_inf_or_nan (double x)
-{
-  return octave::is_int_or_inf_or_nan (x);
-}
-
-template <typename T>
-OCTAVE_DEPRECATED (7, "use 'octave::is_one_or_zero' instead")
-bool
-xis_one_or_zero (const T& x)
-{
-  return octave::is_one_or_zero (x);
-}
-
-template <typename T>
-OCTAVE_DEPRECATED (7, "use 'octave::is_zero' instead")
-bool
-xis_zero (const T& x)
-{
-  return octave::is_zero (x);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::' instead")
-inline bool xtoo_large_for_float (double x)
-{
-  return octave::too_large_for_float (x);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::' instead")
-inline bool xtoo_large_for_float (const Complex&  x)
-{
-  return octave::too_large_for_float (x);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::' instead")
-inline bool xis_int_or_inf_or_nan (float x)
-{
-  return octave::is_int_or_inf_or_nan (x);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::' instead")
-inline bool xtoo_large_for_float (float x)
-{
-  return octave::too_large_for_float (x);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::strsave' instead")
-inline char * strsave (const char *s)
-{
-  return octave::strsave (s);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::fgets' instead")
-inline std::string octave_fgets (std::FILE *f)
-{
-  return octave::fgets (f);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::fgetl' instead")
-inline std::string octave_fgetl (std::FILE *f)
-{
-  return octave::fgetl (f);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::fgets' instead")
-inline std::string octave_fgets (std::FILE *f, bool& eof)
-{
-  return octave::fgets (f, eof);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::fgetl' instead")
-inline std::string octave_fgetl (std::FILE *f, bool& eof)
-{
-  return octave::fgetl (f, eof);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::read_value<T>' instead")
-inline double
-octave_read_double (std::istream& is)
-{
-  return octave::read_value<double> (is);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::read_value<T>' instead")
-inline Complex
-octave_read_complex (std::istream& is)
-{
-  return octave::read_value<Complex> (is);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::read_value<T>' instead")
-inline float
-octave_read_float (std::istream& is)
-{
-  return octave::read_value<float> (is);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::read_value<T>' instead")
-inline FloatComplex
-octave_read_float_complex (std::istream& is)
-{
-  return octave::read_value<FloatComplex> (is);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::write_value<T>' instead")
-inline void
-octave_write_double (std::ostream& os, double value)
-{
-  octave::write_value<double> (os, value);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::write_value<T>' instead")
-inline void
-octave_write_complex (std::ostream& os, const Complex& value)
-{
-  octave::write_value<Complex> (os, value);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::write_value<T>' instead")
-inline void
-octave_write_float (std::ostream& os, float value)
-{
-  octave::write_value<float> (os, value);
-}
-
-OCTAVE_DEPRECATED (7, "use 'octave::write_value<T>' instead")
-inline void
-octave_write_float_complex (std::ostream& os, const FloatComplex& value)
-{
-  octave::write_value<FloatComplex> (os, value);
-}
 #endif
-
-#endif
--- a/oct-conf-post-public.in.h	Fri Dec 02 10:11:46 2022 -0500
+++ b/oct-conf-post-public.in.h	Fri Dec 02 10:12:40 2022 -0500
@@ -39,7 +39,7 @@
    OCTAVE_ATTRIBUTE_NAME in place of vendor specific attribute
    mechanisms.  As compilers evolve, the underlying implementation can
    be changed with the macro definitions below.  FIXME: Update macros
-   to use C++ standard attribute syntax when Octave moves to C++ 2011
+   to use C++ standard attribute syntax when Octave moves to C++ 2014
    standard.  */
 
 #if defined (__GNUC__)
--- a/scripts/deprecated/disable_diagonal_matrix.m	Fri Dec 02 10:11:46 2022 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,65 +0,0 @@
-########################################################################
-##
-## Copyright (C) 2021-2022 The Octave Project Developers
-##
-## See the file COPYRIGHT.md in the top-level directory of this
-## distribution or <https://octave.org/copyright/>.
-##
-## 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 3 of the License, 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, see
-## <https://www.gnu.org/licenses/>.
-##
-########################################################################
-
-## -*- texinfo -*-
-## @deftypefn  {} {@var{val} =} disable_diagonal_matrix ()
-## @deftypefnx {} {@var{old_val} =} disable_diagonal_matrix (@var{new_val})
-## @deftypefnx {} {@var{old_val} =} disable_diagonal_matrix (@var{new_val}, "local")
-##
-## @code{disable_diagonal_matrix} is deprecated and will be removed in Octave
-## version 9.  Use @code{optimize_diagonal_matrix} instead.
-##
-## Query or set whether storing diagonal matrices in a special space-efficient
-## format is disabled.
-##
-## The default value is false.  If this option is set to true, Octave will
-## store ranges as full matrices.
-##
-## When called from inside a function with the @qcode{"local"} option, the
-## setting is changed locally for the function and any subroutines it calls.
-## The original setting is restored when exiting the function.
-## @seealso{disable_diagonal_matrix, disable_permutation_matrix}
-## @end deftypefn
-
-## FIXME: DEPRECATED: Remove in version 9.
-
-function retval = disable_diagonal_matrix (varargin)
-
-  persistent warned = false;
-  if (! warned)
-    warned = true;
-    warning ("Octave:deprecated-function",
-             "disable_diagonal_matrix is obsolete and will be removed from a future version of Octave, please use optimize_diagonal_matrix instead\n");
-  endif
-
-  if (nargin == 0)
-    retval = ! optimize_diagonal_matrix ();
-  elseif (nargout == 0)
-    optimize_diagonal_matrix (! varargin{1}, varargin{2:end});
-  else
-    retval = ! optimize_diagonal_matrix (! varargin{1}, varargin{2:end});
-  endif
-
-endfunction
--- a/scripts/deprecated/disable_permutation_matrix.m	Fri Dec 02 10:11:46 2022 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,65 +0,0 @@
-########################################################################
-##
-## Copyright (C) 2021-2022 The Octave Project Developers
-##
-## See the file COPYRIGHT.md in the top-level directory of this
-## distribution or <https://octave.org/copyright/>.
-##
-## 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 3 of the License, 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, see
-## <https://www.gnu.org/licenses/>.
-##
-########################################################################
-
-## -*- texinfo -*-
-## @deftypefn  {} {@var{val} =} disable_permutation_matrix ()
-## @deftypefnx {} {@var{old_val} =} disable_permutation_matrix (@var{new_val})
-## @deftypefnx {} {@var{old_val} =} disable_permutation_matrix (@var{new_val}, "local")
-##
-## @code{disable_permutation_matrix} is deprecated and will be removed in
-## Octave version 9.  Use @code{optimize_permutation_matrix} instead.
-##
-## Query or set whether storing permutation matrices in a special
-## space-efficient format is disabled.
-##
-## The default value is false.  If this option is set to true, Octave will
-## store ranges as full matrices.
-##
-## When called from inside a function with the @qcode{"local"} option, the
-## setting is changed locally for the function and any subroutines it calls.
-## The original setting is restored when exiting the function.
-## @seealso{disable_diagonal_matrix, disable_permutation_matrix}
-## @end deftypefn
-
-## FIXME: DEPRECATED: Remove in version 9.
-
-function retval = disable_permutation_matrix (varargin)
-
-  persistent warned = false;
-  if (! warned)
-    warned = true;
-    warning ("Octave:deprecated-function",
-             "disable_permutation_matrix is obsolete and will be removed from a future version of Octave, please use optimize_permutation_matrix instead\n");
-  endif
-
-  if (nargin == 0)
-    retval = ! optimize_permutation_matrix ();
-  elseif (nargout == 0)
-    optimize_permutation_matrix (! varargin{1}, varargin{2:end});
-  else
-    retval = ! optimize_permutation_matrix (! varargin{1}, varargin{2:end});
-  endif
-
-endfunction
--- a/scripts/deprecated/disable_range.m	Fri Dec 02 10:11:46 2022 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,65 +0,0 @@
-########################################################################
-##
-## Copyright (C) 2021-2022 The Octave Project Developers
-##
-## See the file COPYRIGHT.md in the top-level directory of this
-## distribution or <https://octave.org/copyright/>.
-##
-## 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 3 of the License, 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, see
-## <https://www.gnu.org/licenses/>.
-##
-########################################################################
-
-## -*- texinfo -*-
-## @deftypefn  {} {@var{val} =} disable_range ()
-## @deftypefnx {} {@var{old_val} =} disable_range (@var{new_val})
-## @deftypefnx {} {@var{old_val} =} disable_range (@var{new_val}, "local")
-##
-## @code{disable_range} is deprecated and will be removed in Octave version 9.
-## Use @code{optimize_range} instead.
-##
-## Query or set whether storing ranges in a special space-efficient format is
-## disabled.
-##
-## The default value is false.  If this option is set to true, Octave will
-## store ranges as full matrices.
-##
-## When called from inside a function with the @qcode{"local"} option, the
-## setting is changed locally for the function and any subroutines it calls.
-## The original setting is restored when exiting the function.
-## @seealso{disable_diagonal_matrix, disable_permutation_matrix}
-## @end deftypefn
-
-## FIXME: DEPRECATED: Remove in version 9.
-
-function retval = disable_range (varargin)
-
-  persistent warned = false;
-  if (! warned)
-    warned = true;
-    warning ("Octave:deprecated-function",
-             "disable_range is obsolete and will be removed from a future version of Octave, please use optimize_range instead\n");
-  endif
-
-  if (nargin == 0)
-    retval = ! optimize_range ();
-  elseif (nargout == 0)
-    optimize_range (! varargin{1}, varargin{2:end});
-  else
-    retval = ! optimize_range (! varargin{1}, varargin{2:end});
-  endif
-
-endfunction
--- a/scripts/deprecated/module.mk	Fri Dec 02 10:11:46 2022 -0500
+++ b/scripts/deprecated/module.mk	Fri Dec 02 10:12:40 2022 -0500
@@ -2,9 +2,6 @@
 
 %canon_reldir%_FCN_FILES = \
   %reldir%/.oct-config \
-  %reldir%/disable_diagonal_matrix.m \
-  %reldir%/disable_permutation_matrix.m \
-  %reldir%/disable_range.m \
   %reldir%/shift.m \
   %reldir%/sparse_auto_mutate.m
 
--- a/scripts/geometry/tsearchn.m	Fri Dec 02 10:11:46 2022 -0500
+++ b/scripts/geometry/tsearchn.m	Fri Dec 02 10:12:40 2022 -0500
@@ -26,15 +26,17 @@
 ## -*- texinfo -*-
 ## @deftypefn  {} {@var{idx} =} tsearchn (@var{x}, @var{t}, @var{xi})
 ## @deftypefnx {} {[@var{idx}, @var{p}] =} tsearchn (@var{x}, @var{t}, @var{xi})
-## Search for the enclosing Delaunay convex hull.
+## Find the simplexes enclosing the given points.
 ##
-## For @code{@var{t} = delaunayn (@var{x})}, finds the index in @var{t}
-## containing the points @var{xi}.  For points outside the convex hull,
-## @var{idx} is NaN.
+## @code{tsearchn} is typically used with @code{delaunayn}:
+## @code{@var{t} = delaunayn (@var{x})} returns a set of simplexes @code{t},
+## then @code{tsearchn} returns the row index of @var{t} containing each point
+## of @var{xi}.  For points outside the convex hull, @var{idx} is NaN.
 ##
-## If requested @code{tsearchn} also returns the Barycentric coordinates
-## @var{p} of the enclosing triangles.
-## @seealso{delaunay, delaunayn}
+## If requested, @code{tsearchn} also returns the barycentric coordinates
+## @var{p} of the enclosing simplexes.
+##
+## @seealso{delaunay, delaunayn, tsearch}
 ## @end deftypefn
 
 function [idx, p] = tsearchn (x, t, xi)
@@ -43,57 +45,53 @@
     print_usage ();
   endif
 
+  if (columns (x) != columns (xi))
+    error ("tsearchn: number of columns of X and XI must match");
+  endif
+
+  if (max (t(:)) > rows (x))
+    error ("tsearchn: triangulation T must not access points outside X");
+  endif
+
+  if (nargout <= 1 && columns (x) == 2)  # pass to the faster tsearch.cc
+    idx = tsearch (x(:,1), x(:,2), t, xi(:,1), xi(:,2));
+    return;
+  endif
+
   nt = rows (t);
   [m, n] = size (x);
   mi = rows (xi);
   idx = NaN (mi, 1);
   p = NaN (mi, n + 1);
-
   ni = [1:mi].';
-  for i = 1 : nt
-    ## Only calculate the Barycentric coordinates for points that have not
-    ## already been found in a triangle.
-    b = cart2bary (x (t (i, :), :), xi(ni,:));
 
-    ## Our points xi are in the current triangle if
-    ## (all (b >= 0) && all (b <= 1)).  However as we impose that
-    ## sum (b,2) == 1 we only need to test all(b>=0).  Note need to add
-    ## a small margin for rounding errors
-    intri = all (b >= -1e-12, 2);
-    idx(ni(intri)) = i;
-    p(ni(intri),:) = b(intri, :);
-    ni(intri) = [];
-  endfor
+  for i = 1 : nt  # each simplex in turn
 
-endfunction
-
-function Beta = cart2bary (T, P)
+    T = x(t(i, :), :);  # T is the current simplex
+    P = xi(ni, :);      # P is the set of points left to calculate
 
-  ## Conversion of Cartesian to Barycentric coordinates.
-  ## Given a reference simplex in N dimensions represented by an
-  ## N+1-by-N matrix, an arbitrary point P in Cartesian coordinates,
-  ## represented by an N-by-1 column vector can be written as
-  ##
-  ## P = Beta * T
-  ##
-  ## Where Beta is an N+1 vector of the barycentric coordinates.  A criteria
-  ## on Beta is that
-  ##
-  ## sum (Beta) == 1
-  ##
-  ## and therefore we can write the above as
-  ##
-  ## P - T(end, :) = Beta(1:end-1) * (T(1:end-1,:) - ones (N,1) * T(end,:))
-  ##
-  ## and then we can solve for Beta as
-  ##
-  ## Beta(1:end-1) = (P - T(end,:)) / (T(1:end-1,:) - ones (N,1) * T(end,:))
-  ## Beta(end) = sum (Beta)
-  ##
-  ## Note code below is generalized for multiple values of P, one per row.
-  [M, N] = size (P);
-  Beta = (P - ones (M,1) * T(end,:)) / (T(1:end-1,:) - ones (N,1) * T(end,:));
-  Beta (:,end+1) = 1 - sum (Beta, 2);
+    ## Convert to barycentric coords: these are used to express a point P
+    ## as    P = Beta * T
+    ## where T is a simplex.
+    ##
+    ## If 0 <= Beta <= 1, then the linear combination is also convex,
+    ## and the point P is inside the simplex T, otherwise it is outside.
+    ## Since the equation system is underdetermined, we apply the constraint
+    ## sum (Beta) == 1  to make it unique up to scaling.
+    ##
+    ## Note that the code below is vectorized over P, one point per row.
+
+    b = (P - T(end,:)) / (T(1:end-1,:) - T(end,:));
+    b(:, end+1) = 1 - sum (b, 2);
+
+    ## The points xi are inside the current simplex if
+    ## (all (b >= 0) && all (b <= 1)).  As sum (b,2) == 1, we only need to
+    ## test all(b>=0).
+    inside = all (b >= -1e-12, 2);  # -1e-12 instead of 0 for rounding errors
+    idx(ni(inside)) = i;
+    p(ni(inside), :) = b(inside, :);
+    ni = ni(! inside);
+  endfor
 
 endfunction
 
@@ -121,3 +119,10 @@
 %! [idx, p] = tsearchn (x,tri,[1,1]);
 %! assert (idx, NaN);
 %! assert (p, [NaN, NaN, NaN]);
+
+## Test input validation
+%!error <Invalid call> tsearchn ()
+%!error <Invalid call> tsearchn (1)
+%!error <Invalid call> tsearchn (1, 2)
+%!error <number of columns of X and XI must match> tsearchn ([1,2], 3, 4)
+%!error <T must not access points outside X> tsearchn (1, 2, 3)
--- a/scripts/linear-algebra/module.mk	Fri Dec 02 10:11:46 2022 -0500
+++ b/scripts/linear-algebra/module.mk	Fri Dec 02 10:12:40 2022 -0500
@@ -35,6 +35,7 @@
   %reldir%/rref.m \
   %reldir%/subspace.m \
   %reldir%/trace.m \
+  %reldir%/tensorprod.m \
   %reldir%/vech.m \
   %reldir%/vecnorm.m
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/linear-algebra/tensorprod.m	Fri Dec 02 10:12:40 2022 -0500
@@ -0,0 +1,437 @@
+########################################################################
+##
+## Copyright (C) 2022 The Octave Project Developers
+##
+## See the file COPYRIGHT.md in the top-level directory of this
+## distribution or <https://octave.org/copyright/>.
+##
+## 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 3 of the License, 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, see
+## <https://www.gnu.org/licenses/>.
+##
+########################################################################
+
+## -*- texinfo -*-
+## @deftypefn  {} {@var{C} =} tensorprod (@var{A}, @var{B}, @var{dimA}, @var{dimB})
+## @deftypefnx {} {@var{C} =} tensorprod (@var{A}, @var{B}, @var{dim})
+## @deftypefnx {} {@var{C} =} tensorprod (@var{A}, @var{B})
+## @deftypefnx {} {@var{C} =} tensorprod (@var{A}, @var{B}, "all")
+## @deftypefnx {} {@var{C} =} tensorprod (@var{A}, @var{B}, @dots{}, "NumDimensionsA", @var{value})
+## Compute the tensor product between numeric tensors @var{A} and @var{B}.
+##
+## The dimensions of @var{A} and @var{B} that are contracted are defined by
+## @var{dimA} and @var{dimB}, respectively.  @var{dimA} and @var{dimB} are
+## scalars or equal length vectors that define the dimensions to match up.
+## The matched dimensions of @var{A} and @var{B} must have equal lengths.
+##
+## When @var{dim} is used, it is equivalent to @var{dimA} = @var{dimB} =
+## @var{dim}.
+##
+## When no dimensions are specified, @var{dimA} = @var{dimB} = [].  This
+## computes the outer product between @var{A} and @var{B}.
+##
+## Using the "all" option results in the inner product between @var{A} and
+## @var{B}.  This requires size(@var{A}) == size(@var{B}).
+##
+## Use the property-value pair with the property name "NumDimensionsA" when
+## @var{A} has trailing singleton dimensions that should be transfered to
+## @var{C}.  The specified @var{value} should be the total number of
+## dimensions of @var{A}.
+##
+## Matlab Compatibility:  Octave does not currently support the "name=value"
+## syntax for the "NumDimensionsA" parameter.
+##
+## @seealso{kron, dot, mtimes}
+## @end deftypefn
+
+function C = tensorprod (A, B, varargin)
+
+  ## FIXME: shortcut code paths could be added for trivial cases, such as if
+  ##        either A or B are a scalars, null, identity tensors, etc.
+
+  if (nargin < 2 || nargin > 6)
+    print_usage ();
+  endif
+
+  ## Check that A and B are single or double
+  if (! isfloat (A))
+    error ("tensorprod: A must be a single or double precision array");
+  endif
+
+  if (! isfloat (B))
+    error ("tensorprod: B must be a single or double precision array");
+  endif
+
+  ## Check for misplaced NumDimensionsA property
+  if (nargin > 2)
+    if (strcmpi (varargin{end}, "NumDimensionsA"))
+      error (["tensorprod: a value for the NumDimensionsA property must ", ...
+              "be provided"]);
+    elseif (strcmpi ( strtok (inputname (nargin, false)), "NumDimensionsA"))
+      ## FIXME: Add support for keyword=value syntax
+      error (["tensorprod: NumDimensionsA=ndimsA syntax is not yet ", ...
+              "supported in Octave - provide the value as a ", ...
+              "property-value pair"]);
+    endif
+  endif
+
+  ## Check for NumDimensionsA property
+  if (nargin > 3)
+    if (strcmpi (varargin{end - 1}, "NumDimensionsA"))
+      if (! (isnumeric (varargin{end}) && isscalar (varargin{end})))
+        error (["tensorprod: value for NumDimensionsA must be a ", ...
+                "numeric scalar"]);
+      elseif (varargin{end} < 1 || rem (varargin{end}, 1) != 0)
+        error (["tensorprod: value for NumDimensionsA must be a ", ...
+                "positive integer"]);
+      endif
+      NumDimensionsA = varargin{end};
+    endif
+  endif
+
+  existNumDimensionsA = exist ("NumDimensionsA");
+  ndimargs = nargin - 2 - 2 * existNumDimensionsA;
+
+  ## Set dimA and dimB
+  if (ndimargs == 0)
+    ## Calling without dimension arguments
+    dimA = [];
+    dimB = [];
+  elseif (ndimargs == 1)
+    ## Calling with dim or "all" option
+    if (isnumeric (varargin{1}))
+      if (! (isvector (varargin{1}) || isnull (varargin{1})))
+        error ("tensorprod: dim must be a numeric vector of integers or []");
+      endif
+      ## Calling with dim
+      dimA = transpose ([varargin{1}(:)]);
+    elseif (ischar (varargin{1}))
+      if (strcmpi (varargin{1}, "all"))
+        if (! size_equal (A, B))
+          error (["tensorprod: size of A and B must be identical when ", ...
+                  "using the 'all' option"]);
+        endif
+      else
+        error ("tensorprod: unknown option '%s'", varargin{1});
+      endif
+      ## Calling with "all" option
+      dimA = 1:ndims(A);
+    else
+      error (["tensorprod: third argument must be a numeric vector of ", ...
+              "integers, [], or 'all'"]);
+    endif
+    dimB = dimA;
+  elseif (ndimargs == 2)
+    ## Calling with dimA and dimB
+    if (! (isnumeric (varargin{1}) && (isvector (varargin{1}) || ...
+        isnull (varargin{1}))))
+      error("tensorprod: dimA must be a numeric vector of integers or []");
+    endif
+
+    if (! (isnumeric (varargin{2}) && (isvector (varargin{2}) || ...
+        isnull (varargin{2}))))
+      error ("tensorprod: dimB must be a numeric vector of integers or []");
+    endif
+
+    if (length (varargin{1}) != length (varargin{2}))
+      error (["tensorprod: an equal number of dimensions must be ", ...
+              "matched for A and B"]);
+    endif
+    dimA = transpose ([varargin{1}(:)]);
+    dimB = transpose ([varargin{2}(:)]);
+  else
+    ## Something is wrong - try to find the error
+    for i = 1:ndimargs
+      if (ischar (varargin{i}))
+        if (strcmpi (varargin{i}, "NumDimensionsA"))
+          error ("tensorprod: misplaced 'NumDimensionsA' option");
+        elseif (strcmpi (varargin{i}, "all"))
+          error ("tensorprod: misplaced 'all' option");
+        else
+          error ("tensorprod: unknown option '%s'", varargin{i});
+        endif
+      elseif (! isnumeric (varargin{i}))
+        error (["tensorprod: optional arguments must be numeric vectors ", ...
+                "of integers, [], 'all', or 'NumDimensionsA'"]);
+      endif
+    endfor
+    error ("tensorprod: too many dimension inputs given");
+  endif
+
+  ## Check that dimensions are positive integers ([] will also pass)
+  if (any ([dimA < 1, dimB < 1, (rem (dimA, 1) != 0), (rem (dimB, 1) != 0)]))
+    error ("tensorprod: dimension(s) must be positive integer(s)");
+  endif
+
+  ## Check that the length of matched dimensions are equal
+  if (any (size (A, dimA) != size (B, dimB)))
+    error (["tensorprod: matched dimension(s) of A and B must have the ", ...
+            "same length(s)"]);
+  endif
+
+  ## Find size and ndims of A and B
+  ndimsA = max ([ndims(A), max(dimA)]);
+  sizeA = size (A, 1:ndimsA);
+  ndimsB = max ([ndims(B), max(dimB)]);
+  sizeB = size (B, 1:ndimsB);
+
+  ## Take NumDimensionsA property into account
+  if (existNumDimensionsA)
+    if (NumDimensionsA < ndimsA)
+      if (ndimargs == 1)
+        error (["tensorprod: highest dimension of dim must be less than ", ...
+                "or equal to NumDimensionsA"]);
+      elseif (ndimargs == 2)
+        error (["tensorprod: highest dimension of dimA must be less ", ...
+                "than or equal to NumDimensionsA"]);
+      else
+        error (["tensorprod: NumDimensionsA cannot be smaller than the ", ...
+                "number of dimensions of A"]);
+      endif
+    elseif (NumDimensionsA > ndimsA)
+      sizeA = [sizeA, ones(1, NumDimensionsA - ndimsA)];
+      ndimsA = NumDimensionsA;
+    endif
+  endif
+
+  ## Interchange the dimension to sum over the end of A and the front of B
+  ## Prepare for A
+  remainDimA = setdiff (1:ndimsA, dimA); # Dimensions of A to keep
+  newDimOrderA =  [remainDimA, dimA]; # New dim order [to_keep, to_contract]
+  newSizeA = [prod(sizeA(remainDimA)), prod(sizeA(dimA))]; # Temp. 2D size for A
+  remainSizeA = sizeA(remainDimA); # Contrib. to size of C from remaining A dims
+
+  ## Prepare for B (See comments for A.  Note that in principle,
+  ## prod (sizeB (dimB)) should always be equal to prod (sizeA (dimA)).  May
+  ## be able to optimize further here.
+  remainDimB = setdiff (1:ndimsB, dimB);
+  newDimOrderB =  [remainDimB, dimB];
+  newSizeB = [prod(sizeB(remainDimB)), prod(sizeB(dimB))];
+  remainSizeB = sizeB(remainDimB);
+
+  ## Do reshaping into 2D array
+  newA = reshape (permute (A, newDimOrderA), newSizeA);
+  newB = reshape (permute (B, newDimOrderB), newSizeB);
+
+  ## Compute
+  C = newA * transpose (newB);
+
+  ## If not an inner product, reshape back to tensor
+  if (! isscalar (C))
+    C = reshape (C, [remainSizeA, remainSizeB]);
+  endif
+
+endfunction
+
+
+%!assert (tensorprod (2, 3), 6)
+%!assert (tensorprod (2, 3, 1), 6)
+%!assert (tensorprod (2, 3, 2), 6)
+%!assert (tensorprod (2, 3, 10), 6)
+%!assert (tensorprod (2, 3, [1 2]), 6)
+%!assert (tensorprod (2, 3, [1 10]), 6)
+%!assert (tensorprod (2, 3, []), 6)
+%!assert (tensorprod (2, 3, 2, 1), 6)
+%!assert (tensorprod (2, 3, [], []), 6)
+
+%!shared v1, v2, M1, M2, T
+%! v1 = [1, 2];
+%! M1 = [1, 2; 3, 4];
+%! M2 = [1, 2; 3, 4; 5, 6];
+%! T = cat (3, M2, M2);
+
+%!assert (tensorprod (3, v1), reshape ([3, 6], [1, 1, 1, 2]));
+%!assert (tensorprod (v1, 3), [3, 6]);
+%!assert (tensorprod (v1, v1, "all"), 5);
+%!assert (tensorprod (v1, v1), reshape ([1, 2, 2, 4], [1, 2, 1, 2]));
+%!assert (tensorprod (v1, v1, 1), [1, 2; 2, 4]);
+%!assert (tensorprod (v1, v1, 2), 5);
+%!assert (tensorprod (v1, v1, 3), reshape ([1, 2, 2, 4], [1, 2, 1, 2]));
+%!assert (tensorprod (v1, v1, 5), reshape ([1, 2, 2, 4], [1, 2, 1, 1, 1, 2]));
+
+%!assert (tensorprod (M1, v1), cat (4, [1,2;3,4], [2,4;6,8]))
+%!assert (tensorprod (M1, v1'), cat (3, [1,2;3,4], [2,4;6,8]))
+%!assert (tensorprod (v1, M1), reshape ([1 2 3 6 2 4 4 8], [1,2,2,2]))
+%!assert (tensorprod (v1', M1), reshape ([1 2 3 6 2 4 4 8], [2,1,2,2]))
+%!assert (tensorprod (M1, v1', 2, 1), [5; 11])
+%!assert (tensorprod (M1, v1', 4, 4), cat(4, M1, 2*M1))
+%!assert (tensorprod (M1, v1', [1, 3]), [7; 10])
+%!assert (tensorprod (M1, v1', [1, 3], [1, 3]), [7; 10])
+%!assert (tensorprod (M1, v1', [2, 3], [1, 3]), [5; 11])
+%!assert (tensorprod (M1, v1', [2; 3], [1; 3]), [5; 11])
+%!assert (tensorprod (M1, v1', [2; 3], [1, 3]), [5; 11])
+%!assert (tensorprod (M1, v1', [2, 3], [1; 3]), [5; 11])
+%!assert (tensorprod (M1, v1', [], []), cat (3, M1, 2*M1))
+%!assert (tensorprod (M1, M1, "all"), 30)
+%!assert (tensorprod (M1, M1, 1), [10, 14; 14, 20])
+%!assert (tensorprod (M1, M1, 2), [5, 11; 11, 25])
+%!assert (tensorprod (M1, M2, 2), [5, 11, 17; 11, 25, 39])
+%!assert (tensorprod (M1, M2, 1, 2), [7, 15, 23; 10, 22, 34])
+%!assert (tensorprod (M1, M2), reshape ([1,3,2,4,3,9,6,12,5,15,10,20,2,6,4, ...
+%!                                      8,4,12,8,16,6,18,12,24], [2,2,3,2]))
+
+%!assert (tensorprod (T, M1),
+%!        reshape([1,3,5,2,4,6,1,3,5,2,4,6,3,9,15,6,12,18,3,9,15,6,12,18,2, ...
+%!                6,10,4,8,12,2,6,10,4,8,12,4,12,20,8,16,24,4,12,20,8,16,24],
+%!                [3,2,2,2,2]))
+%!assert (tensorprod (T, M1, 2),
+%!        cat (3, [5, 5; 11 11; 17, 17], [11, 11; 25, 25; 39, 39]))
+%!assert (tensorprod (T, M2, 1), cat (3, [35, 35; 44, 44], [44, 44; 56, 56]))
+%!assert (tensorprod (T, M2, 2), cat (3, [5, 5; 11, 11; 17, 17],
+%!                     [11,11;25,25;39,39], [17, 17; 39, 39; 61, 61]))
+%!assert (tensorprod (T, T, "all"), 182)
+%!assert (tensorprod (T, T, 1),
+%!        reshape ([35,44,35,44,44,56,44,56,35,44,35,44,44,56,44,56],
+%!                 [2,2,2,2]))
+%!assert (tensorprod (T, T, 2),
+%!        reshape ([5,11,17,5,11,17,11,25,39,11,25,39,17,39,61,17,39,61,5, ...
+%!                 11,17,5,11,17,11,25,39,11,25,39,17,39,61,17,39,61],
+%!                 [3,2,3,2]))
+%!assert (tensorprod (T, T, 3),
+%!        reshape ([2,6,10,4,8,12,6,18,30,12,24,36,10,30,50,20,40,60,4,12, ...
+%!                 20,8,16,24,8,24,40,16,32,48,12,36,60,24,48,72], [3,2,3,2]));
+%!assert (tensorprod (T, T, 10),
+%!        reshape ([1,3,5,2,4,6,1,3,5,2,4,6,3,9,15,6,12,18,3,9,15,6,12,18, ...
+%!                 5,15,25,10,20,30,5,15,25,10,20,30,2,6,10,4,8,12,2,6,10, ...
+%!                 4,8,12,4,12,20,8,16,24,4,12,20,8,16,24,6,18,30,12,24,36, ...
+%!                 6,18,30,12,24,36,1,3,5,2,4,6,1,3,5,2,4,6,3,9,15,6,12,18, ...
+%!                 3,9,15,6,12,18,5,15,25,10,20,30,5,15,25,10,20,30,2,6,10, ...
+%!                 4,8,12,2,6,10,4,8,12,4,12,20,8,16,24,4,12,20,8,16,24,6, ...
+%!                 18,30,12,24,36,6,18,30,12,24,36],
+%!                 [3,2,2,1,1,1,1,1,1,3,2,2]))
+%!assert (tensorprod (T, T, []),
+%!        reshape ([1,3,5,2,4,6,1,3,5,2,4,6,3,9,15,6,12,18,3,9,15,6,12,18, ...
+%!                 5,15,25,10,20,30,5,15,25,10,20,30,2,6,10,4,8,12,2,6,10, ...
+%!                 4,8,12,4,12,20,8,16,24,4,12,20,8,16,24,6,18,30,12,24,36, ...
+%!                 6,18,30,12,24,36,1,3,5,2,4,6,1,3,5,2,4,6,3,9,15,6,12,18, ...
+%!                 3,9,15,6,12,18,5,15,25,10,20,30,5,15,25,10,20,30,2,6,10, ...
+%!                 4,8,12,2,6,10,4,8,12,4,12,20,8,16,24,4,12,20,8,16,24,6, ...
+%!                 18,30,12,24,36,6,18,30,12,24,36],
+%!                 [3,2,2,3,2,2]))
+%!assert (tensorprod (T, T, 2, 3),
+%!        reshape ([3,7,11,3,7,11,9,21,33,9,21,33,15,35,55,15,35,55,6,14, ...
+%!                 22,6,14,22,12,28,44,12,28,44,18,42,66,18,42,66],
+%!                 [3,2,3,2]))
+%!assert (tensorprod (T, T(1:2, 1:2, :), [2, 3],[1, 3]),
+%!        [14, 20; 30, 44; 46, 68])
+%!assert (tensorprod (T, T(1:2, 1:2, :), [3, 2],[1, 3]),
+%!        [12, 18; 28, 42; 44, 66])
+%!assert (tensorprod (T, reshape (T, [2, 2, 3]), 2, 1),
+%!        reshape ([7,15,23,7,15,23,9,23,37,9,23,37,16,36,56,16,36,56,7,15, ...
+%!                 23,7,15,23,9,23,37,9,23,37,16,36,56,16,36,56],
+%!                 [3,2,2,3]))
+%!assert (tensorprod (T, T, [1, 3]), [70, 88; 88, 112])
+%!assert (tensorprod (T, T, [1, 3]), tensorprod (T, T, [3, 1]))
+%!assert (tensorprod (T, reshape (T, [2, 2, 3]), [2, 3], [1, 2]),
+%!        [16, 23, 25; 38, 51, 59; 60, 79, 93])
+
+## NumDimensionsA tests
+%!assert (tensorprod (v1, v1, "NumDimensionsA", 2),
+%!        reshape ([1, 2, 2, 4], [1, 2, 1, 2]));
+%!assert (tensorprod (v1, v1, "numdimensionsa", 2),
+%!        tensorprod (v1, v1, "NumDimensionsA", 2));
+%!assert (tensorprod (v1, v1, "NumDimensionsA", 3),
+%!        reshape ([1, 2, 2, 4], [1, 2, 1, 1, 2]));
+%!assert (tensorprod (v1, v1, [], "NumDimensionsA", 3),
+%!        reshape ([1, 2, 2, 4], [1, 2, 1, 1, 2]));
+%!assert (tensorprod (v1, v1, [], [], "NumDimensionsA", 3),
+%!        reshape ([1, 2, 2, 4], [1, 2, 1, 1, 2]));
+%!assert (tensorprod (v1, v1, "all", "NumDimensionsA", 3), 5);
+%!assert (tensorprod (M1, v1, 2, "NumDimensionsA", 2), [5; 11]);
+%!assert (tensorprod (M1, v1, 2, "NumDimensionsA", 5), [5; 11]);
+%!assert (tensorprod (M1, v1, [2, 3], "NumDimensionsA", 5), [5; 11]);
+%!assert (tensorprod (M1, M2, "NumDimensionsA", 2), reshape ([1,3,2,4,3,9,6, ...
+%!        12,5,15,10,20,2,6,4,8,4,12,8,16,6,18,12,24], [2,2,3,2]))
+%!assert (tensorprod (M1, M2, "NumDimensionsA", 3), reshape ([1,3,2,4,3,9,6, ...
+%!        12,5,15,10,20,2,6,4,8,4,12,8,16,6,18,12,24], [2,2,1,3,2]))
+%!assert (tensorprod (T, T, 1, "NumDimensionsA", 3),
+%!        reshape ([35,44,35,44,44,56,44,56,35,44,35,44,44,56,44,56],
+%!                 [2,2,2,2]))
+%!assert (tensorprod (T, T, 3, "NumDimensionsA", 3),
+%!        reshape ([2,6,10,4,8,12,6,18,30,12,24,36,10,30,50,20,40,60,4,12, ...
+%!                20,8,16,24, 8,24,40,16,32,48,12,36,60,24,48,72],
+%!                [3,2,3,2]))
+%!assert (tensorprod (T, T, 1, "NumDimensionsA", 4),
+%!        reshape ([35,44,35,44,44,56,44,56,35,44,35,44,44,56,44,56],
+%!                [2,2,1,2,2]))
+%!assert (tensorprod (T, T, 4, "NumDimensionsA", 4),
+%!        reshape ([1,3,5,2,4,6,1,3,5,2,4,6,3,9,15,6,12,18,3,9,15,6,12,18,5, ...
+%!                15,25,10,20,30,5,15,25,10,20,30,2,6,10,4,8,12,2,6,10,4,8, ...
+%!                12,4,12,20,8,16,24,4,12,20,8,16,24,6,18,30,12,24,36,6,18, ...
+%!                30,12,24,36,1,3,5,2,4,6,1,3,5,2,4,6,3,9,15,6,12,18,3,9,15, ...
+%!                6,12,18,5,15,25,10,20,30,5,15,25,10,20,30,2,6,10,4,8,12,2, ...
+%!                6,10,4,8,12,4,12,20,8,16,24,4,12,20,8,16,24,6,18,30,12,24, ...
+%!                36,6,18,30,12,24,36],
+%!                [3,2,2,3,2,2]))
+
+## Test empty inputs
+%!assert (tensorprod ([], []), zeros (0, 0, 0, 0))
+%!assert (tensorprod ([], 1), [])
+%!assert (tensorprod (1, []), zeros (1, 1, 0, 0))
+%!assert (tensorprod (zeros (0, 0, 0), zeros (0, 0, 0)), zeros (0, 0, 0, 0, 0, 0))
+%!assert (tensorprod ([], [], []), zeros (0, 0, 0, 0))
+%!assert (tensorprod ([], [], 1), [])
+%!assert (tensorprod ([], [], 2), [])
+%!assert (tensorprod ([], [], 3), zeros (0, 0, 0, 0))
+%!assert (tensorprod ([], [], 4), zeros (0, 0, 1, 0, 0))
+%!assert (tensorprod ([], [], 5), zeros (0, 0, 1, 1, 0, 0))
+%!assert (tensorprod ([], [], 3, "NumDimensionsA", 4), zeros (0, 0, 1, 0, 0))
+%!assert (tensorprod ([], [], 3, 4, "NumDimensionsA", 5), zeros (0, 0, 1, 1, 0, 0))
+
+## Test input validation
+%!error <Invalid call> tensorprod ()
+%!error <Invalid call> tensorprod (1)
+%!error <Invalid call> tensorprod (1,2,3,4,5,6,7)
+%!error <A must be a single or double precision array> tensorprod ("foo", 1)
+%!error <B must be a single or double precision array> tensorprod (1, "bar")
+%!error <A must be a single or double precision array> tensorprod (int32(1), 1)
+%!error <B must be a single or double precision array> tensorprod (1, int32(1))
+%!error <unknown option 'foo'> tensorprod (1, 1, "foo")
+%!error <unknown option 'foo'> tensorprod (1, 1, 1, "foo", 1)
+%!error <dimA must be a numeric vector of integers or \[\]> tensorprod (1, 1, "foo", 1)
+%!error <dimB must be a numeric vector of integers or \[\]> tensorprod (1, 1, 1, "bar")
+%!error <dimA must be a numeric vector of integers or \[\]> tensorprod (1, 1, zeros(0,0,0), [])
+%!error <dimB must be a numeric vector of integers or \[\]> tensorprod (1, 1, [], zeros(0,0,0))
+%!error <dim must be a numeric vector of integers or \[\]> tensorprod (1, 1, zeros(0,0,0))
+%!error <misplaced 'all' option> tensorprod (1, 1, 1, "all", 1)
+%!error <misplaced 'NumDimensionsA' option> tensorprod (1, 1, "NumDimensionsA", 1, 1)
+%!error <optional arguments must be numeric vectors of integers, \[\], 'all', or 'NumDimensionsA'> tensorprod (1, 1, 1, {}, 1)
+%!error <matched dimension\(s\) of A and B must have the same length\(s\)> tensorprod (ones (3, 4), ones (4, 3), 1)
+%!error <matched dimension\(s\) of A and B must have the same length\(s\)> tensorprod (ones (3, 4), ones (4, 3), 1, 1)
+%!error <dimension\(s\) must be positive integer\(s\)> tensorprod (1, 1, 0)
+%!error <dimension\(s\) must be positive integer\(s\)> tensorprod (1, 1, -1)
+%!error <dimension\(s\) must be positive integer\(s\)> tensorprod (1, 1, 1.5)
+%!error <dimension\(s\) must be positive integer\(s\)> tensorprod (1, 1, NaN)
+%!error <dimension\(s\) must be positive integer\(s\)> tensorprod (1, 1, Inf)
+%!error <third argument must be a numeric vector of integers, \[\], or 'all'> tensorprod (1, 1, {})
+%!error <an equal number of dimensions must be matched for A and B> tensorprod (ones (3, 4), ones (4, 3), 1, [1, 2])
+%!error <an equal number of dimensions must be matched for A and B> tensorprod (ones (3, 4), ones (4, 3), 1, [])
+%!error <an equal number of dimensions must be matched for A and B> tensorprod (ones (3, 4), ones (4, 3), [], [1, 2])
+%!error <size of A and B must be identical when using the 'all' option> tensorprod (ones (3, 4), ones (4, 3), "all")
+%!error <a value for the NumDimensionsA property must be provided> tensorprod (1, 1, "NumDimensionsA")
+%!error <NumDimensionsA cannot be smaller than the number of dimensions of A> tensorprod (ones (2, 2, 2), 1, "NumDimensionsA", 2)
+%!error <highest dimension of dim must be less than or equal to NumDimensionsA> tensorprod (1, 1, 5, "NumDimensionsA", 4)
+%!error <highest dimension of dimA must be less than or equal to NumDimensionsA> tensorprod (1, 1, 5, 5, "NumDimensionsA", 4)
+%!error <NumDimensionsA=ndimsA syntax is not yet supported in Octave> tensorprod (1, 1, NumDimensionsA=4)
+%!error <NumDimensionsA=ndimsA syntax is not yet supported in Octave> tensorprod (1, 1, numdimensionsa=4)
+%!error <too many dimension inputs given> tensorprod (1, 1, 2, 1, 1)
+%!error <too many dimension inputs given> tensorprod (1, 1, 2, 1, 1, 1)
+%!error <value for NumDimensionsA must be a numeric scalar> tensorprod (1, 1, 2, 1, "NumDimensionsA", "foo")
+%!error <value for NumDimensionsA must be a numeric scalar> tensorprod (1, 1, 2, 1, "NumDimensionsA", {})
+%!error <value for NumDimensionsA must be a positive integer> tensorprod (1, 1, 2, 1, "NumDimensionsA", -1)
+%!error <value for NumDimensionsA must be a positive integer> tensorprod (1, 1, 2, 1, "NumDimensionsA", 0)
+%!error <value for NumDimensionsA must be a positive integer> tensorprod (1, 1, 2, 1, "NumDimensionsA", 1.5)
+%!error <value for NumDimensionsA must be a positive integer> tensorprod (1, 1, 2, 1, "NumDimensionsA", NaN)
+%!error <value for NumDimensionsA must be a positive integer> tensorprod (1, 1, 2, 1, "NumDimensionsA", Inf)
--- a/scripts/plot/util/__pltopt__.m	Fri Dec 02 10:11:46 2022 -0500
+++ b/scripts/plot/util/__pltopt__.m	Fri Dec 02 10:12:40 2022 -0500
@@ -158,12 +158,6 @@
     topt = opt(1);
     n = 1;
 
-    if (any (topt == "0":"6"))
-      warning ("Octave:deprecated-option", ...
-               ["%s: using numbers to select line colors is deprecated.  ", ...
-                "Use the corresponding color identifier instead."], caller);
-    endif
-
     ## LineStyles
     if (strncmp (opt, "--", 2) || strncmp (opt, "-.", 2))
       options.linestyle = opt(1:2);
@@ -195,20 +189,19 @@
         topt = "+";
       endif
       options.marker = topt;
-    ## Numeric color specs are for backward compatibility.  Don't document.
-    elseif (topt == "k" || topt == "0")
+    elseif (topt == "k")
       options.color = [0, 0, 0];
-    elseif (topt == "r" || topt == "1")
+    elseif (topt == "r")
       if (strncmp (opt, "red", 3))
         n = 3;
       endif
       options.color = [1, 0, 0];
-    elseif (topt == "g" || topt == "2")
+    elseif (topt == "g")
       if (strncmp (opt, "green", 5))
         n = 5;
       endif
       options.color = [0, 1, 0];
-    elseif (topt == "b" || topt == "3")
+    elseif (topt == "b")
       if (strncmp (opt, "black", 5))
         options.color = [0, 0, 0];
         n = 5;
@@ -223,17 +216,17 @@
         n = 6;
       endif
       options.color = [1, 1, 0];
-    elseif (topt == "m" || topt == "4")
+    elseif (topt == "m")
       if (strncmp (opt, "magenta", 7))
         n = 7;
       endif
       options.color = [1, 0, 1];
-    elseif (topt == "c" || topt == "5")
+    elseif (topt == "c")
       if (strncmp (opt, "cyan", 4))
         n = 4;
       endif
       options.color = [0, 1, 1];
-    elseif (topt == "w" || topt == "6")
+    elseif (topt == "w")
       if (strncmp (opt, "white", 5))
         n = 5;
       endif
--- a/scripts/plot/util/private/__print_parse_opts__.m	Fri Dec 02 10:11:46 2022 -0500
+++ b/scripts/plot/util/private/__print_parse_opts__.m	Fri Dec 02 10:12:40 2022 -0500
@@ -234,7 +234,7 @@
 
   if (any (strcmp (unsupported, arg_st.devopt)))
     warning ('Octave:print:deprecated-format',
-             'print: "%s" format is no more officially supported', ...
+             'print: "%s" format is no longer officially supported',
              arg_st.devopt);
   endif
 
--- a/scripts/strings/isstring.m	Fri Dec 02 10:11:46 2022 -0500
+++ b/scripts/strings/isstring.m	Fri Dec 02 10:12:40 2022 -0500
@@ -46,7 +46,7 @@
     print_usage ();
   endif
 
-  tf = false;
+  tf = isa (s, 'string');
 
 endfunction
 
@@ -60,4 +60,3 @@
 %!assert (isstring ({"b"}), false)
 
 %!error <Invalid call> isstring ()
-%!error isstring ("a", "b")
--- a/scripts/testfun/oruntests.m	Fri Dec 02 10:11:46 2022 -0500
+++ b/scripts/testfun/oruntests.m	Fri Dec 02 10:12:40 2022 -0500
@@ -71,29 +71,34 @@
   no_tests = {};
   printf ("Processing files in %s:\n\n", directory);
   fflush (stdout);
-  for i = 1:numel (flist)
-    f = flist{i};
-    if ((length (f) > 2 && strcmpi (f((end-1):end), ".m"))
-        || (length (f) > 3 && strcmpi (f((end-2):end), ".cc")))
-      ff = fullfile (directory, f);
-      if (! isfile (ff))
-        continue;
+  unwind_protect
+    old_dir = cd (directory);
+    for i = 1:numel (flist)
+      f = flist{i};
+      if ((length (f) > 2 && strcmpi (f((end-1):end), ".m"))
+          || (length (f) > 3 && strcmpi (f((end-2):end), ".cc")))
+        ff = fullfile (directory, f);
+        if (! isfile (ff))
+          continue;
+        endif
+        if (has_tests (ff))
+          print_test_file_name (f);
+          [p, n, xf, xb, sk, rtsk, rgrs] = test (ff, "quiet");
+          print_pass_fail (p, n, xf, xb, sk, rtsk, rgrs);
+          fflush (stdout);
+        elseif (has_functions (ff))
+          no_tests(end+1) = f;
+        endif
+      elseif (f(1) == "@")
+        f = fullfile (directory, f);
+        if (isfolder (f))
+          dirs(end+1) = f;
+        endif
       endif
-      if (has_tests (ff))
-        print_test_file_name (f);
-        [p, n, xf, xb, sk, rtsk, rgrs] = test (ff, "quiet");
-        print_pass_fail (p, n, xf, xb, sk, rtsk, rgrs);
-        fflush (stdout);
-      elseif (has_functions (ff))
-        no_tests(end+1) = f;
-      endif
-    elseif (f(1) == "@")
-      f = fullfile (directory, f);
-      if (isfolder (f))
-        dirs(end+1) = f;
-      endif
-    endif
-  endfor
+    endfor
+  unwind_protect_cleanup
+    cd (old_dir);
+  end_unwind_protect
   if (! isempty (no_tests))
     printf ("\nThe following files in %s have no tests:\n\n", directory);
     printf ("%s", list_in_columns (no_tests));
--- a/src/mkoctfile.in.cc	Fri Dec 02 10:11:46 2022 -0500
+++ b/src/mkoctfile.in.cc	Fri Dec 02 10:12:40 2022 -0500
@@ -356,11 +356,6 @@
   vars["LD_STATIC_FLAG"] = get_variable ("LD_STATIC_FLAG",
                                          %OCTAVE_CONF_LD_STATIC_FLAG%);
 
-  // FIXME: Remove LFLAGS in Octave 9
-  vars["LFLAGS"] = get_variable ("LFLAGS", DEFAULT_LDFLAGS);
-  if (vars["LFLAGS"] != DEFAULT_LDFLAGS)
-    std::cerr << "mkoctfile: warning: LFLAGS is deprecated and will be removed in a future version of Octave, use LDFLAGS instead" << std::endl;
-
   vars["F77_INTEGER8_FLAG"] = get_variable ("F77_INTEGER8_FLAG",
                                             %OCTAVE_CONF_F77_INTEGER_8_FLAG%);
   vars["ALL_FFLAGS"] = vars["FFLAGS"] + ' ' + vars["F77_INTEGER8_FLAG"];
@@ -888,10 +883,6 @@
             {
               ++i;
 
-              // FIXME: Remove LFLAGS checking in Octave 9
-              if (argv[i] == "LFLAGS")
-                std::cerr << "mkoctfile: warning: LFLAGS is deprecated and will be removed in a future version of Octave, use LDFLAGS instead" << std::endl;
-
               if (! var_to_print.empty ())
                 std::cerr << "mkoctfile: warning: only one '" << arg
                           << "' option will be processed" << std::endl;
@@ -1317,13 +1308,12 @@
           octave_libs = "-L" + quote_path (vars["OCTLIBDIR"])
                         + ' ' + vars["OCTAVE_LIBS"];
 
-          // FIXME: Remove LFLAGS in Octave 9
           std::string cmd
             = (vars["CXXLD"] + ' ' + vars["CPPFLAGS"] + ' '
                + vars["ALL_CXXFLAGS"] + ' ' + vars["RDYNAMIC_FLAG"] + ' '
                + pass_on_options + ' ' + output_option + ' ' + objfiles + ' '
                + libfiles + ' ' + ldflags + ' ' + vars["ALL_LDFLAGS"] + ' '
-               + vars["LFLAGS"] + ' ' + octave_libs + ' '
+               + octave_libs + ' '
                + vars["OCTAVE_LINK_OPTS"] + ' ' + vars["OCTAVE_LINK_DEPS"]);
 
           int status = run_command (cmd, verbose, printonly);
@@ -1348,12 +1338,11 @@
                     + ' ' + vars["OCTAVE_LIBS"];
 #endif
 
-      // FIXME: Remove LFLAGS in Octave 9
       std::string cmd
         = (vars["CXXLD"] + ' ' + vars["ALL_CXXFLAGS"] + ' '
            + pass_on_options + " -o " + octfile + ' ' + objfiles + ' '
            + libfiles + ' ' + ldflags + ' ' + vars["DL_LDFLAGS"] + ' '
-           + vars["LDFLAGS"] + ' ' + vars["LFLAGS"] + ' ' + octave_libs + ' '
+           + vars["LDFLAGS"] + ' ' + octave_libs + ' '
            + vars["OCT_LINK_OPTS"] + ' ' + vars["OCT_LINK_DEPS"]);
 
 #if defined (OCTAVE_USE_WINDOWS_API) || defined(CROSS)
--- a/test/io.tst	Fri Dec 02 10:11:46 2022 -0500
+++ b/test/io.tst	Fri Dec 02 10:12:40 2022 -0500
@@ -297,6 +297,118 @@
 %!assert (sscanf ('0177 08', '%i'), [127; 0; 8])
 %!assert (sscanf ('0177 08', '%d'), [177; 8])
 
+## Extensive testing of '%c'
+%!test
+%! [val, cnt, msg, pos] = sscanf ('abcde', '%c');
+%! assert (val, 'abcde');
+%! assert (cnt, 5);
+%! assert (msg, '');
+%! assert (pos, 6);
+%! [val, cnt, msg, pos] = sscanf ('abcde', '%10c');
+%! assert (val, 'abcde');
+%! assert (cnt, 1);
+%! assert (msg, '');
+%! assert (pos, 6);
+%! [val, cnt, msg, pos] = sscanf ('abcde', '%3c');
+%! assert (val, 'abcde');
+%! assert (cnt, 2);
+%! assert (msg, '');
+%! assert (pos, 6);
+%! [val, cnt, msg, pos] = sscanf ('abcde', '%3c', 1);
+%! assert (val, 'abc');
+%! assert (cnt, 1);
+%! assert (msg, '');
+%! assert (pos, 4);
+%! [val, cnt, msg, pos] = sscanf ('abcde', '%c', 5);
+%! assert (val, 'abcde');
+%! assert (cnt, 5);
+%! assert (msg, '');
+%! assert (pos, 6);
+
+## Extensive testing of '%s'
+%!test
+%! [val, cnt, msg, pos] = sscanf ('abcde', '%s');
+%! assert (val, 'abcde');
+%! assert (cnt, 1);
+%! assert (msg, '');
+%! assert (pos, 6);
+%! [val, cnt, msg, pos] = sscanf ('abcde', '%10s');
+%! assert (val, 'abcde');
+%! assert (cnt, 1);
+%! assert (msg, '');
+%! assert (pos, 6);
+%! [val, cnt, msg, pos] = sscanf ('abcde', '%3s');
+%! assert (val, 'abcde');
+%! assert (cnt, 2);
+%! assert (msg, '');
+%! assert (pos, 6);
+%! [val, cnt, msg, pos] = sscanf ('abcde', '%3s', 1);
+%! assert (val, 'abc');
+%! assert (cnt, 1);
+%! assert (msg, '');
+%! assert (pos, 4);
+%! [val, cnt, msg, pos] = sscanf ('abcde', '%1s', 5);
+%! assert (val, 'abcde');
+%! assert (cnt, 5);
+%! assert (msg, '');
+%! assert (pos, 6);
+
+## Extensive testing of '%[]'
+%!test
+%! [val, cnt, msg, pos] = sscanf ('abcde', '%[a-c]');
+%! assert (val, 'abc');
+%! assert (cnt, 1);
+%! assert (msg, 'sscanf: format failed to match');
+%! assert (pos, 4);
+%! [val, cnt, msg, pos] = sscanf ('abcde', '%10[a-c]');
+%! assert (val, 'abc');
+%! assert (cnt, 1);
+%! assert (msg, 'sscanf: format failed to match');
+%! assert (pos, 4);
+%! [val, cnt, msg, pos] = sscanf ('abcde', '%2[a-c]');
+%! assert (val, 'abc');
+%! assert (cnt, 2);
+%! assert (msg, 'sscanf: format failed to match');
+%! assert (pos, 4);
+%! [val, cnt, msg, pos] = sscanf ('abcde', '%2[a-c]', 1);
+%! assert (val, 'ab');
+%! assert (cnt, 1);
+%! assert (msg, '');
+%! assert (pos, 3);
+%! [val, cnt, msg, pos] = sscanf ('abcde', '%[a-c]', 1);
+%! assert (val, 'abc');
+%! assert (cnt, 1);
+%! assert (msg, '');
+%! assert (pos, 4);
+
+## Extensive testing of '%[^]'
+%!test
+%! [val, cnt, msg, pos] = sscanf ('abcde', '%[^de]');
+%! assert (val, 'abc');
+%! assert (cnt, 1);
+%! assert (msg, 'sscanf: format failed to match');
+%! assert (pos, 4);
+%! [val, cnt, msg, pos] = sscanf ('abcde', '%10[^de]');
+%! assert (val, 'abc');
+%! assert (cnt, 1);
+%! assert (msg, 'sscanf: format failed to match');
+%! assert (pos, 4);
+%! [val, cnt, msg, pos] = sscanf ('abcde', '%2[^de]');
+%! assert (val, 'abc');
+%! assert (cnt, 2);
+%! assert (msg, 'sscanf: format failed to match');
+%! assert (pos, 4);
+%! [val, cnt, msg, pos] = sscanf ('abcde', '%2[^de]', 1);
+%! assert (val, 'ab');
+%! assert (cnt, 1);
+%! assert (msg, '');
+%! assert (pos, 3);
+%! [val, cnt, msg, pos] = sscanf ('abcde', '%[^de]', 1);
+%! assert (val, 'abc');
+%! assert (cnt, 1);
+%! assert (msg, '');
+%! assert (pos, 4);
+
 ## bug #47741
 %!assert (sscanf ('2147483647', '%d'), 2147483647)
 %!assert (sscanf ('2147483647', '%i'), 2147483647)
@@ -389,10 +501,169 @@
 
 %!test <*62723>
 %! [val, count, msg, pos] = sscanf ("p", "%c");
-%! assert (val, "p");
+%! assert (val, 'p');
+%! assert (count, 1);
+%! assert (msg, '');
+%! assert (pos, 2);
+
+%!test <*62723>
+%! [val, count, msg, pos] = sscanf (' ,1 ', ' %s ', 1);
+%! assert (val, ',1');
 %! assert (count, 1);
-%! assert (msg, "");
-%! assert (pos, 2);
+%! assert (msg, '');
+%! assert (pos, 5);
+
+## Test NaN at EOF
+%!test <*63383>
+%! [val, count, msg, pos] = sscanf ('2 3 n', '%f');
+%! assert (val, [2; 3]);
+%! assert (count, 2);
+%! assert (msg, 'sscanf: format failed to match');
+%! assert (pos, 5);
+%! [val, count, msg, pos] = sscanf ('2 3 na', '%f');
+%! assert (val, [2; 3; NA]);
+%! assert (count, 3);
+%! assert (msg, '');
+%! assert (pos, 7);
+%! [val, count, msg, pos] = sscanf ('2 3 nan', '%f');
+%! assert (val, [2; 3; NaN]);
+%! assert (count, 3);
+%! assert (msg, '');
+%! assert (pos, 8);
+
+## Test NaN within string
+%!test <*63383>
+%! [val, count, msg, pos] = sscanf ('2 3 n 4', '%f');
+%! assert (val, [2; 3]);
+%! assert (count, 2);
+%! assert (msg, 'sscanf: format failed to match');
+%! assert (pos, 5);
+%! [val, count, msg, pos] = sscanf ('2 3 na 4', '%f');
+%! assert (val, [2; 3; NA; 4]);
+%! assert (count, 4);
+%! assert (msg, '');
+%! assert (pos, 9);
+%! [val, count, msg, pos] = sscanf ('2 3 nan 4', '%f');
+%! assert (val, [2; 3; NaN; 4]);
+%! assert (count, 4);
+%! assert (msg, '');
+%! assert (pos, 10);
+
+## Test Inf at EOF
+%!test <*63383>
+%! [val, count, msg, pos] = sscanf ('2 3 i', '%f');
+%! assert (val, [2; 3]);
+%! assert (count, 2);
+%! assert (msg, 'sscanf: format failed to match');
+%! assert (pos, 5);
+%! [val, count, msg, pos] = sscanf ('2 3 in', '%f');
+%! assert (val, [2; 3]);
+%! assert (count, 2);
+%! assert (msg, 'sscanf: format failed to match');
+%! assert (pos, 5);
+%! [val, count, msg, pos] = sscanf ('2 3 inf', '%f');
+%! assert (val, [2; 3; Inf]);
+%! assert (count, 3);
+%! assert (msg, '');
+%! assert (pos, 8);
+
+## Test Inf within string
+%!test <*63383>
+%! [val, count, msg, pos] = sscanf ('2 3 i 4', '%f');
+%! assert (val, [2; 3]);
+%! assert (count, 2);
+%! assert (msg, 'sscanf: format failed to match');
+%! assert (pos, 5);
+%! [val, count, msg, pos] = sscanf ('2 3 in 4', '%f');
+%! assert (val, [2; 3]);
+%! assert (count, 2);
+%! assert (msg, 'sscanf: format failed to match');
+%! assert (pos, 5);
+%! [val, count, msg, pos] = sscanf ('2 3 inf 4', '%f');
+%! assert (val, [2; 3; Inf; 4]);
+%! assert (count, 4);
+%! assert (msg, '');
+%! assert (pos, 10);
+
+## Test '-' at EOF
+%!test <*63383>
+%! [val, count, msg, pos] = sscanf ('2 3 -', '%d');
+%! assert (val, [2; 3]);
+%! assert (count, 2);
+%! assert (msg, 'sscanf: format failed to match');
+%! assert (pos, 5);
+%! [val, count, msg, pos] = sscanf ('2 3 -', '%f');
+%! assert (val, [2; 3]);
+%! assert (count, 2);
+%! assert (msg, 'sscanf: format failed to match');
+%! assert (pos, 5);
+
+## Test '-' within string
+%!test <63383>
+%! [val, count, msg, pos] = sscanf ('1 2 - 3', '%d');
+%! assert (val, [1; 2]);
+%! assert (count, 2);
+%! assert (msg, 'sscanf: format failed to match');
+%! assert (pos, 5);
+%! [val, count, msg, pos] = sscanf ('1 2 - 3', '%f');
+%! assert (val, [1; 2]);
+%! assert (count, 2);
+%! assert (msg, 'sscanf: format failed to match');
+%! assert (pos, 5);
+
+## Test '+' at EOF
+%!test <*63383>
+%! [val, count, msg, pos] = sscanf ('2 3 +', '%d');
+%! assert (val, [2; 3]);
+%! assert (count, 2);
+%! assert (msg, 'sscanf: format failed to match');
+%! assert (pos, 5);
+%! [val, count, msg, pos] = sscanf ('2 3 +', '%f');
+%! assert (val, [2; 3]);
+%! assert (count, 2);
+%! assert (msg, 'sscanf: format failed to match');
+%! assert (pos, 5);
+
+## Test '+' within string
+%!test <63383>
+%! [val, count, msg, pos] = sscanf ('1 2 + 3', '%d');
+%! assert (val, [1; 2]);
+%! assert (count, 2);
+%! assert (msg, 'sscanf: format failed to match');
+%! assert (pos, 5);
+%! [val, count, msg, pos] = sscanf ('1 2 + 3', '%f');
+%! assert (val, [1; 2]);
+%! assert (count, 2);
+%! assert (msg, 'sscanf: format failed to match');
+%! assert (pos, 5);
+
+%## Test +NA, -NA, +NAN, -NAN
+%!test <*63383>
+%! [val, count, msg, pos] = sscanf ('+NA -NA 1 +NAN -NAN', '%f');
+%! assert (val, [NA; NA; 1; NaN; NaN]);
+%! assert (count, 5);
+%! assert (msg, '');
+%! assert (pos, 20);
+%! [val, count, msg, pos] = sscanf ('-NA', '%f');
+%! assert (val, NA);
+%! assert (count, 1);
+%! assert (msg, '');
+%! assert (pos, 4);
+%! [val, count, msg, pos] = sscanf ('+NA', '%f');
+%! assert (val, NA);
+%! assert (count, 1);
+%! assert (msg, '');
+%! assert (pos, 4);
+%! [val, count, msg, pos] = sscanf ('-NaN', '%f');
+%! assert (val, NaN);
+%! assert (count, 1);
+%! assert (msg, '');
+%! assert (pos, 5);
+%! [val, count, msg, pos] = sscanf ('+NaN', '%f');
+%! assert (val, NaN);
+%! assert (count, 1);
+%! assert (msg, '');
+%! assert (pos, 5);
 
 %!test
 %! [a, b, c] = sscanf ("1.2 3 foo", "%f%d%s", "C");
@@ -403,14 +674,16 @@
 %!          && v1 == [1; 2; 3; 4; 5; 6] && c1 == 6 && ischar (m1)
 %!          && v2 == [1; 2] && c2 == 2 && ischar (m2)));
 
-%!error <Invalid call to sscanf> sscanf ()
-%!error sscanf (1, 2)
-%!error <Invalid call to sscanf> sscanf ("foo", "bar", "C", 1)
-
 %!test
 %! [x, n] = sscanf ("   0.024000 0.200 0.200 2.000         1987           5           0  0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0    0 2 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 2 0 0 1 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0    0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 4 5 1 2    2 5 5 8 2 8 12 6 15 18 28 26 47 88 118 162 192 130 88 56 27 23 14 9 6 3 4 1 0    2 3 1 0 0 0 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0    0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0    1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0   0.026000 0.250 0.250 2.100         3115           3           0  0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0    0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 1 0 0 0 0    0 0 0 0 1 0 1 0 0 0 0 0 0 0 2 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 1 1 0 1    1 1 0 1 0 1 3 2 0 5 15 25 44 66 145 179 193 172 104 57 17 11 12 2 1 0 1 1 0 1    0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 1 0 0 0 0    0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0    0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0   0.028000 0.300 0.300 2.200         4929           3           0  1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0    0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0    0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 1 0    1 0 1 0 1 2 2 3 2 3 14 21 49 80 148 184 218 159 124 63 37 13 12 3 1 1 0 0 0 0    0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 1 1 0 0    0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0    0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0   0.030000 0.350 0.350 2.300         7051           5           0  0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 1 0 1 0 0    0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1    0 0 1 0 0 0 2 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 1    0 0 0 2 0 0 0 1 5 6 14 28 51 88 154 177 208 169 124 65 39 15 5 3 3 2 1 0 1 0 1   0 0 0 0 1 1 1 0 0 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 1 0 0 0    0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0    0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0   0.032000 0.400 0.400 2.400         9113           4           0  0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0    1 0 0 0 0 2 0 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 1 0 0 1 0 0 0 0 1 0 0 0 0 0 0 0    0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 0 0 2 0    1 0 0 1 1 0 2 3 5 3 17 30 60 117 156 189 209 129 102 64 56 16 11 4 2 2 0 0 0 0   1 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0    1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0    0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0   0.034000 0.450 0.450 2.500        11811           6           0  0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0    0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 0 0    0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0    0 0 2 1 0 0 1 0 5 5 15 21 57 99 149 190 195 159 130 69 41 16 10 2 5 3 0 1 0 0    0 0 0 1 0 1 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0    0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0    0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0   0.036000 0.500 0.500 2.600        14985           3           0  0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0    0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0    0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 1 0 0 1 0 0 0 0    0 0 0 0 1 0 0 2 2 6 10 34 60 95 126 177 194 155 99 71 44 17 6 7 2 0 0 0 3 0 0    1 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 1 0 0    0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0    0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0   0.038000 0.550 0.550 2.700        18391           3           0  0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 0 0 0 1 0 0 0 0    0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 2    1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 2 0 0 1 1 0 1    2 1 0 0 0 1 0 1 3 6 19 27 52 95 161 154 169 134 94 64 37 19 9 6 0 2 1 0 0 0 0    1 2 0 1 0 0 0 0 0 0 0 0 0 0 0 1 0 2 2 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0    0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0    0 0 0 0 0 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0   0.040000 0.600 0.600 2.800        22933           5           0  0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0    0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 1 0 0 0 0 0 0 0 1 0    0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 1 1 0 1    0 0 0 0 0 2 0 3 4 7 18 27 47 82 134 163 133 138 101 58 34 26 10 5 2 1 2 1 1 0    2 1 0 0 0 0 1 0 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0    0 0 0 0 0 0 0 0 0 0 0 0 0 2 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0    0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0   0.042000 0.650 0.650 2.900        27719           5           0  0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0    0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 1 0 0 0 0 0 0 1 0 0 2 0 0 0 0 0 0 0 0 0 0 0 0    0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0    0 0 1 0 0 0 1 1 2 8 16 37 51 87 128 153 146 123 105 62 35 24 8 3 5 0 1 2 1 0 0   0 1 1 1 0 0 0 1 0 1 0 0 2 1 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 1 0 0 0 0 0    0 0 1 0 1 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0    0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0   0.044000 0.700 0.700 3.000        32922           5           0  0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 1 0 0    0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 1 0 0 0 0 2 0    0 0 0 0 0 0 0 2 1 0 0 0 0 1 1 1 1 0 0 1 0 0 0 1 0 0 0 0 0 0 1 1 0 0 0 1 0 1 1    1 1 0 0 0 1 4 3 5 5 15 35 54 88 132 168 149 105 92 62 30 16 17 4 5 1 0 0 1 0 1   1 0 1 1 0 0 0 1 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 1 0 0 0 0 0 0 0    0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0    0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0   0.046000 0.750 0.750 3.100        38973           3           0  0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0    0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1    0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 1 0 0    0 0 0 1 0 0 0 4 3 5 20 37 56 94 110 135 149 124 84 58 36 17 14 7 1 0 2 0 1 0 0   1 1 0 0 0 0 0 1 1 0 0 0 1 0 1 1 0 0 1 1 1 0 0 0 0 1 1 0 0 1 0 0 0 0 1 0 0 0 1    1 0 1 0 1 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0    1 0 0 0 0 0 1 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0   0.048000 0.800 0.800 3.200        45376           5           0  1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0    0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0    0 0 0 0 0 0 0 1 0 0 0 1 1 0 0 1 1 0 0 2 1 1 2 0 0 0 1 0 0 0 0 0 1 0 0 0 0 1 0    0 0 0 1 0 0 0 0 1 3 18 34 55 82 104 135 116 99 79 60 51 29 10 4 3 1 1 1 0 0 1    0 0 0 1 0 0 3 1 2 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 2 0 0 0 0 0 0 0 0 0 0 0 1    0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0    1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0   0.050000 0.850 0.850 3.300        52060           3           0  0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0    0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 1 0 0 0 0 0 0 0 0 1 0 0    0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 1 1 0 0 0 0 1 1 0 0 0 1    0 0 0 0 0 2 2 1 3 12 24 40 39 107 121 127 138 100 86 68 44 23 15 7 3 1 1 0 1 1   0 0 2 0 0 0 0 0 1 0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 1 1 0 1 0 0 0 2 0 0 0 1 0 0 0    0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0    0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0   0.052000 0.900 0.900 3.400        59454           3           0  0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 1 0 0 0 1    0 0 0 1 0 1 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 0    0 0 0 0 0 1 0 0 0 0 0 2 0 0 0 0 0 0 1 0 0 0 0 1 0 1 0 1 0 0 2 0 2 1 0 0 0 1 0    0 1 0 0 0 0 0 3 3 6 21 32 68 90 132 111 122 107 73 57 47 24 11 7 4 2 2 1 0 0 0   0 0 0 0 0 1 0 0 1 0 0 2 0 1 1 0 0 1 0 0 0 0 0 3 0 1 0 0 0 0 1 1 0 0 0 1 0 0 0    0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0    0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0   0.054000 0.950 0.950 3.500        67013           3           0  0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0    0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0    0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 0 1 0 1 0 0 0 0 1 0 0 1 1 0 0 0    1 0 1 0 1 2 4 3 7 9 28 31 71 94 115 96 108 78 82 60 38 17 12 11 4 3 1 1 0 2 1    0 0 0 2 1 3 0 0 0 0 3 0 0 1 0 0 0 0 0 0 0 2 0 0 0 1 0 2 0 1 0 2 0 1 0 0 1 0 0    0 1 0 0 0 1 0 0 1 0 1 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0    0 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0   0.056000 1.000 1.000 3.600        75475           3           0  0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0    0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0    0 2 0 0 0 0 0 0 0 0 0 0 0 0 1 2 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 1 3 0 0 1    1 2 0 1 4 0 1 8 6 7 17 41 56 71 109 113 84 103 72 54 35 22 6 9 1 7 5 4 0 0 1 0   0 0 0 0 0 1 0 0 2 1 0 0 0 0 2 0 0 1 0 0 1 0 0 0 0 0 0 1 0 2 0 1 0 0 0 0 1 0 1    0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 3 0 0 0 1 0 0 0 0 0 0 1 1 0 0 2 0 0 0 0    0 0 0 0 1 0 0 0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0   0.058000 1.050 1.050 3.700        83558           3           0  0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0    0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0    0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 1 0 1 0 1 0 0 0 0 0 0 0 0 1 2 0 0    2 0 0 1 0 3 2 3 6 15 27 41 77 73 94 94 92 76 61 56 42 23 13 11 6 2 1 2 0 1 2 0   0 1 0 1 0 0 1 0 0 1 1 1 0 0 0 1 0 0 0 1 0 0 0 0 1 1 0 0 0 0 2 0 0 0 0 0 1 2 0    0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0    0 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0   0.060000 1.100 1.100 3.800        93087           3           0  0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1    0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 0 0 0 0 0 0    0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 0 0 0 0 1 2 2 0 0 0 1 0 1 1 0 0 0 1 1 0 4    0 0 1 2 0 3 1 3 5 13 33 31 65 75 77 96 97 80 59 45 36 32 18 2 5 0 1 0 0 1 0 0    3 0 0 0 0 1 0 0 0 0 0 1 0 0 1 2 0 0 0 0 1 0 0 0 0 1 0 1 1 1 0 0 2 0 0 2 0 1 0    0 0 0 0 0 0 1 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0    0 1 1 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0   0.062000 1.150 1.150 3.900       102829           3           0  0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0    0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 1 0 1 0 0 0 1 0 1 0 0 0 0 0 0 0 0 0 1 0 0    0 0 0 0 0 1 1 1 0 0 0 0 1 1 0 0 1 0 1 0 0 0 0 0 1 1 1 0 1 0 1 1 0 1 1 0 2 0 2    1 2 0 0 2 4 3 5 11 9 23 43 53 68 65 87 83 77 59 49 34 18 15 9 4 2 3 2 0 0 0 4    0 1 1 0 0 2 0 0 1 0 0 0 0 1 1 1 0 1 0 0 0 0 2 0 0 0 0 1 0 0 1 1 1 1 0 0 0 1 0    0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 1 0 0 1 0 1 0 0 0 0 0 0 1 0 0 0    0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0   0.064000 1.200 1.200 4.000       113442           3           0  0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0    0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 1 0 1 0 0 1 0 0 0 1 0 0 0 0 0 1 0 0 0    0 0 0 0 0 1 0 1 0 1 0 0 0 0 0 1 0 0 0 0 1 0 0 0 1 0 1 1 1 0 1 1 1 1 1 0 0 0 1    2 0 0 0 2 0 4 5 11 13 29 39 61 68 61 75 76 74 73 44 37 29 19 6 3 3 2 0 1 2 1 0   0 0 0 1 1 1 0 1 1 0 0 0 1 0 1 1 0 1 2 0 2 1 1 1 0 0 0 0 1 0 0 1 1 1 1 1 0 0 0    0 0 0 0 1 0 0 0 0 2 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0    0 1 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 1 0 0 0 0 0 0 0 0 0 0 0   0.066000 1.250 1.250 4.100       126668           3           0  0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0    0 0 1 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 1    0 0 0 0 0 1 0 0 0 0 0 1 0 0 1 1 0 0 0 1 1 2 3 0 2 1 2 0 1 0 3 0 0 0 1 0 1 1 3    0 0 1 3 0 2 4 3 12 12 30 48 56 66 77 78 71 82 52 31 32 19 20 16 8 2 1 3 0 0 2    1 0 1 0 1 0 0 0 1 3 1 0 1 0 1 1 1 0 0 0 0 0 2 0 2 0 0 0 0 0 1 0 0 0 0 1 1 0 0    0 0 0 1 0 0 0 0 0 2 0 3 1 0 0 1 0 0 0 0 0 0 1 0 1 1 0 0 0 1 0 0 0 0 1 0 0 0 0    0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0   0.068000 1.300 1.300 4.200       138042           3           0  0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 1 0 2 0 0 1 0 1 0 0 0 0 0    0 0 0 1 0 0 2 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0    0 1 0 0 0 0 0 0 0 1 0 0 1 0 0 0 1 0 0 0 0 3 0 0 1 0 0 1 2 0 0 0 3 0 1 0 0 3 0    1 0 1 1 3 1 4 7 11 14 27 36 44 68 72 70 71 45 44 46 29 13 16 11 5 2 0 3 0 0 0    0 1 1 2 0 0 1 1 2 1 1 0 1 0 0 0 0 0 0 0 0 0 0 1 0 1 1 0 1 2 0 0 1 1 0 1 1 1 0    0 1 0 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0    0 0 0 1 0 0 1 0 0 0 0 2 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0   0.070000 1.350 1.350 4.300       152335           3           0  0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0    0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 2 0 0 0 1 0 0 0 0 0 0 0 0 1 0 1 0    1 0 0 0 2 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 2 0 0 0 0 1 1 1 0 1 1 0 1 1 1 1 0 2 0    0 0 0 0 2 0 1 7 14 19 34 35 54 72 68 72 68 58 48 36 37 27 25 17 1 4 1 0 0 0 1    2 2 0 0 1 1 1 2 1 0 3 1 0 1 0 2 1 0 0 0 1 1 1 2 0 0 0 0 1 1 0 1 1 0 2 1 1 1 1    0 0 0 1 1 0 0 2 0 0 1 0 0 0 1 1 0 2 1 1 0 0 0 0 2 0 0 0 0 0 0 0 1 1 0 0 0 0 1    0 0 1 0 0 0 0 0 0 0 0 2 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 0 0   0.072000 1.400 1.400 4.400       166280           4           0  0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0    0 1 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 1 0 1 1 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0    2 0 0 0 0 0 0 0 1 0 1 0 1 1 1 0 0 1 0 1 0 0 3 4 2 2 0 0 0 0 0 1 1 3 1 0 3 2 2    1 2 2 0 2 2 1 8 14 26 24 29 47 47 68 65 63 55 42 41 26 29 17 8 4 4 1 0 1 2 0 0   0 1 1 2 0 1 2 1 0 0 1 1 1 0 0 1 0 0 0 1 0 0 1 2 1 2 1 0 0 0 0 0 1 1 2 0 2 2 0    0 0 0 1 1 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 1 0 0    0 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0   0.074000 1.450 1.450 4.500       179484           3           0  0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 0 0 1 0 0 1 0 0 0    1 0 0 1 0 0 0 0 0 0 0 0 0 0 0 2 1 0 0 1 0 1 0 0 1 0 1 2 0 0 0 0 0 0 0 0 0 1 0    0 0 1 0 1 0 1 0 1 1 0 0 0 0 0 0 0 0 1 1 0 0 0 1 0 1 1 0 1 1 1 2 0 0 1 1 2 1 0    1 1 2 2 0 1 5 6 10 20 43 50 57 62 53 62 66 45 42 33 27 26 23 14 3 0 2 0 1 0 0    1 1 0 0 2 1 1 0 0 3 0 1 1 1 0 1 1 0 1 0 1 2 1 0 0 1 2 0 2 0 0 0 0 1 1 3 1 0 0    2 1 1 1 0 0 0 0 0 0 1 2 0 1 0 0 0 0 0 1 1 0 2 0 0 0 0 0 1 0 2 1 0 0 0 0 0 0 1    0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0   0.076000 1.500 1.500 4.600       197657           3           0  0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 2 0 0 0 1 1 0 0 0 0 0 0 1 0 1 0    0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 1 2 0 0 0 1 0 0 0 0    0 0 1 0 1 0 0 0 0 0 0 0 0 1 2 0 0 0 2 1 1 0 1 1 0 1 1 3 2 1 1 2 1 0 1 0 0 0 0    0 1 1 1 0 5 3 7 12 24 38 32 41 48 54 66 71 49 46 31 38 25 15 8 6 6 5 0 1 3 0 1   1 1 1 1 0 1 2 0 1 0 0 0 1 0 2 1 2 0 0 0 0 1 3 1 0 0 0 0 1 1 0 1 0 1 1 1 1 1 0    4 1 1 1 0 3 0 0 0 2 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 1 1 0 0 0 0 0 0 0 0 0 0    0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0   0.078000 1.550 1.550 4.700       212054           3           0  0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 1 0 0 1 0 0 0 0    0 1 0 1 1 0 0 1 0 0 1 0 0 0 0 0 0 0 1 1 1 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 1    0 0 2 0 0 0 1 0 0 1 0 1 1 0 1 3 1 0 0 1 2 0 0 0 1 0 0 0 0 0 2 1 2 1 1 1 0 0 1    5 1 1 2 3 5 7 9 11 22 31 37 48 50 52 54 57 37 38 38 33 24 11 19 11 3 1 2 0 3 3   2 1 0 1 3 0 1 1 1 1 1 2 0 0 0 1 1 2 0 1 1 3 0 1 1 0 0 1 0 2 0 1 0 0 1 3 0 2 0    1 0 1 2 0 1 1 1 1 1 0 3 0 1 0 0 0 1 0 0 0 1 0 1 0 0 0 0 0 0 1 1 0 0 0 0 0 1 0    0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 0 1 0 0 0 0 0 0 0 0   0.080000 1.600 1.600 4.800       231971           3           0  0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 2 0 0 0 1 1 1 0 1 0 0 0 0 1 0 1 1    0 0 0 0 2 0 0 0 1 0 0 0 0 0 1 0 0 0 0 1 2 1 0 1 1 1 0 1 0 0 1 0 1 3 0 0 0 1 0    0 0 1 1 1 0 0 4 1 1 0 2 0 1 1 1 2 0 0 0 1 0 1 2 1 2 3 2 0 1 0 4 3 1 1 1 1 3 1    0 0 0 2 1 0 2 7 17 13 29 47 58 59 52 38 51 51 38 34 35 21 14 13 4 1 0 1 1 1 0    2 2 4 1 0 1 1 4 0 0 0 2 0 2 2 2 0 0 1 3 2 1 1 2 2 2 2 1 0 3 0 2 1 2 1 2 2 0 0    1 1 0 2 0 2 2 0 1 0 2 2 3 1 2 3 1 1 0 1 0 2 0 1 2 1 2 0 2 1 0 0 3 0 0 1 1 1 1    0 0 1 0 0 1 0 0 0 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0   0.082000 1.650 1.650 4.900       252503           3           0  0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 2 0 0    0 0 0 0 0 1 0 0 0 1 1 0 0 1 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0    0 0 0 0 2 0 0 1 0 1 2 2 2 1 0 2 0 1 0 1 1 2 2 0 3 0 0 4 1 0 0 3 0 0 1 2 0 1 1    1 3 0 1 0 2 9 11 25 27 34 53 41 49 43 47 36 31 38 22 30 22 18 9 5 9 2 2 1 2 2    3 1 4 1 1 0 0 1 2 0 2 1 0 0 1 3 2 2 1 0 0 0 1 2 1 0 0 0 2 1 1 0 2 0 0 1 0 0 2    1 3 1 1 1 0 2 1 1 0 2 1 0 1 3 0 0 0 0 2 0 0 1 0 0 0 0 0 1 2 1 1 1 0 2 1 0 0 0    2 0 1 0 0 0 0 1 0 0 0 0 1 0 0 2 0 1 0 1 0 0 0 0 0 0 0 0 0 0   0.084000 1.700 1.700 5.000       267889           3           0  0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 1 0 1 1 0 0 0 0 0 0 0 1 0 1    0 1 0 0 0 0 0 0 0 0 0 1 0 0 1 0 0 1 0 0 0 1 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0    0 1 0 1 1 0 3 0 1 1 1 0 1 2 1 0 2 0 2 4 0 1 0 0 0 1 1 0 1 3 2 0 2 0 4 0 0 2 0    1 4 2 4 3 3 6 10 14 28 37 54 36 40 52 40 50 46 40 32 26 29 12 18 5 2 0 2 4 1 2   1 0 2 1 2 2 1 0 1 0 2 1 2 4 1 1 5 1 0 2 0 1 2 3 2 2 1 2 1 0 2 1 2 1 1 4 1 2 1    4 0 2 2 0 0 3 1 0 2 0 0 1 1 1 0 0 2 1 0 0 0 0 0 0 0 1 1 1 1 0 0 0 1 0 0 0 1 0    0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0   0.086000 1.750 1.750 5.100       290294           3           0  0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 2 0 0 0 1 0 0 0 0 1 0 1 0 0 1 0 0 0 0 0 0    0 0 0 0 1 0 0 0 0 1 0 0 0 1 1 3 1 1 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 1 1 0 0 2    1 0 1 0 1 0 0 2 2 0 1 2 2 0 2 0 2 0 1 0 0 1 1 1 3 1 1 1 1 3 4 1 1 2 2 2 1 0 3    0 0 0 2 4 5 6 16 18 20 31 40 54 55 46 41 52 35 27 21 28 27 20 15 8 6 7 1 0 0 3   0 0 2 2 0 3 1 3 1 1 2 0 0 1 2 1 3 2 0 1 2 1 3 1 1 1 1 1 2 0 2 1 0 1 1 1 3 1 1    2 0 1 0 1 0 2 1 1 0 0 1 2 0 3 1 1 0 0 0 1 3 1 1 1 0 0 1 2 1 0 0 1 1 1 0 0 1 0    0 0 0 0 0 2 0 1 0 0 0 2 1 0 2 0 0 0 0 1 1 0 1 0 0 0 0 0 0 0   0.088000 1.800 1.800 5.200       312476           6           0  0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 1 1 0 0 0 1 0 1 0 1 1 0 0 0 0    0 0 2 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 2 0 0 0 1 0 1 0 0 0 0 0 0 2    1 0 0 1 0 0 1 1 1 1 4 2 0 1 0 0 3 0 0 0 0 0 1 1 4 0 0 0 0 1 1 2 1 0 3 0 0 2 2    4 0 3 1 6 9 10 13 21 24 32 43 33 41 43 49 50 32 26 31 27 12 16 17 3 3 3 5 0 3    0 2 1 3 3 2 1 2 3 1 2 1 1 1 2 0 1 1 0 2 0 3 0 0 2 0 0 0 0 1 0 1 1 3 3 0 1 1 1    1 1 1 2 2 2 0 3 1 0 2 2 2 0 0 0 0 3 1 2 5 1 1 2 0 0 3 3 0 2 2 0 0 0 0 1 2 0 0    1 0 0 1 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0   0.090000 1.850 1.850 5.300       337348           3           0  0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 1 1 2 0 1 0 1 0 0 0 1 0 0 0    0 0 0 1 0 0 0 0 2 0 1 1 0 0 0 1 0 1 0 0 0 0 1 0 1 0 0 0 0 0 0 0 0 1 1 0 0 0 0    2 0 0 0 1 3 2 0 0 2 2 3 3 2 2 2 0 0 1 1 3 1 3 0 0 0 0 0 0 1 2 1 2 1 2 2 2 0 1    1 0 4 2 2 7 6 15 22 21 39 37 50 31 51 30 33 34 34 26 21 14 13 10 9 4 3 3 4 2 2   0 1 2 3 3 0 1 3 2 5 3 2 2 4 0 2 3 0 4 2 1 2 2 2 4 2 1 3 1 3 2 1 3 1 2 4 1 1 1    1 2 4 1 3 3 3 1 0 4 1 0 1 1 1 1 2 3 0 3 0 0 4 1 1 1 0 2 2 2 1 2 2 0 1 1 0 0 0    2 0 1 0 1 0 0 1 0 0 0 1 3 0 0 1 0 0 1 1 1 0 0 1 0 0 0 0 0 0   0.092000 1.900 1.900 5.400       357303           3           0  0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 1 0 0 1 1 0 1 0 0 1 0    0 0 0 0 0 0 1 1 0 0 1 0 0 0 0 0 0 1 3 1 0 1 0 0 0 0 1 0 0 1 0 0 1 1 2 2 0 0 2    2 1 1 1 1 1 1 0 1 0 0 1 1 1 3 1 1 1 1 1 0 1 4 0 1 1 1 3 0 1 1 2 2 2 0 2 3 2 2    2 2 1 2 1 3 8 22 14 32 36 46 39 42 39 29 36 38 26 24 26 18 16 19 10 9 3 6 5 0    3 2 1 1 1 2 0 2 1 1 0 1 1 3 1 0 2 4 2 2 1 4 1 2 2 1 1 0 1 2 0 2 2 2 4 2 1 1 0    2 1 3 1 2 3 4 2 3 2 3 0 1 2 1 0 0 0 4 1 1 1 2 1 3 1 0 5 1 0 0 0 0 0 0 1 0 2 0    1 2 1 0 1 0 0 0 0 0 1 1 0 1 0 1 4 0 0 0 1 0 1 0 0 0 0 0 0 0 0   0.094000 1.950 1.950 5.500       383138           3           0  0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 1 1 1 1 0 1 0 0 0 1 0 0 0 0 0 1 0    0 0 1 0 0 2 1 0 1 1 1 0 0 0 0 0 0 1 1 0 1 0 0 1 1 0 1 0 0 0 0 0 0 0 2 1 1 1 1    2 1 0 2 0 1 0 3 2 1 3 0 1 3 1 1 0 5 0 1 0 1 2 0 0 1 1 2 0 0 6 1 0 3 2 2 3 4 5    0 4 2 1 5 4 11 15 22 27 28 57 38 38 40 38 39 38 27 26 30 18 14 10 10 4 4 4 3 3   2 2 2 2 1 1 1 1 2 2 3 4 1 2 3 1 2 1 2 2 2 1 3 2 1 5 0 1 1 1 3 2 2 2 1 3 1 1 0    3 2 2 0 0 2 2 2 0 0 0 2 0 1 3 1 2 3 2 1 1 0 1 1 1 0 3 2 2 1 0 0 1 3 1 1 0 1 0    0 0 0 0 1 0 0 0 0 1 0 0 3 1 0 0 0 0 1 0 1 1 0 0 0 1 0 0 0 0 0   0.096000 2.000 2.000 5.600       409868           3           0  0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 0 1 0 0 0 1 0 0 0 0 0 0 1 0 1 0 1 0 2 0 0    1 0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 2 0 1 0 0 2 0 2 0 0 0 0 1 0 0 2 1    2 2 2 1 2 1 1 1 1 1 2 0 0 1 1 0 1 0 2 1 2 0 2 0 3 1 2 1 3 1 5 0 2 2 1 2 4 1 2    0 3 1 4 7 5 9 13 22 19 31 27 28 41 34 39 37 22 23 21 22 17 23 15 8 9 3 8 0 3 1   2 2 2 3 1 0 4 2 4 2 2 2 2 4 2 1 1 0 2 0 3 0 3 2 2 1 2 2 1 4 1 2 2 1 1 5 2 1 2    1 2 2 1 0 2 4 3 2 1 2 2 3 2 3 1 2 1 1 1 1 2 1 1 2 2 1 2 3 2 1 1 0 2 2 4 0 1 1    1 1 1 0 0 1 1 3 0 0 0 0 0 1 0 0 2 0 1 2 0 1 1 1 0 1 0 1 0 0   0.098000 2.050 2.050 5.700       439102           3           0  0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 1 1 0 0 1 0 1 0 1 0 0 0 0 1 1 0 1 0 0 1 1 0    0 1 1 0 0 1 1 0 1 0 0 0 0 0 0 0 1 2 0 0 1 1 1 1 2 0 1 1 0 0 0 0 1 1 1 0 4 0 0    0 2 1 1 0 3 4 0 1 2 2 1 0 3 0 3 2 0 0 2 0 1 0 0 1 0 1 3 1 3 5 0 2 2 3 5 2 2 2    0 3 2 3 6 5 16 21 19 23 28 29 35 42 42 44 39 33 23 30 18 25 24 15 13 5 4 2 2 0   3 3 0 0 1 3 0 1 1 3 2 4 3 4 2 1 1 1 3 1 0 0 2 2 4 2 2 1 4 2 4 2 2 2 1 2 2 1 2    0 4 2 2 3 1 2 1 1 2 2 1 2 4 2 1 4 1 2 2 2 2 0 2 0 3 0 1 0 2 1 0 4 2 1 3 2 1 0    2 1 1 1 1 0 1 1 2 1 1 1 2 0 1 0 2 1 1 0 0 1 0 0 1 0 0 0 0 0 0   0.100000 2.100 2.100 5.800       467340           3           0  0 0 0 0 0 0 0 0 0 0 0 0 0 2 1 0 0 1 0 0 1 2 0 0 0 0 0 1 0 2 0 0 2 0 0 1 1 0 0    0 1 0 0 1 1 0 0 0 0 1 1 0 0 1 0 0 1 0 0 0 1 1 0 0 0 0 0 1 0 1 0 0 0 0 1 2 0 2    2 4 1 0 1 1 2 3 4 1 4 1 5 1 2 1 0 2 2 2 1 5 4 1 5 4 0 1 2 4 2 2 0 2 1 2 5 4 1    1 1 2 5 7 9 16 23 31 15 22 36 36 44 42 29 31 28 28 18 35 12 10 13 8 4 3 2 2 5    1 2 3 3 1 3 3 5 2 0 3 4 1 2 2 3 0 0 5 2 3 6 2 1 2 5 3 4 3 1 1 1 1 2 2 4 0 2 3    1 2 1 2 4 5 4 3 5 2 1 2 0 5 0 2 2 4 1 0 4 1 0 2 1 2 0 0 1 3 2 4 3 0 2 3 3 3 4    2 2 0 0 0 0 1 1 0 3 2 0 1 2 0 4 2 1 1 1 2 0 0 0 0 0 0 0 0 0 0   0.102000 2.150 2.150 5.900       497495           5           0  0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 0 1 0 2 1 0 0 0 0 1 0 1 0 0 0 0 1 2    0 0 0 0 0 2 0 0 1 0 1 0 0 0 0 1 1 0 0 0 1 1 1 1 2 0 0 1 0 0 0 1 0 2 2 1 0 0 0    2 0 2 1 1 1 6 3 2 0 3 2 2 2 1 1 3 4 1 0 1 2 4 2 3 3 1 1 1 1 3 3 1 4 1 3 4 3 2    3 1 2 2 5 11 11 14 26 27 28 28 28 36 39 42 29 33 24 20 29 18 13 17 13 6 10 4 3   3 6 1 0 1 0 2 1 3 2 3 1 2 3 1 2 1 2 0 2 2 3 1 3 1 1 2 4 4 1 4 3 2 2 3 5 5 3 0    2 5 3 5 1 4 1 1 3 4 2 2 2 2 1 3 0 1 1 2 2 4 2 1 3 2 0 1 2 1 0 2 3 1 2 0 0 0 2    0 0 1 3 0 0 1 2 0 3 1 0 3 1 2 2 1 1 2 0 0 0 0 2 0 0 1 0 0 0 0 0   0.104000 2.200 2.200 6.000       529288           3           0  0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 2 0 0    0 0 1 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 0 0 0 0 0 2 1 0 0 1 3 0 2 0 2 0 0    3 2 2 0 4 0 3 2 2 1 3 1 7 3 1 1 0 4 3 2 1 0 0 3 2 3 5 2 1 4 1 5 1 0 3 2 3 0 1    2 4 7 3 7 8 12 15 20 24 34 39 34 35 27 36 34 23 22 26 15 24 12 12 14 5 3 0 7 1   1 3 5 1 2 2 2 4 3 1 2 5 2 2 3 1 1 4 2 1 3 0 4 5 4 6 4 5 3 3 3 3 1 1 5 0 6 1 2    4 2 3 2 1 3 2 0 0 0 1 3 3 0 1 4 0 3 2 3 0 3 3 0 2 3 4 3 1 1 1 2 5 3 1 2 1 1 2    4 1 0 2 4 1 3 0 0 3 0 1 3 0 1 0 0 1 1 1 0 1 1 1 0 0 0 0 0 0 0   0.106000 2.250 2.250 6.100       560628           3           0  0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 2 0 1 0 1 0 1 0 1 0 0 1 0 0 0 0 0 0 1 1 0 1    1 0 0 1 1 1 0 1 1 0 0 0 1 1 1 1 0 0 1 1 2 0 0 0 0 2 0 3 1 1 0 0 2 2 2 0 5 2 1    1 1 1 3 1 2 3 0 1 0 0 0 0 1 0 2 2 1 2 1 0 4 3 2 1 2 1 0 4 2 2 0 2 1 1 2 3 1 2    1 2 4 4 11 12 17 19 19 29 30 24 30 35 51 32 36 34 31 19 22 17 11 19 11 7 6 6 3   4 0 3 3 2 0 2 2 2 3 1 5 3 2 3 5 1 0 2 2 5 4 2 3 2 0 1 6 1 2 2 2 2 1 1 2 2 1 4    3 2 2 1 2 5 2 0 2 0 2 5 4 5 2 1 3 6 1 3 4 4 0 0 6 0 2 6 1 2 2 2 0 1 3 1 3 4 2    1 4 2 1 2 3 3 0 3 1 0 2 0 2 1 0 2 1 2 0 0 1 1 0 2 0 0 0 0 0 0 0   0.108000 2.300 2.300 6.200       593293           3           0  0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 2 0 2 2 1 0 0 2 0 1 0 1 0 0 1 2 2 1 0    0 1 0 2 0 0 0 0 0 1 1 1 1 1 0 0 1 1 0 0 1 1 1 2 2 1 0 1 1 0 1 5 0 2 4 1 0 1 4    2 1 3 2 2 3 2 3 2 0 0 3 4 3 1 3 2 2 0 3 0 2 4 0 3 2 5 1 2 1 4 6 1 2 4 0 3 6 1    7 6 4 5 4 10 16 24 22 20 40 37 44 34 29 21 28 36 36 27 23 24 14 10 4 5 2 5 3 6   2 3 3 1 4 2 1 5 1 3 5 3 2 1 2 2 6 2 3 1 1 0 5 3 3 3 4 5 2 2 3 3 5 5 1 6 2 3 2    6 0 5 2 4 3 5 1 2 2 5 1 2 3 1 2 2 2 4 2 5 5 2 2 2 5 0 1 2 5 2 3 2 3 1 1 2 4 0    2 1 4 2 1 1 1 0 1 2 0 0 1 3 1 0 2 1 1 3 3 2 0 0 0 1 2 0 0 0 0   0.110000 2.350 2.350 6.300       636559           3           0  0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 2 1 1 0 0 0 1 1 2 0 0 1 0 0 0 0 0 0 0    1 2 0 0 1 1 1 0 0 0 0 1 0 1 1 0 0 1 0 0 2 0 1 0 1 0 1 0 0 1 1 3 0 1 2 2 0 2 1    1 1 1 0 1 0 1 3 0 3 2 3 4 3 3 4 3 3 2 6 3 1 1 1 2 4 2 3 1 5 1 3 1 4 5 3 3 2 1    3 7 4 3 10 19 17 19 23 27 28 33 39 36 23 23 32 32 16 19 35 23 12 11 12 8 4 5 7   1 2 2 1 2 3 5 4 2 3 2 6 4 4 2 4 1 2 2 1 2 3 0 4 2 1 2 6 2 2 1 3 3 1 6 4 8 5 2    3 5 2 3 0 3 2 3 1 2 2 3 4 3 8 6 2 1 4 6 3 1 2 0 2 0 2 5 0 3 3 3 3 1 3 3 2 5 4    2 1 4 2 2 4 4 1 3 2 5 2 3 1 2 0 4 0 1 0 6 3 1 2 0 2 0 1 0 0 0 0   0.112000 2.400 2.400 6.400       670484           3           0  0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 1 1 1 0 1 0 0 0 1 1 0 0 0 0 0 0 0 0 0 2    0 1 1 1 3 0 0 0 2 1 3 0 1 1 1 0 1 1 1 0 0 1 2 0 1 3 1 5 2 3 0 4 0 2 0 0 1 2 1    0 1 0 0 1 0 2 2 3 2 3 2 2 2 3 4 4 2 3 5 3 3 2 3 3 4 2 4 0 3 2 4 4 1 3 1 3 4 2    2 5 2 8 6 12 17 14 22 27 26 29 39 30 24 36 22 22 20 9 19 15 5 12 16 4 7 5 7 5    5 1 4 5 5 4 4 1 4 4 3 3 3 4 2 2 4 2 4 4 4 4 0 2 3 2 1 4 3 6 1 3 3 3 4 5 4 2 2    2 5 3 0 2 5 4 2 5 3 5 1 1 3 1 1 3 6 6 2 3 2 0 3 2 4 3 4 1 2 2 6 2 0 3 2 2 5 3    3 5 2 1 0 3 1 1 2 2 0 1 1 3 2 3 2 1 1 1 1 3 2 1 0 0 0 0 0 0 0   0.114000 2.450 2.450 6.500       711783           4           0  0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 2 1 0 0 1 0 2 1 2 0 1 0 0 1 0 0 1 1 1 1 0 0 0 1    1 2 0 1 1 0 0 0 2 1 1 1 1 1 2 1 2 3 3 1 1 1 2 3 1 3 2 2 1 0 1 1 4 4 4 1 0 4 0    0 1 1 2 1 3 2 0 3 4 1 1 1 1 3 2 0 1 3 2 1 2 1 0 3 3 2 5 4 2 5 3 4 2 2 5 3 3 3    3 5 5 8 7 14 12 28 22 24 23 36 33 26 32 27 26 18 30 24 15 13 19 15 17 6 5 7 5    4 3 5 3 1 4 4 9 5 3 1 4 0 0 6 2 5 3 3 3 1 2 3 2 4 1 5 5 3 8 2 1 1 4 1 7 5 6 6    4 4 3 2 6 3 3 3 3 1 3 4 5 4 3 4 3 1 2 3 1 2 1 2 2 6 5 2 2 2 4 2 2 0 2 3 3 2 7    4 4 1 4 2 0 3 1 1 2 1 2 3 1 3 2 2 4 3 1 4 0 0 4 2 2 2 1 0 0 0 0   0.116000 2.500 2.500 6.600       745364           5           0  0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 1 2 1 1 2 1 1 1 0 1 0 2 0 1 1    0 1 0 1 0 0 0 0 0 0 1 0 1 0 0 0 0 0 1 1 2 3 0 1 4 4 0 4 0 1 0 1 3 3 0 2 1 2 3    2 1 1 1 2 0 4 0 0 4 5 2 5 4 1 3 5 5 4 0 4 4 2 3 2 3 5 2 2 4 2 3 4 2 3 3 3 3 3    2 4 12 10 13 14 19 22 23 24 36 19 32 25 25 36 24 18 20 21 14 18 13 8 6 9 2 9 5   2 5 3 4 4 3 3 0 4 3 2 5 3 4 2 2 6 3 4 0 2 4 1 3 4 7 4 5 3 2 4 5 5 3 4 4 4 2 3    2 4 4 2 1 5 7 1 5 2 4 1 5 5 3 4 4 3 2 4 2 4 0 6 2 3 4 1 2 2 2 4 1 4 2 2 2 5 6    5 1 4 4 2 3 3 3 1 4 3 4 2 6 2 5 3 2 2 1 3 2 2 5 1 1 0 0 1 0 0 0   0.118000 2.550 2.550 6.700       791846           4           0  0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 2 1 1 0 0 0 0 0 1 0 0 0 1 1 0 1 0 1 0 1 1 0 1 0    1 4 1 2 3 0 3 1 0 1 1 1 0 3 1 2 1 1 1 0 0 1 1 1 3 1 3 2 3 1 2 2 1 3 2 4 1 4 0    2 4 1 4 3 2 1 1 2 1 3 2 3 3 2 1 1 5 3 3 3 3 2 3 4 3 5 3 1 1 2 2 3 5 1 2 1 1 4    4 6 9 6 6 13 17 21 20 24 22 25 20 29 23 28 30 26 27 18 20 17 16 17 12 10 8 5 6   6 6 4 3 1 2 4 6 9 2 2 3 5 7 6 2 3 8 5 4 5 6 4 6 5 3 5 3 2 5 3 2 8 3 5 4 5 3 5    4 3 4 8 4 3 8 3 3 3 1 1 2 2 5 4 7 3 2 3 3 2 2 3 6 3 2 2 1 1 5 2 5 6 3 5 3 4 1    3 1 2 1 0 4 1 4 2 2 2 3 1 1 1 1 3 2 0 1 6 1 1 0 2 1 0 1 0 0 0 0   0.120000 2.600 2.600 6.800       833394           3           0  0 0 0 0 0 0 0 0 0 0 0 1 0 0 2 2 1 1 1 2 1 0 0 0 1 0 1 0 0 0 1 0 0 1 1 2 1 0 0    0 0 0 2 2 0 3 1 0 0 2 1 1 1 1 0 1 2 1 5 0 1 0 2 2 1 2 0 4 2 1 4 3 4 2 2 1 2 1    5 2 3 1 3 0 2 2 2 2 3 4 0 4 2 3 3 4 5 2 2 6 3 4 5 5 5 3 4 6 5 1 3 0 5 4 5 1 3    2 2 6 18 13 17 27 27 21 28 28 24 26 27 29 23 21 16 17 19 22 14 11 9 5 14 7 7 6   4 4 12 3 6 4 5 4 6 4 2 0 1 8 1 6 8 5 2 3 4 5 6 4 2 5 8 3 1 1 6 3 7 8 4 1 6 5 2   8 11 5 6 5 6 2 4 5 1 2 7 2 2 5 5 6 3 3 2 3 8 5 1 9 3 3 2 3 6 3 5 3 2 4 6 3 1 3   5 4 4 4 6 3 3 5 0 2 2 5 1 3 2 2 1 4 2 0 2 2 2 2 4 1 2 1 2 1 1 0   0.122000 2.650 2.650 6.900       876007           3           0  0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 2 1 1 1 1 2 2 1 0 0 1 0 0 0 1 1 0 0 0 2 0 0    4 1 0 2 1 2 0 1 2 0 1 3 2 1 0 1 1 0 1 2 1 0 2 3 3 5 3 3 3 0 1 4 0 1 5 3 4 3 1    2 2 2 4 1 3 3 3 2 3 2 3 2 1 4 4 2 2 5 5 3 4 1 2 1 2 4 2 4 7 2 4 4 2 7 3 5 7 5    3 6 8 10 10 18 21 22 24 14 25 27 29 31 22 25 24 21 27 20 19 22 19 14 13 14 10    5 7 3 4 5 5 3 1 4 3 8 4 5 4 0 3 4 3 4 1 7 6 1 1 3 4 4 3 4 3 6 4 3 4 2 4 4 3 5    6 5 1 1 6 2 6 6 3 5 5 3 2 6 5 4 3 4 6 4 3 5 5 6 5 6 2 4 2 1 2 2 4 2 7 6 2 1 3    1 5 2 1 2 4 3 3 3 2 5 2 4 1 4 3 2 2 5 5 1 1 3 3 2 2 2 2 1 0 0 0 0 0   0.124000 2.700 2.700 7.000       925764           3           0  0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 2 1 3 0 1 1 0 0 0 0 0 1 1 1 1 0 0 0 1 1 0    1 2 0 0 3 2 0 1 2 1 1 2 0 2 1 2 2 0 0 2 3 2 3 2 2 3 2 2 4 0 2 0 5 1 3 2 3 1 2    3 2 0 6 4 3 6 2 5 0 5 2 1 4 4 5 7 4 2 3 5 2 0 2 5 2 4 7 4 4 4 8 5 3 1 7 2 2 1    5 5 5 14 19 16 22 18 30 29 25 36 23 23 22 25 25 27 26 23 14 20 16 16 10 6 6 6    4 2 6 6 6 6 6 4 6 1 0 3 4 4 5 2 4 3 2 4 4 5 5 5 6 10 6 3 6 8 5 5 8 7 4 6 4 3 4   8 5 5 7 4 6 3 5 8 4 3 4 4 3 4 3 1 3 3 7 2 4 8 3 6 4 3 3 2 5 4 4 3 7 4 5 4 4 3    4 7 2 3 3 4 3 0 2 2 4 3 4 2 4 2 2 6 4 4 6 6 1 5 1 1 2 1 0 0 0 0 0   0.126000 2.750 2.750 7.100       969560           3           0  0 0 0 0 0 0 0 0 0 0 0 0 0 2 1 1 1 0 1 2 0 2 0 2 2 0 1 1 1 0 0 1 0 1 1 1 1 2 0    1 2 2 1 2 0 0 1 0 1 0 2 1 0 1 0 1 1 2 0 3 0 3 4 3 1 3 2 0 4 0 1 2 0 3 1 1 2 3    2 2 2 5 1 7 1 5 1 5 4 2 0 0 1 2 1 3 2 3 3 5 4 10 10 2 5 11 4 1 2 1 7 3 5 4 4 1   5 10 8 7 9 9 20 20 21 33 21 28 20 27 32 21 29 22 20 24 15 13 27 14 13 15 10 9    3 11 6 7 5 3 6 8 5 4 4 1 3 3 5 2 7 3 6 6 1 6 4 6 5 3 4 2 4 3 3 9 4 5 4 4 5 2 3   10 4 3 2 6 10 6 3 6 5 5 5 4 8 8 5 4 3 6 4 4 2 4 4 4 5 7 4 4 4 4 5 2 2 3 4 5 2    1 3 2 6 2 7 7 1 6 4 4 6 5 5 4 0 2 2 3 2 7 5 0 4 1 1 4 6 1 0 3 2 0 0 1   0.128000 2.800 2.800 7.200      1022713           5           0  0 0 0 0 0 0 0 0 0 0 0 1 0 2 0 0 0 1 0 1 1 0 0 1 1 1 0 0 0 2 1 0 0 4 0 0 1 2 3    1 1 0 1 0 1 0 3 1 1 1 2 2 1 1 1 3 1 0 2 4 2 1 2 1 2 0 3 1 3 2 1 5 2 1 3 1 2 1    5 3 2 1 2 5 3 8 2 3 2 5 5 4 3 6 4 4 4 3 2 3 8 4 3 4 5 4 5 4 7 6 5 3 3 3 5 2 9    10 7 9 12 11 13 17 15 22 19 33 24 28 30 26 21 24 22 27 20 26 16 10 10 9 20 10    7 4 5 7 7 2 7 5 3 5 1 6 1 5 7 5 6 3 1 5 1 1 3 4 8 6 3 9 5 5 3 6 7 4 6 7 6 4 2    4 6 2 3 6 5 6 7 6 4 4 9 6 8 6 9 7 1 2 6 2 7 5 4 4 4 4 5 5 4 4 3 6 3 5 3 6 4 3    6 6 2 5 2 8 4 5 3 6 5 4 5 8 4 3 5 6 5 5 2 8 1 2 2 5 4 1 3 0 0 0 0 0   0.130000 2.850 2.850 7.300      1081669           3           0  0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 5 0 0 2 2 0 0 1 0 0 0 1 1 0 2 0 2 2 2 1 0    1 0 2 2 3 1 1 0 2 0 1 0 2 1 1 2 2 0 1 4 3 0 2 1 1 0 2 5 2 1 0 1 3 2 5 2 1 2 5    2 3 4 3 6 6 6 4 6 6 3 1 3 2 3 4 7 5 2 9 7 4 1 4 4 3 2 2 2 7 4 8 4 7 4 6 8 5 1    8 6 10 18 21 18 15 21 24 21 26 22 30 28 27 23 22 21 17 25 20 17 13 17 9 12 7 8   5 4 4 5 5 2 4 1 1 2 5 7 6 4 9 7 7 5 5 5 5 5 2 4 5 3 6 8 2 4 9 4 10 5 1 4 5 5 5   10 3 2 8 6 5 7 3 13 3 3 6 5 1 4 5 9 5 2 7 4 5 6 3 5 6 5 4 5 9 6 4 3 4 4 4 5 8    5 5 0 3 6 3 4 3 7 5 6 4 3 3 6 8 4 1 3 1 2 7 3 4 6 6 1 3 4 1 0 1 0 0   0.132000 2.900 2.900 7.400      1131887           3           0  0 0 0 0 0 0 0 0 1 0 0 1 2 1 1 0 0 0 1 2 2 1 1 0 2 1 1 0 1 1 1 0 2 2 3 1 0 1 0    1 0 2 0 2 0 1 4 0 1 2 2 0 0 0 2 3 0 1 2 3 0 1 2 3 5 6 2 2 3 1 4 4 8 4 3 3 3 7    2 2 5 7 4 1 2 4 8 1 5 2 7 3 4 2 9 6 5 5 6 2 2 3 6 2 5 6 7 7 2 8 3 3 3 3 6 6 5    3 10 15 15 17 19 13 29 20 23 22 34 28 28 33 20 20 22 17 22 18 15 19 14 11 9 13   6 6 13 4 2 9 8 8 7 6 5 6 4 4 9 6 2 8 9 7 2 6 3 7 3 6 3 7 4 4 5 4 5 6 4 7 5 4     10 2 6 6 8 3 6 6 9 5 8 8 7 6 4 8 5 7 5 5 7 3 5 5 5 10 7 3 8 7 5 7 2 4 4 6 4 10   7 6 4 4 4 4 3 2 4 2 6 5 9 7 3 2 6 2 5 1 5 6 2 2 1 9 2 5 2 5 1 0 0 0 1 1   0.134000 2.950 2.950 7.500      1185706           3           0  0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 3 2 1 0 1 1 0 0 0 0 0 1 0 1 1 2 0 1 0 1 2 0 0 0    1 1 0 1 1 1 0 2 2 0 1 3 3 2 3 0 0 2 2 3 2 1 1 3 0 0 1 1 3 4 3 1 1 9 1 4 0 1 3    4 1 3 2 6 4 7 7 3 2 8 5 2 5 2 4 6 7 3 7 7 8 4 7 2 4 7 7 9 9 2 5 5 8 3 5 7 3 6    10 6 10 15 10 13 14 29 21 23 37 26 20 28 20 16 24 25 16 19 21 20 20 17 11 10     12 8 7 7 5 5 5 4 5 6 7 3 6 5 7 5 11 9 6 8 11 6 4 6 8 8 7 7 7 4 5 4 8 5 4 3 4 8   10 7 9 4 7 6 8 9 7 3 5 7 7 6 2 6 4 7 3 9 8 12 7 6 6 6 4 5 7 2 4 7 3 2 4 4 7 1    4 5 0 4 6 3 10 8 5 4 3 4 5 7 5 7 5 7 3 5 2 5 6 4 5 2 4 1 6 6 2 4 2 0 0 1 0   0.136000 3.000 3.000 7.600      1238426           3           0  0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 2 4 0 2 0 2 2 0 1 1 1 0 2 1 1 2 1 0 1 1 0 3 1 0    0 1 0 1 0 0 2 1 1 0 4 0 2 6 3 3 4 0 3 1 2 4 0 4 4 0 1 5 2 2 5 1 3 4 3 3 5 2 4    4 6 2 5 3 4 5 4 5 6 7 5 6 2 8 3 4 7 2 4 4 3 7 6 5 1 4 8 3 7 10 3 3 6 1 5 3 8     11 5 7 15 11 15 17 21 23 21 24 28 16 21 29 15 22 27 28 20 13 19 13 7 15 10 11    9 6 8 8 4 7 5 4 6 5 10 6 7 8 9 3 5 5 9 5 9 4 4 4 3 5 7 4 10 6 8 4 9 8 4 6 7 9    11 6 8 3 5 8 12 3 6 9 7 11 9 6 7 4 7 7 7 2 5 4 5 0 2 9 5 5 5 10 7 5 6 3 9 4 4    13 2 7 5 7 4 7 2 0 4 5 4 4 6 8 1 2 5 6 4 7 3 11 4 3 3 5 5 4 4 3 1 4 2 2 1 1 0   0.138000 3.050 3.050 7.700      1299809           6           0  0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 0 1 2 1 1 0 0 1 0 0 2 0 1 2 0 0 3 0 0 1 3 1    2 0 2 0 1 1 2 1 2 3 2 1 2 5 2 2 2 4 3 2 5 3 0 3 2 4 5 4 3 0 5 4 1 4 3 8 6 4 4    7 4 5 4 3 6 5 6 10 3 6 6 2 6 3 4 4 3 6 7 6 8 3 4 7 5 4 9 2 4 8 5 9 8 3 7 5 7 7   13 7 11 15 17 16 18 18 18 20 17 26 25 19 20 26 31 22 18 20 18 14 11 16 4 7 11    10 8 9 9 6 3 8 8 7 5 6 10 3 5 6 6 3 12 7 8 8 2 10 4 13 9 9 12 4 5 9 7 9 5 7 4    8 9 6 7 8 10 8 7 5 7 11 6 4 4 4 6 4 9 4 5 9 10 7 4 12 7 4 9 5 10 10 6 8 4 7 2    4 7 2 6 8 4 11 3 3 9 7 6 7 3 8 7 4 8 5 3 7 4 5 5 7 4 6 7 5 5 3 5 2 5 4 1 2 0 0   1   0.140000 3.100 3.100 7.800      1361810           3           0  0 0 0 0 0 0 0 0 0 1 0 0 0 0 3 2 1 0 0 0 1 1 1 2 0 0 0 0 1 0 2 2 2 1 0 0 3 3 0    2 0 6 2 3 1 0 3 3 1 2 2 5 3 5 3 3 2 2 7 3 2 2 3 4 2 3 4 4 1 3 7 4 5 4 2 3 5 4    2 1 3 6 3 4 3 8 7 6 5 3 5 11 5 5 3 3 7 3 6 4 4 2 4 4 4 1 5 5 9 6 6 9 3 10 8 6    8 3 10 8 16 16 13 18 23 29 25 19 19 20 27 19 22 27 24 21 15 18 11 20 21 17 12    5 18 6 12 7 9 11 7 12 11 4 8 8 4 8 7 7 2 6 4 4 9 6 9 3 4 7 7 7 4 10 4 11 5 8 8   8 5 4 4 8 6 4 9 8 12 12 8 5 8 3 10 8 7 5 3 5 6 8 5 6 10 7 2 11 2 5 5 6 8 10 2    7 5 5 14 2 7 3 9 3 5 2 8 2 3 4 4 7 9 5 4 7 6 7 5 6 3 5 4 7 6 7 7 9 3 0 2 1 1 1   0 0   0.142000 3.150 3.150 7.900      1429499           3           0  0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 3 1 2 1 1 0 0 0 3 0 2 2 1 0 3 0 2 1 3 0 0 1    1 3 1 2 4 1 5 3 5 1 0 7 1 3 2 3 2 2 2 3 0 0 1 3 6 3 2 2 4 4 4 6 4 3 6 4 10 3 7   2 5 4 7 4 5 8 4 7 4 1 7 11 5 2 10 2 11 3 7 8 10 9 6 3 5 3 6 3 10 11 5 5 9 7 10   8 9 5 15 11 9 18 18 15 24 17 23 17 19 25 17 24 18 37 16 17 21 17 14 20 17 15     15 9 4 11 7 3 8 10 8 8 6 8 3 4 5 8 4 6 3 9 9 6 2 10 4 4 3 8 4 9 1 7 5 9 7 10 9   10 4 6 5 8 6 6 10 10 6 5 7 6 6 10 5 7 8 8 8 7 7 11 12 8 3 10 6 9 13 11 4 6 7 6   3 10 5 8 4 7 7 7 5 8 4 9 5 5 7 6 6 7 11 11 7 8 5 3 5 7 7 10 3 3 6 5 7 9 2 3 7    1 0 0 0 0 1   0.144000 3.200 3.200 8.000      1493946           3           0  0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 0 2 3 0 0 1 2 1 1 1 4 1 0 1 0 1 2 1 3 1 1 1 1 2    1 1 3 2 6 0 4 0 1 4 2 4 5 2 1 3 0 2 2 4 2 3 2 4 3 5 4 4 4 1 5 1 3 4 5 6 4 7 2    8 8 8 5 3 6 0 7 3 2 2 5 7 5 7 5 8 9 6 4 3 6 8 6 10 2 5 6 3 3 6 6 6 6 17 5 10 6   6 11 11 13 12 21 26 18 24 21 24 23 30 18 22 20 24 19 13 17 25 22 17 15 8 13 7    10 8 9 6 7 9 8 7 8 9 7 7 6 12 5 9 9 12 9 12 6 9 7 10 7 7 4 9 7 4 2 7 4 5 8 8 9   7 6 7 5 9 4 8 13 6 5 4 7 9 6 7 7 9 4 4 5 8 10 9 10 6 6 7 9 12 11 8 8 9 11 5 8    7 5 5 8 5 9 10 5 5 11 11 6 8 8 4 8 5 5 5 4 7 4 5 6 5 6 6 7 7 4 2 6 3 2 1 0 0 0   0 0   0.146000 3.250 3.250 8.100      1562352           5           0  0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 0 2 0 1 2 1 1 0 0 1 0 1 2 0 0 0 3 1 2 0 4 4 2 0    0 2 3 2 0 1 3 3 4 0 1 4 3 3 4 5 5 4 2 1 4 2 5 3 2 7 6 3 5 6 5 5 5 1 5 2 7 4 8    7 4 6 5 7 5 3 5 8 1 6 4 6 8 7 6 7 6 3 4 6 3 5 8 4 10 3 3 11 6 5 3 9 6 4 3 17 9   11 11 24 13 15 14 25 26 26 21 17 32 32 22 18 25 29 29 27 24 21 12 23 14 12 11    9 17 7 9 11 3 7 6 5 5 12 3 6 8 7 4 7 11 10 8 9 5 8 2 10 9 8 10 10 7 7 4 7 5 7    7 9 10 8 7 7 16 6 8 10 5 6 6 12 12 7 11 11 8 9 7 8 12 10 7 8 7 11 8 9 7 7 4 9    4 7 14 9 8 8 13 9 8 7 13 5 9 5 7 4 9 5 7 8 7 8 7 3 10 9 3 4 4 4 5 2 6 6 3 5 10   4 4 2 3 0 1 0 0   0.148000 3.300 3.300 8.200      1630559           3           0  0 0 0 0 0 0 0 0 1 0 0 1 0 0 0 0 4 2 1 1 1 2 1 2 0 2 1 5 0 1 1 4 0 2 1 4 5 3 0    1 1 1 2 1 3 3 3 1 1 1 1 1 3 4 6 6 8 8 4 3 2 7 2 2 1 7 4 4 5 1 10 6 4 4 4 3 3 3   6 11 6 4 5 4 8 5 5 9 4 5 5 7 6 4 13 12 3 6 7 5 2 7 9 7 8 8 4 7 6 4 10 6 8 9 9    9 13 15 17 23 25 13 16 24 22 26 21 27 24 24 21 21 21 15 17 22 25 21 22 17 14     11 8 12 5 9 7 8 5 11 10 6 6 5 9 13 10 9 8 8 8 6 4 9 10 9 9 7 8 7 5 7 8 14 13 5   14 5 12 11 8 9 6 5 4 9 13 7 10 13 11 11 8 5 9 10 8 7 6 7 13 3 13 8 7 13 17 5 8   5 10 7 12 7 6 6 9 7 8 8 11 8 11 9 11 11 8 5 6 10 4 9 3 10 8 7 10 8 7 8 10 10 7   4 11 5 7 8 2 4 3 0 0 1 0 1   0.150000 3.350 3.350 8.300      1707576           3           0  0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 2 1 2 1 0 2 0 2 3 1 3 2 2 2 2 0 2 1 4 3 2 2 3    1 2 1 0 2 2 4 2 5 3 3 5 2 8 4 5 4 2 3 6 7 6 1 0 7 4 7 7 6 5 4 3 4 6 6 7 6 2 7    4 4 2 5 5 6 9 3 3 3 6 6 5 3 5 7 8 8 6 8 8 6 8 3 9 6 6 8 8 6 4 8 6 6 10 4 11 6    11 15 23 16 8 17 20 21 19 24 15 14 19 21 30 25 21 15 19 16 18 21 21 15 14 12     16 8 10 12 7 10 9 8 10 10 7 9 8 10 12 6 6 9 11 6 5 9 12 6 7 12 7 5 6 8 5 9 4     11 9 8 8 10 7 6 10 7 11 13 7 4 13 11 8 11 9 16 6 12 11 10 10 19 2 9 11 8 7 8 8   6 13 6 10 12 12 9 12 9 9 8 7 7 9 6 12 8 4 9 9 8 5 7 8 9 5 12 5 7 5 9 10 9 10 3   6 6 8 7 11 3 5 5 4 2 0 0 0 0   0.152000 3.400 3.400 8.400      1777231           3           0  0 0 0 0 0 0 0 0 1 0 0 0 0 1 1 1 0 0 1 1 3 1 0 3 4 2 3 3 3 3 3 2 1 1 1 1 3 3 0    1 8 0 0 5 3 7 4 4 4 4 4 3 5 2 2 5 3 6 1 7 6 1 2 2 5 2 1 6 6 8 7 7 5 10 4 1 6 9   3 4 5 3 5 8 4 9 8 11 8 3 2 7 7 9 10 9 10 8 6 8 6 8 7 10 8 7 3 8 4 10 7 6 8 9 6   5 16 9 19 24 23 17 23 24 22 30 21 15 23 27 20 20 20 18 20 23 18 17 15 19 17 18   13 9 4 4 7 12 7 10 4 8 6 10 5 6 13 2 3 8 7 8 7 3 11 8 7 9 7 19 7 8 9 6 14 8 8    11 10 11 13 14 10 16 8 9 13 8 9 9 12 7 12 11 6 9 15 5 9 9 9 11 11 13 6 10 6 4    12 9 9 12 11 8 6 9 16 10 10 10 8 10 10 6 7 4 1 15 6 8 4 9 13 11 8 10 11 9 8 3    3 6 6 7 9 4 6 8 7 4 2 1 2 2 1 0   0.154000 3.450 3.450 8.500      1849489           6           0  0 0 0 0 0 0 0 0 0 0 1 1 3 0 1 2 2 0 1 4 1 1 0 1 0 2 1 0 0 1 1 1 1 6 3 6 1 3 1    3 3 0 6 0 4 2 7 4 6 4 4 3 7 4 5 7 5 5 2 3 9 9 2 5 5 3 9 4 2 7 6 2 8 2 5 7 12 6   5 4 5 10 4 12 10 6 4 14 7 9 10 11 7 7 7 7 3 9 7 4 3 8 7 5 7 9 6 8 9 6 8 8 12 6   5 11 12 13 11 13 21 26 19 23 25 18 23 22 23 23 18 27 20 15 20 25 24 19 18 12     14 13 15 8 15 10 11 7 9 13 11 12 13 11 11 7 11 13 6 5 10 6 6 10 8 14 5 14 11 8   5 9 7 10 10 8 7 15 13 3 13 12 18 15 7 10 9 10 8 15 9 6 8 9 10 10 9 5 7 7 5 10    11 13 12 12 12 10 6 17 10 11 9 4 8 7 6 6 9 12 8 16 18 7 5 10 8 12 10 15 6 13     11 6 10 16 10 11 16 8 9 5 11 10 14 11 5 2 5 7 3 1 1 0 1 0   0.156000 3.500 3.500 8.600      1920727           4           0  0 0 0 0 0 0 0 0 0 0 0 1 1 0 1 0 2 1 2 0 3 0 1 1 0 1 0 3 0 4 4 1 3 1 2 3 3 4 3    1 2 3 9 5 2 3 7 3 3 6 5 2 6 1 4 3 2 3 6 5 1 8 3 8 5 3 7 6 13 11 9 5 8 7 7 5 8    7 4 8 6 4 10 4 6 5 6 9 9 12 6 7 10 9 9 8 8 3 8 9 8 8 2 12 11 13 8 13 7 8 6 6 9   6 8 16 13 14 16 16 22 20 21 21 17 20 18 19 22 20 11 20 22 21 14 19 15 23 17 15   12 14 19 16 10 11 14 11 9 11 9 12 8 16 14 9 6 18 10 11 7 10 11 17 10 13 8 10     12 9 12 7 7 10 10 11 11 9 8 8 14 10 10 9 14 9 14 13 9 19 16 17 4 11 8 12 11 10   21 6 10 8 9 12 9 7 7 12 7 16 14 10 13 6 13 8 9 10 6 10 8 7 10 4 6 11 19 12 6 7   5 8 11 10 12 13 9 6 10 5 11 11 4 14 10 7 2 6 5 1 2 5 1 1 0 0   0.158000 3.550 3.550 8.700      1999833           3           0  0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 2 2 3 2 2 2 1 2 3 0 1 0 1 3 2 0 0 3 2 3 2 5 7 0    3 4 1 10 7 7 4 5 2 3 4 3 8 3 6 4 4 4 8 2 3 4 5 5 7 1 6 7 8 1 6 8 1 4 4 11 9 4    7 11 9 10 5 6 8 4 3 9 7 9 11 5 5 8 8 4 8 7 8 11 9 12 6 4 13 4 12 10 6 9 11 10    11 10 11 11 11 14 15 14 23 18 17 29 16 26 23 15 19 14 18 19 22 31 13 21 20 12    16 15 14 18 17 15 8 12 14 13 10 10 10 10 10 13 11 6 8 11 8 14 8 10 11 11 8 10    13 5 14 7 12 9 10 10 12 15 18 8 6 9 9 12 8 9 20 14 16 10 11 14 5 5 13 6 11 9     11 15 6 9 13 11 7 8 7 10 8 16 12 11 8 10 14 11 17 11 8 16 13 9 10 5 10 17 13     14 16 8 10 9 11 5 10 9 10 12 8 11 12 11 8 6 7 12 15 13 12 7 13 5 0 3 2 0 0 0 0   0.160000 3.600 3.600 8.800      2073149           3           0  0 0 0 0 0 0 0 0 0 1 0 0 0 0 2 1 2 1 2 2 1 0 2 2 1 0 3 6 4 5 5 2 2 2 5 5 3 6 4    6 4 5 2 4 4 3 2 4 6 3 3 6 5 7 4 5 7 5 3 5 6 13 5 3 10 5 9 7 4 5 6 5 10 6 5 5 6   6 4 14 7 6 11 6 9 10 9 8 5 3 8 10 10 6 6 8 9 5 6 14 7 11 10 9 9 11 13 8 4 5 10   12 6 16 8 8 7 19 20 23 10 16 27 25 23 19 26 21 16 20 21 24 18 25 8 11 13 16 18   13 22 18 9 16 4 16 10 12 13 9 7 9 8 17 11 10 13 10 14 4 9 12 16 8 9 16 17 13     11 14 8 8 13 9 11 15 10 11 14 8 6 4 9 11 18 9 9 8 9 15 11 11 11 9 6 13 13 10 7   8 10 15 14 9 7 4 10 12 17 10 14 13 10 10 12 20 9 7 6 11 15 11 10 8 9 6 10 13     17 6 8 9 6 13 13 16 10 15 5 11 14 11 12 6 5 12 9 4 9 2 4 1 1 0 0 0   0.162000 3.650 3.650 8.900      2156456           5           0  0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 2 0 1 1 3 2 3 4 3 3 2 1 3 6 5 2 3 4 4 3 6 2 3    4 4 5 5 3 4 1 4 5 9 3 3 4 3 3 8 5 6 12 2 10 3 4 6 8 9 8 8 2 2 7 5 8 2 8 9 7 2    6 8 6 5 8 2 7 5 6 13 5 6 8 11 6 10 5 6 3 8 10 11 10 10 14 10 11 8 11 8 12 6 12   5 15 12 13 10 13 13 18 23 12 21 18 21 23 20 30 20 23 26 24 24 21 21 29 19 21     16 23 20 13 19 13 16 11 15 13 13 11 8 11 14 14 13 4 16 15 18 13 9 19 8 11 6 9    14 8 13 12 13 10 13 10 14 11 13 11 8 10 13 11 11 14 11 8 14 11 10 9 14 12 14     18 8 12 7 13 12 10 14 14 8 12 17 11 13 9 12 12 15 7 9 13 17 11 11 11 12 17 12    11 16 15 8 9 12 7 13 15 11 16 7 10 7 14 5 18 10 10 8 8 6 6 13 14 6 9 11 9 9 3    5 1 1 3 0 0   0.164000 3.700 3.700 9.000      2234753           3           0  0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 4 1 4 2 1 3 1 1 3 2 3 3 1 3 6 2 4 4 3 3 3 6 5 2    6 4 1 3 3 7 1 4 4 6 12 4 5 2 6 4 9 3 1 8 11 5 2 7 6 3 8 4 7 3 8 3 9 6 7 8 9 2    7 6 9 6 15 6 9 5 9 4 9 17 15 10 2 10 6 8 12 12 11 12 10 9 7 11 8 7 5 11 10 14    16 7 7 7 13 15 10 16 17 21 19 14 18 24 19 27 27 24 20 22 24 21 20 14 24 17 17    18 32 15 12 13 15 12 8 14 11 11 19 11 14 15 18 10 5 12 11 11 9 15 9 7 9 16 12    9 12 10 15 9 18 7 11 12 14 7 20 8 10 13 14 11 6 6 9 11 8 10 16 8 17 13 17 9 16   11 10 9 13 20 17 14 12 10 13 11 9 9 17 20 10 16 8 14 13 14 18 15 15 8 10 12 11   22 12 13 9 12 9 11 14 19 12 12 8 8 12 11 19 11 11 12 15 11 15 13 9 9 10 9 4 9    4 2 1 0 0   0.166000 3.750 3.750 9.100      2327990           3           0  0 0 0 0 0 0 0 0 0 0 0 0 3 2 2 0 1 2 2 1 1 0 0 3 1 4 2 6 4 2 4 3 2 5 5 2 3 1 3    1 2 10 2 7 4 3 4 3 3 4 3 10 6 9 6 3 8 5 5 3 4 4 6 8 4 4 7 5 5 11 14 5 3 6 8 8    7 10 11 7 17 7 11 10 8 7 8 12 13 11 12 6 13 9 7 7 6 5 8 13 10 10 14 11 11 8 12   15 14 9 13 10 9 18 13 18 12 23 14 17 24 15 23 25 31 19 17 29 19 19 19 26 25 19   17 22 19 19 19 11 11 12 22 21 8 10 18 10 14 19 17 13 14 10 6 9 10 15 11 5 13     13 11 11 17 16 9 7 14 7 19 6 10 13 7 12 18 14 7 12 15 13 13 9 13 13 13 12 12     14 12 19 10 16 18 18 12 8 10 10 9 7 14 9 11 13 12 8 15 12 11 10 12 11 17 15 19   14 14 12 7 7 12 11 15 16 12 11 12 10 19 19 12 14 12 15 11 20 13 7 18 9 15 19     16 11 5 9 8 6 2 4 0 2 0 1   0.168000 3.800 3.800 9.200      2406866           3           0  0 0 0 0 0 0 0 0 0 1 0 2 0 1 0 2 3 2 3 1 2 1 2 2 5 2 1 2 3 2 2 2 5 3 5 3 3 1 3    6 8 6 1 3 9 6 3 6 10 5 5 7 4 5 7 12 9 5 7 5 6 6 8 3 5 4 7 8 5 6 5 8 13 4 10 2    10 9 7 7 16 9 10 9 13 8 12 9 13 15 9 15 9 10 11 6 6 6 7 7 6 8 15 9 8 9 6 12 12   11 14 12 11 13 8 17 18 18 11 14 19 14 25 21 15 10 15 19 27 23 22 24 17 19 18     12 16 22 21 25 9 25 15 19 15 21 15 8 11 13 12 10 12 7 13 11 17 11 13 10 16 19    14 23 11 8 12 13 10 9 17 4 14 10 7 10 17 14 11 11 20 18 13 8 12 6 8 13 12 23     15 14 15 16 9 14 9 13 14 17 11 17 11 10 15 17 11 6 12 12 14 15 17 12 16 16 8     17 15 15 10 15 11 10 15 12 13 9 12 9 12 15 12 6 18 7 15 14 12 21 18 11 10 18     11 19 11 7 11 3 2 5 4 0 1 1   0.170000 3.850 3.850 9.300      2508471           7           0  0 0 0 0 0 0 0 0 0 0 0 0 1 3 1 2 1 4 3 3 1 2 7 0 3 2 2 2 2 5 2 3 2 3 3 4 3 7 3    5 3 4 4 6 2 3 10 4 11 3 13 7 7 5 6 3 8 10 6 6 4 10 11 4 12 7 8 9 7 7 8 4 6 7 9   9 5 9 11 5 14 9 10 7 9 8 8 5 6 11 13 14 10 10 10 10 8 9 9 9 9 14 14 13 11 8 18   9 10 9 16 12 13 15 13 10 17 16 20 14 22 20 26 29 29 27 24 20 37 21 24 13 18 13   28 24 22 25 21 13 14 15 9 11 18 8 16 17 16 13 12 16 11 11 17 15 11 15 10 11 12   13 12 12 20 15 14 15 16 12 17 15 15 12 10 14 14 17 15 19 15 13 13 11 12 16 14    17 16 8 16 12 8 14 13 13 10 10 9 12 11 19 20 13 11 4 15 11 14 11 20 18 18 13     20 12 20 21 15 15 12 13 18 18 11 16 9 14 9 18 11 10 11 20 11 13 17 13 13 12 14   16 10 12 12 23 12 11 12 8 8 1 0 1 2 0   0.172000 3.900 3.900 9.400      2591210           3           0  0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 4 4 3 2 1 3 3 2 3 0 3 6 1 3 1 5 5 4 3 9 9 0 4 7    5 3 5 5 8 7 3 3 5 5 8 5 11 10 8 10 3 6 6 6 7 7 8 8 12 9 6 10 8 7 10 8 8 10 4 6   12 20 4 6 11 7 9 10 7 5 10 6 12 11 7 13 13 16 12 6 8 14 13 9 7 5 14 17 17 10     12 11 6 13 11 17 3 23 13 21 12 21 28 11 23 30 28 23 24 26 26 17 21 15 27 23 33   16 22 25 11 20 22 23 21 20 7 21 13 16 12 16 16 13 18 18 9 13 16 15 9 20 13 19    15 8 9 11 14 13 10 9 10 16 15 14 17 15 19 16 12 14 12 14 14 16 19 19 4 24 8 12   15 16 11 15 14 20 14 13 13 14 16 19 14 13 19 14 18 23 15 15 4 14 17 14 8 10 15   20 11 15 19 12 9 13 12 11 16 12 16 13 14 16 13 16 16 19 19 12 11 10 19 15 15     14 12 5 11 18 17 10 13 12 9 6 2 0 0 1 0   0.174000 3.950 3.950 9.500      2675515           3           0  0 0 0 0 0 0 0 0 0 0 2 0 1 1 0 2 1 2 3 3 1 3 1 3 7 5 3 6 4 3 9 4 5 2 5 3 3 3 6    9 5 5 2 6 8 5 8 4 8 5 6 5 6 4 6 3 7 11 6 9 9 3 6 6 7 6 8 7 9 12 18 6 9 8 11 11   8 14 15 15 11 15 13 9 19 10 15 14 9 4 18 5 8 10 8 10 13 9 12 11 8 8 12 6 15 8    9 9 18 7 17 21 9 13 18 14 21 24 18 22 17 26 15 21 23 25 19 26 23 20 27 17 27     20 26 15 22 15 19 15 16 24 12 15 24 13 13 17 11 7 10 21 15 15 16 13 20 22 12     16 12 16 15 14 18 11 12 14 14 24 10 13 16 19 8 11 18 19 15 15 23 16 16 11 12     18 11 13 14 16 10 14 13 18 12 15 15 14 8 11 17 12 22 13 12 14 15 10 11 15 19     15 12 17 8 21 23 13 19 11 8 12 15 11 14 15 19 15 10 17 9 16 14 18 14 16 14 14    23 14 14 13 16 12 14 15 14 9 14 7 5 2 3 1 1 1   0.176000 4.000 4.000 9.600      2779386           5           0  0 0 0 0 0 0 0 0 0 0 0 2 2 3 0 1 3 0 6 2 6 3 1 5 0 4 1 6 5 1 6 3 6 5 6 2 5 4 5    3 9 8 5 7 5 8 4 12 8 12 6 8 5 7 5 7 10 5 5 6 7 9 7 10 7 10 10 8 12 10 6 13 10    11 12 11 10 10 16 9 6 12 9 11 17 10 11 10 14 11 16 7 11 13 12 10 17 14 11 13     12 10 13 16 16 17 17 15 14 11 8 15 13 27 22 14 19 17 22 22 27 18 28 19 27 32     24 33 21 17 23 12 27 25 20 20 17 22 14 15 22 21 14 9 16 12 19 16 17 16 16 20     14 18 15 14 18 10 12 9 16 12 12 10 13 19 12 12 15 14 15 22 12 11 15 18 19 18     10 6 11 14 10 23 17 14 16 19 10 10 16 19 17 23 16 18 19 18 16 12 14 14 14 13     11 10 24 21 22 26 18 18 18 14 17 5 13 17 11 13 16 14 18 16 9 15 15 18 16 14 21   13 22 17 9 8 16 17 16 16 19 7 20 19 18 16 10 6 10 6 3 5 1 0 0 2   0.178000 4.050 4.050 9.700      2869617           3           0  0 0 0 0 0 0 0 0 0 0 2 2 2 0 1 4 1 3 2 2 1 2 3 2 2 4 4 7 5 6 5 3 6 6 5 7 8 1 5    2 3 5 5 8 10 7 6 10 9 6 8 9 7 8 10 15 4 10 5 8 8 6 11 8 8 11 7 5 8 14 5 11 7     13 10 9 7 8 9 14 12 10 9 11 6 14 15 14 13 11 9 18 18 10 14 14 10 12 16 12 9 8    14 15 6 11 11 12 10 14 12 11 18 13 13 27 16 23 23 20 21 32 20 18 25 22 24 32     25 34 19 23 21 25 22 25 19 23 19 21 16 19 16 18 9 18 6 13 12 13 18 12 8 19 14    14 11 16 13 15 14 21 11 14 14 13 11 20 14 14 26 10 22 16 18 15 20 24 18 19 19    16 14 14 14 21 13 19 18 20 13 17 11 17 14 22 17 15 15 20 8 21 15 16 16 23 17     13 19 21 20 12 15 18 15 19 15 18 17 20 15 13 14 24 18 15 15 14 18 20 19 17 19    20 21 21 15 19 19 17 11 16 16 11 23 10 20 13 10 5 10 2 3 1 1 0   0.180000 4.100 4.100 9.800      2975040           3           0  0 0 0 0 0 0 0 0 1 0 0 1 2 2 4 4 2 4 4 1 2 5 0 3 3 5 2 5 5 4 9 2 7 8 4 8 3 11 6   10 4 7 8 6 6 5 8 8 7 11 4 4 11 12 7 11 7 10 11 7 11 11 10 9 7 13 12 18 8 14 12   14 12 8 8 16 10 10 14 16 10 6 8 15 15 15 22 13 19 18 12 6 11 10 7 12 12 24 15    17 9 17 21 10 17 18 14 14 14 9 22 11 23 17 15 23 32 20 11 12 20 15 23 30 20 25   19 26 29 19 27 23 15 19 11 30 16 21 24 18 18 14 8 6 25 13 21 13 13 19 13 21 25   23 18 14 14 13 20 12 14 8 10 25 14 15 20 15 10 15 16 21 8 15 20 21 20 13 16 15   20 11 18 17 17 9 12 24 19 13 18 17 20 14 15 20 10 23 19 25 8 7 13 14 11 15 18    13 10 12 10 17 11 24 16 17 11 12 13 16 20 14 26 12 17 13 14 16 16 6 20 16 23     22 11 17 16 14 25 19 17 21 22 19 13 19 16 18 10 11 7 4 6 0 0 2   0.182000 4.150 4.150 9.900      3083416           6           0  0 0 0 0 0 0 0 0 0 0 2 1 1 4 1 3 4 3 5 6 2 1 4 2 3 5 6 6 7 2 4 1 11 7 5 2 6 6 8   9 8 12 7 11 9 6 12 7 8 9 6 6 8 11 6 6 8 11 8 11 12 11 13 9 10 7 9 6 11 9 13 12   12 8 14 15 8 9 8 8 11 22 16 6 11 16 15 9 13 12 12 13 11 15 9 9 16 14 14 12 21    12 12 12 16 19 10 15 18 8 16 14 16 16 21 30 22 9 25 19 19 26 23 33 25 22 21 19   21 20 20 21 20 26 20 29 27 25 25 21 20 25 21 21 18 14 19 15 6 20 18 16 20 16     13 13 15 15 15 15 22 16 15 15 11 21 19 11 19 13 14 15 17 21 12 18 12 22 18 21    18 13 23 15 18 9 21 11 14 23 18 21 25 18 22 15 21 23 15 15 16 19 21 18 19 21     17 13 24 23 22 19 14 20 22 15 14 14 20 20 23 13 18 15 18 20 20 24 9 12 17 21     21 12 16 17 16 16 21 26 19 15 21 22 24 15 11 13 13 6 8 1 4 0 1 0   0.184000 4.200 4.200 10.00      3174897           3           0  0 0 0 0 0 0 0 0 0 0 1 1 2 3 0 5 4 3 3 0 7 3 2 4 2 8 6 4 5 9 3 8 6 4 2 7 6 8 7    9 3 5 8 5 9 7 7 6 11 14 7 12 9 9 5 15 12 14 15 12 9 11 5 8 13 11 12 10 9 17 12   11 8 17 11 19 11 15 9 11 7 15 14 16 16 16 7 12 10 14 13 13 16 16 11 15 13 14     12 16 11 12 13 17 10 13 19 11 17 11 13 14 13 10 19 19 23 24 22 24 24 31 19 23    22 28 21 25 29 17 23 17 21 30 22 19 25 27 27 22 23 23 17 25 17 20 17 12 23 21    9 17 20 16 19 16 17 20 9 16 11 22 16 15 12 15 17 23 24 16 16 18 26 11 16 20 18   10 14 17 26 19 17 15 17 19 12 21 20 24 17 27 13 16 18 19 23 14 19 14 10 11 18    19 6 15 21 23 25 17 17 18 21 27 20 17 18 20 25 22 20 18 22 18 17 15 24 16 15     22 18 22 14 20 20 22 18 22 25 19 26 12 19 19 13 12 16 19 14 9 7 5 4 2 0 2   0.186000 4.250 4.250 10.10      3283256           3           0  0 0 0 0 0 0 0 1 0 0 1 1 4 1 5 2 5 5 3 4 6 3 2 4 7 8 2 6 6 4 10 7 8 7 5 4 4 9 8   18 10 7 6 6 13 12 10 13 10 7 15 4 7 10 13 12 8 8 13 5 14 6 9 14 9 10 16 12 13    11 8 12 11 10 13 9 11 15 17 23 18 13 10 12 11 12 14 14 14 10 12 12 16 13 15 13   13 14 18 10 13 17 14 14 14 12 12 8 18 14 23 20 16 19 16 16 16 27 18 21 19 20     19 37 22 21 22 28 24 26 18 21 28 21 22 21 21 22 16 15 13 22 22 27 22 11 13 20    10 17 16 19 20 30 18 25 8 7 22 18 17 14 23 16 17 11 16 24 19 18 22 15 15 23 16   13 15 22 14 8 12 18 13 15 22 17 15 15 17 27 21 19 21 24 17 10 12 14 19 17 22     18 19 17 28 19 15 14 16 28 17 20 15 11 22 18 19 16 21 17 24 19 22 22 20 10 20    18 18 18 21 18 23 18 32 26 21 21 22 20 22 16 17 20 22 21 17 13 13 11 9 5 0 1 1   1   0.188000 4.300 4.300 10.20      3396610           5           0  0 0 0 0 0 0 0 0 0 0 1 2 3 0 2 5 5 4 3 3 5 1 2 3 6 9 3 3 3 8 7 2 9 5 7 5 11 8 9   7 6 9 6 4 5 8 6 10 9 14 10 15 6 7 13 15 10 13 7 15 10 10 11 14 14 6 7 17 13 19   3 13 9 6 13 13 14 10 11 12 16 17 13 10 15 15 19 19 11 11 15 11 13 9 13 20 8 18   14 18 23 23 23 15 19 20 14 11 7 18 16 15 22 28 20 24 22 25 17 20 39 24 26 25     25 33 25 25 25 33 15 29 18 29 18 12 18 23 17 24 28 22 16 20 33 23 18 23 26 23    15 24 16 16 16 16 17 15 15 16 14 11 9 23 17 13 13 18 12 19 20 30 20 20 15 21     19 16 18 20 23 19 15 10 11 15 19 13 22 22 18 19 16 19 23 16 10 25 23 20 21 20    31 19 19 18 15 22 18 14 13 21 18 19 22 19 16 17 21 14 20 26 18 26 22 19 26 19    20 22 15 13 24 23 15 21 21 21 27 18 22 19 24 17 22 16 18 23 10 12 3 5 3 3 0 0   0.190000 4.350 4.350 10.30      3502025           3           0  0 0 0 0 0 0 0 0 0 0 0 3 0 3 2 3 4 4 3 4 5 10 7 6 6 4 5 12 10 6 6 13 10 6 7 14    9 6 13 10 12 16 3 9 9 7 5 6 13 11 10 8 11 19 12 14 13 16 13 14 9 12 14 13 14     16 10 14 7 16 18 16 9 15 11 20 15 10 14 14 11 14 17 10 6 16 10 15 12 17 17 20    15 7 12 23 15 8 13 12 8 16 15 20 16 16 20 14 11 20 24 23 20 16 18 27 25 31 27    27 25 21 31 27 20 23 24 32 17 21 34 27 17 19 19 25 30 27 21 24 28 30 19 26 21    14 16 21 23 27 8 17 21 17 11 23 15 22 15 18 10 17 20 23 18 18 17 19 22 15 22     21 19 23 18 18 26 17 18 26 18 24 15 22 23 23 19 23 25 23 24 26 10 21 16 32 23    18 19 24 21 28 26 22 19 19 14 30 21 24 23 22 21 13 27 20 27 24 15 20 22 22 13    25 14 19 32 21 18 18 23 22 22 14 18 20 24 14 19 20 18 17 24 29 27 20 12 18 17    11 9 2 3 2 1 0   0.192000 4.400 4.400 10.40      3593938           3           0  0 0 0 0 0 0 0 0 0 0 1 0 1 1 2 3 4 7 8 1 5 6 8 3 7 5 4 9 8 8 7 7 9 7 9 9 15 5 7   8 15 14 9 9 13 8 8 15 10 7 10 9 10 14 7 8 18 16 17 11 14 15 13 8 15 8 15 18 16   16 22 12 8 16 13 10 13 13 10 21 11 10 16 16 13 13 17 16 20 23 13 22 16 14 15     22 19 22 15 22 24 16 16 16 19 12 15 16 17 20 18 19 26 17 23 18 32 20 28 36 22    25 30 29 31 36 24 24 21 29 24 32 29 30 23 34 19 33 34 25 20 31 27 24 16 14 21    20 13 24 17 28 13 24 16 26 15 26 21 11 15 20 13 20 18 25 23 18 24 26 22 16 22    14 13 16 20 24 25 19 29 20 15 20 16 25 26 21 22 17 24 22 21 17 23 23 15 19 30    23 17 21 19 18 21 26 14 29 24 20 33 19 15 20 23 28 19 23 25 15 19 17 31 23 18    29 26 25 14 24 25 18 19 19 24 35 31 23 23 14 15 19 11 20 19 24 17 16 9 10 12 3   2 2 0 1   0.194000 4.450 4.450 10.50      3712573           7           0  0 0 0 0 0 0 0 0 0 0 0 1 1 1 5 3 5 4 3 11 3 10 4 6 7 8 5 5 5 8 9 12 7 7 11 8 6    7 9 10 13 10 6 13 9 9 9 11 14 14 12 13 10 6 13 13 15 12 13 19 8 14 13 16 11 13   14 15 9 15 16 13 16 17 17 17 23 18 16 19 10 13 18 16 10 9 21 11 22 14 20 14 18   13 15 12 13 14 16 14 15 20 29 17 14 18 8 15 21 15 19 15 22 20 17 15 23 26 16     26 24 23 23 23 23 30 24 29 28 26 35 33 31 22 23 22 20 37 22 27 33 26 27 26 17    16 18 27 22 21 24 18 18 18 17 15 18 14 19 24 22 15 20 21 15 19 25 15 16 26 19    22 29 20 16 13 15 16 32 24 23 13 33 17 22 18 18 23 24 22 21 20 26 21 16 22 18    18 16 15 26 26 17 22 21 13 25 24 13 23 18 18 25 32 20 24 21 17 19 24 24 23 33    19 19 21 32 18 22 23 19 23 32 18 31 22 25 23 23 31 29 21 16 20 20 15 22 14 12    5 10 9 2 1 0 1   0.196000 4.500 4.500 10.60      3829518           3           0  0 0 0 0 0 0 0 0 0 1 2 2 1 6 2 6 5 9 3 5 6 8 6 3 8 10 7 11 9 4 8 9 5 11 10 13 9   16 13 10 9 5 12 9 15 10 13 9 12 18 14 19 9 13 14 12 13 21 17 17 18 16 13 12 16   14 18 10 15 15 16 11 15 22 17 19 17 11 12 26 12 17 19 18 21 20 27 17 18 19 21    14 19 16 12 16 21 20 18 8 17 17 13 13 18 15 19 15 19 20 28 21 29 27 27 34 24     26 31 25 24 16 17 23 23 30 28 18 28 32 28 37 18 26 18 16 33 21 31 21 20 22 19    20 25 18 18 20 11 17 20 22 23 14 14 17 18 20 25 20 19 20 22 19 16 33 25 21 21    24 18 16 22 29 22 16 27 26 28 21 20 22 17 25 23 20 23 18 16 19 26 22 21 22 23    15 20 19 17 23 19 20 15 22 18 22 26 23 23 31 17 29 18 13 15 19 18 24 22 28 22    17 23 24 26 21 23 25 24 29 26 18 41 24 29 22 27 23 28 16 30 24 18 23 19 17 18    21 17 14 8 2 5 2 0 0   0.198000 4.550 4.550 10.70      3950740           3           0  0 0 0 0 0 0 0 0 1 1 1 2 1 3 7 5 6 7 7 7 4 5 6 4 1 8 9 10 9 8 10 8 12 6 10 8 10   8 11 9 10 15 7 11 8 13 11 13 15 15 17 12 10 8 17 12 9 14 12 14 11 14 21 14 15    20 18 16 8 15 22 24 14 10 18 14 15 16 12 10 16 21 16 25 17 20 17 17 20 15 24     15 17 22 25 17 13 22 18 20 19 11 21 22 21 16 21 24 16 22 17 21 17 24 22 24 35    27 24 28 24 32 37 34 25 24 29 37 37 25 28 21 23 24 22 21 20 25 22 32 19 21 22    24 20 21 20 22 18 27 17 14 20 22 22 22 14 19 20 20 21 23 22 14 20 21 23 20 18    23 20 25 31 24 18 22 14 23 22 21 23 27 27 20 21 18 22 23 24 23 21 18 22 17 22    21 35 15 24 24 12 27 30 27 28 22 31 24 24 19 27 24 28 23 25 26 35 27 22 29 21    24 18 19 26 33 29 31 23 25 19 24 26 21 10 23 24 26 28 20 27 26 17 29 22 18 14    22 8 10 11 4 4 1 2 0   0.200000 4.600 4.600 10.80      4068161           5           0  0 0 0 0 0 0 0 0 0 1 1 0 1 5 5 2 9 3 11 6 9 8 7 7 8 3 3 13 10 8 7 5 8 13 8 7 14   12 10 7 15 13 13 11 12 12 14 12 13 12 10 15 11 14 7 16 15 8 15 13 15 13 18 13    17 21 15 12 13 13 17 18 18 18 16 19 20 17 14 17 24 13 12 18 19 19 13 21 18 26    21 23 16 14 18 19 13 33 13 19 20 14 20 23 14 26 19 22 21 21 16 27 30 25 28 22    32 21 30 27 31 21 30 22 27 27 31 27 21 17 38 41 17 21 20 19 30 24 27 20 20 21    30 20 19 19 31 25 24 13 21 23 19 24 33 24 17 20 17 12 25 23 18 24 11 24 25 22    33 20 11 22 31 21 20 26 27 21 26 24 14 23 23 20 20 26 28 10 20 27 24 22 17 27    28 20 23 23 33 20 24 26 32 33 29 21 25 24 17 18 19 27 26 20 24 26 24 24 26 21    19 24 21 36 32 18 33 33 20 23 25 33 19 27 25 27 24 27 21 21 23 28 18 27 25 19    24 15 17 12 15 7 2 1 0 0 ", "%f ", Inf);
 %! assert (rows (x) == n);
 
+## Test input validation
+%!error <Invalid call to sscanf> sscanf ()
+%!error <STRING must be a string> sscanf (1, "2")
+%!error <TEMPLATE must be a string> sscanf ("1", 2)
+%!error <Invalid call to sscanf> sscanf ("foo", "bar", 1, 2)
+
 %% Note use fprintf so output not sent to stdout
 %!test
 %! nm = tempname ();
--- a/test/line-continue.tst	Fri Dec 02 10:11:46 2022 -0500
+++ b/test/line-continue.tst	Fri Dec 02 10:12:40 2022 -0500
@@ -33,34 +33,6 @@
 %! b];
 %! assert (y, x);
 
-## FIXME: Next 3 tests use '\' continuation outside of a double-quoted string
-##        This behavior is deprecated and will be removed at some point.
-##        When it does these
-%!test
-%! x = [1;2];
-%! y = [a... # comments here ok
-%! ;\
-%!
-%! b];
-%! assert (y, x);
-
-%!assert (1 + ...
-%! 2 - \# comments here ok
-%! 3 / ... # comments here ok
-%! -1,6);
-
-%!function y = f (a,...
-%!                b,  ...
-%!                c,  ...   % comments ok
-%!                x,  # continuation characters not required in parens
-%!                y,  \# but they should work too.
-%!                z)
-%!
-%!  y = 1;
-%!endfunction
-%!
-%!assert (f (), 1)
-
 ## String continuation using '\'
 %!assert (["abc\
 %! def"], "abc def")