changeset 16205:a8f9eb92fa6e classdef

maint: periodic merge of default to classdef
author John W. Eaton <jwe@octave.org>
date Wed, 06 Mar 2013 16:43:33 -0500
parents 0259254a3ccc (current diff) 127cccb037bf (diff)
children 3449bf257514
files libinterp/Makefile.am libinterp/octave.cc libinterp/parse-tree/lex.h libinterp/parse-tree/lex.ll libinterp/parse-tree/module.mk libinterp/parse-tree/oct-parse.in.yy libinterp/parse-tree/oct-parse.yy libinterp/parse-tree/parse.h libinterp/parse-tree/pt-check.cc libinterp/parse-tree/pt-check.h src/Makefile.am test/classes/classes.tst
diffstat 58 files changed, 2416 insertions(+), 1508 deletions(-) [+]
line wrap: on
line diff
--- a/.hgtags
+++ b/.hgtags
@@ -75,3 +75,4 @@
 0000000000000000000000000000000000000000 ss-3-7-2
 23a7661e529ae9bfc91693618f8c314c31f695ca ss-3-7-2
 cc5a7d1233f3acea85648baeb754fc0e8f225225 rc-3-6-4-2
+b29b10fbb7448cdfe29322446e1a589e7fe1a40a release-3-6-4
new file mode 100644
--- /dev/null
+++ b/CITATION
@@ -0,0 +1,20 @@
+To cite GNU Octave in publications use:
+
+  John W. Eaton, David Bateman, and Søren Hauberg (2009).  GNU Octave version
+  3.0.1 manual: a high-level interactive language for numerical computations.
+  CreateSpace Independent Publishing Platform.  ISBN 1441413006,
+  URL http://www.gnu.org/software/octave/doc/interpreter/
+
+A BibTeX entry for LaTeX users is:
+
+  @book{,
+    author    = {John W. Eaton and David Bateman and S\oren Hauberg},
+    title     = {{GNU Octave} version 3.0.1 manual: a high-level interactive language for numerical computations},
+    publisher = {CreateSpace Independent Publishing Platform},
+    year      = {2009},
+    note      = {{ISBN} 1441413006},
+    url       = {http://www.gnu.org/software/octave/doc/interpreter},
+  }
+
+We have invested a lot of time and effort in creating GNU Octave, please cite it
+when using it.  See also `citation pkgname' for citing Octave packages.
--- a/Makefile.am
+++ b/Makefile.am
@@ -37,6 +37,7 @@
   INSTALL.OCTAVE \
   NEWS \
   README \
+  CITATION \
   bootstrap \
   bootstrap.conf \
   build-aux/find-files-with-tests.sh \
@@ -132,7 +133,9 @@
 	mv $@.t $@
 .PHONY: ChangeLog
 
-octetc_DATA = NEWS
+octetc_DATA = \
+  NEWS \
+  CITATION
 
 DIRS_TO_MAKE = \
   $(localfcnfiledir) \
--- a/NEWS
+++ b/NEWS
@@ -177,6 +177,9 @@
       CC_VERSION  (now GCC_VERSION)
       CXX_VERSION (now GXX_VERSION)
 
+ ** A citation command has been added to display information on how to
+    cite Octave and packages in publications.  The package system will
+    look for and install CITATION files from packages.
 
 Summary of important user-visible changes for version 3.6:
 ---------------------------------------------------------
--- a/bootstrap.conf
+++ b/bootstrap.conf
@@ -156,7 +156,7 @@
   ## with building the rest of Octave, and INSTALL, which is linked from
   ## gnulib/doc/INSTALL by the bootstrap script.
 
-  for f in NEWS README COPYING; do
+  for f in NEWS README COPYING CITATION; do
     if ! test -f $f; then
       echo "required file $f is missing" 2>&1
       exit 1
--- a/build-aux/common.mk
+++ b/build-aux/common.mk
@@ -44,6 +44,7 @@
 
 YACC = @YACC@
 AM_YFLAGS = -dv
+BISON_PUSH_PULL_DECL_STYLE = @BISON_PUSH_PULL_DECL_STYLE@
 
 GPERF = @GPERF@
 
@@ -121,7 +122,6 @@
 # endif
 
 DEFS = @DEFS@
-UGLY_DEFS = @UGLY_DEFS@
 
 # C++ compiler flags.
 
@@ -475,9 +475,8 @@
 fi
 endef
 
-# Yes, the second sed command near the end is needed, to avoid limits
-# in command lengths for some versions of sed.  UGLY_DEFS is often
-# quite large, so it makes sense to split this command there.
+## To avoid shell command line limits, break the replacement patterns
+## into two roughly equal sized parts.
 
 define do_subst_config_vals
 echo "making $@ from $<"
@@ -529,6 +528,7 @@
   -e "s|%OCTAVE_CONF_CXXPICFLAG%|\"${CXXPICFLAG}\"|" \
   -e "s|%OCTAVE_CONF_CXX_VERSION%|\"${CXX_VERSION}\"|" \
   -e "s|%OCTAVE_CONF_DEFAULT_PAGER%|\"${DEFAULT_PAGER}\"|" \
+  -e "s|%OCTAVE_CONF_DEFS%|\"${DEFS}\"|" \
   -e "s|%OCTAVE_CONF_DEPEND_FLAGS%|\"${DEPEND_FLAGS}\"|" \
   -e "s|%OCTAVE_CONF_DEPEND_EXTRA_SED_PATTERN%|\"${DEPEND_EXTRA_SED_PATTERN}\"|" \
   -e "s|%OCTAVE_CONF_DL_LD%|\"${DL_LD}\"|" \
@@ -559,8 +559,8 @@
   -e "s|%OCTAVE_CONF_GNUPLOT%|\"${GNUPLOT}\"|" \
   -e "s|%OCTAVE_CONF_GRAPHICS_CFLAGS%|\"${GRAPHICS_CFLAGS}\"|" \
   -e "s|%OCTAVE_CONF_GRAPHICS_LIBS%|\"${GRAPHICS_LIBS}\"|" \
-  -e "s|%OCTAVE_CONF_HDF5_CPPFLAGS%|\"${HDF5_CPPFLAGS}\"|" \
-  -e "s|%OCTAVE_CONF_HDF5_LDFLAGS%|\"${HDF5_LDFLAGS}\"|" \
+  -e "s|%OCTAVE_CONF_HDF5_CPPFLAGS%|\"${HDF5_CPPFLAGS}\"|" | \
+  $(SED) -e "s|%OCTAVE_CONF_HDF5_LDFLAGS%|\"${HDF5_LDFLAGS}\"|" \
   -e "s|%OCTAVE_CONF_HDF5_LIBS%|\"${HDF5_LIBS}\"|" \
   -e "s|%OCTAVE_CONF_INCLUDEDIR%|\"${includedir}\"|" \
   -e "s|%OCTAVE_CONF_LAPACK_LIBS%|\"${LAPACK_LIBS}\"|" \
@@ -624,7 +624,6 @@
   -e "s|%OCTAVE_CONF_SONAME_FLAGS%|\"${SONAME_FLAGS}\"|" \
   -e "s|%OCTAVE_CONF_STATIC_LIBS%|\"${STATIC_LIBS}\"|" \
   -e "s|%OCTAVE_CONF_TERM_LIBS%|\"${TERM_LIBS}\"|" \
-  -e "s|%OCTAVE_CONF_UGLY_DEFS%|\"${UGLY_DEFS}\"|" \
   -e "s|%OCTAVE_CONF_UMFPACK_CPPFLAGS%|\"${UMFPACK_CPPFLAGS}\"|" \
   -e "s|%OCTAVE_CONF_UMFPACK_LDFLAGS%|\"${UMFPACK_LDFLAGS}\"|" \
   -e "s|%OCTAVE_CONF_UMFPACK_LIBS%|\"${UMFPACK_LIBS}\"|" \
@@ -641,8 +640,7 @@
   -e "s|%OCTAVE_CONF_Z_CPPFLAGS%|\"${Z_CPPFLAGS}\"|" \
   -e "s|%OCTAVE_CONF_Z_LDFLAGS%|\"${Z_LDFLAGS}\"|" \
   -e "s|%OCTAVE_CONF_Z_LIBS%|\"${Z_LIBS}\"|" \
-  -e "s|%OCTAVE_CONF_config_opts%|\"${config_opts}\"|" | \
-  $(SED)  -e "s|%OCTAVE_CONF_DEFS%|\"${UGLY_DEFS}\"|" > $@-t
+  -e "s|%OCTAVE_CONF_config_opts%|\"${config_opts}\"|" > $@-t
 $(simple_move_if_change_rule)
 endef
 
--- a/configure.ac
+++ b/configure.ac
@@ -190,6 +190,17 @@
   AC_DEFINE(BOUNDS_CHECKING, 1, [Define to 1 to use internal bounds checking.])
 fi
 
+### Enable experimental push parser.
+
+OCTAVE_USE_PUSH_PARSER=no
+AC_ARG_ENABLE([push-parser],
+  [AS_HELP_STRING([--enable-push-parser],
+    [enable experimental push parser])],
+  [if test "$enableval" = yes; then OCTAVE_USE_PUSH_PARSER=yes; fi], [])
+if test $OCTAVE_USE_PUSH_PARSER = yes; then
+  AC_DEFINE(OCTAVE_USE_PUSH_PARSER, 1, [Define to 1 to use experimental push parser.])
+fi
+
 ### Use Octave's built-in memory allocator rather than straightforward malloc.
 ### Disabled by default.
 
@@ -2834,18 +2845,9 @@
 ### Make all AC_DEFINES available to testif feature of test.m function.
 ### This must reside at the bottom of configure.ac after all AC_DEFINES
 ### have been made.
-### Use UGLY_DEFS to hold all the -D options.  These are ultimately placed
-### in the DEFS field of the struct returned by octave_config_info, which
-### is used by test.m.
 
 AC_OUTPUT_MAKE_DEFS
 
-## We have to insert extra levels of backslash quoting here so that
-## the right thing ends up in oct-conf.h.
-UGLY_DEFS=`echo $DEFS | $SED 's,\\",\\\\\\\\\\\\\\\\\\",g'`
-AC_MSG_NOTICE([defining UGLY_DEFS to be $UGLY_DEFS])
-AC_SUBST(UGLY_DEFS)
-
 ### Do the substitutions in all the Makefiles.
 
 AC_SUBST(ac_config_files)
@@ -2974,6 +2976,7 @@
   Build Java interface:               $build_java
   Do internal array bounds checking:  $BOUNDS_CHECKING
   Use octave_allocator:               $USE_OCTAVE_ALLOCATOR
+  Use push parser:                    $OCTAVE_USE_PUSH_PARSER
   Build static libraries:             $STATIC_LIBS
   Build shared libraries:             $SHARED_LIBS
   Dynamic Linking:                    $ENABLE_DYNAMIC_LINKING $DL_API_MSG
--- a/doc/interpreter/find-docstring-files.sh
+++ b/doc/interpreter/find-docstring-files.sh
@@ -5,7 +5,7 @@
   exit 1
 fi
 
-## if there is a file in teh build directory tree, assume it is
+## if there is a file in the build directory tree, assume it is
 ## the file we are looking for.  Otherwise, get the one from the
 ## source tree.
 
--- a/doc/interpreter/geometryimages.m
+++ b/doc/interpreter/geometryimages.m
@@ -29,7 +29,7 @@
     d_typ = cstrcat ("-d", typ);
   endif
 
-  if (isempty (findstr (octave_config_info ("DEFS"), "HAVE_QHULL"))
+  if (! __have_feature__ ("QHULL")
       && (strcmp (nm, "voronoi") || strcmp (nm, "griddata")
           || strcmp (nm, "convhull") || strcmp (nm, "delaunay")
           || strcmp (nm, "triplot")))
--- a/doc/interpreter/package.txi
+++ b/doc/interpreter/package.txi
@@ -182,6 +182,11 @@
 following files:
 
 @table @code
+@item package/CITATION
+This is am optional file describing instructions on how to cite
+the package for publication.  It will be displayed verbatim by the
+function @code{citation}.
+
 @item package/COPYING
 This is a required file containing the license of the package.  No
 restrictions is made on the license in general.  If however the
--- a/doc/interpreter/sparseimages.m
+++ b/doc/interpreter/sparseimages.m
@@ -23,9 +23,9 @@
     set (0, "defaulttextfontname", "*");
   endif
 
-  if (! isempty (findstr (octave_config_info ("DEFS"), "HAVE_COLAMD"))
-      && ! isempty (findstr (octave_config_info ("DEFS"), "HAVE_CHOLMOD"))
-      && ! isempty (findstr (octave_config_info ("DEFS"), "HAVE_UMFPACK")))
+  if (__have_feature__ ("COLAMD")
+      && __have_feature__ ("CHOLMOD")
+      && __have_feature__ ("UMFPACK"))
     if (strcmp(typ,"txt"))
       txtimages (nm, 15, typ);
     else
@@ -86,8 +86,8 @@
   elseif (strcmp (nm, "spmatrix"))
     printsparse(a,cstrcat("spmatrix.",typ));
   else
-    if (!isempty(findstr(octave_config_info ("DEFS"),"HAVE_COLAMD")) &&
-        !isempty(findstr(octave_config_info ("DEFS"),"HAVE_CHOLMOD")))
+    if (__have_feature__ ("COLAMD")
+        && __have_feature__ ("CHOLMOD"))
       if (strcmp (nm, "spchol"))
         r1 = chol(a);
         printsparse(r1,cstrcat("spchol.",typ));
@@ -116,8 +116,8 @@
     print(cstrcat("spmatrix.",typ), d_typ)
     hide_output ();
   else
-    if (!isempty(findstr(octave_config_info ("DEFS"),"HAVE_COLAMD")) &&
-        !isempty(findstr(octave_config_info ("DEFS"),"HAVE_CHOLMOD")))
+    if (__have_feature__ ("COLAMD")
+        && __have_feature__ ("CHOLMOD"))
       if (strcmp (nm, "spchol"))
         r1 = chol(a);
         spy(r1);
@@ -182,9 +182,9 @@
     d_typ = cstrcat ("-d", typ);
   endif
 
-  if (!isempty(findstr(octave_config_info ("DEFS"),"HAVE_COLAMD")) &&
-      !isempty(findstr(octave_config_info ("DEFS"),"HAVE_CHOLMOD")) &&
-      !isempty(findstr(octave_config_info ("DEFS"),"HAVE_UMFPACK")))
+  if (__have_feature__ ("COLAMD")
+      && __have_feature__ ("CHOLMOD")
+      && __have_feature__ ("UMFPACK"))
     ## build a rectangle
     node_y = [1;1.2;1.5;1.8;2]*ones(1,11);
     node_x = ones(5,1)*[1,1.05,1.1,1.2,1.3,1.5,1.7,1.8,1.9,1.95,2];
--- a/libgui/src/files-dockwidget.cc
+++ b/libgui/src/files-dockwidget.cc
@@ -124,7 +124,8 @@
   Qt::SortOrder sort_order = _file_tree_view->header ()->sortIndicatorOrder ();
   settings->setValue ("filesdockwidget/sort_files_by_column", sort_column);
   settings->setValue ("filesdockwidget/sort_files_by_order", sort_order);
-  settings->setValue ("filesdockwidget/column_state", _file_tree_view->header ()->saveState ()); 
+  settings->setValue ("filesdockwidget/column_state", _file_tree_view->header ()->saveState ());
+  settings->sync ();
 }
 
 void
--- a/libgui/src/m-editor/file-editor.cc
+++ b/libgui/src/m-editor/file-editor.cc
@@ -427,6 +427,7 @@
     QSettings *settings = resource_manager::get_settings ();
     // FIXME -- what should happen if settings is 0?
     settings->setValue ("editor/mru_file_list",_mru_files);
+    settings->sync ();
 }
 
 void
@@ -600,6 +601,10 @@
   _cut_action->setEnabled(false);
   _run_action->setShortcut                      (Qt::ControlModifier+ Qt::Key_R);
   _run_action->setShortcutContext               (Qt::WindowShortcut);
+  save_action->setShortcut                      (QKeySequence::Save);
+  save_action->setShortcutContext               (Qt::WindowShortcut);
+  save_as_action->setShortcut                   (QKeySequence::SaveAs);
+  save_as_action->setShortcutContext            (Qt::WindowShortcut);
   next_bookmark_action->setShortcut             (Qt::Key_F2);
   next_bookmark_action->setShortcutContext      (Qt::WindowShortcut);
   previous_bookmark_action->setShortcut         (Qt::SHIFT + Qt::Key_F2);
@@ -610,7 +615,7 @@
   comment_selection_action->setShortcutContext  (Qt::WindowShortcut);
   uncomment_selection_action->setShortcut       (Qt::ControlModifier + Qt::Key_8);
   uncomment_selection_action->setShortcutContext(Qt::WindowShortcut);
-  find_action->setShortcut                      (Qt::ControlModifier+Qt::Key_F);
+  find_action->setShortcut                      (QKeySequence::Find);
   find_action->setShortcutContext               (Qt::WindowShortcut);
 
   // toolbar
--- a/libgui/src/main-window.cc
+++ b/libgui/src/main-window.cc
@@ -129,7 +129,7 @@
 main_window::handle_save_workspace_request ()
 {
   QString selectedFile =
-    QFileDialog::getSaveFileName (this, tr ("Save Workspace"),
+    QFileDialog::getSaveFileName (this, tr ("Save Workspace As"),
                                   resource_manager::get_home_path ());
   if (!selectedFile.isEmpty ())
     octave_link::post_event (this, &main_window::save_workspace_callback,
@@ -698,7 +698,8 @@
 
   QAction *new_script_action
     = new_menu->addAction (QIcon(":/actions/icons/filenew.png"), tr ("Script"));
-  new_script_action->setShortcut (Qt::ControlModifier + Qt::Key_N);
+  new_script_action->setShortcut (QKeySequence::New);
+  new_script_action->setShortcutContext (Qt::ApplicationShortcut);
 
   QAction *new_function_action = new_menu->addAction (tr ("Function"));
   new_function_action->setEnabled (false); // TODO: Make this work.
@@ -717,24 +718,24 @@
 
   QAction *open_action
     = file_menu->addAction (QIcon(":/actions/icons/fileopen.png"), tr ("Open..."));
-  open_action->setShortcut (Qt::ControlModifier + Qt::Key_O);
+  open_action->setShortcut (QKeySequence::Open);
+  open_action->setShortcutContext (Qt::ApplicationShortcut);
 
   file_menu->addMenu(_file_editor->get_mru_menu ());
 
   QAction *close_command_window_action
     = file_menu->addAction (tr ("Close Command Window"));
-  close_command_window_action->setShortcut (Qt::ControlModifier + Qt::Key_W);
+  close_command_window_action->setShortcut (QKeySequence::Close);
   close_command_window_action->setEnabled (false); // TODO: Make this work.
 
   file_menu->addSeparator (); /////
 
   QAction *import_data_action
-    = file_menu->addAction (tr ("Import Data..."));
+    = file_menu->addAction (tr ("Import Data"));
   import_data_action->setEnabled (false); // TODO: Make this work.
 
   QAction *save_workspace_action
-    = file_menu->addAction (tr ("Save Workspace..."));
-  save_workspace_action->setShortcut (Qt::ControlModifier + Qt::Key_S);
+    = file_menu->addAction (tr ("Save Workspace As"));
 
   file_menu->addSeparator (); /////
 
@@ -749,7 +750,7 @@
   page_setup_action->setEnabled (false); // TODO: Make this work.
   QAction *print_action
     = file_menu->addAction (tr ("Print"));
-  print_action->setShortcut (Qt::ControlModifier + Qt::Key_P);
+  print_action->setShortcut (QKeySequence::Print);
   print_action->setEnabled (false); // TODO: Make this work.
   QAction *print_selection_action
     = file_menu->addAction (tr ("Print Selection..."));
@@ -758,7 +759,7 @@
   file_menu->addSeparator (); /////
 
   QAction *exit_action = file_menu->addAction (tr ("Exit"));
-  exit_action->setShortcut (Qt::ControlModifier + Qt::Key_Q);
+  exit_action->setShortcut (QKeySequence::Quit);
 
 
   QMenu *edit_menu = menuBar ()->addMenu (tr ("&Edit"));
@@ -879,58 +880,61 @@
   show_command_window_action->setCheckable (true);
   show_command_window_action->setShortcut (Qt::ControlModifier
                                            + Qt::ShiftModifier + Qt::Key_0);
-
+  show_command_window_action->setShortcutContext (Qt::ApplicationShortcut);
   QAction * show_history_action
     = window_menu->addAction (tr ("Show Command History"));
   show_history_action->setCheckable (true);
   show_history_action->setShortcut (Qt::ControlModifier
                                     + Qt::ShiftModifier + Qt::Key_1);
+  show_history_action->setShortcutContext (Qt::ApplicationShortcut);
   QAction * show_file_browser_action
     = window_menu->addAction (tr ("Show Current Directory"));
   show_file_browser_action->setCheckable (true);
   show_file_browser_action->setShortcut (Qt::ControlModifier
                                          + Qt::ShiftModifier + Qt::Key_2);
-
+  show_file_browser_action->setShortcutContext (Qt::ApplicationShortcut);
   QAction * show_workspace_action
     = window_menu->addAction (tr ("Show Workspace"));
   show_workspace_action->setCheckable (true);
   show_workspace_action->setShortcut (Qt::ControlModifier
                                       + Qt::ShiftModifier + Qt::Key_3);
-
+  show_workspace_action->setShortcutContext (Qt::ApplicationShortcut);
   QAction * show_editor_action = window_menu->addAction (tr ("Show Editor"));
   show_editor_action->setCheckable (true);
   show_editor_action->setShortcut (Qt::ControlModifier + Qt::ShiftModifier
                                    + Qt::Key_4);
-
+  show_editor_action->setShortcutContext (Qt::ApplicationShortcut);
   QAction * show_documentation_action = window_menu->addAction (tr ("Show Documentation"));
   show_documentation_action->setCheckable (true);
   show_documentation_action->setShortcut (Qt::ControlModifier + Qt::ShiftModifier
                                           + Qt::Key_5);
+  show_documentation_action->setShortcutContext (Qt::ApplicationShortcut);
   window_menu->addSeparator (); /////
 
   QAction * command_window_action
     = window_menu->addAction (tr ("Command Window"));
   command_window_action->setShortcut (Qt::ControlModifier + Qt::Key_0);
-
+  command_window_action->setShortcutContext (Qt::ApplicationShortcut);
   QAction * history_action
     = window_menu->addAction (tr ("Command History"));
   history_action->setShortcut (Qt::ControlModifier + Qt::Key_1);
-
+  history_action->setShortcutContext (Qt::ApplicationShortcut);
   QAction * file_browser_action
     = window_menu->addAction (tr ("Current Directory"));
   file_browser_action->setShortcut (Qt::ControlModifier + Qt::Key_2);
-
+  file_browser_action->setShortcutContext (Qt::ApplicationShortcut);
   QAction * workspace_action
     = window_menu->addAction (tr ("Workspace"));
   workspace_action->setShortcut (Qt::ControlModifier + Qt::Key_3);
-
+  workspace_action->setShortcutContext (Qt::ApplicationShortcut);
   QAction * editor_action
     = window_menu->addAction (tr ("Editor"));
   editor_action->setShortcut (Qt::ControlModifier + Qt::Key_4);
-
+  editor_action->setShortcutContext (Qt::ApplicationShortcut);
   QAction * documentation_action
     = window_menu->addAction (tr ("Documentation"));
   documentation_action->setShortcut (Qt::ControlModifier + Qt::Key_5);
+  documentation_action->setShortcutContext (Qt::ApplicationShortcut);
 
   window_menu->addSeparator (); /////
 
--- a/libgui/src/octave-adapter/octave-main-thread.cc
+++ b/libgui/src/octave-adapter/octave-main-thread.cc
@@ -40,6 +40,8 @@
 octave_main_thread::run ()
 {
   setlocale (LC_ALL, "en_US.UTF-8");
+  // Matlab uses "C" locale for LC_NUMERIC class regardless of local setting
+  setlocale (LC_NUMERIC, "C");
 
   emit ready ();
 
--- a/libgui/src/workspace-view.cc
+++ b/libgui/src/workspace-view.cc
@@ -97,13 +97,11 @@
 workspace_view::~workspace_view ()
 {
   QSettings *settings = resource_manager::get_settings ();
-
-  // FIXME -- what should happen if settings is 0?
-
   settings->setValue("workspaceview/local_collapsed", _explicit_collapse.local);
   settings->setValue("workspaceview/global_collapsed", _explicit_collapse.global);
   settings->setValue("workspaceview/persistent_collapsed", _explicit_collapse.persistent);
   settings->setValue("workspaceview/column_state", _workspace_tree_view->header ()->saveState ());
+  settings->sync ();
 }
 
 void
--- a/libinterp/Makefile.am
+++ b/libinterp/Makefile.am
@@ -58,13 +58,15 @@
   parse-tree/oct-gperf.h \
   parse-tree/oct-parse.cc \
   oct-conf.h \
+  oct-conf-features.h \
   version.h \
   builtin-defun-decls.h \
   builtins.cc
 
 BUILT_DISTFILES = \
   parse-tree/oct-gperf.h \
-  parse-tree/oct-parse.h
+  parse-tree/oct-parse.h \
+  parse-tree/oct-parse.yy
 
 ## Files that are created during build process and installed,
 ## BUT not distributed in tarball.
@@ -76,6 +78,7 @@
   builtin-defun-decls.h \
   operators/ops.cc \
   oct-conf.h \
+  oct-conf-features.h \
   version.h \
   $(OPT_HANDLERS) \
   $(OPT_INC) \
@@ -85,6 +88,7 @@
 EXTRA_DIST = \
   Makefile.in \
   DOCSTRINGS \
+  config-features.sh \
   find-defun-files.sh \
   gendoc.pl \
   genprops.awk \
@@ -94,6 +98,7 @@
   mkdefs \
   mkops \
   oct-conf.in.h \
+  parse-tree/oct-parse.in.yy \
   version.in.h \
   $(BUILT_DISTFILES)
 
@@ -162,6 +167,7 @@
   builtin-defun-decls.h \
   builtins.cc \
   oct-conf.h \
+  oct-conf-features.h \
   version.h \
   $(OPT_INC)
 
@@ -192,7 +198,11 @@
   $(LIBOCTINTERP_LINK_OPTS)
 
 ## Section for defining and creating DEF_FILES
-SRC_DEF_FILES := $(shell $(srcdir)/find-defun-files.sh "$(srcdir)" $(DIST_SRC))
+
+ULT_DIST_SRC := \
+  $(filter-out parse-tree/oct-parse.yy, $(DIST_SRC)) parse-tree/oct-parse.in.yy
+
+SRC_DEF_FILES := $(shell $(srcdir)/find-defun-files.sh "$(srcdir)" $(ULT_DIST_SRC))
 
 DLDFCN_DEF_FILES = $(DLDFCN_SRC:.cc=.df)
 
@@ -232,7 +242,7 @@
 
 ## Rules to build test files
 
-TST_FILES_SRC := $(shell $(top_srcdir)/build-aux/find-files-with-tests.sh "$(srcdir)" $(DIST_SRC) $(DLDFCN_SRC))
+TST_FILES_SRC := $(shell $(top_srcdir)/build-aux/find-files-with-tests.sh "$(srcdir)" $(ULT_DIST_SRC) $(DLDFCN_SRC))
 
 TST_FILES := $(addsuffix -tst,$(TST_FILES_SRC))
 
@@ -256,6 +266,10 @@
 oct-conf.h: oct-conf.in.h Makefile
 	@$(do_subst_config_vals)
 
+oct-conf-features.h: $(top_builddir)/config.h config-features.sh
+	$(srcdir)/config-features.sh $< > $@-t
+	mv $@-t $@
+
 version.h: version.in.h Makefile
 	$(SED) < $< \
 	  -e "s|%NO_EDIT_WARNING%|DO NOT EDIT!  Generated automatically from $(<F) by Make.|" \
new file mode 100755
--- /dev/null
+++ b/libinterp/config-features.sh
@@ -0,0 +1,36 @@
+#! /bin/sh
+
+set -e
+AWK=${AWK:-awk}
+
+conffile=$1
+
+cat << EOF
+// DO NOT EDIT!  Generated automatically from $conffile by Make."
+
+#include "oct-map.h"
+#include "ov.h"
+
+octave_scalar_map
+octave_config_features (void)
+{
+  octave_scalar_map m;
+
+EOF
+
+$AWK \
+  '/#define HAVE_/ {
+     sub (/HAVE_/, "", $2);
+     printf ("  m.assign (\"%s\", octave_value (true));\n", $2);
+   }
+   /\/\* #undef HAVE_/ {
+     sub (/HAVE_/, "", $3);
+     printf ("  m.assign (\"%s\", octave_value (false));\n", $3);
+   } {
+   }' $conffile
+
+cat << EOF
+
+  return m;
+}
+EOF
--- a/libinterp/find-defun-files.sh
+++ b/libinterp/find-defun-files.sh
@@ -21,6 +21,6 @@
     file="$srcdir/$arg"
   fi
   if [ "`$EGREP -l "$DEFUN_PATTERN" $file`" ]; then
-    echo "$file" | $SED "s,\\$srcdir/,," | $SED 's/\.cc$/.df/; s/\.ll$/.df/; s/\.yy$/.df/';
+    echo "$file" | $SED "s,\\$srcdir/,," | $SED 's/\.cc$/.df/; s/\.ll$/.df/; s/\.in.yy$/.df/';
   fi
 done
--- a/libinterp/interp-core/txt-eng-ft.cc
+++ b/libinterp/interp-core/txt-eng-ft.cc
@@ -564,6 +564,11 @@
   return pixels;
 }
 
+// Note:
+// x-extent accurately measures width of glyphs.
+// y-extent is overly large because it is measured from baseline-to-baseline.
+// Calling routines, such as ylabel, may need to account for this mismatch.
+
 Matrix
 ft_render::get_extent (text_element *elt, double rotation)
 {
--- a/libinterp/interpfcn/graphics.cc
+++ b/libinterp/interpfcn/graphics.cc
@@ -5194,11 +5194,20 @@
       graphics_xform xform = get_transform ();
 
       Matrix ext (1, 2, 0.0);
+
+      // The underlying get_extents() from FreeType produces mismatched values.
+      // x-extent accurately measures the width of the glyphs.
+      // y-extent instead measures from baseline-to-baseline.
+      // Pad x-extent (+4) so that it approximately matches y-extent.
+      // This keeps ylabels about the same distance from y-axis as
+      // xlabels are from x-axis.
+      // ALWAYS use an even number for padding or horizontal alignment
+      // will be off.
       ext = get_ticklabel_extents (get_ytick ().matrix_value (),
                                    get_yticklabel ().all_strings (),
                                    get_ylim ().matrix_value ());
 
-      double wmax = ext(0), hmax = ext(1), angle = 0;
+      double wmax = ext(0)+4, hmax = ext(1), angle = 0;
       ColumnVector p =
         graphics_xform::xform_vector (xpTick, (ypTickN+ypTick)/2, zpTick);
 
--- a/libinterp/interpfcn/help.cc
+++ b/libinterp/interpfcn/help.cc
@@ -902,11 +902,6 @@
 {
   bool retval = false;
 
-  // FIXME -- this is a bit of a kluge...
-  unwind_protect frame;
-  frame.protect_var (reading_script_file);
-  reading_script_file = true;
-
   h = get_help_from_file (nm, symbol_found, file);
 
   if (h.length () > 0)
--- a/libinterp/interpfcn/input.cc
+++ b/libinterp/interpfcn/input.cc
@@ -94,37 +94,9 @@
 // Character to append after successful command-line completion attempts.
 static char Vcompletion_append_char = ' ';
 
-// Global pointer for eval().
-std::string current_eval_string;
-
-// TRUE means get input from current_eval_string.
-bool get_input_from_eval_string = false;
-
-// TRUE means that input is coming from a file that was named on
-// the command line.
-bool input_from_command_line_file = false;
-
 // TRUE means that stdin is a terminal, not a pipe or redirected file.
 bool stdin_is_tty = false;
 
-// TRUE means we're parsing a function file.
-bool reading_fcn_file = false;
-
-// TRUE means we're parsing a classdef file.
-bool reading_classdef_file = false;
-
-// Simple name of function file we are reading.
-std::string curr_fcn_file_name;
-
-// Full name of file we are reading.
-std::string curr_fcn_file_full_name;
-
-// TRUE means we're parsing a script file.
-bool reading_script_file = false;
-
-// If we are reading from an M-file, this is it.
-FILE *ff_instream = 0;
-
 // TRUE means this is an interactive shell.
 bool interactive = false;
 
@@ -160,7 +132,7 @@
 static void
 do_input_echo (const std::string& input_string)
 {
-  int do_echo = reading_script_file ?
+  int do_echo = CURR_LEXER->reading_script_file ?
     (Vecho_executing_commands & ECHO_SCRIPTS)
       : (Vecho_executing_commands & ECHO_CMD_LINE) && ! forced_interactive;
 
@@ -186,53 +158,25 @@
     }
 }
 
-std::string
-gnu_readline (const std::string& s, bool& eof, bool force_readline)
+static std::string
+gnu_readline (const std::string& s, bool& eof)
 {
   octave_quit ();
 
   eof = false;
 
-  std::string retval;
-
-  if (line_editing || force_readline)
-    {
-      retval = command_editor::readline (s, eof);
+  assert (line_editing);
 
-      if (! eof && retval.empty ())
-        retval = "\n";
-    }
-  else
-    {
-      if (! s.empty () && (interactive || forced_interactive))
-        {
-          FILE *stream = command_editor::get_output_stream ();
+  std::string retval = command_editor::readline (s, eof);
 
-          gnulib::fputs (s.c_str (), stream);
-          gnulib::fflush (stream);
-        }
-
-      FILE *curr_stream = command_editor::get_input_stream ();
-
-      if (reading_fcn_file || reading_script_file || reading_classdef_file)
-        curr_stream = ff_instream;
-
-      retval = octave_fgets (curr_stream, eof);
-    }
+  if (! eof && retval.empty ())
+    retval = "\n";
 
   return retval;
 }
 
-extern std::string
-gnu_readline (const std::string& s, bool force_readline)
-{
-  bool eof = false;
-
-  return gnu_readline (s, eof, force_readline);
-}
-
 static inline std::string
-interactive_input (const std::string& s, bool& eof, bool force_readline)
+interactive_input (const std::string& s, bool& eof)
 {
   Vlast_prompt_time.stamp ();
 
@@ -251,19 +195,11 @@
         return "\n";
     }
 
-  return gnu_readline (s, eof, force_readline);
+  return gnu_readline (s, eof);
 }
 
-static inline std::string
-interactive_input (const std::string& s, bool force_readline = false)
-{
-  bool eof = false;
-
-  return interactive_input (s, eof, force_readline);
-}
-
-static std::string
-octave_gets (bool& eof)
+std::string
+octave_base_reader::octave_gets (bool& eof)
 {
   octave_quit ();
 
@@ -273,127 +209,59 @@
 
   bool history_skip_auto_repeated_debugging_command = false;
 
-  if ((interactive || forced_interactive)
-      && (! (reading_fcn_file
-             || reading_classdef_file
-             || reading_script_file
-             || get_input_from_eval_string
-             || input_from_startup_file
-             || input_from_command_line_file)))
-    {
-      std::string ps = (promptflag > 0) ? VPS1 : VPS2;
+  std::string ps = (promptflag > 0) ? VPS1 : VPS2;
+
+  std::string prompt = command_editor::decode_prompt_string (ps);
+
+  pipe_handler_error_count = 0;
 
-      std::string prompt = command_editor::decode_prompt_string (ps);
-
-      pipe_handler_error_count = 0;
+  flush_octave_stdout ();
 
-      flush_octave_stdout ();
+  octave_pager_stream::reset ();
+  octave_diary_stream::reset ();
 
-      octave_pager_stream::reset ();
-      octave_diary_stream::reset ();
+  octave_diary << prompt;
 
-      octave_diary << prompt;
+  retval = interactive_input (prompt, eof);
 
-      retval = interactive_input (prompt, eof, false);
-
-      // There is no need to update the load_path cache if there is no
-      // user input.
-      if (! retval.empty ()
-          && retval.find_first_not_of (" \t\n\r") != std::string::npos)
-        {
-          load_path::update ();
+  // There is no need to update the load_path cache if there is no
+  // user input.
+  if (! retval.empty ()
+      && retval.find_first_not_of (" \t\n\r") != std::string::npos)
+    {
+      load_path::update ();
 
-          if (Vdebugging)
-            last_debugging_command = retval;
-          else
-            last_debugging_command = std::string ();
-        }
-      else if (Vdebugging)
-        {
-          retval = last_debugging_command;
-          history_skip_auto_repeated_debugging_command = true;
-        }
+      if (Vdebugging)
+        last_debugging_command = retval;
+      else
+        last_debugging_command = std::string ();
     }
-  else
-    retval = gnu_readline ("", eof, false);
+  else if (Vdebugging)
+    {
+      retval = last_debugging_command;
+      history_skip_auto_repeated_debugging_command = true;
+    }
 
   current_input_line = retval;
 
   if (! current_input_line.empty ())
     {
-      if (! (input_from_startup_file || input_from_command_line_file
-             || history_skip_auto_repeated_debugging_command))
+      if (! history_skip_auto_repeated_debugging_command)
         command_history::add (current_input_line);
 
-      if (! (reading_fcn_file || reading_script_file || reading_classdef_file))
-        {
-          octave_diary << current_input_line;
+      octave_diary << current_input_line;
 
-          if (current_input_line[current_input_line.length () - 1] != '\n')
-            octave_diary << "\n";
-        }
+      if (current_input_line[current_input_line.length () - 1] != '\n')
+        octave_diary << "\n";
 
       do_input_echo (current_input_line);
     }
-  else if (! (reading_fcn_file || reading_script_file || reading_classdef_file))
+  else
     octave_diary << "\n";
 
   return retval;
 }
 
-// Read a line from the input stream.
-
-std::string
-get_user_input (bool& eof)
-{
-  octave_quit ();
-
-  eof = false;
-
-  std::string retval;
-
-  if (get_input_from_eval_string)
-    {
-      retval = current_eval_string;
-
-      size_t len = retval.length ();
-
-      // Clear the global eval string so that the next call will return
-      // an empty character string with EOF = true.
-      current_eval_string = "";
-
-      eof = true;
-    }
-  else
-    retval = octave_gets (eof);
-
-  current_input_line = retval;
-
-  return retval;
-}
-
-// Fix things up so that input can come from file 'name', printing a
-// warning if the file doesn't exist.
-
-FILE *
-get_input_from_file (const std::string& name, int warn)
-{
-  FILE *instream = 0;
-
-  if (name.length () > 0)
-    instream = gnulib::fopen (name.c_str (), "rb");
-
-  if (! instream && warn)
-    warning ("%s: no such file or directory", name.c_str ());
-
-  if (reading_fcn_file || reading_script_file || reading_classdef_file)
-    ff_instream = instream;
-  else
-    command_editor::set_input_stream (instream);
-
-  return instream;
-}
-
 // Fix things up so that input can come from the standard input.  This
 // may need to become much more complicated, which is why it's in a
 // separate function.
@@ -640,40 +508,19 @@
   VPS1 = prompt;
 
   if (! (interactive || forced_interactive)
-      || (reading_fcn_file
-          || reading_classdef_file
-          || reading_script_file
-          || get_input_from_eval_string
-          || input_from_startup_file
-          || input_from_command_line_file))
+      || CURR_LEXER->reading_fcn_file
+      || CURR_LEXER->reading_classdef_file
+      || CURR_LEXER->reading_script_file
+      || CURR_LEXER->input_from_eval_string ())
     {
       frame.protect_var (forced_interactive);
       forced_interactive = true;
-
-      frame.protect_var (reading_fcn_file);
-      reading_fcn_file = false;
-
-      frame.protect_var (reading_classdef_file);
-      reading_classdef_file = false;
-
-      frame.protect_var (reading_script_file);
-      reading_script_file = false;
-
-      frame.protect_var (input_from_startup_file);
-      input_from_startup_file = false;
-
-      frame.protect_var (input_from_command_line_file);
-      input_from_command_line_file = false;
-
-      frame.protect_var (get_input_from_eval_string);
-      get_input_from_eval_string = false;
     }
 
   // octave_parser constructor sets this for us.
   frame.protect_var (CURR_LEXER);
 
-  octave_parser *curr_parser = new octave_parser ();
-  frame.add_fcn (octave_parser::cleanup, curr_parser);
+  octave_parser curr_parser;
 
   while (Vdebugging)
     {
@@ -681,31 +528,18 @@
 
       reset_error_handler ();
 
-      curr_parser->reset ();
-
-      // Save current value of global_command.
-      middle_frame.protect_var (global_command);
-
-      global_command = 0;
+      curr_parser.reset ();
 
       // Do this with an unwind-protect cleanup function so that the
       // forced variables will be unmarked in the event of an interrupt.
       symbol_table::scope_id scope = symbol_table::top_scope ();
       middle_frame.add_fcn (symbol_table::unmark_forced_variables, scope);
 
-      int retval = curr_parser->run ();
-
-      if (retval == 0 && global_command)
-        {
-          unwind_protect inner_frame;
+      int retval = curr_parser.run ();
 
-          // Use an unwind-protect cleanup function so that the
-          // global_command list will be deleted in the event of an
-          // interrupt.
-
-          inner_frame.add_fcn (cleanup_statement_list, &global_command);
-
-          global_command->accept (*current_evaluator);
+      if (retval == 0 && curr_parser.stmt_list)
+        {
+          curr_parser.stmt_list->accept (*current_evaluator);
 
           if (octave_completion_matches_called)
             octave_completion_matches_called = false;
@@ -715,6 +549,65 @@
     }
 }
 
+const std::string octave_base_reader::in_src ("invalid");
+
+const std::string octave_terminal_reader::in_src ("terminal");
+
+std::string
+octave_terminal_reader::get_input (bool& eof)
+{
+  octave_quit ();
+
+  eof = false;
+
+  std::string retval = octave_gets (eof);
+
+  current_input_line = retval;
+
+  return retval;
+}
+
+const std::string octave_file_reader::in_src ("file");
+
+std::string
+octave_file_reader::get_input (bool& eof)
+{
+  octave_quit ();
+
+  eof = false;
+
+  std::string retval = octave_fgets (file, eof);
+
+  current_input_line = retval;
+
+  return retval;
+}
+
+const std::string octave_eval_string_reader::in_src ("eval_string");
+
+std::string
+octave_eval_string_reader::get_input (bool& eof)
+{
+  octave_quit ();
+
+  eof = false;
+
+  std::string retval;
+
+  retval = eval_string;
+
+  // Clear the eval string so that the next call will return
+  // an empty character string with EOF = true.
+  eval_string = "";
+
+  if (retval.empty ())
+    eof = true;
+
+  current_input_line = retval;
+
+  return retval;
+}
+
 // If the user simply hits return, this will produce an empty matrix.
 
 static octave_value_list
@@ -744,13 +637,12 @@
 
   octave_diary << prompt;
 
-  std::string input_buf = interactive_input (prompt.c_str (), true);
+  bool eof = false;
+
+  std::string input_buf = interactive_input (prompt.c_str (), eof);
 
   if (! (error_state || input_buf.empty ()))
     {
-      if (! input_from_startup_file)
-        command_history::add (input_buf);
-
       size_t len = input_buf.length ();
 
       octave_diary << input_buf;
@@ -841,7 +733,9 @@
 
   while (1)
     {
-      std::string input_buf = interactive_input (prompt_string, true);
+      bool eof = false;
+
+      std::string input_buf = interactive_input (prompt_string, eof);
 
       if (input_buf == "yes")
         return true;
--- a/libinterp/interpfcn/input.h
+++ b/libinterp/interpfcn/input.h
@@ -35,44 +35,11 @@
 
 class octave_value;
 
-extern OCTINTERP_API std::string get_user_input (bool& eof);
-
-extern OCTINTERP_API FILE *get_input_from_file (const std::string& name,
-                                                int warn = 1);
-
 extern OCTINTERP_API FILE *get_input_from_stdin (void);
 
-// Global pointer for eval().
-extern std::string current_eval_string;
-
-// TRUE means get input from current_eval_string.
-extern bool get_input_from_eval_string;
-
-// TRUE means that input is coming from a file that was named on
-// the command line.
-extern bool input_from_command_line_file;
-
 // TRUE means that stdin is a terminal, not a pipe or redirected file.
 extern bool stdin_is_tty;
 
-// TRUE means we're parsing a function file.
-extern bool reading_fcn_file;
-
-// Simple name of function file we are reading.
-extern std::string curr_fcn_file_name;
-
-// Full name of file we are reading.
-extern std::string curr_fcn_file_full_name;
-
-// TRUE means we're parsing a script file.
-extern bool reading_script_file;
-
-// TRUE means we're parsing a classdef file.
-extern bool reading_classdef_file;
-
-// If we are reading from an M-file, this is it.
-extern FILE *ff_instream;
-
 // TRUE means this is an interactive shell.
 extern bool interactive;
 
@@ -95,8 +62,6 @@
 // TRUE if we are in debugging mode.
 extern OCTINTERP_API bool Vdebugging;
 
-extern std::string gnu_readline (const std::string& s, bool force_readline = false);
-
 extern void initialize_command_input (void);
 
 extern bool octave_yes_or_no (const std::string& prompt);
@@ -119,4 +84,139 @@
 
 extern octave_time Vlast_prompt_time;
 
+class
+octave_base_reader
+{
+public:
+
+  friend class octave_input_reader;
+
+  octave_base_reader (void) : count (1) { }
+
+  octave_base_reader (const octave_base_reader&) : count (1) { }
+
+  virtual ~octave_base_reader (void) { }
+
+  virtual std::string get_input (bool& eof) = 0;
+
+  virtual std::string input_source (void) const { return in_src; }
+
+  std::string octave_gets (bool& eof);
+
+private:
+
+  int count;
+
+  static const std::string in_src;
+};
+
+class
+octave_terminal_reader : public octave_base_reader
+{
+public:
+
+  octave_terminal_reader (void) : octave_base_reader () { }
+
+  std::string get_input (bool& eof);
+
+  std::string input_source (void) const { return in_src; }
+
+private:
+
+  static const std::string in_src;
+};
+
+class
+octave_file_reader : public octave_base_reader
+{
+public:
+
+  octave_file_reader (FILE *f_arg)
+    : octave_base_reader (), file (f_arg) { }
+
+  std::string get_input (bool& eof);
+
+  std::string input_source (void) const { return in_src; }
+
+private:
+
+  FILE *file;
+
+  static const std::string in_src;
+};
+
+class
+octave_eval_string_reader : public octave_base_reader
+{
+public:
+
+  octave_eval_string_reader (const std::string& str)
+    : octave_base_reader (), eval_string (str)
+  { }
+
+  std::string get_input (bool& eof);
+
+  std::string input_source (void) const { return in_src; }
+
+private:
+
+  std::string eval_string;
+
+  static const std::string in_src;
+};
+
+class
+octave_input_reader
+{
+public:
+  octave_input_reader (void)
+    : rep (new octave_terminal_reader ())
+  { }
+
+  octave_input_reader (FILE *file)
+    : rep (new octave_file_reader (file))
+  { }
+
+  octave_input_reader (const std::string& str)
+    : rep (new octave_eval_string_reader (str))
+  { }
+
+  octave_input_reader (const octave_input_reader& ir)
+  {
+    rep = ir.rep;
+    rep->count++;
+  }
+
+  octave_input_reader& operator = (const octave_input_reader& ir)
+  {
+    if (&ir != this)
+      {
+        rep = ir.rep;
+        rep->count++;
+      }
+
+    return *this;
+  }
+
+  ~octave_input_reader (void)
+  {
+    if (--rep->count == 0)
+      delete rep;
+  }
+
+  std::string get_input (bool& eof)
+  {
+    return rep->get_input (eof);
+  }
+
+  std::string input_source (void) const
+  {
+    return rep->input_source ();
+  }
+
+private:
+
+  octave_base_reader *rep;
+};
+
 #endif
--- a/libinterp/interpfcn/load-path.cc
+++ b/libinterp/interpfcn/load-path.cc
@@ -1956,10 +1956,6 @@
 
   unwind_protect frame;
 
-  frame.protect_var (input_from_startup_file);
-
-  input_from_startup_file = true;
-
   std::string file = file_ops::concat (dir, script_file);
 
   file_stat fs (file);
--- a/libinterp/interpfcn/oct-hist.cc
+++ b/libinterp/interpfcn/oct-hist.cc
@@ -299,6 +299,11 @@
 // appear in the history list.  This way you can do 'run_history' to
 // your heart's content.
 
+// FIXME: Don't delete this block of code until memory
+//        leak in edit_history has been plugged and
+//        it is clear that this code can be removed.
+//        See additional FIXME in do_edit_history.
+/*
 static void
 edit_history_repl_hist (const std::string& command)
 {
@@ -329,6 +334,7 @@
         }
     }
 }
+*/
 
 static void
 edit_history_add_hist (const std::string& line)
@@ -404,8 +410,14 @@
       if (get_int_arg (args(0), hist_beg)
           && get_int_arg (args(1), hist_end))
         {
-          hist_beg--;
-          hist_end--;
+          if (hist_beg < 0)
+            hist_beg += (hist_count + 1);
+          else
+            hist_beg--;
+          if (hist_end < 0)
+            hist_end += (hist_count + 1);
+          else
+            hist_end--;
         }
       else
         usage_error = true;
@@ -414,23 +426,25 @@
     {
       if (get_int_arg (args(0), hist_beg))
         {
-          hist_beg--;
+          if (hist_beg < 0)
+            hist_beg += (hist_count + 1);
+          else
+            hist_beg--;
           hist_end = hist_beg;
         }
       else
         usage_error = true;
     }
 
-  if (hist_beg < 0 || hist_end < 0 || hist_beg > hist_count
-      || hist_end > hist_count)
+  if (usage_error)
     {
-      error ("%s: history specification out of range", warn_for);
+      usage ("%s [first] [last]", warn_for);
       return retval;
     }
 
-  if (usage_error)
+  if (hist_beg > hist_count || hist_end > hist_count)
     {
-      usage ("%s [first] [last]", warn_for);
+      error ("%s: history specification out of range", warn_for);
       return retval;
     }
 
@@ -484,9 +498,7 @@
   // Call up our favorite editor on the file of commands.
 
   std::string cmd = VEDITOR;
-  cmd.append (" \"");
-  cmd.append (name);
-  cmd.append ("\"");
+  cmd.append (" \"" + name + "\"");
 
   // Ignore interrupts while we are off editing commands.  Should we
   // maybe avoid using system()?
@@ -512,7 +524,7 @@
   std::fstream file (name.c_str (), std::ios::in);
 
   char *line;
-  int first = 1;
+  //int first = 1;
   while ((line = edit_history_readline (file)) != 0)
     {
       // Skip blank lines.
@@ -523,8 +535,10 @@
           continue;
         }
 
-      // Command 'edit history' has already been removed in
-      // mk_tmp_hist_file ()
+      // FIXME: Don't delete this block of code until memory
+      //        leak in edit_history has been plugged and
+      //        it is clear that this code can be removed.
+      // Command 'edit history' has already been removed in mk_tmp_hist_file ()
       //if (first)
       //  {
       //    first = 0;
@@ -561,8 +575,7 @@
   if (name.empty ())
     return;
 
-  // Turn on command echo so the output from this will make better
-  // sense.
+  // Turn on command echo so the output from this will make better sense.
 
   unwind_protect frame;
 
@@ -598,38 +611,37 @@
 
 DEFUN (edit_history, args, ,
   "-*- texinfo -*-\n\
-@deftypefn {Command} {} edit_history [@var{first}] [@var{last}]\n\
-If invoked with no arguments, @code{edit_history} allows you to edit the\n\
-history list using the editor named by the variable @w{@env{EDITOR}}.  The\n\
-commands to be edited are first copied to a temporary file.  When you\n\
-exit the editor, Octave executes the commands that remain in the file.\n\
-It is often more convenient to use @code{edit_history} to define functions\n\
+@deftypefn  {Command} {} edit_history\n\
+@deftypefnx {Command} {} edit_history @var{cmd_number}\n\
+@deftypefnx {Command} {} edit_history @var{first} @var{last}\n\
+Edit the history list using the editor named by the variable\n\
+@w{@env{EDITOR}}.\n\
+\n\
+The commands to be edited are first copied to a temporary file.  When you\n\
+exit the editor, Octave executes the commands that remain in the file.  It\n\
+is often more convenient to use @code{edit_history} to define functions\n\
 rather than attempting to enter them directly on the command line.\n\
-By default, the block of commands is executed as soon as you exit the\n\
-editor.  To avoid executing any commands, simply delete all the lines\n\
-from the buffer before exiting the editor.\n\
+The block of commands is executed as soon as you exit the editor.\n\
+To avoid executing any commands, simply delete all the lines from the buffer\n\
+before leaving the editor.\n\
 \n\
-The @code{edit_history} command takes two optional arguments specifying\n\
-the history numbers of first and last commands to edit.  For example,\n\
-the command\n\
+When invoked with no arguments, edit the previously executed command;\n\
+With one argument, edit the specified command @var{cmd_number};\n\
+With two arguments, edit the list of commands between @var{first} and\n\
+@var{last}.  Command number specifiers may also be negative where -1\n\
+refers to the most recently executed command.\n\
+The following are equivalent and edit the most recently executed command.\n\
 \n\
 @example\n\
-edit_history 13\n\
+@group\n\
+edit_history\n\
+edit_history -1\n\
+@end group\n\
 @end example\n\
 \n\
-@noindent\n\
-extracts all the commands from the 13th through the last in the history\n\
-list.  The command\n\
-\n\
-@example\n\
-edit_history 13 169\n\
-@end example\n\
-\n\
-@noindent\n\
-only extracts commands 13 through 169.  Specifying a larger number for\n\
-the first command than the last command reverses the list of commands\n\
-before placing them in the buffer to be edited.  If both arguments are\n\
-omitted, the previous command in the history list is used.\n\
+When using ranges, specifying a larger number for the first command than the\n\
+last command reverses the list of commands before they are placed in the\n\
+buffer to be edited.\n\
 @seealso{run_history}\n\
 @end deftypefn")
 {
@@ -688,9 +700,52 @@
 
 DEFUN (run_history, args, ,
   "-*- texinfo -*-\n\
-@deftypefn {Command} {} run_history [@var{first}] [@var{last}]\n\
-Similar to @code{edit_history}, except that the editor is not invoked,\n\
-and the commands are simply executed as they appear in the history list.\n\
+@deftypefn  {Command} {} run_history\n\
+@deftypefnx {Command} {} run_history @var{cmd_number}\n\
+@deftypefnx {Command} {} run_history @var{first} @var{last}\n\
+Run commands from the history list.\n\
+\n\
+When invoked with no arguments, run the previously executed command;\n\
+With one argument, run the specified command @var{cmd_number};\n\
+With two arguments, run the list of commands between @var{first} and\n\
+@var{last}.  Command number specifiers may also be negative where -1\n\
+refers to the most recently executed command.\n\
+For example, the command\n\
+\n\
+@example\n\
+@group\n\
+run_history\n\
+     OR\n\
+run_history -1\n\
+@end group\n\
+@end example\n\
+\n\
+@noindent\n\
+executes the most recent command again.\n\
+The command\n\
+\n\
+@example\n\
+run_history 13 169\n\
+@end example\n\
+\n\
+@noindent\n\
+executes commands 13 through 169.\n\
+\n\
+Specifying a larger number for the first command than the last command\n\
+reverses the list of commands before executing them.\n\
+For example:\n\
+\n\
+@example\n\
+@group\n\
+disp (1)\n\
+disp (2)\n\
+run_history -1 -2\n\
+@result{}\n\
+ 2\n\
+ 1\n\
+@end group\n\
+@end example\n\
+\n\
 @seealso{edit_history}\n\
 @end deftypefn")
 {
--- a/libinterp/interpfcn/pr-output.cc
+++ b/libinterp/interpfcn/pr-output.cc
@@ -2724,14 +2724,17 @@
                 {
                   octave_quit ();
 
-                  double val = base + i * increment;
+                  double val;
+                  if (i == 0)
+                    val = base;
+                  else
+                    val = base + i * increment;
 
                   if (i == num_elem - 1)
                     {
                       // See the comments in Range::matrix_value.
-
-                      if ((increment > 0 && val > limit)
-                          || (increment < 0 && val < limit))
+                      if ((increment > 0 && val >= limit)
+                          || (increment < 0 && val <= limit))
                         val = limit;
                     }
 
--- a/libinterp/interpfcn/toplev.cc
+++ b/libinterp/interpfcn/toplev.cc
@@ -57,6 +57,7 @@
 #include "input.h"
 #include "lex.h"
 #include "oct-conf.h"
+#include "oct-conf-features.h"
 #include "oct-hist.h"
 #include "oct-map.h"
 #include "oct-obj.h"
@@ -98,9 +99,6 @@
 // TRUE means we've processed all the init code and we are good to go.
 bool octave_initialized = false;
 
-// Current command to execute.
-tree_statement_list *global_command = 0;
-
 octave_call_stack *octave_call_stack::instance = 0;
 
 void
@@ -564,8 +562,7 @@
   // octave_parser constructor sets this for us.
   frame.protect_var (CURR_LEXER);
 
-  octave_parser *curr_parser = new octave_parser ();
-  frame.add_fcn (octave_parser::cleanup, curr_parser);
+  octave_parser curr_parser;
 
   int retval = 0;
   do
@@ -576,7 +573,7 @@
 
           reset_error_handler ();
 
-          curr_parser->reset ();
+          curr_parser.reset ();
 
           if (symbol_table::at_top_level ())
             tree_evaluator::reset_debug_state ();
@@ -587,23 +584,13 @@
           symbol_table::scope_id scope = symbol_table::top_scope ();
           inner_frame.add_fcn (symbol_table::unmark_forced_variables, scope);
 
-          inner_frame.protect_var (global_command);
-
-          global_command = 0;
-
-          retval = curr_parser->run ();
+          retval = curr_parser.run ();
 
           if (retval == 0)
             {
-              if (global_command)
+              if (curr_parser.stmt_list)
                 {
-                  // Use an unwind-protect cleanup function so that the
-                  // global_command list will be deleted in the event of
-                  // an interrupt.
-
-                  frame.add_fcn (cleanup_statement_list, &global_command);
-
-                  global_command->accept (*current_evaluator);
+                  curr_parser.stmt_list->accept (*current_evaluator);
 
                   octave_quit ();
 
@@ -639,7 +626,7 @@
                         command_editor::increment_current_command_number ();
                     }
                 }
-              else if (curr_parser->end_of_input)
+              else if (curr_parser.curr_lexer->end_of_input)
                 break;
             }
         }
@@ -1373,7 +1360,6 @@
       { false, "SONAME_FLAGS", OCTAVE_CONF_SONAME_FLAGS },
       { false, "STATIC_LIBS", OCTAVE_CONF_STATIC_LIBS },
       { false, "TERM_LIBS", OCTAVE_CONF_TERM_LIBS },
-      { false, "UGLY_DEFS", OCTAVE_CONF_UGLY_DEFS },
       { false, "UMFPACK_CPPFLAGS", OCTAVE_CONF_UMFPACK_CPPFLAGS },
       { false, "UMFPACK_LDFLAGS", OCTAVE_CONF_UMFPACK_LDFLAGS },
       { false, "UMFPACK_LIBS", OCTAVE_CONF_UMFPACK_LIBS },
@@ -1442,6 +1428,8 @@
       m.assign ("words_little_endian",
                 octave_value (oct_mach_info::words_little_endian ()));
 
+      m.assign ("features", octave_value (octave_config_features ()));
+
       int i = 0;
 
       while (true)
--- a/libinterp/interpfcn/toplev.h
+++ b/libinterp/interpfcn/toplev.h
@@ -67,9 +67,6 @@
 extern OCTINTERP_API bool
 octave_remove_atexit_function (const std::string& fname);
 
-// Current command to execute.
-extern OCTINTERP_API tree_statement_list *global_command;
-
 // TRUE means we are ready to interpret commands, but not everything
 // is ready for interactive use.
 extern OCTINTERP_API bool octave_interpreter_ready;
--- a/libinterp/oct-conf.in.h
+++ b/libinterp/oct-conf.in.h
@@ -546,10 +546,6 @@
 #define OCTAVE_CONF_TERM_LIBS %OCTAVE_CONF_TERM_LIBS%
 #endif
 
-#ifndef OCTAVE_CONF_UGLY_DEFS
-#define OCTAVE_CONF_UGLY_DEFS %OCTAVE_CONF_UGLY_DEFS%
-#endif
-
 #ifndef OCTAVE_CONF_UMFPACK_CPPFLAGS
 #define OCTAVE_CONF_UMFPACK_CPPFLAGS %OCTAVE_CONF_UMFPACK_CPPFLAGS%
 #endif
--- a/libinterp/octave-value/ov-fcn-handle.cc
+++ b/libinterp/octave-value/ov-fcn-handle.cc
@@ -1304,7 +1304,8 @@
 %! hdld2 = hdld;
 %! hbi2 = hbi;
 %! modes = {"-text", "-binary"};
-%! if (!isempty (findstr (octave_config_info ("DEFS"), "HAVE_HDF5")))
+%! if (isfield (octave_config_info, "HAVE_HDF5")
+%!     && octave_config_info ("HAVE_HDF5"))
 %!   modes(end+1) = "-hdf5";
 %! endif
 %! for i = 1:numel (modes)
@@ -1356,7 +1357,8 @@
 %! hdld2 = hdld;
 %! hbi2 = hbi;
 %! modes = {"-text", "-binary"};
-%! if (!isempty (findstr (octave_config_info ("DEFS"), "HAVE_HDF5")))
+%! if (isfield (octave_config_info, "HAVE_HDF5")
+%!     && octave_config_info ("HAVE_HDF5"))
 %!   modes(end+1) = "-hdf5";
 %! endif
 %! for i = 1:numel (modes)
--- a/libinterp/octave.cc
+++ b/libinterp/octave.cc
@@ -356,10 +356,6 @@
 {
   unwind_protect frame;
 
-  frame.protect_var (input_from_startup_file);
-
-  input_from_startup_file = true;
-
   std::string context;
 
   bool verbose = (verbose_flag && ! inhibit_startup_message);
@@ -489,30 +485,18 @@
   octave_initialized = true;
 
   frame.protect_var (interactive);
-  frame.protect_var (reading_script_file);
-  frame.protect_var (input_from_command_line_file);
-
-  frame.protect_var (curr_fcn_file_name);
-  frame.protect_var (curr_fcn_file_full_name);
 
   frame.protect_var (octave_program_invocation_name);
   frame.protect_var (octave_program_name);
 
   interactive = false;
-  reading_script_file = true;
-  input_from_command_line_file = true;
 
-  curr_fcn_file_name = fname;
-  curr_fcn_file_full_name = curr_fcn_file_name;
+  octave_program_invocation_name = fname;
 
-  octave_program_invocation_name = curr_fcn_file_name;
-
-  size_t pos = curr_fcn_file_name.find_last_of (file_ops::dir_sep_chars ());
+  size_t pos = fname.find_last_of (file_ops::dir_sep_chars ());
 
-  std::string tmp = (pos != std::string::npos)
-    ? curr_fcn_file_name.substr (pos+1) : curr_fcn_file_name;
-
-  octave_program_name = tmp;
+  octave_program_name
+    = (pos != std::string::npos) ? fname.substr (pos+1) : fname;
 
   std::string context;
   bool verbose = false;
--- a/libinterp/parse-tree/lex.h
+++ b/libinterp/parse-tree/lex.h
@@ -27,6 +27,8 @@
 #include <set>
 #include <stack>
 
+#include "input.h"
+
 extern OCTINTERP_API void cleanup_parser (void);
 
 // Is the given string a keyword?
@@ -50,7 +52,7 @@
   stream_reader& operator = (const stream_reader&);
 };
 
-// Forward decl for lexical_feedback::token_stack.
+// Forward decl for octave_lexer::token_stack.
 class token;
 
 // For communication between the lexer and parser.
@@ -106,6 +108,12 @@
 
     ~bbp_nesting_level (void) { }
 
+    void reset (void)
+    {
+      while (! context.empty ())
+        context.pop ();
+    }
+
     void bracket (void) { context.push (BRACKET); }
 
     bool is_bracket (void)
@@ -151,9 +159,9 @@
 
     std::stack<int> context;
   };
-
+  
   lexical_feedback (void)
-    : scanner (0), convert_spaces_to_comma (true),
+    : end_of_input (false), convert_spaces_to_comma (true),
       do_comma_insert (false), at_beginning_of_statement (true),
       looking_at_anon_fcn_args (false), looking_at_return_list (false),
       looking_at_parameter_list (false), looking_at_decl_list (false),
@@ -162,13 +170,16 @@
       looking_for_object_index (false), 
       looking_at_indirect_ref (false), parsing_class_method (false),
       maybe_classdef_get_set_method (false), parsing_classdef (false),
-      quote_is_transpose (false),
+      quote_is_transpose (false), force_script (false),
+      reading_fcn_file (false), reading_script_file (false),
+      reading_classdef_file (false),
       input_line_number (1), current_input_column (1),
       bracketflag (0), braceflag (0),
       looping (0), defining_func (0), looking_at_function_handle (0),
-      block_comment_nesting_level (0),
+      block_comment_nesting_level (0), token_count (0),
+      help_text (), fcn_file_name (), fcn_file_full_name (),
       looking_at_object_index (), parsed_function_name (),
-      pending_local_variables (), nesting_level ()
+      pending_local_variables (), nesting_level (), token_stack ()
   {
     init ();
   }
@@ -179,13 +190,220 @@
 
   void reset (void);
 
-  void prep_for_script_file (void);
+  // true means that we have encountered eof on the input stream.
+  bool end_of_input;
+
+  // true means that we should convert spaces to a comma inside a
+  // matrix definition.
+  bool convert_spaces_to_comma;
+
+<<<<<<< local
+  void prep_for_classdef_file (void);
+=======
+  // gag.  stupid kludge so that [[1,2][3,4]] will work.
+  bool do_comma_insert;
+>>>>>>> other
+
+<<<<<<< local
+  int octave_read (char *buf, unsigned int max_size);
+=======
+  // true means we are at the beginning of a statement, where a
+  // command name is possible.
+  bool at_beginning_of_statement;
+
+  // true means we are parsing an anonymous function argument list.
+  bool looking_at_anon_fcn_args;
+
+  // true means we're parsing the return list for a function.
+  bool looking_at_return_list;
+
+  // true means we're parsing the parameter list for a function.
+  bool looking_at_parameter_list;
+
+  // true means we're parsing a declaration list (global or
+  // persistent).
+  bool looking_at_decl_list;
+
+  // true means we are looking at the initializer expression for a
+  // parameter list element.
+  bool looking_at_initializer_expression;
+
+  // true means we're parsing a matrix or the left hand side of
+  // multi-value assignment statement.
+  bool looking_at_matrix_or_assign_lhs;
+
+  // object index not possible until we've seen something.
+  bool looking_for_object_index;
+
+  // true means we're looking at an indirect reference to a
+  // structure element.
+  bool looking_at_indirect_ref;
+
+  // true means we are parsing a class method in function or classdef file.
+  bool parsing_class_method;
 
-  void prep_for_function_file (void);
+  // true means we are parsing a class method declaration line in a
+  // classdef file and can accept a property get or set method name.
+  // for example, "get.propertyname" is recognized as a function name.
+  bool maybe_classdef_get_set_method;
+
+  // true means we are parsing a classdef file
+  bool parsing_classdef;
+
+  // return transpose or start a string?
+  bool quote_is_transpose;
+
+  // TRUE means treat the current file as a script even if the first
+  // token is "function" or "classdef".
+  bool force_script;
+
+  // TRUE means we're parsing a function file.
+  bool reading_fcn_file;
+
+  // TRUE means we're parsing a script file.
+  bool reading_script_file;
+
+  // TRUE means we're parsing a classdef file.
+  bool reading_classdef_file;
+
+  // the current input line number.
+  int input_line_number;
+
+  // the column of the current token.
+  int current_input_column;
+
+  // square bracket level count.
+  int bracketflag;
+
+  // curly brace level count.
+  int braceflag;
+
+  // true means we're in the middle of defining a loop.
+  int looping;
+
+  // nonzero means we're in the middle of defining a function.
+  int defining_func;
+
+  // nonzero means we are parsing a function handle.
+  int looking_at_function_handle;
+
+  // nestng level for blcok comments.
+  int block_comment_nesting_level;
+
+  // Count of tokens recognized by this lexer since initialized or
+  // since the last reset.
+  size_t token_count;
+
+  // The current help text.
+  std::string help_text;
 
-  void prep_for_classdef_file (void);
+  // Simple name of function file we are reading.
+  std::string fcn_file_name;
+
+  // Full name of file we are reading.
+  std::string fcn_file_full_name;
+
+  // if the front of the list is true, the closest paren, brace, or
+  // bracket nesting is an index for an object.
+  std::list<bool> looking_at_object_index;
+
+  // if the top of the stack is true, then we've already seen the name
+  // of the current function.  should only matter if
+  // current_function_level > 0
+  std::stack<bool> parsed_function_name;
+
+  // set of identifiers that might be local variable names.
+  std::set<std::string> pending_local_variables;
+
+  // is the closest nesting level a square bracket, squiggly brace or
+  // a paren?
+  bbp_nesting_level nesting_level;
+
+  // Stack to hold tokens so that we can delete them when the parser is
+  // reset and avoid growing forever just because we are stashing some
+  // information.
+  std::stack <token*> token_stack;
+
+private:
+
+  void reset_token_stack (void);
+
+  // No copying!
+
+  lexical_feedback (const lexical_feedback&);
+
+  lexical_feedback& operator = (const lexical_feedback&);
+};
+
+// octave_lexer inherits from lexical_feedback because we will
+// eventually have several different constructors and it is easier to
+// intialize if everything is grouped in a parent class rather than
+// listing all the members in the octave_lexer class.
+
+class
+octave_lexer : public lexical_feedback
+{
+public:
+
+  // Handle buffering of input for lexer.
+
+  class input_buffer
+  {
+  public:
 
-  int octave_read (char *buf, unsigned int max_size);
+    input_buffer (void)
+      : buffer (), pos (0), chars_left (0), eof (false)
+    { }
+
+    void fill (const std::string& input, bool eof_arg);
+
+    // Copy at most max_size characters to buf.
+    int copy_chunk (char *buf, size_t max_size);
+
+    bool empty (void) const { return chars_left == 0; }
+
+    bool at_eof (void) const { return eof; }
+
+  private:
+
+    std::string buffer;
+    const char *pos;
+    size_t chars_left;
+    bool eof;
+  };
+
+  octave_lexer (void)
+    : lexical_feedback (), scanner (0), input_buf (), input_reader ()
+  {
+    init ();
+  }
+
+  octave_lexer (FILE *file)
+    : lexical_feedback (), scanner (0), input_buf (),
+      input_reader (file)
+  {
+    init ();
+  }
+
+  octave_lexer (const std::string& eval_string)
+    : lexical_feedback (), scanner (0), input_buf (),
+      input_reader (eval_string)
+  {
+    init ();
+  }
+
+  ~octave_lexer (void);
+
+  void init (void);
+
+  void reset (void);
+
+  void prep_for_file (void);
+
+  int read (char *buf, unsigned int max_size);
+
+  int handle_end_of_input (void);
+>>>>>>> other
 
   char *flex_yytext (void);
 
@@ -277,23 +495,27 @@
   // Internal state of the flex-generated lexer.
   void *scanner;
 
-  // TRUE means that we should convert spaces to a comma inside a
-  // matrix definition.
-  bool convert_spaces_to_comma;
+  // Object that reads and buffers input.
+  input_buffer input_buf;
+
+  octave_input_reader input_reader;
 
-  // GAG.  Stupid kludge so that [[1,2][3,4]] will work.
-  bool do_comma_insert;
+  std::string input_source (void) const
+  {
+    return input_reader.input_source ();
+  }
 
-  // TRUE means we are at the beginning of a statement, where a
-  // command name is possible.
-  bool at_beginning_of_statement;
+  bool input_from_terminal (void) const
+  {
+    return input_source () == "terminal";
+  }
 
-  // TRUE means we are parsing an anonymous function argument list.
-  bool looking_at_anon_fcn_args;
+  bool input_from_file (void) const
+  {
+    return input_source () == "file";
+  }
 
-  // TRUE means we're parsing the return list for a function.
-  bool looking_at_return_list;
-
+<<<<<<< local
   // TRUE means we're parsing the parameter list for a function.
   bool looking_at_parameter_list;
 
@@ -375,22 +597,23 @@
   // Is the closest nesting level a square bracket, squiggly brace or
   // a paren?
   bbp_nesting_level nesting_level;
+=======
+  bool input_from_eval_string (void) const
+  {
+    return input_source () == "eval_string";
+  }
+>>>>>>> other
 
   // For unwind protect.
-  static void cleanup (lexical_feedback *lexer) { delete lexer; }
+  static void cleanup (octave_lexer *lexer) { delete lexer; }
 
 private:
 
-  // Stack to hold tokens so that we can delete them when the parser is
-  // reset and avoid growing forever just because we are stashing some
-  // information.
-  std::stack <token*> token_stack;
-
   // No copying!
 
-  lexical_feedback (const lexical_feedback&);
+  octave_lexer (const octave_lexer&);
 
-  lexical_feedback& operator = (const lexical_feedback&);
+  octave_lexer& operator = (const octave_lexer&);
 };
 
 #endif
--- a/libinterp/parse-tree/lex.ll
+++ b/libinterp/parse-tree/lex.ll
@@ -46,9 +46,13 @@
 %s COMMAND_START
 %s MATRIX_START
 
+<<<<<<< local
 %x SCRIPT_FILE_BEGIN
 %x FUNCTION_FILE_BEGIN
 %x CLASSDEF_FILE_BEGIN
+=======
+%x INPUT_FILE_BEGIN
+>>>>>>> other
 
 %{
 
@@ -110,7 +114,7 @@
 #error lex.l requires flex version 2.5.4 or later
 #endif
 
-#define YY_EXTRA_TYPE lexical_feedback *
+#define YY_EXTRA_TYPE octave_lexer *
 #define curr_lexer yyextra
 
 // Arrange to get input via readline.
@@ -119,7 +123,7 @@
 #undef YY_INPUT
 #endif
 #define YY_INPUT(buf, result, max_size) \
-  result = curr_lexer->octave_read (buf, max_size)
+  result = curr_lexer->read (buf, max_size)
 
 // Try to avoid crashing out completely on fatal scanner errors.
 
@@ -148,7 +152,11 @@
 #define COUNT_TOK_AND_RETURN(tok) \
   do \
     { \
-      Vtoken_count++; \
+      if (tok != '\n') \
+        { \
+          Vtoken_count++; \
+          curr_lexer->token_count++; \
+        } \
       DISPLAY_TOK_AND_RETURN (tok); \
     } \
   while (0)
@@ -257,20 +265,17 @@
 // the parser go down a special path.
 %}
 
-<SCRIPT_FILE_BEGIN>. {
-    LEXER_DEBUG ("<SCRIPT_FILE_BEGIN>.");
+<INPUT_FILE_BEGIN>. {
+    LEXER_DEBUG ("<INPUT_FILE_BEGIN>.");
 
     BEGIN (INITIAL);
     curr_lexer->xunput (yytext[0]);
-    COUNT_TOK_AND_RETURN (SCRIPT_FILE);
-  }
-
-<FUNCTION_FILE_BEGIN>. {
-    LEXER_DEBUG ("<FUNCTION_FILE_BEGIN>.");
-
-    BEGIN (INITIAL);
-    curr_lexer->xunput (yytext[0]);
-    COUNT_TOK_AND_RETURN (FUNCTION_FILE);
+
+    // May be reset later if we see "function" or "classdef" appears
+    // as the first token.
+    curr_lexer->reading_script_file = true;
+
+    DISPLAY_TOK_AND_RETURN (INPUT_FILE);
   }
 
 <CLASSDEF_FILE_BEGIN>. {
@@ -362,7 +367,7 @@
     curr_lexer->at_beginning_of_statement = false;
 
     int c = yytext[yyleng-1];
-    bool cont_is_spc = (curr_lexer->eat_continuation () != lexical_feedback::NO_WHITESPACE);
+    bool cont_is_spc = (curr_lexer->eat_continuation () != octave_lexer::NO_WHITESPACE);
     bool spc_gobbled = (cont_is_spc || c == ' ' || c == '\t');
     int tok_to_return = curr_lexer->handle_close_bracket (spc_gobbled, ']');
 
@@ -388,7 +393,7 @@
     curr_lexer->at_beginning_of_statement = false;
 
     int c = yytext[yyleng-1];
-    bool cont_is_spc = (curr_lexer->eat_continuation () != lexical_feedback::NO_WHITESPACE);
+    bool cont_is_spc = (curr_lexer->eat_continuation () != octave_lexer::NO_WHITESPACE);
     bool spc_gobbled = (cont_is_spc || c == ' ' || c == '\t');
     int tok_to_return = curr_lexer->handle_close_bracket (spc_gobbled, '}');
 
@@ -418,7 +423,7 @@
 
     if (! curr_lexer->looking_at_object_index.front ())
       {
-        if ((tmp & lexical_feedback::NEWLINE) == lexical_feedback::NEWLINE)
+        if ((tmp & octave_lexer::NEWLINE) == octave_lexer::NEWLINE)
           {
             curr_lexer->maybe_warn_separator_insert (';');
 
@@ -455,7 +460,7 @@
             && curr_lexer->nesting_level.is_bracket_or_brace ()
             && curr_lexer->convert_spaces_to_comma)
           {
-            if ((tmp & lexical_feedback::NEWLINE) == lexical_feedback::NEWLINE)
+            if ((tmp & octave_lexer::NEWLINE) == octave_lexer::NEWLINE)
               {
                 curr_lexer->maybe_warn_separator_insert (';');
 
@@ -621,19 +626,7 @@
 %}
 
 <<EOF>> {
-    LEXER_DEBUG ("<<EOF>>");
-
-    if (curr_lexer->block_comment_nesting_level != 0)
-      {
-        warning ("block comment open at end of input");
-
-        if ((reading_fcn_file || reading_script_file || reading_classdef_file)
-            && ! curr_fcn_file_name.empty ())
-          warning ("near line %d of file '%s.m'",
-                   curr_lexer->input_line_number, curr_fcn_file_name.c_str ());
-      }
-
-    TOK_RETURN (END_OF_INPUT);
+   return curr_lexer->handle_end_of_input ();
   }
 
 %{
@@ -785,7 +778,7 @@
     int tok = curr_lexer->process_comment (false, eof);
 
     if (eof)
-      TOK_RETURN (END_OF_INPUT);
+      return curr_lexer->handle_end_of_input ();
     else if (tok > 0)
       COUNT_TOK_AND_RETURN (tok);
   }
@@ -984,7 +977,7 @@
         return LEXICAL_ERROR;
       }
     else
-      TOK_RETURN (END_OF_INPUT);
+      return curr_lexer->handle_end_of_input ();
   }
 
 %%
@@ -1293,7 +1286,7 @@
 flex_stream_reader : public stream_reader
 {
 public:
-  flex_stream_reader (lexical_feedback *l, char *buf_arg)
+  flex_stream_reader (octave_lexer *l, char *buf_arg)
     : stream_reader (), lexer (l), buf (buf_arg)
   { }
 
@@ -1308,13 +1301,75 @@
 
   flex_stream_reader& operator = (const flex_stream_reader&);
 
-  lexical_feedback *lexer;
+  octave_lexer *lexer;
 
   char *buf;
 };
 
 lexical_feedback::~lexical_feedback (void)
 {
+  reset_token_stack ();
+}
+
+void
+lexical_feedback::init (void)
+{
+  // The closest paren, brace, or bracket nesting is not an object
+  // index.
+  looking_at_object_index.push_front (false);
+}
+
+void
+lexical_feedback::reset (void)
+{
+  end_of_input = false;
+  convert_spaces_to_comma = true;
+  do_comma_insert = false;
+  at_beginning_of_statement = true;
+  looking_at_anon_fcn_args = false;
+  looking_at_return_list = false;
+  looking_at_parameter_list = false;
+  looking_at_decl_list = false;
+  looking_at_initializer_expression = false;
+  looking_at_matrix_or_assign_lhs = false;
+  looking_for_object_index = false; 
+  looking_at_indirect_ref = false;
+  parsing_class_method = false;
+  maybe_classdef_get_set_method = false;
+  parsing_classdef = false;
+  quote_is_transpose = false;
+  force_script = false;
+  reading_fcn_file = false;
+  reading_script_file = false;
+  reading_classdef_file = false;
+  input_line_number = 1;
+  current_input_column = 1;
+  bracketflag = 0;
+  braceflag = 0;
+  looping = 0;
+  defining_func = 0;
+  looking_at_function_handle = 0;
+  block_comment_nesting_level = 0;
+  token_count = 0;
+  help_text = "";
+  fcn_file_name = "";
+  fcn_file_full_name = "";
+  looking_at_object_index.clear ();
+  looking_at_object_index.push_front (false);
+
+  while (! parsed_function_name.empty ())
+    parsed_function_name.pop ();
+
+  pending_local_variables.clear ();
+
+  nesting_level.reset ();
+
+  reset_token_stack ();
+}
+
+void
+lexical_feedback::reset_token_stack (void)
+{
   // Clear out the stack of token info used to track line and
   // column numbers.
 
@@ -1323,27 +1378,70 @@
       delete token_stack.top ();
       token_stack.pop ();
     }
-
+}
+
+void
+octave_lexer::input_buffer::fill (const std::string& input, bool eof_arg)
+{
+  buffer = input;
+  chars_left = buffer.length ();
+  pos = buffer.c_str ();
+  eof = eof_arg;
+}
+
+int
+octave_lexer::input_buffer::copy_chunk (char *buf, size_t max_size)
+{
+  static const char * const eol = "\n";
+
+  size_t len = max_size > chars_left ? chars_left : max_size;
+  assert (len > 0);
+
+  memcpy (buf, pos, len);
+
+  chars_left -= len;
+  pos += len;
+
+  // Make sure input ends with a new line character.
+  if (chars_left == 0 && buf[len-1] != '\n')
+    {
+      if (len < max_size)
+        {
+          // There is enough room to plug the newline character in
+          // the buffer.
+          buf[len++] = '\n';
+        }
+      else
+        {
+          // There isn't enough room to plug the newline character
+          // in the buffer so arrange to have it returned on the next
+          // call to octave_lexer::read.
+          pos = eol;
+          chars_left = 1;
+        }
+    }
+
+  return len;
+}
+
+octave_lexer::~octave_lexer (void)
+{
   yylex_destroy (scanner);
 }
 
 void
-lexical_feedback::init (void)
+octave_lexer::init (void)
 {
-  // The closest paren, brace, or bracket nesting is not an object
-  // index.
-  looking_at_object_index.push_front (false);
-
   yylex_init (&scanner);
 
-  // Make lexical_feedback object available through yyextra in
+  // Make octave_lexer object available through yyextra in
   // flex-generated lexer.
   yyset_extra (this, scanner);
 }
 
 // Inside Flex-generated functions, yyg is the scanner cast to its real
 // type.  The BEGIN macro uses yyg and we want to use that in
-// lexical_feedback member functions.  If we could set the start state
+// octave_lexer member functions.  If we could set the start state
 // by calling a function instead of using the BEGIN macro, we could
 // eliminate the OCTAVE_YYG macro.
 
@@ -1351,7 +1449,7 @@
   struct yyguts_t *yyg = static_cast<struct yyguts_t*> (scanner)
 
 void
-lexical_feedback::reset (void)
+octave_lexer::reset (void)
 {
   OCTAVE_YYG;
 
@@ -1371,26 +1469,26 @@
       && ! (reading_fcn_file
             || reading_classdef_file
             || reading_script_file
-            || get_input_from_eval_string
-            || input_from_startup_file))
+            || input_from_eval_string ()))
     yyrestart (stdin, scanner);
 
-  // Clear the buffer for help text.
-  while (! help_buf.empty ())
-    help_buf.pop ();
+  lexical_feedback::reset ();
 }
 
 void
-lexical_feedback::prep_for_script_file (void)
+octave_lexer::prep_for_file (void)
 {
   OCTAVE_YYG;
 
-  BEGIN (SCRIPT_FILE_BEGIN);
+  reading_script_file = true;
+
+  BEGIN (INPUT_FILE_BEGIN);
 }
 
-void
-lexical_feedback::prep_for_function_file (void)
+int
+octave_lexer::read (char *buf, unsigned max_size)
 {
+<<<<<<< local
   OCTAVE_YYG;
 
   BEGIN (FUNCTION_FILE_BEGIN);
@@ -1413,69 +1511,60 @@
   static size_t chars_left = 0;
   static bool eof = false;
 
+=======
+>>>>>>> other
   int status = 0;
 
-  if (chars_left == 0)
-    {
-      pos = 0;
-
-      input_buf = get_user_input (eof);
-
-      chars_left = input_buf.length ();
-
-      pos = input_buf.c_str ();
-    }
-
-  if (chars_left > 0)
+  if (input_buf.empty ())
     {
-      size_t len = max_size > chars_left ? chars_left : max_size;
-      assert (len > 0);
-
-      memcpy (buf, pos, len);
-
-      chars_left -= len;
-      pos += len;
-
-      // Make sure input ends with a new line character.
-      if (chars_left == 0 && buf[len-1] != '\n')
-        {
-          if (len < max_size)
-            {
-              // There is enough room to plug the newline character in
-              // the buffer.
-              buf[len++] = '\n';
-            }
-          else
-            {
-              // There isn't enough room to plug the newline character
-              // in the buffer so make sure it is returned on the next
-              // octave_read call.
-              pos = eol;
-              chars_left = 1;
-            }
-        }
-
-      status = len;
+      bool eof = false;
+      std::string input = input_reader.get_input (eof);
+      input_buf.fill (input, eof);
     }
+
+  if (! input_buf.empty ())
+    status = input_buf.copy_chunk (buf, max_size);
   else
     {
       status = YY_NULL;
 
-      if (! eof)
-        fatal_error ("octave_read () in flex scanner failed");
+      if (! input_buf.at_eof ())
+        fatal_error ("octave_lexer::read () in flex scanner failed");
     }
 
   return status;
 }
 
+int
+octave_lexer::handle_end_of_input (void)
+{
+  // FIXME -- we need this because of the way TOK_RETURN is defined.  DO
+  // something better than that...
+  OCTAVE_YYG;
+
+  LEXER_DEBUG ("<<EOF>>");
+
+  if (block_comment_nesting_level != 0)
+    {
+      warning ("block comment open at end of input");
+
+      if ((reading_fcn_file || reading_script_file || reading_classdef_file)
+          && ! fcn_file_name.empty ())
+        warning ("near line %d of file '%s.m'",
+                 input_line_number, fcn_file_name.c_str ());
+    }
+
+  TOK_RETURN (END_OF_INPUT);
+}
+
 char *
-lexical_feedback::flex_yytext (void)
+octave_lexer::flex_yytext (void)
 {
   return yyget_text (scanner);
 }
 
 int
-lexical_feedback::flex_yyleng (void)
+octave_lexer::flex_yyleng (void)
 {
   return yyget_leng (scanner);
 }
@@ -1486,9 +1575,9 @@
 // that we insert a comma ahead of it.
 
 void
-lexical_feedback::do_comma_insert_check (void)
+octave_lexer::do_comma_insert_check (void)
 {
-  bool spc_gobbled = (eat_continuation () != lexical_feedback::NO_WHITESPACE);
+  bool spc_gobbled = (eat_continuation () != octave_lexer::NO_WHITESPACE);
 
   int c = text_yyinput ();
 
@@ -1502,7 +1591,7 @@
 }
 
 int
-lexical_feedback::text_yyinput (void)
+octave_lexer::text_yyinput (void)
 {
   int c = yyinput (scanner);
 
@@ -1540,23 +1629,26 @@
 }
 
 void
-lexical_feedback::xunput (char c, char *buf)
+octave_lexer::xunput (char c, char *buf)
 {
-  if (lexer_debug_flag)
+  if (c != EOF)
     {
-      std::cerr << "U: ";
-      display_character (c);
-      std::cerr << std::endl;
+      if (lexer_debug_flag)
+        {
+          std::cerr << "U: ";
+          display_character (c);
+          std::cerr << std::endl;
+        }
+
+      if (c == '\n')
+        input_line_number--;
+
+      yyunput (c, buf, scanner);
     }
-
-  if (c == '\n')
-    input_line_number--;
-
-  yyunput (c, buf, scanner);
 }
 
 void
-lexical_feedback::xunput (char c)
+octave_lexer::xunput (char c)
 {
   char *yytxt = flex_yytext ();
 
@@ -1567,7 +1659,7 @@
 // really looking at.
 
 void
-lexical_feedback::fixup_column_count (char *s)
+octave_lexer::fixup_column_count (char *s)
 {
   char c;
   while ((c = *s++) != '\0')
@@ -1583,7 +1675,7 @@
 }
 
 bool
-lexical_feedback::inside_any_object_index (void)
+octave_lexer::inside_any_object_index (void)
 {
   bool retval = false;
 
@@ -1603,7 +1695,7 @@
 // Handle keywords.  Return -1 if the keyword should be ignored.
 
 int
-lexical_feedback::is_keyword_token (const std::string& s)
+octave_lexer::is_keyword_token (const std::string& s)
 {
   int l = input_line_number;
   int c = current_input_column;
@@ -1631,11 +1723,11 @@
         case static_kw:
           if ((reading_fcn_file || reading_script_file
                || reading_classdef_file)
-              && ! curr_fcn_file_full_name.empty ())
+              && ! fcn_file_full_name.empty ())
             warning_with_id ("Octave:deprecated-keyword",
                              "the 'static' keyword is obsolete and will be removed from a future version of Octave; please use 'persistent' instead; near line %d of file '%s'",
                              input_line_number,
-                             curr_fcn_file_full_name.c_str ());
+                             fcn_file_full_name.c_str ());
           else
             warning_with_id ("Octave:deprecated-keyword",
                              "the 'static' keyword is obsolete and will be removed from a future version of Octave; please use 'persistent' instead; near line %d",
@@ -1774,6 +1866,12 @@
         case classdef_kw:
           // 'classdef' is always a keyword.
           promptflag--;
+
+          if (! force_script && token_count == 0 && input_from_file ())
+            {
+              reading_classdef_file = true;
+              reading_script_file = false;
+            }
           break;
 
         case function_kw:
@@ -1782,6 +1880,12 @@
           defining_func++;
           parsed_function_name.push (false);
 
+          if (! force_script && token_count == 0 && input_from_file ())
+            {
+              reading_fcn_file = true;
+              reading_script_file = false;
+            }
+
           if (! (reading_fcn_file || reading_script_file
                  || reading_classdef_file))
             input_line_number = 1;
@@ -1791,8 +1895,8 @@
           {
             if ((reading_fcn_file || reading_script_file
                  || reading_classdef_file)
-                && ! curr_fcn_file_full_name.empty ())
-              tok_val = new token (curr_fcn_file_full_name, l, c);
+                && ! fcn_file_full_name.empty ())
+              tok_val = new token (fcn_file_full_name, l, c);
             else
               tok_val = new token ("stdin", l, c);
           }
@@ -1818,7 +1922,7 @@
 }
 
 bool
-lexical_feedback::is_variable (const std::string& name)
+octave_lexer::is_variable (const std::string& name)
 {
   return (symbol_table::is_variable (name)
           || (pending_local_variables.find (name)
@@ -1826,7 +1930,7 @@
 }
 
 std::string
-lexical_feedback::grab_block_comment (stream_reader& reader, bool& eof)
+octave_lexer::grab_block_comment (stream_reader& reader, bool& eof)
 {
   std::string buf;
 
@@ -1932,8 +2036,8 @@
 }
 
 std::string
-lexical_feedback::grab_comment_block (stream_reader& reader, bool at_bol,
-                                      bool& eof)
+octave_lexer::grab_comment_block (stream_reader& reader, bool at_bol,
+                                  bool& eof)
 {
   std::string buf;
 
@@ -2071,18 +2175,28 @@
   return buf;
 }
 
+static bool
+looks_like_copyright (const std::string& s)
+{
+  bool retval = false;
+
+  if (! s.empty ())
+    {
+      size_t offset = s.find_first_not_of (" \t");
+
+      retval = (s.substr (offset, 9) == "Copyright" || s.substr (offset, 6) == "Author");
+    }
+
+  return retval;
+}
+
 int
-lexical_feedback::process_comment (bool start_in_block, bool& eof)
+octave_lexer::process_comment (bool start_in_block, bool& eof)
 {
   OCTAVE_YYG;
 
   eof = false;
 
-  std::string help_txt;
-
-  if (! help_buf.empty ())
-    help_txt = help_buf.top ();
-
   char *yytxt = flex_yytext ();
   flex_stream_reader flex_reader (this, yytxt);
 
@@ -2096,13 +2210,9 @@
   if (lexer_debug_flag)
     std::cerr << "C: " << txt << std::endl;
 
-  if (help_txt.empty () && nesting_level.none ())
-    {
-      if (! help_buf.empty ())
-        help_buf.pop ();
-
-      help_buf.push (txt);
-    }
+  if (nesting_level.none () && help_text.empty () && ! txt.empty ()
+      && ! looks_like_copyright (txt))
+    help_text = txt;
 
   octave_comment_buffer::append (txt);
 
@@ -2126,7 +2236,7 @@
 // replaced by a single LF.
 
 bool
-lexical_feedback::next_token_is_sep_op (void)
+octave_lexer::next_token_is_sep_op (void)
 {
   bool retval = false;
 
@@ -2143,7 +2253,7 @@
 // unary operator.  This is ugly, but it seems to do the right thing.
 
 bool
-lexical_feedback::next_token_is_postfix_unary_op (bool spc_prev)
+octave_lexer::next_token_is_postfix_unary_op (bool spc_prev)
 {
   bool un_op = false;
 
@@ -2190,7 +2300,7 @@
 // parsed as a binary operator.
 
 bool
-lexical_feedback::next_token_is_bin_op (bool spc_prev)
+octave_lexer::next_token_is_bin_op (bool spc_prev)
 {
   bool bin_op = false;
 
@@ -2291,7 +2401,7 @@
 // FIXME -- we need to handle block comments here.
 
 void
-lexical_feedback::scan_for_comments (const char *text)
+octave_lexer::scan_for_comments (const char *text)
 {
   std::string comment_buf;
 
@@ -2352,9 +2462,9 @@
 // FIXME -- we need to handle block comments here.
 
 int
-lexical_feedback::eat_whitespace (void)
+octave_lexer::eat_whitespace (void)
 {
-  int retval = lexical_feedback::NO_WHITESPACE;
+  int retval = octave_lexer::NO_WHITESPACE;
 
   std::string comment_buf;
 
@@ -2376,11 +2486,11 @@
               comment_buf += static_cast<char> (c);
               beginning_of_comment = false;
             }
-          retval |= lexical_feedback::SPACE_OR_TAB;
+          retval |= octave_lexer::SPACE_OR_TAB;
           break;
 
         case '\n':
-          retval |= lexical_feedback::NEWLINE;
+          retval |= octave_lexer::NEWLINE;
           if (in_comment)
             {
               comment_buf += static_cast<char> (c);
@@ -2465,7 +2575,7 @@
 }
 
 void
-lexical_feedback::handle_number (void)
+octave_lexer::handle_number (void)
 {
   double value = 0.0;
   int nread = 0;
@@ -2523,7 +2633,7 @@
 // FIXME -- we need to handle block comments here.
 
 bool
-lexical_feedback::have_continuation (bool trailing_comments_ok)
+octave_lexer::have_continuation (bool trailing_comments_ok)
 {
   std::ostringstream buf;
 
@@ -2611,7 +2721,7 @@
 // line character.
 
 bool
-lexical_feedback::have_ellipsis_continuation (bool trailing_comments_ok)
+octave_lexer::have_ellipsis_continuation (bool trailing_comments_ok)
 {
   char c1 = text_yyinput ();
   if (c1 == '.')
@@ -2635,9 +2745,9 @@
 // whitespace on the next line.
 
 int
-lexical_feedback::eat_continuation (void)
+octave_lexer::eat_continuation (void)
 {
-  int retval = lexical_feedback::NO_WHITESPACE;
+  int retval = octave_lexer::NO_WHITESPACE;
 
   int c = text_yyinput ();
 
@@ -2651,7 +2761,7 @@
 }
 
 int
-lexical_feedback::handle_string (char delim)
+octave_lexer::handle_string (char delim)
 {
   std::ostringstream buf;
 
@@ -2744,7 +2854,7 @@
 }
 
 bool
-lexical_feedback::next_token_is_assign_op (void)
+octave_lexer::next_token_is_assign_op (void)
 {
   bool retval = false;
 
@@ -2828,7 +2938,7 @@
 }
 
 bool
-lexical_feedback::next_token_is_index_op (void)
+octave_lexer::next_token_is_index_op (void)
 {
   int c = text_yyinput ();
   xunput (c);
@@ -2836,7 +2946,7 @@
 }
 
 int
-lexical_feedback::handle_close_bracket (bool spc_gobbled, int bracket_type)
+octave_lexer::handle_close_bracket (bool spc_gobbled, int bracket_type)
 {
   OCTAVE_YYG;
 
@@ -2904,7 +3014,7 @@
 }
 
 void
-lexical_feedback::maybe_unput_comma (int spc_gobbled)
+octave_lexer::maybe_unput_comma (int spc_gobbled)
 {
   if (nesting_level.is_bracket ()
       || (nesting_level.is_brace ()
@@ -2943,7 +3053,7 @@
 }
 
 bool
-lexical_feedback::next_token_can_follow_bin_op (void)
+octave_lexer::next_token_can_follow_bin_op (void)
 {
   std::stack<char> buf;
 
@@ -2985,7 +3095,7 @@
 }
 
 bool
-lexical_feedback::looks_like_command_arg (void)
+octave_lexer::looks_like_command_arg (void)
 {
   bool retval = true;
 
@@ -3207,7 +3317,7 @@
 }
 
 int
-lexical_feedback::handle_superclass_identifier (void)
+octave_lexer::handle_superclass_identifier (void)
 {
   char *yytxt = flex_yytext ();
   int c = yytxt[flex_yyleng()-1];
@@ -3249,7 +3359,7 @@
 }
 
 int
-lexical_feedback::handle_meta_identifier (void)
+octave_lexer::handle_meta_identifier (void)
 {
   char *yytxt = flex_yytext ();
   int c = yytxt[flex_yyleng()-1];
@@ -3290,7 +3400,7 @@
 // should be ignored.
 
 int
-lexical_feedback::handle_identifier (void)
+octave_lexer::handle_identifier (void)
 {
   OCTAVE_YYG;
 
@@ -3302,7 +3412,7 @@
 
   int c = yytxt[flex_yyleng()-1];
 
-  bool cont_is_spc = (eat_continuation () != lexical_feedback::NO_WHITESPACE);
+  bool cont_is_spc = (eat_continuation () != octave_lexer::NO_WHITESPACE);
 
   int spc_gobbled = (cont_is_spc || c == ' ' || c == '\t');
 
@@ -3459,9 +3569,9 @@
 }
 
 void
-lexical_feedback::maybe_warn_separator_insert (char sep)
+octave_lexer::maybe_warn_separator_insert (char sep)
 {
-  std::string nm = curr_fcn_file_full_name;
+  std::string nm = fcn_file_full_name;
 
   if (nm.empty ())
     warning_with_id ("Octave:separator-insert",
@@ -3474,9 +3584,9 @@
 }
 
 void
-lexical_feedback::gripe_single_quote_string (void)
+octave_lexer::gripe_single_quote_string (void)
 {
-  std::string nm = curr_fcn_file_full_name;
+  std::string nm = fcn_file_full_name;
 
   if (nm.empty ())
     warning_with_id ("Octave:single-quote-string",
@@ -3489,9 +3599,9 @@
 }
 
 void
-lexical_feedback::gripe_matlab_incompatible (const std::string& msg)
+octave_lexer::gripe_matlab_incompatible (const std::string& msg)
 {
-  std::string nm = curr_fcn_file_full_name;
+  std::string nm = fcn_file_full_name;
 
   if (nm.empty ())
     warning_with_id ("Octave:matlab-incompatible",
@@ -3504,20 +3614,20 @@
 }
 
 void
-lexical_feedback::maybe_gripe_matlab_incompatible_comment (char c)
+octave_lexer::maybe_gripe_matlab_incompatible_comment (char c)
 {
   if (c == '#')
     gripe_matlab_incompatible ("# used as comment character");
 }
 
 void
-lexical_feedback::gripe_matlab_incompatible_continuation (void)
+octave_lexer::gripe_matlab_incompatible_continuation (void)
 {
   gripe_matlab_incompatible ("\\ used as line continuation marker");
 }
 
 void
-lexical_feedback::gripe_matlab_incompatible_operator (const std::string& op)
+octave_lexer::gripe_matlab_incompatible_operator (const std::string& op)
 {
   std::string t = op;
   int n = t.length ();
@@ -3527,7 +3637,7 @@
 }
 
 void
-lexical_feedback::push_token (token *tok)
+octave_lexer::push_token (token *tok)
 {
   YYSTYPE *lval = yyget_lval (scanner);
   lval->tok_val = tok;
@@ -3535,14 +3645,14 @@
 }
 
 token *
-lexical_feedback::current_token (void)
+octave_lexer::current_token (void)
 {
   YYSTYPE *lval = yyget_lval (scanner);
   return lval->tok_val;
 }
 
 void
-lexical_feedback::display_token (int tok)
+octave_lexer::display_token (int tok)
 {
   switch (tok)
     {
@@ -3655,9 +3765,13 @@
     case LEXICAL_ERROR: std::cerr << "LEXICAL_ERROR\n\n"; break;
     case FCN: std::cerr << "FCN\n"; break;
     case CLOSE_BRACE: std::cerr << "CLOSE_BRACE\n"; break;
+<<<<<<< local
     case SCRIPT_FILE: std::cerr << "SCRIPT_FILE\n"; break;
     case FUNCTION_FILE: std::cerr << "FUNCTION_FILE\n"; break;
     case CLASSDEF_FILE: std::cerr << "CLASSDEF_FILE\n"; break;
+=======
+    case INPUT_FILE: std::cerr << "INPUT_FILE\n"; break;
+>>>>>>> other
     case SUPERCLASSREF: std::cerr << "SUPERCLASSREF\n"; break;
     case METAQUERY: std::cerr << "METAQUERY\n"; break;
     case GET: std::cerr << "GET\n"; break;
@@ -3671,7 +3785,7 @@
     case '\t': std::cerr << "TAB\n"; break;
     default:
       {
-        if (tok < 256)
+        if (tok < 256 && tok > 31)
           std::cerr << static_cast<char> (tok) << "\n";
         else
           std::cerr << "UNKNOWN(" << tok << ")\n";
@@ -3699,12 +3813,8 @@
       std::cerr << "MATRIX_START" << std::endl;
       break;
 
-    case SCRIPT_FILE_BEGIN:
-      std::cerr << "SCRIPT_FILE_BEGIN" << std::endl;
-      break;
-
-    case FUNCTION_FILE_BEGIN:
-      std::cerr << "FUNCTION_FILE_BEGIN" << std::endl;
+    case INPUT_FILE_BEGIN:
+      std::cerr << "INPUT_FILE_BEGIN" << std::endl;
       break;
 
     case CLASSDEF_FILE_BEGIN:
@@ -3718,7 +3828,7 @@
 }
 
 void
-lexical_feedback::fatal_error (const char *msg)
+octave_lexer::fatal_error (const char *msg)
 {
   error (msg);
 
@@ -3728,7 +3838,7 @@
 }
 
 void
-lexical_feedback::lexer_debug (const char *pattern, const char *text)
+octave_lexer::lexer_debug (const char *pattern, const char *text)
 {
   OCTAVE_YYG;
 
--- a/libinterp/parse-tree/module.mk
+++ b/libinterp/parse-tree/module.mk
@@ -96,6 +96,18 @@
 	mv $@-t $@
 	rm -f $@-t1
 
+parse-tree/oct-parse.yy: parse-tree/oct-parse.in.yy
+	case "$(BISON_PUSH_PULL_DECL_STYLE)" in \
+          *quote*) quote='"' ;; \
+	  *) quote="" ;; \
+        esac; \
+        case "$(BISON_PUSH_PULL_DECL_STYLE)" in \
+          *dash*) decl="%define api.push-pull $${quote}both$${quote}"; ;; \
+          *underscore*) decl="%define api.push_pull $${quote}both$${quote}"; ;; \
+        esac; \
+	$(SED) "s/%PUSH_PULL_DECL%/$$decl/" $< > $@-t
+	mv $@-t $@
+
 noinst_LTLIBRARIES += parse-tree/libparse-tree.la
 
 parse_tree_libparse_tree_la_SOURCES = $(PARSE_TREE_SRC)
rename from libinterp/parse-tree/oct-parse.yy
rename to libinterp/parse-tree/oct-parse.in.yy
--- a/libinterp/parse-tree/oct-parse.yy
+++ b/libinterp/parse-tree/oct-parse.in.yy
@@ -86,7 +86,7 @@
 
 // Global access to currently active lexer.
 // FIXME -- to be removed after more parser+lexer refactoring.
-lexical_feedback *CURR_LEXER = 0;
+octave_lexer *CURR_LEXER = 0;
 
 #if defined (GNULIB_NAMESPACE)
 // Calls to the following functions appear in the generated output from
@@ -97,9 +97,6 @@
 #define malloc GNULIB_NAMESPACE::malloc
 #endif
 
-// Buffer for help text snagged from function files.
-std::stack<std::string> help_buf;
-
 // TRUE means we are using readline.
 // (--no-line-editing)
 bool line_editing = true;
@@ -107,9 +104,6 @@
 // TRUE means we printed messages about reading startup files.
 bool reading_startup_message_printed = false;
 
-// TRUE means input is coming from startup file.
-bool input_from_startup_file = false;
-
 // Keep track of symbol table information when parsing functions.
 symtab_context parser_symtab_context;
 
@@ -119,7 +113,7 @@
 // Forward declarations for some functions defined at the bottom of
 // the file.
 
-static void yyerror (octave_parser *curr_parser, const char *s);
+static void yyerror (octave_parser& curr_parser, const char *s);
 
 // Finish building a statement.
 template <class T>
@@ -134,19 +128,18 @@
 #define ABORT_PARSE \
   do \
     { \
-      global_command = 0; \
       yyerrok; \
       if (! parser_symtab_context.empty ()) \
         parser_symtab_context.pop (); \
       if ((interactive || forced_interactive)   \
-          && ! get_input_from_eval_string)      \
+          && ! (curr_lexer)->input_from_eval_string ()) \
         YYACCEPT; \
       else \
         YYABORT; \
     } \
   while (0)
 
-#define curr_lexer curr_parser->curr_lexer
+#define curr_lexer curr_parser.curr_lexer
 #define scanner curr_lexer->scanner
 
 %}
@@ -168,7 +161,8 @@
 // object) relevant global values before and after the nested call.
 
 %define api.pure
-%parse-param { octave_parser *curr_parser }
+%PUSH_PULL_DECL%
+%parse-param { octave_parser& curr_parser }
 %lex-param { void *scanner }
 
 %union
@@ -261,14 +255,24 @@
 
 // Other tokens.
 %token END_OF_INPUT LEXICAL_ERROR
+<<<<<<< local
 %token FCN SCRIPT_FILE CLASSDEF_FILE FUNCTION_FILE
+=======
+%token FCN INPUT_FILE CLASSDEF
+>>>>>>> other
 // %token VARARGIN VARARGOUT
 %token CLOSE_BRACE
 
 // Nonterminals we construct.
+<<<<<<< local
 %type <comment_type> stash_comment function_beg
 %type <tok_type> classdef_beg
 %type <sep_type> sep_no_nl opt_sep_no_nl sep opt_sep opt_comma
+=======
+%type <comment_type> stash_comment function_beg classdef_beg
+%type <comment_type> properties_beg methods_beg events_beg enum_beg
+%type <sep_type> sep_no_nl opt_sep_no_nl nl opt_nl sep opt_sep opt_comma
+>>>>>>> other
 %type <tree_type> input
 %type <tree_constant_type> string constant magic_colon
 %type <tree_anon_fcn_handle_type> anon_fcn_handle
@@ -288,11 +292,16 @@
 %type <tree_parameter_list_type> param_list param_list1 param_list2
 %type <tree_parameter_list_type> return_list return_list1
 %type <tree_command_type> command select_command loop_command
+<<<<<<< local
 %type <tree_command_type> jump_command except_command
 %type <tree_function_def_type> function
 %type <tree_classdef_type> classdef
 %type <tree_command_type> script_file classdef_file
 %type <tree_command_type> function_file function_list
+=======
+%type <tree_command_type> jump_command except_command function
+%type <tree_command_type> file classdef
+>>>>>>> other
 %type <tree_if_command_type> if_command
 %type <tree_if_clause_type> elseif_clause else_clause
 %type <tree_if_command_list_type> if_cmd_list1 if_cmd_list
@@ -350,14 +359,17 @@
 
 input           : input1
                   {
-                    global_command = $1;
+                    curr_parser.stmt_list = $1;
                     promptflag = 1;
                     YYACCEPT;
                   }
+<<<<<<< local
                 | function_file
                   { YYACCEPT; }
                 | classdef_file
                   { YYACCEPT; }
+=======
+>>>>>>> other
                 | simple_list parse_error
                   { ABORT_PARSE; }
                 | parse_error
@@ -368,7 +380,7 @@
                   { $$ = 0; }
                 | END_OF_INPUT
                   {
-                    curr_parser->end_of_input = true;
+                    curr_lexer->end_of_input = true;
                     $$ = 0;
                   }
                 | simple_list
@@ -380,13 +392,13 @@
                 ;
 
 simple_list     : simple_list1 opt_sep_no_nl
-                  { $$ = curr_parser->set_stmt_print_flag ($1, $2, false); }
+                  { $$ = curr_parser.set_stmt_print_flag ($1, $2, false); }
                 ;
 
 simple_list1    : statement
-                  { $$ = curr_parser->make_statement_list ($1); }
+                  { $$ = curr_parser.make_statement_list ($1); }
                 | simple_list1 sep_no_nl statement
-                  { $$ = curr_parser->append_statement_list ($1, $2, $3, false); }
+                  { $$ = curr_parser.append_statement_list ($1, $2, $3, false); }
                 ;
 
 opt_list        : // empty
@@ -396,13 +408,13 @@
                 ;
 
 list            : list1 opt_sep
-                  { $$ = curr_parser->set_stmt_print_flag ($1, $2, true); }
+                  { $$ = curr_parser.set_stmt_print_flag ($1, $2, true); }
                 ;
 
 list1           : statement
-                  { $$ = curr_parser->make_statement_list ($1); }
+                  { $$ = curr_parser.make_statement_list ($1); }
                 | list1 sep statement
-                  { $$ = curr_parser->append_statement_list ($1, $2, $3, true); }
+                  { $$ = curr_parser.append_statement_list ($1, $2, $3, true); }
                 ;
 
 statement       : expression
@@ -422,7 +434,7 @@
 // WHILE, etc.
 
 word_list_cmd   : identifier word_list
-                  { $$ = curr_parser->make_index_expression ($1, $2, '('); }
+                  { $$ = curr_parser.make_index_expression ($1, $2, '('); }
                 ;
 
 word_list       : string
@@ -470,15 +482,15 @@
                 ;
 
 string          : DQ_STRING
-                  { $$ = curr_parser->make_constant (DQ_STRING, $1); }
+                  { $$ = curr_parser.make_constant (DQ_STRING, $1); }
                 | SQ_STRING
-                  { $$ = curr_parser->make_constant (SQ_STRING, $1); }
+                  { $$ = curr_parser.make_constant (SQ_STRING, $1); }
                 ;
 
 constant        : NUM
-                  { $$ = curr_parser->make_constant (NUM, $1); }
+                  { $$ = curr_parser.make_constant (NUM, $1); }
                 | IMAG_NUM
-                  { $$ = curr_parser->make_constant (IMAG_NUM, $1); }
+                  { $$ = curr_parser.make_constant (IMAG_NUM, $1); }
                 | string
                   { $$ = $1; }
                 ;
@@ -503,7 +515,7 @@
                   }
                 | '[' matrix_rows ']'
                   {
-                    $$ = curr_parser->finish_matrix ($2);
+                    $$ = curr_parser.finish_matrix ($2);
                     curr_lexer->looking_at_matrix_or_assign_lhs = false;
                     curr_lexer->pending_local_variables.clear ();
                   }
@@ -529,7 +541,7 @@
                 | '{' ';' '}'
                   { $$ = new tree_constant (octave_value (Cell ())); }
                 | '{' cell_rows '}'
-                  { $$ = curr_parser->finish_cell ($2); }
+                  { $$ = curr_parser.finish_cell ($2); }
                 ;
 
 cell_rows       : cell_rows1
@@ -549,14 +561,14 @@
 
 cell_or_matrix_row
                 : arg_list
-                  { $$ = curr_parser->validate_matrix_row ($1); }
+                  { $$ = curr_parser.validate_matrix_row ($1); }
                 | arg_list ','  // Ignore trailing comma.
-                  { $$ = curr_parser->validate_matrix_row ($1); }
+                  { $$ = curr_parser.validate_matrix_row ($1); }
                 ;
 
 fcn_handle      : '@' FCN_HANDLE
                   {
-                    $$ = curr_parser->make_fcn_handle ($2);
+                    $$ = curr_parser.make_fcn_handle ($2);
                     curr_lexer->looking_at_function_handle--;
                   }
                 ;
@@ -564,7 +576,7 @@
 anon_fcn_handle : '@' param_list statement
                   {
                     curr_lexer->quote_is_transpose = false;
-                    $$ = curr_parser->make_anon_fcn_handle ($2, $3);
+                    $$ = curr_parser.make_anon_fcn_handle ($2, $3);
                   }
                 ;
 
@@ -629,63 +641,63 @@
 oper_expr       : primary_expr
                   { $$ = $1; }
                 | oper_expr PLUS_PLUS
-                  { $$ = curr_parser->make_postfix_op (PLUS_PLUS, $1, $2); }
+                  { $$ = curr_parser.make_postfix_op (PLUS_PLUS, $1, $2); }
                 | oper_expr MINUS_MINUS
-                  { $$ = curr_parser->make_postfix_op (MINUS_MINUS, $1, $2); }
+                  { $$ = curr_parser.make_postfix_op (MINUS_MINUS, $1, $2); }
                 | oper_expr '(' ')'
-                  { $$ = curr_parser->make_index_expression ($1, 0, '('); }
+                  { $$ = curr_parser.make_index_expression ($1, 0, '('); }
                 | oper_expr '(' arg_list ')'
-                  { $$ = curr_parser->make_index_expression ($1, $3, '('); }
+                  { $$ = curr_parser.make_index_expression ($1, $3, '('); }
                 | oper_expr '{' '}'
-                  { $$ = curr_parser->make_index_expression ($1, 0, '{'); }
+                  { $$ = curr_parser.make_index_expression ($1, 0, '{'); }
                 | oper_expr '{' arg_list '}'
-                  { $$ = curr_parser->make_index_expression ($1, $3, '{'); }
+                  { $$ = curr_parser.make_index_expression ($1, $3, '{'); }
                 | oper_expr QUOTE
-                  { $$ = curr_parser->make_postfix_op (QUOTE, $1, $2); }
+                  { $$ = curr_parser.make_postfix_op (QUOTE, $1, $2); }
                 | oper_expr TRANSPOSE
-                  { $$ = curr_parser->make_postfix_op (TRANSPOSE, $1, $2); }
+                  { $$ = curr_parser.make_postfix_op (TRANSPOSE, $1, $2); }
                 | oper_expr indirect_ref_op STRUCT_ELT
-                  { $$ = curr_parser->make_indirect_ref ($1, $3->text ()); }
+                  { $$ = curr_parser.make_indirect_ref ($1, $3->text ()); }
                 | oper_expr indirect_ref_op '(' expression ')'
-                  { $$ = curr_parser->make_indirect_ref ($1, $4); }
+                  { $$ = curr_parser.make_indirect_ref ($1, $4); }
                 | PLUS_PLUS oper_expr %prec UNARY
-                  { $$ = curr_parser->make_prefix_op (PLUS_PLUS, $2, $1); }
+                  { $$ = curr_parser.make_prefix_op (PLUS_PLUS, $2, $1); }
                 | MINUS_MINUS oper_expr %prec UNARY
-                  { $$ = curr_parser->make_prefix_op (MINUS_MINUS, $2, $1); }
+                  { $$ = curr_parser.make_prefix_op (MINUS_MINUS, $2, $1); }
                 | EXPR_NOT oper_expr %prec UNARY
-                  { $$ = curr_parser->make_prefix_op (EXPR_NOT, $2, $1); }
+                  { $$ = curr_parser.make_prefix_op (EXPR_NOT, $2, $1); }
                 | '+' oper_expr %prec UNARY
-                  { $$ = curr_parser->make_prefix_op ('+', $2, $1); }
+                  { $$ = curr_parser.make_prefix_op ('+', $2, $1); }
                 | '-' oper_expr %prec UNARY
-                  { $$ = curr_parser->make_prefix_op ('-', $2, $1); }
+                  { $$ = curr_parser.make_prefix_op ('-', $2, $1); }
                 | oper_expr POW oper_expr
-                  { $$ = curr_parser->make_binary_op (POW, $1, $2, $3); }
+                  { $$ = curr_parser.make_binary_op (POW, $1, $2, $3); }
                 | oper_expr EPOW oper_expr
-                  { $$ = curr_parser->make_binary_op (EPOW, $1, $2, $3); }
+                  { $$ = curr_parser.make_binary_op (EPOW, $1, $2, $3); }
                 | oper_expr '+' oper_expr
-                  { $$ = curr_parser->make_binary_op ('+', $1, $2, $3); }
+                  { $$ = curr_parser.make_binary_op ('+', $1, $2, $3); }
                 | oper_expr '-' oper_expr
-                  { $$ = curr_parser->make_binary_op ('-', $1, $2, $3); }
+                  { $$ = curr_parser.make_binary_op ('-', $1, $2, $3); }
                 | oper_expr '*' oper_expr
-                  { $$ = curr_parser->make_binary_op ('*', $1, $2, $3); }
+                  { $$ = curr_parser.make_binary_op ('*', $1, $2, $3); }
                 | oper_expr '/' oper_expr
-                  { $$ = curr_parser->make_binary_op ('/', $1, $2, $3); }
+                  { $$ = curr_parser.make_binary_op ('/', $1, $2, $3); }
                 | oper_expr EPLUS oper_expr
-                  { $$ = curr_parser->make_binary_op ('+', $1, $2, $3); }
+                  { $$ = curr_parser.make_binary_op ('+', $1, $2, $3); }
                 | oper_expr EMINUS oper_expr
-                  { $$ = curr_parser->make_binary_op ('-', $1, $2, $3); }
+                  { $$ = curr_parser.make_binary_op ('-', $1, $2, $3); }
                 | oper_expr EMUL oper_expr
-                  { $$ = curr_parser->make_binary_op (EMUL, $1, $2, $3); }
+                  { $$ = curr_parser.make_binary_op (EMUL, $1, $2, $3); }
                 | oper_expr EDIV oper_expr
-                  { $$ = curr_parser->make_binary_op (EDIV, $1, $2, $3); }
+                  { $$ = curr_parser.make_binary_op (EDIV, $1, $2, $3); }
                 | oper_expr LEFTDIV oper_expr
-                  { $$ = curr_parser->make_binary_op (LEFTDIV, $1, $2, $3); }
+                  { $$ = curr_parser.make_binary_op (LEFTDIV, $1, $2, $3); }
                 | oper_expr ELEFTDIV oper_expr
-                  { $$ = curr_parser->make_binary_op (ELEFTDIV, $1, $2, $3); }
+                  { $$ = curr_parser.make_binary_op (ELEFTDIV, $1, $2, $3); }
                 ;
 
 colon_expr      : colon_expr1
-                  { $$ = curr_parser->finish_colon_expression ($1); }
+                  { $$ = curr_parser.finish_colon_expression ($1); }
                 ;
 
 colon_expr1     : oper_expr
@@ -700,29 +712,29 @@
 simple_expr     : colon_expr
                   { $$ = $1; }
                 | simple_expr LSHIFT simple_expr
-                  { $$ = curr_parser->make_binary_op (LSHIFT, $1, $2, $3); }
+                  { $$ = curr_parser.make_binary_op (LSHIFT, $1, $2, $3); }
                 | simple_expr RSHIFT simple_expr
-                  { $$ = curr_parser->make_binary_op (RSHIFT, $1, $2, $3); }
+                  { $$ = curr_parser.make_binary_op (RSHIFT, $1, $2, $3); }
                 | simple_expr EXPR_LT simple_expr
-                  { $$ = curr_parser->make_binary_op (EXPR_LT, $1, $2, $3); }
+                  { $$ = curr_parser.make_binary_op (EXPR_LT, $1, $2, $3); }
                 | simple_expr EXPR_LE simple_expr
-                  { $$ = curr_parser->make_binary_op (EXPR_LE, $1, $2, $3); }
+                  { $$ = curr_parser.make_binary_op (EXPR_LE, $1, $2, $3); }
                 | simple_expr EXPR_EQ simple_expr
-                  { $$ = curr_parser->make_binary_op (EXPR_EQ, $1, $2, $3); }
+                  { $$ = curr_parser.make_binary_op (EXPR_EQ, $1, $2, $3); }
                 | simple_expr EXPR_GE simple_expr
-                  { $$ = curr_parser->make_binary_op (EXPR_GE, $1, $2, $3); }
+                  { $$ = curr_parser.make_binary_op (EXPR_GE, $1, $2, $3); }
                 | simple_expr EXPR_GT simple_expr
-                  { $$ = curr_parser->make_binary_op (EXPR_GT, $1, $2, $3); }
+                  { $$ = curr_parser.make_binary_op (EXPR_GT, $1, $2, $3); }
                 | simple_expr EXPR_NE simple_expr
-                  { $$ = curr_parser->make_binary_op (EXPR_NE, $1, $2, $3); }
+                  { $$ = curr_parser.make_binary_op (EXPR_NE, $1, $2, $3); }
                 | simple_expr EXPR_AND simple_expr
-                  { $$ = curr_parser->make_binary_op (EXPR_AND, $1, $2, $3); }
+                  { $$ = curr_parser.make_binary_op (EXPR_AND, $1, $2, $3); }
                 | simple_expr EXPR_OR simple_expr
-                  { $$ = curr_parser->make_binary_op (EXPR_OR, $1, $2, $3); }
+                  { $$ = curr_parser.make_binary_op (EXPR_OR, $1, $2, $3); }
                 | simple_expr EXPR_AND_AND simple_expr
-                  { $$ = curr_parser->make_boolean_op (EXPR_AND_AND, $1, $2, $3); }
+                  { $$ = curr_parser.make_boolean_op (EXPR_AND_AND, $1, $2, $3); }
                 | simple_expr EXPR_OR_OR simple_expr
-                  { $$ = curr_parser->make_boolean_op (EXPR_OR_OR, $1, $2, $3); }
+                  { $$ = curr_parser.make_boolean_op (EXPR_OR_OR, $1, $2, $3); }
                 ;
 
 // Arrange for the lexer to return CLOSE_BRACE for ']' by looking ahead
@@ -748,35 +760,35 @@
                 ;
 
 assign_expr     : assign_lhs '=' expression
-                  { $$ = curr_parser->make_assign_op ('=', $1, $2, $3); }
+                  { $$ = curr_parser.make_assign_op ('=', $1, $2, $3); }
                 | assign_lhs ADD_EQ expression
-                  { $$ = curr_parser->make_assign_op (ADD_EQ, $1, $2, $3); }
+                  { $$ = curr_parser.make_assign_op (ADD_EQ, $1, $2, $3); }
                 | assign_lhs SUB_EQ expression
-                  { $$ = curr_parser->make_assign_op (SUB_EQ, $1, $2, $3); }
+                  { $$ = curr_parser.make_assign_op (SUB_EQ, $1, $2, $3); }
                 | assign_lhs MUL_EQ expression
-                  { $$ = curr_parser->make_assign_op (MUL_EQ, $1, $2, $3); }
+                  { $$ = curr_parser.make_assign_op (MUL_EQ, $1, $2, $3); }
                 | assign_lhs DIV_EQ expression
-                  { $$ = curr_parser->make_assign_op (DIV_EQ, $1, $2, $3); }
+                  { $$ = curr_parser.make_assign_op (DIV_EQ, $1, $2, $3); }
                 | assign_lhs LEFTDIV_EQ expression
-                  { $$ = curr_parser->make_assign_op (LEFTDIV_EQ, $1, $2, $3); }
+                  { $$ = curr_parser.make_assign_op (LEFTDIV_EQ, $1, $2, $3); }
                 | assign_lhs POW_EQ expression
-                  { $$ = curr_parser->make_assign_op (POW_EQ, $1, $2, $3); }
+                  { $$ = curr_parser.make_assign_op (POW_EQ, $1, $2, $3); }
                 | assign_lhs LSHIFT_EQ expression
-                  { $$ = curr_parser->make_assign_op (LSHIFT_EQ, $1, $2, $3); }
+                  { $$ = curr_parser.make_assign_op (LSHIFT_EQ, $1, $2, $3); }
                 | assign_lhs RSHIFT_EQ expression
-                  { $$ = curr_parser->make_assign_op (RSHIFT_EQ, $1, $2, $3); }
+                  { $$ = curr_parser.make_assign_op (RSHIFT_EQ, $1, $2, $3); }
                 | assign_lhs EMUL_EQ expression
-                  { $$ = curr_parser->make_assign_op (EMUL_EQ, $1, $2, $3); }
+                  { $$ = curr_parser.make_assign_op (EMUL_EQ, $1, $2, $3); }
                 | assign_lhs EDIV_EQ expression
-                  { $$ = curr_parser->make_assign_op (EDIV_EQ, $1, $2, $3); }
+                  { $$ = curr_parser.make_assign_op (EDIV_EQ, $1, $2, $3); }
                 | assign_lhs ELEFTDIV_EQ expression
-                  { $$ = curr_parser->make_assign_op (ELEFTDIV_EQ, $1, $2, $3); }
+                  { $$ = curr_parser.make_assign_op (ELEFTDIV_EQ, $1, $2, $3); }
                 | assign_lhs EPOW_EQ expression
-                  { $$ = curr_parser->make_assign_op (EPOW_EQ, $1, $2, $3); }
+                  { $$ = curr_parser.make_assign_op (EPOW_EQ, $1, $2, $3); }
                 | assign_lhs AND_EQ expression
-                  { $$ = curr_parser->make_assign_op (AND_EQ, $1, $2, $3); }
+                  { $$ = curr_parser.make_assign_op (AND_EQ, $1, $2, $3); }
                 | assign_lhs OR_EQ expression
-                  { $$ = curr_parser->make_assign_op (OR_EQ, $1, $2, $3); }
+                  { $$ = curr_parser.make_assign_op (OR_EQ, $1, $2, $3); }
                 ;
 
 expression      : simple_expr
@@ -803,7 +815,7 @@
                   { $$ = $1; }
                 | function
                   { $$ = $1; }
-                | script_file
+                | file
                   { $$ = $1; }
                 ;
 
@@ -817,12 +829,12 @@
 
 declaration     : GLOBAL parsing_decl_list decl1
                   {
-                    $$ = curr_parser->make_decl_command (GLOBAL, $1, $3);
+                    $$ = curr_parser.make_decl_command (GLOBAL, $1, $3);
                     curr_lexer->looking_at_decl_list = false;
                   }
                 | PERSISTENT parsing_decl_list decl1
                   {
-                    $$ = curr_parser->make_decl_command (PERSISTENT, $1, $3);
+                    $$ = curr_parser.make_decl_command (PERSISTENT, $1, $3);
                     curr_lexer->looking_at_decl_list = false;
                   }
                 ;
@@ -868,7 +880,7 @@
 
 if_command      : IF stash_comment if_cmd_list END
                   {
-                    if (! ($$ = curr_parser->finish_if_command ($1, $3, $4, $2)))
+                    if (! ($$ = curr_parser.finish_if_command ($1, $3, $4, $2)))
                       ABORT_PARSE;
                   }
                 ;
@@ -884,9 +896,9 @@
 
 if_cmd_list1    : expression opt_sep opt_list
                   {
-                    $1->mark_braindead_shortcircuit (curr_fcn_file_full_name);
-
-                    $$ = curr_parser->start_if_command ($1, $3);
+                    $1->mark_braindead_shortcircuit (curr_lexer->fcn_file_full_name);
+
+                    $$ = curr_parser.start_if_command ($1, $3);
                   }
                 | if_cmd_list1 elseif_clause
                   {
@@ -897,9 +909,9 @@
 
 elseif_clause   : ELSEIF stash_comment opt_sep expression opt_sep opt_list
                   {
-                    $4->mark_braindead_shortcircuit (curr_fcn_file_full_name);
-
-                    $$ = curr_parser->make_elseif_clause ($1, $4, $6, $2);
+                    $4->mark_braindead_shortcircuit (curr_lexer->fcn_file_full_name);
+
+                    $$ = curr_parser.make_elseif_clause ($1, $4, $6, $2);
                   }
                 ;
 
@@ -913,7 +925,7 @@
 
 switch_command  : SWITCH stash_comment expression opt_sep case_list END
                   {
-                    if (! ($$ = curr_parser->finish_switch_command ($1, $3, $5, $6, $2)))
+                    if (! ($$ = curr_parser.finish_switch_command ($1, $3, $5, $6, $2)))
                       ABORT_PARSE;
                   }
                 ;
@@ -941,7 +953,7 @@
                 ;
 
 switch_case     : CASE stash_comment opt_sep expression opt_sep opt_list
-                  { $$ = curr_parser->make_switch_case ($1, $4, $6, $2); }
+                  { $$ = curr_parser.make_switch_case ($1, $4, $6, $2); }
                 ;
 
 default_case    : OTHERWISE stash_comment opt_sep opt_list
@@ -956,37 +968,37 @@
 
 loop_command    : WHILE stash_comment expression opt_sep opt_list END
                   {
-                    $3->mark_braindead_shortcircuit (curr_fcn_file_full_name);
-
-                    if (! ($$ = curr_parser->make_while_command ($1, $3, $5, $6, $2)))
+                    $3->mark_braindead_shortcircuit (curr_lexer->fcn_file_full_name);
+
+                    if (! ($$ = curr_parser.make_while_command ($1, $3, $5, $6, $2)))
                       ABORT_PARSE;
                   }
                 | DO stash_comment opt_sep opt_list UNTIL expression
                   {
-                    if (! ($$ = curr_parser->make_do_until_command ($5, $4, $6, $2)))
+                    if (! ($$ = curr_parser.make_do_until_command ($5, $4, $6, $2)))
                       ABORT_PARSE;
                   }
                 | FOR stash_comment assign_lhs '=' expression opt_sep opt_list END
                   {
-                    if (! ($$ = curr_parser->make_for_command (FOR, $1, $3, $5, 0,
+                    if (! ($$ = curr_parser.make_for_command (FOR, $1, $3, $5, 0,
                                                   $7, $8, $2)))
                       ABORT_PARSE;
                   }
                 | FOR stash_comment '(' assign_lhs '=' expression ')' opt_sep opt_list END
                   {
-                    if (! ($$ = curr_parser->make_for_command (FOR, $1, $4, $6, 0,
+                    if (! ($$ = curr_parser.make_for_command (FOR, $1, $4, $6, 0,
                                                   $9, $10, $2)))
                       ABORT_PARSE;
                   }
                 | PARFOR stash_comment assign_lhs '=' expression opt_sep opt_list END
                   {
-                    if (! ($$ = curr_parser->make_for_command (PARFOR, $1, $3, $5,
+                    if (! ($$ = curr_parser.make_for_command (PARFOR, $1, $3, $5,
                                                   0, $7, $8, $2)))
                       ABORT_PARSE;
                   }
                 | PARFOR stash_comment '(' assign_lhs '=' expression ',' expression ')' opt_sep opt_list END
                   {
-                    if (! ($$ = curr_parser->make_for_command (PARFOR, $1, $4, $6,
+                    if (! ($$ = curr_parser.make_for_command (PARFOR, $1, $4, $6,
                                                   $8, $11, $12, $2)))
                       ABORT_PARSE;
                   }
@@ -998,17 +1010,17 @@
 
 jump_command    : BREAK
                   {
-                    if (! ($$ = curr_parser->make_break_command ($1)))
+                    if (! ($$ = curr_parser.make_break_command ($1)))
                       ABORT_PARSE;
                   }
                 | CONTINUE
                   {
-                    if (! ($$ = curr_parser->make_continue_command ($1)))
+                    if (! ($$ = curr_parser.make_continue_command ($1)))
                       ABORT_PARSE;
                   }
                 | FUNC_RET
                   {
-                    if (! ($$ = curr_parser->make_return_command ($1)))
+                    if (! ($$ = curr_parser.make_return_command ($1)))
                       ABORT_PARSE;
                   }
                 ;
@@ -1020,18 +1032,18 @@
 except_command  : UNWIND stash_comment opt_sep opt_list CLEANUP
                   stash_comment opt_sep opt_list END
                   {
-                    if (! ($$ = curr_parser->make_unwind_command ($1, $4, $8, $9, $2, $6)))
+                    if (! ($$ = curr_parser.make_unwind_command ($1, $4, $8, $9, $2, $6)))
                       ABORT_PARSE;
                   }
                 | TRY stash_comment opt_sep opt_list CATCH
                   stash_comment opt_sep opt_list END
                   {
-                    if (! ($$ = curr_parser->make_try_command ($1, $4, $8, $9, $2, $6)))
+                    if (! ($$ = curr_parser.make_try_command ($1, $4, $8, $9, $2, $6)))
                       ABORT_PARSE;
                   }
                 | TRY stash_comment opt_sep opt_list END
                   {
-                    if (! ($$ = curr_parser->make_try_command ($1, $4, 0, $5, $2, 0)))
+                    if (! ($$ = curr_parser.make_try_command ($1, $4, 0, $5, $2, 0)))
                       ABORT_PARSE;
                   }
                 ;
@@ -1042,23 +1054,25 @@
 
 push_fcn_symtab : // empty
                   {
-                    curr_parser->curr_fcn_depth++;
-
-                    if (curr_parser->max_fcn_depth < curr_parser->curr_fcn_depth)
-                      curr_parser->max_fcn_depth = curr_parser->curr_fcn_depth;
+                    curr_parser.curr_fcn_depth++;
+
+                    if (curr_parser.max_fcn_depth < curr_parser.curr_fcn_depth)
+                      curr_parser.max_fcn_depth = curr_parser.curr_fcn_depth;
 
                     parser_symtab_context.push ();
 
                     symbol_table::set_scope (symbol_table::alloc_scope ());
 
-                    curr_parser->function_scopes.push_back (symbol_table::current_scope ());
-
-                    if (! reading_script_file && curr_parser->curr_fcn_depth == 1
-                        && ! curr_parser->parsing_subfunctions)
-                      curr_parser->primary_fcn_scope = symbol_table::current_scope ();
-
-                    if (reading_script_file && curr_parser->curr_fcn_depth > 1)
-                      curr_parser->bison_error ("nested functions not implemented in this context");
+                    curr_parser.function_scopes.push_back (symbol_table::current_scope ());
+
+                    if (! curr_lexer->reading_script_file
+                        && curr_parser.curr_fcn_depth == 1
+                        && ! curr_parser.parsing_subfunctions)
+                      curr_parser.primary_fcn_scope = symbol_table::current_scope ();
+
+                    if (curr_lexer->reading_script_file
+                        && curr_parser.curr_fcn_depth > 1)
+                      curr_parser.bison_error ("nested functions not implemented in this context");
                   }
                 ;
 
@@ -1094,7 +1108,7 @@
                   }
                 | param_list_beg error
                   {
-                    curr_parser->bison_error ("invalid parameter list");
+                    curr_parser.bison_error ("invalid parameter list");
                     $$ = 0;
                     ABORT_PARSE;
                   }
@@ -1157,35 +1171,26 @@
                   }
                 ;
 
-// ===========
-// Script file
-// ===========
-
-script_file     : SCRIPT_FILE opt_list END_OF_INPUT
+// =======================
+// Script or function file
+// =======================
+
+file            : INPUT_FILE opt_nl opt_list END_OF_INPUT
                   {
-                    tree_statement *end_of_script
-                      = curr_parser->make_end ("endscript",
-                                               curr_lexer->input_line_number,
-                                               curr_lexer->current_input_column);
-
-                    curr_parser->make_script ($2, end_of_script);
+                    if (! curr_lexer->reading_fcn_file)
+                      {
+                        tree_statement *end_of_script
+                          = curr_parser.make_end ("endscript",
+                                                  curr_lexer->input_line_number,
+                                                  curr_lexer->current_input_column);
+
+                        curr_parser.make_script ($3, end_of_script);
+                      }
 
                     $$ = 0;
                   }
                 ;
 
-// =============
-// Function file
-// =============
-
-function_file   : FUNCTION_FILE function_list opt_sep END_OF_INPUT
-                  { $$ = 0; }
-                ;
-
-function_list   : function
-                | function_list sep function
-                ;
-
 // ===================
 // Function definition
 // ===================
@@ -1193,21 +1198,21 @@
 function_beg    : push_fcn_symtab FCN stash_comment
                   {
                     $$ = $3;
-
-                    if (reading_classdef_file || curr_lexer->parsing_classdef)
+                    if (curr_lexer->reading_classdef_file
+                        || curr_lexer->parsing_classdef)
                       curr_lexer->maybe_classdef_get_set_method = true;
                   }
                 ;
 
 function        : function_beg function1
                   {
-                    $$ = curr_parser->finish_function (0, $2, $1);
-                    curr_parser->recover_from_parsing_function ();
+                    $$ = curr_parser.finish_function (0, $2, $1);
+                    curr_parser.recover_from_parsing_function ();
                   }
                 | function_beg return_list '=' function1
                   {
-                    $$ = curr_parser->finish_function ($2, $4, $1);
-                    curr_parser->recover_from_parsing_function ();
+                    $$ = curr_parser.finish_function ($2, $4, $1);
+                    curr_parser.recover_from_parsing_function ();
                   }
                 ;
 
@@ -1242,56 +1247,56 @@
 
                     delete $1;
 
-                    if (! ($$ = curr_parser->frob_function (fname, $2)))
+                    if (! ($$ = curr_parser.frob_function (fname, $2)))
                       ABORT_PARSE;
                   }
                 ;
 
 function2       : param_list opt_sep opt_list function_end
-                  { $$ = curr_parser->start_function ($1, $3, $4); }
+                  { $$ = curr_parser.start_function ($1, $3, $4); }
                 | opt_sep opt_list function_end
-                  { $$ = curr_parser->start_function (0, $2, $3); }
+                  { $$ = curr_parser.start_function (0, $2, $3); }
                 ;
 
 function_end    : END
                   {
-                    curr_parser->endfunction_found = true;
-                    if (curr_parser->end_token_ok ($1, token::function_end))
-                      $$ = curr_parser->make_end ("endfunction", $1->line (), $1->column ());
+                    curr_parser.endfunction_found = true;
+                    if (curr_parser.end_token_ok ($1, token::function_end))
+                      $$ = curr_parser.make_end ("endfunction", $1->line (), $1->column ());
                     else
                       ABORT_PARSE;
                   }
                 | END_OF_INPUT
                   {
 // A lot of tests are based on the assumption that this is OK
-//                  if (reading_script_file)
+//                  if (curr_lexer->reading_script_file)
 //                    {
-//                      curr_parser->bison_error ("function body open at end of script");
+//                      curr_parser.bison_error ("function body open at end of script");
 //                      YYABORT;
 //                    }
 
-                    if (curr_parser->endfunction_found)
+                    if (curr_parser.endfunction_found)
                       {
-                        curr_parser->bison_error ("inconsistent function endings -- "
+                        curr_parser.bison_error ("inconsistent function endings -- "
                                  "if one function is explicitly ended, "
                                  "so must all the others");
                         YYABORT;
                       }
 
-                    if (! (reading_fcn_file || reading_script_file
-                           || get_input_from_eval_string))
+                    if (! (curr_lexer->reading_fcn_file || curr_lexer->reading_script_file
+                           || (curr_lexer)->input_from_eval_string ()))
                       {
-                        curr_parser->bison_error ("function body open at end of input");
+                        curr_parser.bison_error ("function body open at end of input");
                         YYABORT;
                       }
 
-                    if (reading_classdef_file)
+                    if (curr_lexer->reading_classdef_file)
                       {
-                        curr_parser->bison_error ("classdef body open at end of input");
+                        curr_parser.bison_error ("classdef body open at end of input");
                         YYABORT;
                       }
 
-                    $$ = curr_parser->make_end ("endfunction",
+                    $$ = curr_parser.make_end ("endfunction",
                                                 curr_lexer->input_line_number,
                                                 curr_lexer->current_input_column);
                   }
@@ -1328,7 +1333,14 @@
 classdef        : classdef_beg stash_comment opt_attr_list identifier opt_superclass_list opt_sep class_body opt_sep END
                   {
                     curr_lexer->parsing_classdef = false;
+<<<<<<< local
                     if (! ($$ = curr_parser->make_classdef ($1, $3, $4, $5, $7, $9, $2)))
+=======
+
+                    if (curr_parser.end_token_ok ($1, token::classdef_end))
+                      $$ = curr_parser.make_end ("endclassdef", $1->line (), $1->column ());
+                    else
+>>>>>>> other
                       ABORT_PARSE;
                   }
                 ;
@@ -1518,7 +1530,7 @@
                 ;
 
 parse_error     : LEXICAL_ERROR
-                  { curr_parser->bison_error ("parse error"); }
+                  { curr_parser.bison_error ("parse error"); }
                 | error
                 ;
 
@@ -1538,6 +1550,18 @@
                   { $$ = $1; }
                 ;
 
+opt_nl          : // empty
+                  { $$ = 0; }
+                | nl
+                  { $$ = $1; }
+                ;
+
+nl              : '\n'
+                  { $$ = '\n'; }
+                | nl '\n'
+                  { $$ = $1; }
+                ;
+
 sep             : ','
                   { $$ = ','; }
                 | ';'
@@ -1571,15 +1595,66 @@
 #undef curr_lexer
 
 static void
-yyerror (octave_parser *curr_parser, const char *s)
+yyerror (octave_parser& curr_parser, const char *s)
+{
+  curr_parser.bison_error (s);
+}
+
+octave_parser::~octave_parser (void)
 {
-  curr_parser->bison_error (s);
+#if defined (OCTAVE_USE_PUSH_PARSER)
+  yypstate_delete (static_cast<yypstate *> (parser_state));
+#endif
+
+  delete stmt_list;
+
+  delete curr_lexer;
+}
+void octave_parser::init (void)
+{
+#if defined (OCTAVE_USE_PUSH_PARSER)
+  parser_state = yypstate_new ();
+#endif
+
+  CURR_LEXER = curr_lexer;
+}
+
+void
+octave_parser::reset (void)
+{
+  delete stmt_list;
+
+  stmt_list = 0;
+
+  curr_lexer->reset ();
 }
 
 int
 octave_parser::run (void)
 {
-  return octave_parse (this);
+  int status = 0;
+
+#if defined (OCTAVE_USE_PUSH_PARSER)
+
+  do
+    {
+      YYSTYPE lval;
+
+      int token = octave_lex (&lval, scanner);
+
+      yypstate *pstate = static_cast<yypstate *> (parser_state);
+
+      status = octave_push_parse (pstate, token, &lval, *this);
+    }
+  while (status == YYPUSH_MORE);
+
+#else
+
+  status = octave_parse (*this);
+
+#endif
+
+  return status;
 }
 
 // Error mesages for mismatched end tokens.
@@ -1713,7 +1788,7 @@
   if (expr->is_assignment_expression ()
       && expr->paren_count () < 2)
     {
-      if (curr_fcn_file_full_name.empty ())
+      if (curr_lexer->fcn_file_full_name.empty ())
         warning_with_id
           ("Octave:assign-as-truth-value",
            "suggest parenthesis around assignment used as truth value");
@@ -1721,7 +1796,7 @@
         warning_with_id
           ("Octave:assign-as-truth-value",
            "suggest parenthesis around assignment used as truth value near line %d, column %d in file '%s'",
-           expr->line (), expr->column (), curr_fcn_file_full_name.c_str ());
+           expr->line (), expr->column (), curr_lexer->fcn_file_full_name.c_str ());
     }
 }
 
@@ -1732,14 +1807,14 @@
 {
   if (! expr->is_constant ())
     {
-      if (curr_fcn_file_full_name.empty ())
+      if (curr_lexer->fcn_file_full_name.empty ())
         warning_with_id ("Octave:variable-switch-label",
                          "variable switch label");
       else
         warning_with_id
           ("Octave:variable-switch-label",
            "variable switch label near line %d, column %d in file '%s'",
-           expr->line (), expr->column (), curr_fcn_file_full_name.c_str ());
+           expr->line (), expr->column (), curr_lexer->fcn_file_full_name.c_str ());
     }
 }
 
@@ -2001,7 +2076,7 @@
     = new tree_anon_fcn_handle (param_list, ret_list, body, fcn_scope, l, c);
   // FIXME: Stash the filename.  This does not work and produces
   // errors when executed.
-  //retval->stash_file_name (curr_fcn_file_name);
+  //retval->stash_file_name (curr_lexer->fcn_file_name);
 
   return retval;
 }
@@ -2625,22 +2700,17 @@
 octave_parser::make_script (tree_statement_list *cmds,
                             tree_statement *end_script)
 {
-  std::string doc_string;
-
-  if (! help_buf.empty ())
-    {
-      doc_string = help_buf.top ();
-      help_buf.pop ();
-    }
-
   if (! cmds)
     cmds = new tree_statement_list ();
 
   cmds->append (end_script);
 
   octave_user_script *script
-    = new octave_user_script (curr_fcn_file_full_name, curr_fcn_file_name,
-                              cmds, doc_string);
+    = new octave_user_script (curr_lexer->fcn_file_full_name,
+                              curr_lexer->fcn_file_name,
+                              cmds, curr_lexer->help_text);
+
+  curr_lexer->help_text = "";
 
   octave_time now;
 
@@ -2700,36 +2770,36 @@
   // the file does not match the name of the function stated in the
   // file.  Matlab doesn't provide a diagnostic (it ignores the stated
   // name).
-  if (! autoloading && reading_fcn_file
+  if (! autoloading && curr_lexer->reading_fcn_file
       && curr_fcn_depth == 1 && ! parsing_subfunctions)
   {
-    // FIXME -- should curr_fcn_file_name already be
+    // FIXME -- should curr_lexer->fcn_file_name already be
     // preprocessed when we get here?  It seems to only be a
     // problem with relative file names.
 
-    std::string nm = curr_fcn_file_name;
+    std::string nm = curr_lexer->fcn_file_name;
 
     size_t pos = nm.find_last_of (file_ops::dir_sep_chars ());
 
     if (pos != std::string::npos)
-      nm = curr_fcn_file_name.substr (pos+1);
+      nm = curr_lexer->fcn_file_name.substr (pos+1);
 
     if (nm != id_name)
       {
         warning_with_id
           ("Octave:function-name-clash",
            "function name '%s' does not agree with function file name '%s'",
-           id_name.c_str (), curr_fcn_file_full_name.c_str ());
+           id_name.c_str (), curr_lexer->fcn_file_full_name.c_str ());
 
         id_name = nm;
       }
   }
 
-  if (reading_fcn_file || reading_classdef_file || autoloading)
+  if (curr_lexer->reading_fcn_file || curr_lexer->reading_classdef_file || autoloading)
     {
       octave_time now;
 
-      fcn->stash_fcn_file_name (curr_fcn_file_full_name);
+      fcn->stash_fcn_file_name (curr_lexer->fcn_file_full_name);
       fcn->stash_fcn_file_time (now);
       fcn->mark_as_system_fcn_file ();
 
@@ -2738,7 +2808,7 @@
 
       if (curr_fcn_depth > 1 || parsing_subfunctions)
         {
-          fcn->stash_parent_fcn_name (curr_fcn_file_name);
+          fcn->stash_parent_fcn_name (curr_lexer->fcn_file_name);
 
           if (curr_fcn_depth > 1)
             fcn->stash_parent_fcn_scope (function_scopes[function_scopes.size ()-2]);
@@ -2764,27 +2834,28 @@
         warning_with_id ("Octave:future-time-stamp",
                          "time stamp for '%s' is in the future", nm.c_str ());
     }
-  else if (! (input_from_tmp_history_file || input_from_startup_file)
-           && reading_script_file
-           && curr_fcn_file_name == id_name)
+  else if (! input_from_tmp_history_file
+           && ! curr_lexer->force_script
+           && curr_lexer->reading_script_file
+           && curr_lexer->fcn_file_name == id_name)
     {
       warning ("function '%s' defined within script file '%s'",
-               id_name.c_str (), curr_fcn_file_full_name.c_str ());
+               id_name.c_str (), curr_lexer->fcn_file_full_name.c_str ());
     }
 
   fcn->stash_function_name (id_name);
   fcn->stash_fcn_location (curr_lexer->input_line_number,
                            curr_lexer->current_input_column);
 
-  if (! help_buf.empty () && curr_fcn_depth == 1
+  if (! curr_lexer->help_text.empty () && curr_fcn_depth == 1
       && ! parsing_subfunctions)
     {
-      fcn->document (help_buf.top ());
-
-      help_buf.pop ();
+      fcn->document (curr_lexer->help_text);
+
+      curr_lexer->help_text = "";
     }
 
-  if (reading_fcn_file && curr_fcn_depth == 1
+  if (curr_lexer->reading_fcn_file && curr_fcn_depth == 1
       && ! parsing_subfunctions)
     primary_fcn_ptr = fcn;
 
@@ -2837,7 +2908,7 @@
       if (curr_fcn_depth == 1 && fcn)
         symbol_table::update_nest (fcn->scope ());
 
-      if (! reading_fcn_file && curr_fcn_depth == 1)
+      if (! curr_lexer->reading_fcn_file && curr_fcn_depth == 1)
         {
           // We are either reading a script file or defining a function
           // at the command line, so this definition creates a
@@ -2870,7 +2941,7 @@
 
   parser_symtab_context.pop ();
 
-  if (reading_fcn_file && curr_fcn_depth == 1
+  if (curr_lexer->reading_fcn_file && curr_fcn_depth == 1
       && ! parsing_subfunctions)
     parsing_subfunctions = true;
 
@@ -3164,9 +3235,9 @@
         retval = new tree_persistent_command (lst, l, c);
       else
         {
-          if (reading_script_file)
+          if (curr_lexer->reading_script_file)
             warning ("ignoring persistent declaration near line %d of file '%s'",
-                     l, curr_fcn_file_full_name.c_str ());
+                     l, curr_lexer->fcn_file_full_name.c_str ());
           else
             warning ("ignoring persistent declaration near line %d", l);
         }
@@ -3251,7 +3322,7 @@
         warning_with_id
           ("Octave:missing-semicolon",
            "missing semicolon near line %d, column %d in file '%s'",
-            tmp->line (), tmp->column (), curr_fcn_file_full_name.c_str ());
+            tmp->line (), tmp->column (), curr_lexer->fcn_file_full_name.c_str ());
     }
 }
 
@@ -3318,9 +3389,9 @@
 
   std::ostringstream output_buf;
 
-  if (reading_fcn_file || reading_script_file || reading_classdef_file)
+  if (curr_lexer->reading_fcn_file || curr_lexer->reading_script_file || curr_lexer->reading_classdef_file)
     output_buf << "parse error near line " << curr_lexer->input_line_number
-               << " of file " << curr_fcn_file_full_name;
+               << " of file " << curr_lexer->fcn_file_full_name;
   else
     output_buf << "parse error:";
 
@@ -3372,216 +3443,9 @@
     fclose (static_cast<FILE *> (f));
 }
 
-static bool
-looks_like_copyright (const std::string& s)
-{
-  bool retval = false;
-
-  if (! s.empty ())
-    {
-      size_t offset = s.find_first_not_of (" \t");
-
-      retval = (s.substr (offset, 9) == "Copyright" || s.substr (offset, 6) == "Author");
-    }
-
-  return retval;
-}
-
-static int
-text_getc (FILE *f)
-{
-  int c = gnulib::getc (f);
-
-  // Convert CRLF into just LF and single CR into LF.
-
-  if (c == '\r')
-    {
-      c = gnulib::getc (f);
-
-      if (c != '\n')
-        {
-          ungetc (c, f);
-          c = '\n';
-        }
-    }
-
-  return c;
-}
-
-class
-stdio_stream_reader : public stream_reader
-{
-public:
-
-  stdio_stream_reader (FILE *f_arg, int& l, int& c)
-    : stream_reader (), f (f_arg), line_num (l), column_num (c)
-  { }
-
-  int getc (void)
-  {
-    char c = ::text_getc (f);
-
-    if (c == '\n')
-      {
-        line_num++;
-        column_num = 0;
-      }
-    else
-      {
-        // FIXME -- try to be smarter about tabs?
-        column_num++;
-      }
-        
-    return c;
-  }
-
-  int ungetc (int c)
-  {
-    if (c == '\n')
-      {   
-        line_num--;
-        column_num = 0;
-      }
-    else
-      {
-        // FIXME -- try to be smarter about tabs?
-        column_num--;
-      }
-
-    return ::ungetc (c, f);
-  }
-
-private:
-
-  FILE *f;
-
-  int& line_num;
-
-  int& column_num;
-
-  // No copying!
-
-  stdio_stream_reader (const  stdio_stream_reader&);
-
-  stdio_stream_reader & operator = (const  stdio_stream_reader&);
-};
-
-static bool
-skip_white_space (stream_reader& reader)
-{
-  int c = 0;
-
-  while ((c = reader.getc ()) != EOF)
-    {
-      switch (c)
-        {
-        case ' ':
-        case '\t':
-        case '\n':
-          break;
-
-        default:
-          reader.ungetc (c);
-          goto done;
-        }
-    }
-
- done:
-
-  return (c == EOF);
-}
-
-static bool
-looking_at_classdef_keyword (FILE *ffile)
-{
-  bool status = false;
-
-  long pos = gnulib::ftell (ffile);
-
-  char buf [10];
-  gnulib::fgets (buf, 10, ffile);
-  size_t len = strlen (buf);
-  if (len > 8 && strncmp (buf, "classdef", 8) == 0
-      && ! (isalnum (buf[8]) || buf[8] == '_'))
-    status = true;
-
-  gnulib::fseek (ffile, pos, SEEK_SET);
-
-  return status;
- }
-
-static std::string
-gobble_leading_white_space (FILE *ffile, bool& eof, int& line_num,
-                            int& column_num)
-{
-  std::string help_txt;
-
-  eof = false;
-
-  // TRUE means we have already cached the help text.
-  bool have_help_text = false;
-
-  std::string txt;
-
-  stdio_stream_reader stdio_reader (ffile, line_num, column_num);
-
-  while (true)
-    {
-      eof = skip_white_space (stdio_reader);
-
-      if (eof)
-        break;
-
-      txt = CURR_LEXER->grab_comment_block (stdio_reader, true, eof);
-
-      if (txt.empty ())
-        break;
-
-      if (! (have_help_text || looks_like_copyright (txt)))
-        {
-          help_txt = txt;
-          have_help_text = true;
-        }
-
-      octave_comment_buffer::append (txt);
-
-      if (eof)
-        break;
-    }
-
-  return help_txt;
-}
-
-static std::string
-gobble_leading_white_space (FILE *ffile, bool& eof)
-{
-  int line_num = 1;
-  int column_num = 1;
-
-  return gobble_leading_white_space (ffile, eof, line_num, column_num);
-}
-
-static bool
-looking_at_function_keyword (FILE *ffile)
-{
-  bool status = false;
-
-  long pos = gnulib::ftell (ffile);
-
-  char buf [10];
-  gnulib::fgets (buf, 10, ffile);
-  size_t len = strlen (buf);
-  if (len > 8 && strncmp (buf, "function", 8) == 0
-      && ! (isalnum (buf[8]) || buf[8] == '_'))
-    status = true;
-
-  gnulib::fseek (ffile, pos, SEEK_SET);
-
-  return status;
-}
-
 static octave_function *
-parse_fcn_file (const std::string& ff, const std::string& dispatch_type,
+parse_fcn_file (const std::string& full_file, const std::string& file,
+                const std::string& dispatch_type,
                 bool require_file, bool force_script, bool autoload,    
                 bool relative_lookup, const std::string& warn_for)
 {
@@ -3595,12 +3459,8 @@
 
   frame.add_fcn (command_editor::set_input_stream, in_stream);
 
-  frame.protect_var (ff_instream);
-
-  frame.protect_var (reading_fcn_file);
   frame.protect_var (line_editing);
 
-  reading_fcn_file = true;
   line_editing = false;
 
   frame.add_fcn (command_history::ignore_entries,
@@ -3608,7 +3468,10 @@
 
   command_history::ignore_entries ();
 
-  FILE *ffile = get_input_from_file (ff, 0);
+  FILE *ffile = 0;
+
+  if (! full_file.empty ())
+    ffile = gnulib::fopen (full_file.c_str (), "rb");
 
   frame.add_fcn (safe_fclose, ffile);
 
@@ -3619,34 +3482,72 @@
       // octave_parser constructor sets this for us.
       frame.protect_var (CURR_LEXER);
 
+<<<<<<< local
       octave_parser *curr_parser = new octave_parser ();
       frame.add_fcn (octave_parser::cleanup, curr_parser);
-
+=======
+      octave_parser curr_parser (ffile);
+>>>>>>> other
+
+<<<<<<< local
       curr_parser->curr_class_name = dispatch_type;
       curr_parser->autoloading = autoload;
       curr_parser->fcn_file_from_relative_lookup = relative_lookup;
-
+=======
+      curr_parser.curr_class_name = dispatch_type;
+      curr_parser.autoloading = autoload;
+      curr_parser.fcn_file_from_relative_lookup = relative_lookup;
+>>>>>>> other
+
+<<<<<<< local
       std::string help_txt
         = gobble_leading_white_space
             (ffile, eof,
              curr_parser->curr_lexer->input_line_number,
              curr_parser->curr_lexer->current_input_column);
-
+=======
+      // Do this with an unwind-protect cleanup function so that
+      // the forced variables will be unmarked in the event of an
+      // interrupt.
+      symbol_table::scope_id scope = symbol_table::top_scope ();
+      frame.add_fcn (symbol_table::unmark_forced_variables, scope);
+>>>>>>> other
+
+<<<<<<< local
       if (! help_txt.empty ())
         help_buf.push (help_txt);
-
+=======
+      curr_parser.curr_lexer->force_script = force_script;
+      curr_parser.curr_lexer->prep_for_file ();
+      curr_parser.curr_lexer->parsing_class_method = ! dispatch_type.empty ();
+>>>>>>> other
+
+<<<<<<< local
       if (! eof)
         {
           std::string file_type;
-
+=======
+      curr_parser.curr_lexer->fcn_file_name = file;
+      curr_parser.curr_lexer->fcn_file_full_name = full_file;
+>>>>>>> other
+
+<<<<<<< local
           frame.protect_var (get_input_from_eval_string);
           frame.protect_var (reading_fcn_file);
           frame.protect_var (reading_script_file);
           frame.protect_var (reading_classdef_file);
           frame.protect_var (Vecho_executing_commands);
-
+=======
+      int status = curr_parser.run ();
+>>>>>>> other
+
+<<<<<<< local
           get_input_from_eval_string = false;
-
+=======
+      fcn_ptr = curr_parser.primary_fcn_ptr;
+>>>>>>> other
+
+<<<<<<< local
           if (! force_script && looking_at_function_keyword (ffile))
             {
               file_type = "function";
@@ -3742,50 +3643,56 @@
 
           fcn_ptr = curr_parser->primary_fcn_ptr;
         }
+=======
+      if (status != 0)
+        error ("parse error while reading file %s", full_file.c_str ());
+>>>>>>> other
     }
   else if (require_file)
-    error ("no such file, '%s'", ff.c_str ());
+    error ("no such file, '%s'", full_file.c_str ());
   else if (! warn_for.empty ())
-    error ("%s: unable to open file '%s'", warn_for.c_str (), ff.c_str ());
+    error ("%s: unable to open file '%s'", warn_for.c_str (),
+           full_file.c_str ());
 
   return fcn_ptr;
 }
 
 std::string
 get_help_from_file (const std::string& nm, bool& symbol_found,
-                    std::string& file)
+                    std::string& full_file)
 {
   std::string retval;
 
-  file = fcn_file_in_path (nm);
+  full_file = fcn_file_in_path (nm);
+
+  std::string file = full_file;
+
+  size_t file_len = file.length ();
+
+  if ((file_len > 4 && file.substr (file_len-4) == ".oct")
+      || (file_len > 4 && file.substr (file_len-4) == ".mex")
+      || (file_len > 2 && file.substr (file_len-2) == ".m"))
+    {
+      file = octave_env::base_pathname (file);
+      file = file.substr (0, file.find_last_of ('.'));
+
+      size_t pos = file.find_last_of (file_ops::dir_sep_str ());
+      if (pos != std::string::npos)
+        file = file.substr (pos+1);
+    }
 
   if (! file.empty ())
     {
       symbol_found = true;
 
-      FILE *fptr = gnulib::fopen (file.c_str (), "r");
-
-      if (fptr)
+      octave_function *fcn
+        = parse_fcn_file (full_file, file, "", true, false, false, false, "");
+
+      if (fcn)
         {
-          unwind_protect frame;
-          frame.add_fcn (safe_fclose, fptr);
-
-          bool eof;
-          retval = gobble_leading_white_space (fptr, eof);
-
-          if (retval.empty ())
-            {
-              octave_function *fcn = parse_fcn_file (file, "", true,
-                                                     false, false,
-                                                     false, "");
-
-              if (fcn)
-                {
-                  retval = fcn->doc_string ();
-
-                  delete fcn;
-                }
-            }
+          retval = fcn->doc_string ();
+
+          delete fcn;
         }
     }
 
@@ -3888,14 +3795,9 @@
     {
       // Temporarily load m-file version of mex-file, if it exists,
       // to get the help-string to use.
-      frame.protect_var (curr_fcn_file_name);
-      frame.protect_var (curr_fcn_file_full_name);
-
-      curr_fcn_file_name = nm;
-      curr_fcn_file_full_name = file.substr (0, len - 2);
 
       octave_function *tmpfcn = parse_fcn_file (file.substr (0, len - 2),
-                                                dispatch_type, false,
+                                                nm, dispatch_type, false,
                                                 autoload, autoload,
                                                 relative_lookup, "");
 
@@ -3907,15 +3809,7 @@
     }
   else if (len > 2)
     {
-      // These are needed by yyparse.
-
-      frame.protect_var (curr_fcn_file_name);
-      frame.protect_var (curr_fcn_file_full_name);
-
-      curr_fcn_file_name = nm;
-      curr_fcn_file_full_name = file;
-
-      retval = parse_fcn_file (file, dispatch_type, true, autoload,
+      retval = parse_fcn_file (file, nm, dispatch_type, true, autoload,
                                autoload, relative_lookup, "");
     }
 
@@ -4085,12 +3979,6 @@
 
   unwind_protect frame;
 
-  frame.protect_var (curr_fcn_file_name);
-  frame.protect_var (curr_fcn_file_full_name);
-
-  curr_fcn_file_name = file_name;
-  curr_fcn_file_full_name = file_full_name;
-
   if (source_call_depth.find (file_full_name) == source_call_depth.end ())
     source_call_depth[file_full_name] = -1;
 
@@ -4119,9 +4007,9 @@
 
   if (! error_state)
     {
-      octave_function *fcn = parse_fcn_file (file_full_name, "",
-                                             require_file, true, false,
-                                             false, warn_for);
+      octave_function *fcn = parse_fcn_file (file_full_name, file_name,
+                                             "", require_file, true,
+                                             false, false, warn_for);
 
       if (! error_state)
         {
@@ -4426,7 +4314,8 @@
 }
 
 octave_value_list
-eval_string (const std::string& s, bool silent, int& parse_status, int nargout)
+eval_string (const std::string& eval_str, bool silent,
+             int& parse_status, int nargout)
 {
   octave_value_list retval;
 
@@ -4435,31 +4324,15 @@
   // octave_parser constructor sets this for us.
   frame.protect_var (CURR_LEXER);
 
-  octave_parser *curr_parser = new octave_parser ();
-  frame.add_fcn (octave_parser::cleanup, curr_parser);
-
-  frame.protect_var (get_input_from_eval_string);
+  octave_parser curr_parser (eval_str);
+
   frame.protect_var (line_editing);
-  frame.protect_var (current_eval_string);
-  frame.protect_var (reading_fcn_file);
-  frame.protect_var (reading_script_file);
-  frame.protect_var (reading_classdef_file);
-
-  get_input_from_eval_string = true;
+
   line_editing = false;
-  reading_fcn_file = false;
-  reading_script_file = false;
-  reading_classdef_file = false;
-
-  current_eval_string = s;
 
   do
     {
-      curr_parser->reset ();
-
-      frame.protect_var (global_command);
-
-      global_command = 0;
+      curr_parser.reset ();
 
       // Do this with an unwind-protect cleanup function so that the
       // forced variables will be unmarked in the event of an
@@ -4467,30 +4340,19 @@
       symbol_table::scope_id scope = symbol_table::top_scope ();
       frame.add_fcn (symbol_table::unmark_forced_variables, scope);
 
-      parse_status = curr_parser->run ();
-
-      tree_statement_list *command_list = global_command;
+      parse_status = curr_parser.run ();
 
       // Unmark forced variables.
-      // Restore previous value of global_command.
-      frame.run (2);
+      frame.run (1);
 
       if (parse_status == 0)
         {
-          if (command_list)
+          if (curr_parser.stmt_list)
             {
-              unwind_protect inner_frame;
-
-              // Use an unwind-protect cleanup function so that the
-              // global_command list will be deleted in the event of an
-              // interrupt.
-
-              inner_frame.add_fcn (cleanup_statement_list, &command_list);
-
               tree_statement *stmt = 0;
 
-              if (command_list->length () == 1
-                  && (stmt = command_list->front ())
+              if (curr_parser.stmt_list->length () == 1
+                  && (stmt = curr_parser.stmt_list->front ())
                   && stmt->is_expression ())
                 {
                   tree_expression *expr = stmt->expression ();
@@ -4519,7 +4381,7 @@
                     retval = octave_value_list ();
                 }
               else if (nargout == 0)
-                command_list->accept (*current_evaluator);
+                curr_parser.stmt_list->accept (*current_evaluator);
               else
                 error ("eval: invalid use of statement list");
 
@@ -4529,7 +4391,7 @@
                   || tree_continue_command::continuing)
                 break;
             }
-          else if (curr_parser->end_of_input)
+          else if (curr_parser.curr_lexer->end_of_input)
             break;
         }
     }
@@ -4539,11 +4401,11 @@
 }
 
 octave_value
-eval_string (const std::string& s, bool silent, int& parse_status)
+eval_string (const std::string& eval_str, bool silent, int& parse_status)
 {
   octave_value retval;
 
-  octave_value_list tmp = eval_string (s, silent, parse_status, 1);
+  octave_value_list tmp = eval_string (eval_str, silent, parse_status, 1);
 
   if (! tmp.empty ())
     retval = tmp(0);
--- a/libinterp/parse-tree/parse.h
+++ b/libinterp/parse-tree/parse.h
@@ -83,18 +83,12 @@
 // Nonzero means print parser debugging info (-d).
 extern int octave_debug;
 
-// Buffer for help text snagged from function files.
-extern std::stack<std::string> help_buf;
-
 // TRUE means we are using readline.
 extern bool line_editing;
 
 // TRUE means we printed messages about reading startup files.
 extern bool reading_startup_message_printed;
 
-// TRUE means input is coming from startup file.
-extern bool input_from_startup_file;
-
 extern OCTINTERP_API std::string
 get_help_from_file (const std::string& nm, bool& symbol_found,
                     std::string& file);
@@ -144,7 +138,7 @@
 
 // Global access to currently active lexer.
 // FIXME -- to be removed after more parser+lexer refactoring.
-extern lexical_feedback *CURR_LEXER;
+extern octave_lexer *CURR_LEXER;
 
 class
 octave_parser
@@ -152,25 +146,50 @@
 public:
 
   octave_parser (void)
-    : end_of_input (false), endfunction_found (false),
+    : endfunction_found (false),
+      autoloading (false), fcn_file_from_relative_lookup (false),
+      parsing_subfunctions (false), max_fcn_depth (0),
+      curr_fcn_depth (0), primary_fcn_scope (-1),
+      curr_class_name (), function_scopes (), primary_fcn_ptr (0),
+<<<<<<< local
+      classdef_object (0), curr_lexer (new lexical_feedback ())
+=======
+      stmt_list (0),
+      curr_lexer (new octave_lexer ()), parser_state (0)
+>>>>>>> other
+  {
+    init ();
+  }
+
+  octave_parser (FILE *file)
+    : endfunction_found (false),
       autoloading (false), fcn_file_from_relative_lookup (false),
       parsing_subfunctions (false), max_fcn_depth (0),
       curr_fcn_depth (0), primary_fcn_scope (-1),
       curr_class_name (), function_scopes (), primary_fcn_ptr (0),
-      classdef_object (0), curr_lexer (new lexical_feedback ())
+      stmt_list (0),
+      curr_lexer (new octave_lexer (file)), parser_state (0)
   {
-    CURR_LEXER = curr_lexer;
+    init ();
   }
 
-  ~octave_parser (void)
+  octave_parser (const std::string& eval_string)
+    : endfunction_found (false),
+      autoloading (false), fcn_file_from_relative_lookup (false),
+      parsing_subfunctions (false), max_fcn_depth (0),
+      curr_fcn_depth (0), primary_fcn_scope (-1),
+      curr_class_name (), function_scopes (), primary_fcn_ptr (0),
+      stmt_list (0),
+      curr_lexer (new octave_lexer (eval_string)), parser_state (0)
   {
-    delete curr_lexer;
+    init ();
   }
 
-  void reset (void)
-  {
-    curr_lexer->reset ();
-  }
+  ~octave_parser (void);
+
+  void init (void);
+
+  void reset (void);
 
   int run (void);
 
@@ -396,9 +415,6 @@
   // Generic error messages.
   void bison_error (const char *s);
 
-  // TRUE means that we have encountered EOF on the input stream.
-  bool end_of_input;
-
   // Have we found an explicit end to a function?
   bool endfunction_found;
 
@@ -440,11 +456,20 @@
   // Pointer to the primary user function or user script function.
   octave_function *primary_fcn_ptr;
 
+<<<<<<< local
   // Pointer to the classdef object we just parsed, if any.
   tree_classdef *classdef_object;
+=======
+  // Result of parsing input.
+  tree_statement_list *stmt_list;
+>>>>>>> other
 
   // State of the lexer.
-  lexical_feedback *curr_lexer;
+  octave_lexer *curr_lexer;
+
+  // Internal state of the parser.  Only used if USE_PUSH_PARSER is
+  // defined.
+  void *parser_state;
 
   // For unwind protect.
   static void cleanup (octave_parser *parser) { delete parser; }
--- a/libinterp/parse-tree/pt-check.cc
+++ b/libinterp/parse-tree/pt-check.cc
@@ -559,8 +559,8 @@
 void
 tree_checker::gripe (const std::string& msg, int line)
 {
-  if (curr_fcn_file_name.empty ())
+  if (file_name.empty ())
     error ("%s", msg.c_str ());
   else
-    error ("%s: %d: %s", curr_fcn_file_name.c_str (), line, msg.c_str ());
+    error ("%s: %d: %s", file_name.c_str (), line, msg.c_str ());
 }
--- a/libinterp/parse-tree/pt-check.h
+++ b/libinterp/parse-tree/pt-check.h
@@ -35,7 +35,7 @@
 public:
 
   tree_checker (void)
-    : do_lvalue_check (false) { }
+    : do_lvalue_check (false), file_name () { }
 
   ~tree_checker (void) { }
 
@@ -127,6 +127,8 @@
 
   bool do_lvalue_check;
 
+  std::string file_name;
+
   void do_decl_command (tree_decl_command&);
 
   void gripe (const std::string& msg, int line);
--- a/liboctave/array/Range.cc
+++ b/liboctave/array/Range.cc
@@ -36,14 +36,6 @@
 #include "lo-utils.h"
 #include "Array-util.h"
 
-Range::Range (double b, double i, octave_idx_type n)
-  : rng_base (b), rng_limit (b + (n-1) * i), rng_inc (i),
-    rng_nelem (n), cache ()
-{
-  if (! xfinite (b) || ! xfinite (i))
-    rng_nelem = -2;
-}
-
 bool
 Range::all_elements_are_ints (void) const
 {
@@ -64,17 +56,24 @@
       cache.resize (1, rng_nelem);
       double b = rng_base;
       double increment = rng_inc;
-      for (octave_idx_type i = 0; i < rng_nelem; i++)
-        cache(i) = b + i * increment;
+      if (rng_nelem > 0)
+        {
+          // The first element must always be *exactly* the base.
+          // E.g, -0 would otherwise become +0 in the loop (-0 + 0*increment).
+          cache(0) = b; 
+          for (octave_idx_type i = 1; i < rng_nelem; i++)
+            cache(i) = b + i * increment;
+        }
 
       // 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.
+      // elements.  The tests need equality (>= rng_limit or <= rng_limit)
+      // to have expressions like -5:1:-0 result in a -0 endpoint.
 
-      if ((rng_inc > 0 && cache(rng_nelem-1) > rng_limit)
-          || (rng_inc < 0 && cache(rng_nelem-1) < rng_limit))
+      if ((rng_inc > 0 && cache(rng_nelem-1) >= rng_limit)
+          || (rng_inc < 0 && cache(rng_nelem-1) <= rng_limit))
         cache(rng_nelem-1) = rng_limit;
     }
 
@@ -87,16 +86,71 @@
   if (i < 0 || i >= rng_nelem)
     gripe_index_out_of_range (1, 1, i+1, rng_nelem);
 
-  return rng_base + rng_inc * i;
+  if (i == 0)
+    return rng_base;
+  else if (i < rng_nelem - 1) 
+    return rng_base + i * rng_inc;
+  else
+    {
+      double end = rng_base + i * rng_inc;
+      if ((rng_inc > 0 && end >= rng_limit)
+          || (rng_inc < 0 && end <= rng_limit))
+        return rng_limit;
+      else
+        return end;
+    }
 }
 
-struct _rangeidx_helper
+double
+Range::elem (octave_idx_type i) const
+{
+#if defined (BOUNDS_CHECKING)
+  return checkelem (i);
+#else
+  if (i == 0)
+    return rng_base;
+  else if (i < rng_nelem - 1) 
+    return rng_base + i * rng_inc;
+  else
+    {
+      double end = rng_base + i * rng_inc;
+      if ((rng_inc > 0 && end >= rng_limit)
+          || (rng_inc < 0 && end <= rng_limit))
+        return rng_limit;
+      else
+        return end;
+    }
+#endif
+}
+
+// Helper class used solely for idx_vector.loop () function call
+class __rangeidx_helper
 {
-  double *array, base, inc;
-  _rangeidx_helper (double *a, double b, double i)
-    : array (a), base (b), inc (i) { }
+ public:
+  __rangeidx_helper (double *a, double b, double i, double l, octave_idx_type n)
+    : array (a), base (b), inc (i), limit (l), nmax (n-1) { }
+
   void operator () (octave_idx_type i)
-    { *array++ = base + i * inc; }
+    {
+      if (i == 0)
+        *array++ = base;
+      else if (i < nmax) 
+        *array++ = base + i * inc;
+      else
+        {
+          double end = base + i * inc;
+          if ((inc > 0 && end >= limit) || (inc < 0 && end <= limit))
+            *array++ = limit;
+          else
+            *array++ = end;
+        }
+    }
+
+ private:
+
+  double *array, base, inc, limit;
+  octave_idx_type nmax;
+
 };
 
 Array<double>
@@ -119,19 +173,22 @@
       octave_idx_type il = i.length (n);
 
       // taken from Array.cc.
-
       if (n != 1 && rd.is_vector ())
         rd = dim_vector (1, il);
 
       retval.clear (rd);
 
-      i.loop (n, _rangeidx_helper (retval.fortran_vec (), rng_base, rng_inc));
+      // idx_vector loop across all values in i,
+      // executing __rangeidx_helper (i) for each i
+      i.loop (n, __rangeidx_helper (retval.fortran_vec (),
+                                    rng_base, rng_inc, rng_limit, rng_nelem));
     }
 
   return retval;
 }
 
 // NOTE: max and min only return useful values if nelem > 0.
+//       do_minmax_body() in max.cc avoids calling Range::min/max if nelem == 0.
 
 double
 Range::min (void) const
@@ -146,8 +203,7 @@
           retval = rng_base + (rng_nelem - 1) * rng_inc;
 
           // See the note in the matrix_value method above.
-
-          if (retval < rng_limit)
+          if (retval <= rng_limit)
             retval = rng_limit;
         }
 
@@ -166,8 +222,7 @@
           retval = rng_base + (rng_nelem - 1) * rng_inc;
 
           // See the note in the matrix_value method above.
-
-          if (retval > rng_limit)
+          if (retval >= rng_limit)
             retval = rng_limit;
         }
       else
@@ -268,7 +323,7 @@
   if (dim == 1)
     {
       if (mode == ASCENDING)
-          retval.sort_internal (sidx, true);
+        retval.sort_internal (sidx, true);
       else if (mode == DESCENDING)
         retval.sort_internal (sidx, false);
     }
@@ -281,10 +336,10 @@
 sortmode
 Range::is_sorted (sortmode mode) const
 {
-  if (rng_nelem > 1 && rng_inc < 0)
+  if (rng_nelem > 1 && rng_inc > 0)
+    mode = (mode == DESCENDING) ? UNSORTED : ASCENDING;
+  else if (rng_nelem > 1 && rng_inc < 0)
     mode = (mode == ASCENDING) ? UNSORTED : DESCENDING;
-  else if (rng_nelem > 1 && rng_inc > 0)
-    mode = (mode == DESCENDING) ? UNSORTED : ASCENDING;
   else
     mode = mode ? mode : ASCENDING;
 
@@ -298,12 +353,15 @@
   double increment = a.inc ();
   octave_idx_type num_elem = a.nelem ();
 
-  for (octave_idx_type i = 0; i < num_elem-1; i++)
-    os << b + i * increment << " ";
+  if (num_elem > 1)
+    {
+      // First element must be the base *exactly* (-0).
+      os << b << " ";
+      for (octave_idx_type i = 1; i < num_elem-1; i++)
+        os << b + i * increment << " ";
+    }
 
-  // Prevent overshoot.  See comment in the matrix_value method
-  // above.
-
+  // Prevent overshoot.  See comment in the matrix_value method above.
   os << (increment > 0 ? a.max () : a.min ()) << "\n";
 
   return os;
@@ -502,7 +560,7 @@
             n_elt++;
         }
 
-      retval = (n_elt >= std::numeric_limits<octave_idx_type>::max () - 1) ? -1 : n_elt;
+      retval = (n_elt < std::numeric_limits<octave_idx_type>::max () - 1) ? n_elt : -1;
     }
 
   return retval;
--- a/liboctave/array/Range.h
+++ b/liboctave/array/Range.h
@@ -50,7 +50,13 @@
       rng_nelem (nelem_internal ()), cache () { }
 
   // For operators' usage (to preserve element count).
-  Range (double b, double i, octave_idx_type n);
+  Range (double b, double i, octave_idx_type n)
+    : rng_base (b), rng_limit (b + (n-1) * i), rng_inc (i),
+      rng_nelem (n), cache ()
+    {
+      if (! xfinite (b) || ! xfinite (i))
+        rng_nelem = -2;
+    }
 
   double base (void) const { return rng_base; }
   double limit (void) const { return rng_limit; }
@@ -80,14 +86,7 @@
 
   double checkelem (octave_idx_type i) const;
 
-  double elem (octave_idx_type i) const
-    {
-#if defined (BOUNDS_CHECKING)
-      return checkelem (i);
-#else
-      return rng_base + rng_inc * i;
-#endif
-    }
+  double elem (octave_idx_type i) const;
 
   Array<double> index (const idx_vector& i) const;
 
--- a/m4/acinclude.m4
+++ b/m4/acinclude.m4
@@ -1405,6 +1405,62 @@
   AC_PROG_YACC
   case "$YACC" in
     bison*)
+    AC_CACHE_CHECK([syntax of bison push/pull declaration],
+                   [octave_cv_bison_push_pull_decl_style], [
+      style="dash underscore"
+      quote="noquote quote"
+      for s in $style; do
+        for q in $quote; do
+          if test $s = "dash"; then
+            def="%define api.push-pull"
+          else
+            def="%define api.push_pull"
+          fi
+          if test $q = "quote"; then
+            def="$def \"both\""
+          else
+            def="$def both"
+          fi
+          cat << EOF > conftest.yy
+$def
+%start input
+%%
+input:;
+%%
+EOF
+          $YACC conftest.yy > /dev/null 2>&1
+          ac_status=$?
+          if test $ac_status -eq 0; then
+            if test $q = noquote; then
+              q=
+            fi
+            octave_cv_bison_push_pull_decl_style="$s $q"
+            break
+          fi
+        done
+        if test $ac_status -eq 0; then
+          break
+        fi
+      done
+      rm -f conftest.yy y.tab.h y.tab.c
+      ])
+    ;;
+  esac
+
+  AC_SUBST(BISON_PUSH_PULL_DECL_STYLE, $octave_cv_bison_push_pull_decl_style)
+
+  if test -z "$octave_cv_bison_push_pull_decl_style"; then
+    YACC=
+    warn_bison_push_pull_decl_style="
+
+I wasn't able to find a suitable style for declaring a push-pull
+parser in a bison input file so I'm disabling bison.
+"
+    OCTAVE_CONFIGURE_WARNING([warn_bison_push_pull_decl_style])
+  fi
+
+  case "$YACC" in
+    bison*)
     ;;
     *)
       YACC='$(top_srcdir)/build-aux/missing bison'
--- a/scripts/general/celldisp.m
+++ b/scripts/general/celldisp.m
@@ -17,7 +17,8 @@
 ## <http://www.gnu.org/licenses/>.
 
 ## -*- texinfo -*-
-## @deftypefn {Function File} {} celldisp (@var{c}, @var{name})
+## @deftypefn  {Function File} {} celldisp (@var{c})
+## @deftypefnx {Function File} {} celldisp (@var{c}, @var{name})
 ## Recursively display the contents of a cell array.  By default the values
 ## are displayed with the name of the variable @var{c}.  However, this name
 ## can be replaced with the variable @var{name}.  For example:
@@ -44,12 +45,13 @@
 ## This is ugly, but seems to be what matlab does..
 
 function celldisp (c, name)
+
   if (nargin < 1 || nargin > 2)
     print_usage ();
   endif
 
   if (! iscell (c))
-    error ("celldisp: argument must be a cell array");
+    error ("celldisp: C must be a cell array");
   endif
 
   if (nargin == 1)
@@ -83,7 +85,7 @@
 %! c = {1, 2, {31, 32}};
 %! celldisp (c, "b")
 
+## Test input validation
 %!error celldisp ()
 %!error celldisp ({}, "name", 1)
-%!error celldisp (1)
-
+%!error <C must be a cell array> celldisp (1)
--- a/scripts/general/num2str.m
+++ b/scripts/general/num2str.m
@@ -24,8 +24,9 @@
 ## optional second argument may either give the number of significant
 ## digits (@var{precision}) to be used in the output or a format
 ## template string (@var{format}) as in @code{sprintf} (@pxref{Formatted
-## Output}).  @code{num2str} can also handle complex numbers.  For
-## example:
+## Output}).  @code{num2str} can also handle complex numbers.
+##
+## Examples:
 ##
 ## @example
 ## @group
@@ -50,11 +51,17 @@
 ## @end group
 ## @end example
 ##
+## Notes:
+##
+## For Matlab compatibility, leading spaces are stripped before returning
+## the string.
+##
 ## The @code{num2str} function is not very flexible.  For better control
 ## over the results, use @code{sprintf} (@pxref{Formatted Output}).
-## Note that for complex @var{x}, the format string may only contain one
-## output conversion specification and nothing else.  Otherwise, you
-## will get unpredictable results.
+##
+## For complex @var{x}, the format string may only contain one
+## output conversion specification and nothing else.  Otherwise, results
+## will be unpredictable.
 ## @seealso{sprintf, int2str, mat2str}
 ## @end deftypefn
 
new file mode 100644
--- /dev/null
+++ b/scripts/miscellaneous/citation.m
@@ -0,0 +1,51 @@
+## Copyright (C) 2013 Carnë Draug
+##
+## 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
+## <http://www.gnu.org/licenses/>.
+
+## -*- texinfo -*-
+## @deftypefn  {Command} {} citation
+## @deftypefnx {Command} {} citation @var{package}
+## Display instructions to cite GNU Octave and packages in publications.
+##
+## When called without an argument, displays information on how to cite the core
+## GNU Octave system in publications.  When given a package name @var{package},
+## display information on to cite it.  However, note that some packages may not
+## have instructions on how to cite them.
+##
+## The GNU Octave developers and its active community of package authors have
+## invested a lot of time and effort in creating GNU Octave as it is today.
+## Please give credit where credit is due and cite GNU Octave and its packages
+## when you use them.
+##
+## @end deftypefn
+
+## Author: Carnë Draug <carandraug+dev@gmail.com>
+## Idea and documentation from R's citation() (also under GPL)
+
+function citation (package = "octave")
+
+  if (nargin > 1)
+    print_usage ();
+  else
+    display_info_file ("citation", package, "CITATION");
+  endif
+
+endfunction
+
+%!error citation (1, 2)
+%!error <citation: PACKAGE must be a string> citation (1)
+%!error <citation: package .* is not installed> citation ("__NOT_A_VALID_PKG_NAME__")
--- a/scripts/miscellaneous/module.mk
+++ b/scripts/miscellaneous/module.mk
@@ -1,6 +1,7 @@
 FCN_FILE_DIRS += miscellaneous
 
 miscellaneous_PRIVATE_FCN_FILES = \
+  miscellaneous/private/display_info_file.m \
   miscellaneous/private/__xzip__.m
 
 miscellaneous_FCN_FILES = \
@@ -10,6 +11,7 @@
   miscellaneous/bunzip2.m \
   miscellaneous/bzip2.m \
   miscellaneous/cast.m \
+  miscellaneous/citation.m \
   miscellaneous/comma.m \
   miscellaneous/compare_versions.m \
   miscellaneous/computer.m \
--- a/scripts/miscellaneous/news.m
+++ b/scripts/miscellaneous/news.m
@@ -17,8 +17,8 @@
 ## <http://www.gnu.org/licenses/>.
 
 ## -*- texinfo -*-
-## @deftypefn  {Function File} {} news
-## @deftypefnx {Function File} {} news (@var{package})
+## @deftypefn  {Command} {} news
+## @deftypefnx {Command} {} news @var{package}
 ## Display the current NEWS file for Octave or an installed package.
 ##
 ## When called without an argument, display the NEWS file for Octave.
@@ -30,42 +30,13 @@
 
   if (nargin > 1)
     print_usage ();
-  elseif (! ischar (package))
-    error ("news: PACKAGE must be a string");
+  else
+    display_info_file ("news", package, "NEWS");
   endif
 
-  if (strcmpi (package, "octave"))
-    octetcdir = octave_config_info ("octetcdir");
-    newsfile  = fullfile (octetcdir, "NEWS");
-  else
-    installed = pkg ("list");
-    names     = cellfun (@(x) x.name, installed, "UniformOutput", false);
-    ## we are nice and let the user use any case on the package name
-    pos = strcmpi (names, package);
-    if (!any (pos))
-      error ("Package '%s' is not installed.", package);
-    endif
-    newsfile = fullfile (installed{pos}.dir, "packinfo", "NEWS");
-  endif
-
-  if (! exist (newsfile, "file"))
-    if (strcmpi (package, "octave"))
-      error ("news: unable to locate NEWS file");
-    else
-      error ("news: unable to locate NEWS file for package %s", package);
-    endif
-  endif
-
-  fid = fopen (newsfile, "r");
-  while (ischar (line = fgets (fid)))
-    puts (line);
-  endwhile
-  fclose (fid);
-
 endfunction
 
 
 %!error news (1, 2)
-%!error <PACKAGE must be a string> news (1)
-%!error <Package .* is not installed> news ("__NOT_A_VALID_PKG_NAME__")
-
+%!error <news: PACKAGE must be a string> news (1)
+%!error <news: package .* is not installed> news ("__NOT_A_VALID_PKG_NAME__")
new file mode 100644
--- /dev/null
+++ b/scripts/miscellaneous/private/display_info_file.m
@@ -0,0 +1,59 @@
+## Copyright (C) 2013 Carnë Draug
+##
+## 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
+## <http://www.gnu.org/licenses/>.
+
+## news() and citation() are very much alike. They both do the same thing, just
+## for different files. This function does all the work.
+
+function display_info_file (func, package, file)
+
+  if (nargin != 3)
+    print_usage ();
+  endif
+
+  if (! ischar (package))
+    error ("%s: PACKAGE must be a string", func);
+  endif
+
+  if (strcmpi (package, "octave"))
+    octetcdir = octave_config_info ("octetcdir");
+    filepath  = fullfile (octetcdir, file);
+  else
+    installed = pkg ("list");
+    names     = cellfun (@(x) x.name, installed, "UniformOutput", false);
+    pos       = strcmpi (names, package);
+    if (! any (pos))
+      error ("%s: package '%s' is not installed.", func, package);
+    endif
+    filepath = fullfile (installed{pos}.dir, "packinfo", file);
+  endif
+
+  if (! exist (filepath, "file"))
+    if (strcmpi (package, "octave"))
+      error ("%s: broken installation -- unable to locate %s file", func, file);
+    else
+      error ("%s: unable to locate %s file for package %s", func, file, package);
+    endif
+  endif
+
+  fid = fopen (filepath, "r");
+  while (ischar (line = fgets (fid)))
+    puts (line);
+  endwhile
+  fclose (fid);
+
+endfunction
--- a/scripts/pkg/pkg.m
+++ b/scripts/pkg/pkg.m
@@ -423,7 +423,7 @@
         local_packages = prefix;
         global_packages = archprefix;
       elseif (length (files) >= 1 && nargout <= 2 && ischar (files{1}))
-        prefix = files{1};
+        prefix = tilde_expand (files{1});
         if (! exist (prefix, "dir"))
           [status, msg, msgid] = mkdir (prefix);
           if (status == 0)
@@ -434,7 +434,7 @@
         local_packages = prefix = canonicalize_file_name (prefix);
         user_prefix = true;
         if (length (files) >= 2 && ischar (files{2}))
-          archprefix = files{2};
+          archprefix = tilde_expand (files{2});
           if (! exist (archprefix, "dir"))
             [status, msg, msgid] = mkdir (archprefix);
             if (status == 0)
--- a/scripts/pkg/private/build.m
+++ b/scripts/pkg/private/build.m
@@ -35,7 +35,7 @@
     endif
   endif
   [builddir, status] = canonicalize_file_name (builddir);
-  if (! status)
+  if (status != 0)
     error ("cannot find directory %s", builddir);
   endif
   installdir = fullfile (builddir, "install");
--- a/scripts/pkg/private/copy_files.m
+++ b/scripts/pkg/private/copy_files.m
@@ -105,6 +105,7 @@
   packinfo_copy_file ("DESCRIPTION", "required", packdir, packinfo, desc, octfiledir);
   packinfo_copy_file ("COPYING", "required", packdir, packinfo, desc, octfiledir);
 
+  packinfo_copy_file ("CITATION", "optional", packdir, packinfo, desc, octfiledir);
   packinfo_copy_file ("NEWS", "optional", packdir, packinfo, desc, octfiledir);
   packinfo_copy_file ("ONEWS", "optional", packdir, packinfo, desc, octfiledir);
   packinfo_copy_file ("ChangeLog", "optional", packdir, packinfo, desc, octfiledir);
--- a/scripts/plot/__gnuplot_drawnow__.m
+++ b/scripts/plot/__gnuplot_drawnow__.m
@@ -296,13 +296,18 @@
     if (! __gnuplot_has_feature__ ("has_termoption_dashed"))
       ## If "set termoption dashed" isn't available add "dashed" option
       ## to the "set terminal ..." command, if it is supported.
-      if (any (strcmpi (term, {"aqua", "cgm", "eepic", "emf", "epslatex", \
-                               "fig", "pcl5", "mp", "next", "openstep", "pdf", \
-                               "pdfcairo", "pngcairo", "postscript", \
-                               "pslatex", "pstext", "svg", "tgif", "x11"})))
+      if (any (strcmp (term, {"aqua", "cgm", "eepic", "emf", "epslatex", \
+                              "fig", "pcl5", "mp", "next", "openstep", "pdf", \
+                              "pdfcairo", "pngcairo", "postscript", \
+                              "pslatex", "pstext", "svg", "tgif", "x11"})))
         term_str = [term_str " dashed"];
       endif
     end
+    if (any (strcmp (term, {"aqua", "wxt"})))
+      term_str = [term_str, " ", "dashlength 1"];
+    elseif (any (strcmp (term, {"epslatex", "postscript", "pslatex"})))
+      term_str = [term_str, " ", "dashlength 2"];
+    endif
 
     ## Work around the gnuplot feature of growing the x11 window and
     ## flickering window (x11, windows, & wxt) when the mouse and
--- a/scripts/plot/printd.m
+++ b/scripts/plot/printd.m
@@ -20,9 +20,11 @@
 
 ## -*- texinfo -*-
 ## @deftypefn  {Function File} {} printd (@var{obj}, @var{filename})
+## @deftypefnx {Function File} {@var{out_file} =} printd (@dots{})
 ##
 ## Convert any object acceptable to @code{disp} into the format
-## selected by the suffix of @var{filename}.
+## selected by the suffix of @var{filename}.  If the return argument
+## @var{out_file} is given, the name of the created file is returned.
 ##
 ## This function is intended to facilitate manipulation of the output
 ## of functions such as @code{stemleaf}.
@@ -32,7 +34,7 @@
 ## Author: Michael D. Godfrey <michaeldgodfrey@gmail.com>
 ## Description: Convert objects into other file formats.
 
-function printd (obj, filename)
+function pr_out = printd (obj, filename)
   ## Convert any object acceptable to disp() into various display formats.
   ## obj is the input object.
   ## filename is the output file (with required suffix).
@@ -79,19 +81,31 @@
   endswitch
   fclose (pf);
   delete (tempf);
-  printf ("%s file %s written\n", opt, filename);
+  pr_out =  sprintf ("%s file %s written\n", opt, filename);
 endfunction
 
 %!demo
-%!  r2 = ["stem step: 10, data: unsorted.\nHinges:    lo: 12, hi: 42\n";...
-%! "   1 | 22118";"   2 | 28";"   3 | 98";"   4 | 244";"   5 | 2"];
+%! r2 = char (
+%! "stem step: 10, data: unsorted.",
+%! "Hinges:    lo: 12, hi: 42"     ,
+%! "   1 | 22118"                  ,
+%! "   2 | 28"                     ,
+%! "   3 | 98"                     ,
+%! "   4 | 244"                    ,
+%! "   5 | 2"                      );
 %! printd (r2, "test_p.txt");
 %! system ("cat test_p.txt");
 %! delete ("test_p.txt");
 
 %!test
-%! r2 = ["stem step: 10, data: unsorted.\nHinges:    lo: 12, hi: 42\n";...
-%! "   1 | 22118";"   2 | 28";"   3 | 98";"   4 | 244";"   5 | 2"];
+%! r2 = char (
+%! "stem step: 10, data: unsorted.",
+%! "Hinges:    lo: 12, hi: 42"     ,
+%! "   1 | 22118"                  ,
+%! "   2 | 28"                     ,
+%! "   3 | 98"                     ,
+%! "   4 | 244"                    ,
+%! "   5 | 2"                      );
 %! printd (r2, "test_p.txt");
 %! r4 = fileread ("test_p.txt");
 %! delete ("test_p.txt");
--- a/scripts/plot/stemleaf.m
+++ b/scripts/plot/stemleaf.m
@@ -20,48 +20,82 @@
 
 
 ## -*- texinfo -*-
-## @deftypefn  {Function File} {} stemleaf (@var{x})
-## @deftypefnx {Function File} {@var{plot} =} stemleaf (@var{x}, @var{opt})
-##
+## @deftypefn  {Function File} {} stemleaf (@var{x}, @var{caption})
+## @deftypefnx {Function File} {} stemleaf (@var{x}, @var{caption}, @var{stem_sz})
+## @deftypefnx {Function File} {@var{plotstr} =} stemleaf (@dots{})
 ## Compute and display a stem and leaf plot of the vector @var{x}.
 ##
-## The @var{x} vector is converted to integer by @var{x} = @code{fix} (@var{x}). 
-## If an output argument is provided, the plot is returned as
-## an array of strings.  The first element is the heading
-## followed by an element for each stem.
-## The default stem step is 10.  
-## The @var{x} vector should be integers.  It will be treated so that
-## the last digit is the leaf value and the other digits are
-## the stems.
-## The leaf digits are not sorted.  If sorted leaf values
-## are wanted, use @code{sort} (@var{x}) before calling @code{stemleaf} (@var{x}).
-## The stem and leaf plot is described in: Ch. 3,
-## Exploratory Data Analysis by J. W. Tukey, Addison-Wesley, 1977.
+## The input @var{x} should be a vector of integers.  Any non-integer values
+## will be converted to integer by @code{@var{x} = fix (@var{x})}.  By default
+## each element of @var{x} will be plotted with the last digit of the element
+## as a leaf value and the remaining digits as the stem.  For example, 123
+## will be plotted with the stem @samp{12} and the leaf @samp{3}.  The second
+## argument, @var{caption}, should be a character array which provides a
+## description of the data.  It is included as a heading for the output.
+##
+## The optional input @var{stem_sz} sets the width of each stem.
+## The stem width is determined by @code{10^(@var{stem_sz} + 1)}.
+## The default stem width is 10.
+##
+## The output of @code{stemleaf} is composed of two parts: a
+## "Fenced Letter Display," followed by the stem-and-leaf plot itself.
+## The Fenced Letter Display is described in @cite{Exploratory Data Analysis}.
+## Briefly, the entries are as shown:
+##
+## @example
+## @group
+##
+##         Fenced Letter Display
+##   #% nx|___________________          nx = numel (x)
+##   M% mi|       md         |          mi median index, md median
+##   H% hi|hl              hu|   hs     hi lower hinge index, hl,hu hinges, hs h_spread
+##   1    |x(1)         x(nx)|          x(1), x(nx) first and last data value
+##              _______   
+##        ______|step |_______          step 1.5*h_spread
+##       f|ifl            ifh|          inner fence, lower and higher
+##        |nfl            nfh|          # data points within fences
+##       F|ofl            ofh|          outer fence, lower and higher
+##        |nFl            nFh|          # data points outside outer fences
+## @end group
+## @end example
+##
+## The stem-and-leaf plot shows on each line the stem value followed by the
+## string made up of the leaf digits.  If the @var{stem_sz} is not 1 the
+## successive leaf values are separated by ",".
+##
+## With no return argument, the plot is immediately displayed.  If an output
+## argument is provided, the plot is returned as an array of strings. 
+##
+## The leaf digits are not sorted.  If sorted leaf values are desired, use
+## @code{@var{xs} = sort (@var{x})} before calling @code{stemleaf (@var{xs})}.
+##
+## The stem and leaf plot and associated displays are described in: 
+## Ch. 3, @cite{Exploratory Data Analysis} by J. W. Tukey, Addison-Wesley, 1977.
 ## @seealso{hist, printd}
 ## @end deftypefn
 
 ## Author: Michael D. Godfrey <michaeldgodfrey@gmail.com>
 ## Description: Compute stem and leaf plot
 
-function varargout = stemleaf (x, stem_unit)
-  ## Compute and display a stem and leaf plot of the vector x. The x
-  ## vector is converted to integer by x = fix(x). If an output argument
+function plotstr = stemleaf (x, caption, stem_sz)
+  ## Compute and display a stem and leaf plot of the vector x.  The x
+  ## vector is converted to integer by x = fix(x).  If an output argument
   ## is provided, the plot is returned as an array of strings.  The
   ## first element is the heading followed by an element for each stem.
   ##
-  ## The default stem step is 10.  If stem_unit is provided the stem
-  ## step is set to: 10^(stem_unit+1) The x vector should be integers.
+  ## The default stem step is 10.  If stem_sz is provided the stem
+  ## step is set to: 10^(stem_sz+1).  The x vector should be integers.
   ## It will be treated so that the last digit is the leaf value and the
   ## other digits are the stems.
   ##
   ## When we first implemented stem and leaf plots in the early 1960's
   ## there was some discussion about sorting vs. leaving the leaf
-  ## entries in the original order in the data. We decided in favor or
-  ## sorting the leaves for most purposes. This is the choice
+  ## entries in the original order in the data.  We decided in favor of
+  ## sorting the leaves for most purposes.  This is the choice
   ## implemented in the SNAP/IEDA system that was written at that time.
   ##
-  ## SNAP/IEDA and particularly its stem and leaf plotting were further
-  ## developed by Hale Trotter, David Hoagland (at Princeton and MIT)
+  ## SNAP/IEDA, and particularly its stem and leaf plotting, were further
+  ## developed by Hale Trotter, David Hoagland (at Princeton and MIT),
   ## and others.
   ##
   ## Tukey, in EDA, generally uses unsorted leaves.  In addition, he
@@ -72,13 +106,13 @@
   ##
   ## I doubt if providing other options is worthwhile.  The code can
   ## quite easily be modified to provide specific display results.  Or,
-  ## the returned output string can be edited. The returned output is an
+  ## the returned output string can be edited.  The returned output is an
   ## array of strings with each row containing a line of the plot
   ## preceded by the lines of header text as the first row.  This
   ## facilitates annotation.
   ##
   ## Note that the code has some added complexity due to the need to
-  ## distinguish both + and - 0 stems. The +- stem values are essential
+  ## distinguish both + and - 0 stems.  The +- stem values are essential
   ## for all plots which span 0. After dealing with +-0 stems, the added
   ## complexity of putting +- data values in the correct stem is minor,
   ## but the sign of 0 leaves must be checked.  And, the cases where the
@@ -87,232 +121,473 @@
   ## The fact that IEEE floating point defines +- 0 helps make this
   ## easier.
   ##
-  ##
   ## Michael D. Godfrey   January 2013
 
-  ## More could be implemented for better data scaling. And, of course,
+  ## More could be implemented for better data scaling.  And, of course,
   ## other options for the kinds of plots described by Tukey could be
-  ## provided. This may best be left to users.
+  ## provided.  This may best be left to users.
 
-  if (nargin >= 2)
-    stem_step = 10^(stem_unit+1);
-  else
-    stem_step = 10;
+  if (nargin < 2 || nargin > 3)
+    print_usage ();
   endif
-  if (any (x == int32 (x)) == 0)
-    printf ('Input vector truncated to integer values.\n')
-    x = fix (x);
+
+  if (! isvector (x))
+    error ("stemleaf: X must be a vector");
   endif
 
-  ## Avoid use of int32 due to:
+  if (isinteger (x))
+    ## Avoid use of integers because rounding rules do not use fix():
+    ## Example: floor (int32 (-44)/10) == -4, floor (int32 (-46)/10) = -5 !!!
+    x = single (x);
+  elseif (isfloat (x))
+    xint = fix (x);
+    if (any (x != xint))
+      warning ("stemleaf: X truncated to integer values");
+      x = xint;
+    endif
+  else
+    error ("stemleaf: X must be a numeric vector");
+  endif
 
-  ##  floor (int32 (-44)/10) == -4 and floor (int32 (-46)/10) = -5 !!!
-  ##  x  = sort (fix (x));  % User can decide about sorting x.
-  ##  x  = fix (x);
-  ##  %Adjust scale if too small.
-  ##  while any(abs((fix(x) - x)) >= abs(x/100))
-  ##    x =10*x;
-  ##  endwhile
+  if (! ischar (caption))
+    error ("stemleaf: CAPTION must be a character array");
+  endif
+
+  if (nargin == 2)
+    stem_step = 10;
+  else
+    if (isscalar (stem_sz) && stem_sz >= 0 && isreal (stem_sz))
+      stem_sz = fix (stem_sz);
+      stem_step = 10^(stem_sz+1);
+    else
+      error ("stemleaf: STEM_SZ must be a real integer >= 0");
+    endif
+  endif
 
   ## Note that IEEE 754 states that -+ 0 should compare equal. This has
   ## led to C sort (and therefore Octave) treating them as equal.  Thus,
-  ## sort([ -1 0 -0 1]) yields: -1 0 -0 1. and, sort([-1 -0 0 1])
-  ## yields: -1 -0 0 1. This means that stem-and-leaf plotting cannot
+  ## sort([-1 0 -0 1]) yields [-1 0 -0 1], and sort([-1 -0 0 1])
+  ## yields: [-1 -0 0 1].  This means that stem-and-leaf plotting cannot
   ## rely on sort to order the data as needed for display.
+  ## This also applies to min()/max() so these routines can't be relied
+  ## upon if the max or min is -+ 0.
+
+  ## Compute hinges and fences based on ref: EDA pgs. 33 and 44.
+  ## Note that these outlier estimates are meant to be "distribution free".
 
-  if (all((sort(x) == x)) == 1)
-    hsort = 'sorted.';
-  else
-    hsort = 'unsorted.';
-  endif
-  nx = max (size (x));
+  nx = numel (x);
+  xs = sort (x);                # Note that sort preserves -0
+  mdidx = fix ((nx + 1)/2);     # median index
+  hlidx = fix ((mdidx + 1)/2);  # lower hinge index
+  huidx = fix (nx + 1 - hlidx); # upper hinge index
+  md = xs(mdidx);               # median
+  hl = xs(hlidx);               # lower hinge
+  hu = xs(huidx);               # upper hinge
+  h_spread = hu - hl;           # h_spread: difference between hinges
+  step = 1.5*h_spread;          # step: 1.5 * h_spread
+  i_fence_l = hl - step;        # inner fences: outside hinges + step
+  o_fence_l = hl - 2*step;      # outer fences: outside hinges + 2*step
+  i_fence_h = hu + step;
+  o_fence_h = hu + 2*step;
+  n_out_l   = sum (x<i_fence_l) - sum (x<o_fence_l);
+  n_out_h   = sum (x>i_fence_h) - sum (x>o_fence_h);
+  n_far_l   = sum (x<o_fence_l);
+  n_far_h   = sum (x>o_fence_h);
+
+  # display table similar to that on pg. 33
+  plot_out = sprintf ("       Data: %s", caption);
+  plot_out = [plot_out; sprintf(" ")];
+  plot_out = [plot_out; sprintf("         Fenced Letter Display")];
+  plot_out = [plot_out; sprintf(" ")];
+  plot_out = [plot_out; sprintf("     #%3d|___________________", nx)];
+  plot_out = [plot_out; sprintf("     M%3d|       %5d      |", mdidx, md)];
+  plot_out = [plot_out; sprintf("     H%3d|%5d        %5d|   %d", hlidx, hl, hu, h_spread)];
+  plot_out = [plot_out; sprintf("     1   |%5d        %5d|", xs(1), xs(nx))];
+  plot_out = [plot_out; sprintf("               _______")];   
+  plot_out = [plot_out; sprintf("         ______|%5d|_______",step)];
+  plot_out = [plot_out; sprintf("        f|%5d        %5d|", i_fence_l, i_fence_h)];
+  plot_out = [plot_out; sprintf("         |%5d        %5d|  out", n_out_l, n_out_h)];
+  plot_out = [plot_out; sprintf("        F|%5d        %5g|", o_fence_l, o_fence_h)];
+  plot_out = [plot_out; sprintf("         |%5d        %5d|  far",n_far_l,n_far_h)];
+  plot_out = [plot_out; " "];
+
   ## Determine stem values
-  if (min(x) < 0)
-    if (signbit(max(x)) == 0)     # max is positive
-      stems = [fix(min(x)/stem_step)-1 : -1 -0];
-      stems = [stems 0 : fix(max(x)/stem_step)+1 ];
-    else
-      if (max(x) < 0)
-        stems = [(fix(min(x)/stem_step)-1) : fix(max(x)/stem_step)];
+  min_x = min (x);
+  max_x = max (x);
+  if (min_x > 0)      # all stems > 0
+    stems = [fix(min(x)/stem_step) : (fix(max(x)/stem_step)+1)];
+  elseif (max_x < 0)  # all stems < 0
+    stems = [(fix(min_x/stem_step)-1) : fix(max_x/stem_step)];
+  elseif (min_x < 0 && max_x > 0)  # range crosses 0
+    stems = [(fix(min_x/stem_step)-1) : -0, 0 : fix(max_x/stem_step)+1 ];
+  else   # one endpoint is a zero which may be +0 or -0
+    if (min_x == 0)
+      if (any (x == 0 & signbit (x)))
+        min_x = -0;
       else
-        stems = [(fix(min(x)/stem_step)-1) : -1 -0];
-        stems = [stems 0 : fix(max(x)/stem_step)];
+        min_x = +0;
       endif
     endif
-  else                            # All stems are > 0
-    stems = [fix(min(x)/stem_step) : fix(max(x)/stem_step) + 1];
-  endif
-  ##stems
-  ##x
-  nstems = max(size(stems));
-  ## compute hinges at +- 1.5 * quartiles
-  ## this requires sorted data!
-  xs = sort (x);                   # Note that sort preserves -0
-  threeh = 1.5;
-  two    = 2.0;
-  j  = idivide(nx, 4, "fix") + 1;  # Use F95 truncation.
-  k  = nx - j + 1;
-  hl = xs (j);
-  hu = xs (k);
-  if ( (nx + 1) ==  (4 * j) ) 
-    hl = (xs (j + 1) + hl) / two;
-    hu = (xs (k - 1) + hu) / two;
+    if (max_x == 0)
+      if (any (x == 0 & ! signbit (x)))
+        max_x = +0;
+      else
+        max_x = -0;
+      endif
+    endif
+    stems = [];
+    if (signbit (min_x))
+      stems = [(fix(min_x/stem_step)-1) : -0];
+    endif
+    if (! signbit (max_x))
+      stems = [stems, 0 : fix(max_x/stem_step)+1 ];
+    endif
   endif
 
-  ##     ::::::::  determine h-spread (dh) and fences  ::::::::
-  dh = hu - hl;
-  fu = hu + threeh * dh;
-  fl = hl - threeh * dh;
-
-  ##     ::::::::  find value adjacent to lower fence  ::::::::
-  for i = 1:j
-    if ( xs (i) >= fl ) 
-      continue; 
-    endif
-  endfor
-  ilow = i;
-  xlo = xs (ilow);
-
-  ##     :::::::: find value adjacent to upper fence  ::::::::
-  for  i = 1:j
-    if ( xs (nx -i + 1) <= fu )
-      continue;
-    endif
-  endfor
-
-  ihi = nx - i + 1;
-  xhi = xs (ihi);
-
-  ## Heading for output:
-  plot_out = "";
-  plot_out = [plot_out sprintf("stem step: %i, data: %s\nHinges:    lo: %g, hi: %g\n",
-                               stem_step, hsort, xlo, xhi)];
-
-  ## This may appear to be a good place to use vectorization using the
-  ## stem and data arrays but the necessary special case treatment of 0
-  ## and -0 seems to result in little reduction of complexity, and since
-  ## this algorithm is for small data vectors only there would be
-  ## practically no performance improvement.
-
+  ## Vectorized version provided by Rik Wehbring (rik@octave.org)
   ## Determine leaves for each stem:
-  for kx = 2:nstems
-    line_out = "";
-    steml    = "";
-    ## Build a string of leaf digits for stem(kx) if stem(kx) <= 0, or
-    ## stem(kx-1) if stem(kx) > 0
+  new_line  = 1;
+  for kx = 2: numel (stems)
 
-    ## stems -+ 0 have to be handled as special cases.
-    for xi = 1:nx
-      if(signbit(stems(kx)) != 0)
-        t1 = ((x(xi) <= stems(kx)*10) && (x(xi) > (stems(kx-1)*10)));
-      else
-        t1 = ((x(xi) < stems(kx)*10) && (x(xi) >= (stems(kx-1)*10)));
-      endif
-      ## Special tests for stem -+ 0
-      if ((stems(kx) == 0) && signbit(stems(kx)) && (x(xi) == 0)) && !signbit(x(xi))
-        t1 = 0;
-      endif
-      if ((stems(kx-1) == 0) && !signbit(stems(kx-1)) && (x(xi) == 0)) && signbit(x(xi))
-        t1 = 0;
-      endif
-      ## Create line as a string
-      if t1
-        if (stems(kx) <= 0)
-          xz =  abs (x(xi) - stems(kx)*10);
-        else
-          xz =  abs (x(xi) - stems(kx-1)*10);
-        endif
-        if ((stems(kx) == 0) && signbit(stems(kx)))
-          steml = [steml sprintf("%d", abs(x(xi) - stems(kx)*10))];
-        else
-          steml = [steml sprintf("%d", xz)];
-        endif
-      endif    %  t1
-    endfor    % xi = 1:nx
-
-    ## Set correct -0
-    if ((stems(kx) == 0) && signbit(stems(kx)))
-      line_out = [line_out sprintf("  -0 | %s",  steml)];  % -0 stem.
+    stem_sign = signbit (stems(kx));
+    if (stems(kx) <= 0)
+      idx = ((x <= stems(kx)*stem_step) & (x > (stems(kx-1)*stem_step))
+              & (signbit (x) == stem_sign));
+      xlf = abs (x(idx) - stems(kx)*stem_step);
     else
-      if( stems(kx) < 0)
-        line_out = [line_out sprintf("%4d | %s", stems(kx), steml)];
-      else
-        if stems(kx) > 0
-          line_out = [line_out sprintf("%4d | %s", stems(kx-1), steml)];
+      idx = ((x < stems(kx)*stem_step) & (x >= (stems(kx-1)*stem_step))
+              & (signbit (x) == stem_sign));
+      xlf = abs (x(idx) - stems(kx-1)*stem_step);
+    endif
+    ## Convert leaves to a string
+    if (stem_step == 10)
+      lf_str = sprintf ("%d", xlf);
+    else
+      lf_str = "";
+      if (! isempty (xlf))
+        lf_str = sprintf ("%d", xlf(1));
+        if (numel (xlf) > 1)
+          lf_str = [lf_str sprintf(",%d", xlf(2:end))];
         endif
       endif
     endif
-    plot_out = [plot_out; line_out];
-  endfor    % kx = 2:nstems
+
+    ## Set correct -0
+    if (stems(kx) == 0 && signbit (stems(kx)))
+      line = sprintf ("  -0 | %s",  lf_str);  # -0 stem.
+    elseif (stems(kx) < 0)
+      line = sprintf ("%4d | %s", stems(kx), lf_str);
+    elseif (stems(kx) > 0)
+      line = sprintf ("%4d | %s", stems(kx-1), lf_str);
+    else
+      line = "";
+    endif
+
+    if (! isempty (lf_str) || stems(kx) == 0 || stems(kx-1) == 0)
+      plot_out = [plot_out; line];
+      new_line = 1;
+    else
+      if (new_line == 1) 
+        plot_out = [plot_out; "     :"];  # just print one : if no leaves
+        new_line = 0;
+      endif
+    endif
+
+  endfor    # kx = 2: numel (stems)
+
   if (nargout == 0)
-    rows = size (plot_out)(1);
-    cols = size (plot_out)(2);
-    for k = 1:rows
-      printf("%s\n", plot_out(k,1:cols));
-    endfor
+    disp (plot_out);
   else
-    varargout{1} = plot_out;
+    plotstr = plot_out;
   endif
+
 endfunction
 
+
 %!demo
 %! ## Unsorted plot:
 %! x = [-22 12 -28 52  39 -2 12 10 11 11 42 38 44 18 44];
-%! stemleaf (x, 0);
+%! stemleaf (x, "Unsorted plot");
 
 %!demo
 %! ## Sorted leaves:
 %! x = [-22 12 -28 52  39 -2 12 10 11 11 42 38 44 18 44];
-%! y = sort(x);
-%! stemleaf (y, 0);
+%! y = sort (x);
+%! stemleaf (y, "Sorted leaves");
 
 %!demo
-%! ## More data (sorted)
-%! x = [-22 12 -28 52  39 -2 12 10 11 11 42 38 44 18 44 37 113 124 37 48 127 36 29 31 125 139 131 115 105 132 104 123 35 113 122 42 117 119 58 109 23 105 63 27 44 105 99 41 128 121 116 125 32 61 37 127 29 113 121 58 114 126 53 114 96 25 109 7 31 141 46 -13 71 43 117 116 27 7 68 40 31 115 124 42 128 52 71 118 117 38 27 106 33 117 116 111 40 119 47 105 57 122 109 124 115 43 120 43 27 27 18 28 48 125 107 114 34 133 45 120 30 127 31 116 146 21 23 30 10 20 21 30 0 100 110 1 20 0 ];
-%! y = sort(x);
-%! stemleaf (y, 0);
+%! ## Sorted leaves (large dataset):
+%! x = [-22 12 -28 52  39 -2 12 10 11 11 42 38 44 18 44 37 113 124 37 48 127  \
+%!      36 29 31 125 139 131 115 105 132 104 123 35 113 122 42 117 119 58 109 \
+%!      23 105 63 27 44 105 99 41 128 121 116 125 32 61 37 127 29 113 121 58  \
+%!      114 126 53 114 96 25 109 7 31 141 46 -13 71 43 117 116 27 7 68 40 31  \
+%!      115 124 42 128 52 71 118 117 38 27 106 33 117 116 111 40 119 47 105 57\
+%!      122 109 124 115 43 120 43 27 27 18 28 48 125 107 114 34 133 45 120 30 \
+%!      127 31 116 146 21 23 30 10 20 21 30 0 100 110 1 20 0];
+%! y = sort (x);
+%! stemleaf (y, "Sorted leaves (large dataset)");
+
+%!demo
+%! ## Gaussian leaves:
+%! x = fix (30 * randn (300,1));
+%! stemleaf (x);
 
 %!test
 %! ## test minus to plus
-%! x = [-22 12 -28 52  39 -2 12 10 11 11 42 38 44 18 44 37 113 124 37 48 127 36 29 31 125 139 131 115 105 132 104 123 35 113 122 42 117 119 58 109 23 105 63 27 44 105 99 41 128 121 116 125 32 61 37 127 29 113 121 58 114 126 53 114 96 25 109 7 31 141 46 -13 71 43 117 116 27 7 68 40 31 115 124 42 128 52 71 118 117 38 27 106 33 117 116 111 40 119 47 105 57 122 109 124 115 43 120 43 27 27 18 28 48 125 107 114 34 133 45 120 30 127 31 116 146 21 23 30 10 20 21 30 0 100 110 1 20 0 ];
-%! x = sort(x);
-%! r2 = ["stem step: 10, data: sorted.\nHinges:    lo: 30, hi: 116\n";...
-%! "  -2 | 82";"  -1 | 3";"  -0 | 2";"   0 | 00177";...
-%! "   1 | 00112288";"   2 | 001133577777899";...
-%! "   3 | 000111123456777889";"   4 | 00122233344456788";...
-%! "   5 | 223788";"   6 | 138";"   7 | 11";"   8 | ";...
-%! "   9 | 69";"  10 | 04555567999";"  11 | 0133344455566667777899";...
-%! "  12 | 0011223444555677788";"  13 | 1239";"  14 | 16"];
-%! rx = stemleaf (x, 0);
-%! assert(r2, rx);
+%! x = [-22 12 -28 52  39 -2 12 10 11 11 42 38 44 18 44 37 113 124 37 48 127  \
+%!      36 29 31 125 139 131 115 105 132 104 123 35 113 122 42 117 119 58 109 \
+%!      23 105 63 27 44 105 99 41 128 121 116 125 32 61 37 127 29 113 121 58  \
+%!      114 126 53 114 96 25 109 7 31 141 46 -13 71 43 117 116 27 7 68 40 31  \
+%!      115 124 42 128 52 71 118 117 38 27 106 33 117 116 111 40 119 47 105 57\
+%!      122 109 124 115 43 120 43 27 27 18 28 48 125 107 114 34 133 45 120 30 \
+%!      127 31 116 146 21 23 30 10 20 21 30 0 100 110 1 20 0];
+%! x = sort (x);
+%! rexp = char (
+%! "       Data: test minus to plus"    ,
+%! " "                                  ,
+%! "         Fenced Letter Display"     ,
+%! " "                                  ,
+%! "     #138|___________________"      ,     
+%! "     M 69|          52      |"      ,     
+%! "     H 35|   30          116|   86" ,
+%! "     1   |  -28          146|"      ,
+%! "               _______"             ,
+%! "         ______|  129|_______"      ,
+%! "        f|  -99          245|"      ,     
+%! "         |    0            0|  out" ,
+%! "        F| -228          374|"      ,
+%! "         |    0            0|  far" ,
+%! " "                                  ,
+%! "  -2 | 82"                          ,
+%! "  -1 | 3"                           ,
+%! "  -0 | 2"                           ,
+%! "   0 | 00177"                       ,
+%! "   1 | 00112288"                    ,
+%! "   2 | 001133577777899"             ,
+%! "   3 | 000111123456777889"          ,
+%! "   4 | 00122233344456788"           ,
+%! "   5 | 223788"                      ,
+%! "   6 | 138"                         ,
+%! "   7 | 11"                          ,
+%! "     : "                            ,
+%! "   9 | 69"                          ,
+%! "  10 | 04555567999"                 ,
+%! "  11 | 0133344455566667777899"      ,
+%! "  12 | 0011223444555677788"         ,
+%! "  13 | 1239"                        ,
+%! "  14 | 16"                          );
+%! r = stemleaf (x, "test minus to plus", 0);
+%! assert (r, rexp);
+
 %!test
 %! ## positive values above 0
-%! x = [22 12 28 52  39 12 11 11 42 38 44 18 44 ];
-%! r2 = ["stem step: 10, data: unsorted.\nHinges:    lo: 12, hi: 42\n";...
-%! "   1 | 22118";"   2 | 28";"   3 | 98";"   4 | 244";"   5 | 2"];
-%! rx = stemleaf (x, 0);
-%! assert(r2, rx);
+%! x = [5 22 12 28 52 39 12 11 11 42 38 44 18 44];
+%! rexp = char (
+%! "       Data: positive values above 0",
+%! " "                                   ,
+%! "         Fenced Letter Display"      ,
+%! " "                                   ,
+%! "     # 14|___________________"       ,     
+%! "     M  7|          22      |"       ,     
+%! "     H  4|   12           42|   30"  ,
+%! "     1   |    5           52|"       ,
+%! "               _______"              ,
+%! "         ______|   45|_______"       ,
+%! "        f|  -33           87|"       ,     
+%! "         |    0            0|  out"  ,
+%! "        F|  -78          132|"       ,
+%! "         |    0            0|  far"  ,
+%! " "                                   ,
+%! "   0 | 5"                            ,
+%! "   1 | 22118"                        ,
+%! "   2 | 28"                           ,
+%! "   3 | 98"                           ,
+%! "   4 | 244"                          ,
+%! "   5 | 2"                            );
+%! r = stemleaf (x, "positive values above 0");
+%! assert (r, rexp);
+
 %!test
 %! ## negative values below 0
-%! x = [22 12 28 52  39 12 11 11 42 38 44 18 44];
+%! x = [5 22 12 28 52 39 12 11 11 42 38 44 18 44];
 %! x = -x;
-%! r2 = ["stem step: 10, data: unsorted.\nHinges:    lo: -42, hi: -12\n";...
-%! "  -5 | 2";"  -4 | 244";"  -3 | 98";"  -2 | 28";"  -1 | 22118"];
-%! rx = stemleaf (x, 0);
-%! assert(r2, rx);
+%! rexp = char (
+%! "       Data: negative values below 0",
+%! " "                                   ,
+%! "         Fenced Letter Display"      ,
+%! " "                                   ,
+%! "     # 14|___________________"       ,     
+%! "     M  7|         -28      |"       ,     
+%! "     H  4|  -42          -12|   30"  ,
+%! "     1   |  -52           -5|"       ,
+%! "               _______"              ,
+%! "         ______|   45|_______"       ,
+%! "        f|  -87           33|"       ,     
+%! "         |    0            0|  out"  ,
+%! "        F| -132           78|"       ,
+%! "         |    0            0|  far"  ,
+%! " "                                   ,
+%! "  -5 | 2"                            ,
+%! "  -4 | 244"                          ,
+%! "  -3 | 98"                           ,
+%! "  -2 | 28"                           ,
+%! "  -1 | 22118"                        ,
+%! "  -0 | 5"                            );
+%! r = stemleaf (x, "negative values below 0");
+%! assert (r, rexp);
+
 %!test
 %! ## positive values from 0
-%! x = [22 12 28 52  39 2 12 0 11 11 42 38 44 18 44];
-%! r2 = ["stem step: 10, data: unsorted.\nHinges:    lo: 11, hi: 42\n";...
-%! "   0 | 20";"   1 | 22118";"   2 | 28";"   3 | 98";"   4 | 244";"   5 | 2"];
-%! rx = stemleaf (x, 0);
-%! assert(r2, rx);
+%! x = [22 12 28 52 39 2 12 0 11 11 42 38 44 18 44];
+%! rexp = char (
+%! "       Data: positive values from 0",
+%! " "                                  ,
+%! "         Fenced Letter Display"     ,
+%! " "                                  ,
+%! "     # 15|___________________"      ,     
+%! "     M  8|          22      |"      ,     
+%! "     H  4|   11           42|   31" ,
+%! "     1   |    0           52|"      ,
+%! "               _______"             ,
+%! "         ______|   46|_______"      ,
+%! "        f|  -35           88|"      ,     
+%! "         |    0            0|  out" ,
+%! "        F|  -82          135|"      ,
+%! "         |    0            0|  far" ,
+%! " "                                  ,
+%! "   0 | 20"                          ,
+%! "   1 | 22118"                       ,
+%! "   2 | 28"                          ,
+%! "   3 | 98"                          ,
+%! "   4 | 244"                         ,
+%! "   5 | 2"                           );
+%! r = stemleaf (x, "positive values from 0");
+%! assert (r, rexp);
+
 %!test
 %! ## negative values from 0
-%! x = [22 12 28 52  39 2 12 0 11 11 42 38 44 18 44];
+%! x = [22 12 28 52 39 2 12 0 11 11 42 38 44 18 44];
 %! x = -x;
-%! r2 = ["stem step: 10, data: unsorted.\nHinges:    lo: -42, hi: -11\n";...
-%! "  -5 | 2";"  -4 | 244";"  -3 | 98";"  -2 | 28";"  -1 | 22118";"  -0 | 20"];
-%! rx = stemleaf (x, 0);
-%! assert(r2, rx);
+%! rexp = char (
+%! "       Data: negative values from 0",
+%! " "                                  ,
+%! "         Fenced Letter Display"     ,
+%! " "                                  ,
+%! "     # 15|___________________"      ,     
+%! "     M  8|         -22      |"      ,     
+%! "     H  4|  -42          -11|   31" ,
+%! "     1   |  -52            0|"      ,
+%! "               _______"             ,
+%! "         ______|   46|_______"      ,
+%! "        f|  -88           35|"      ,     
+%! "         |    0            0|  out" ,
+%! "        F| -135           82|"      ,
+%! "         |    0            0|  far" ,
+%! " "                                  ,
+%! "  -5 | 2"                           ,
+%! "  -4 | 244"                         ,
+%! "  -3 | 98"                          ,
+%! "  -2 | 28"                          ,
+%! "  -1 | 22118"                       ,
+%! "  -0 | 20"                          );
+%! r = stemleaf (x, "negative values from 0");
+%! assert (r, rexp);
+
+%!test
+%! ## both +0 and -0 present
+%! x = [-9 -7 -0 0 -0];
+%! rexp = char (
+%! "       Data: both +0 and -0 present",
+%! " "                                  ,
+%! "         Fenced Letter Display"     ,
+%! " "                                  ,
+%! "     #  5|___________________"      ,     
+%! "     M  3|           0      |"      ,     
+%! "     H  2|   -7            0|   7"  ,
+%! "     1   |   -9            0|"      ,
+%! "               _______"             ,
+%! "         ______|   10|_______"      ,
+%! "        f|  -17           10|"      ,     
+%! "         |    0            0|  out" ,
+%! "        F|  -28           21|"      ,
+%! "         |    0            0|  far" ,
+%! " "                                  ,
+%! "  -0 | 9700"                        ,
+%! "   0 | 0"                           );
+%! r = stemleaf (x, "both +0 and -0 present");
+%! assert (r, rexp);
 
+%!test
+%! ## both <= 0 and -0 present
+%! x = [-9 -7 0 -0];
+%! rexp = char (
+%! "       Data: both <= 0 and -0 present",
+%! " "                                    ,
+%! "         Fenced Letter Display"       ,
+%! " "                                    ,
+%! "     #  4|___________________"        ,     
+%! "     M  2|          -7      |"        ,     
+%! "     H  1|   -9            0|   9"    ,
+%! "     1   |   -9            0|"        ,
+%! "               _______"               ,
+%! "         ______|   13|_______"        ,
+%! "        f|  -22           13|"        ,     
+%! "         |    0            0|  out"   ,
+%! "        F|  -36           27|"        ,
+%! "         |    0            0|  far"   ,
+%! " "                                    ,
+%! "  -0 | 970"                           ,
+%! "   0 | 0"                             );
+%! r = stemleaf (x, "both <= 0 and -0 present");
+%! assert (r, rexp);
+
+%!test
+%! ##   Example from EDA: Chevrolet Prices pg. 30
+%! x = [150 250 688 695 795 795 895 895 895 1099 1166 1333 1499 1693 1699 1775 1995];
+%! rexp = char (
+%! "       Data: Chevrolet Prices EDA pg.30",
+%! " "                                      ,
+%! "         Fenced Letter Display"         ,
+%! " "                                      ,
+%! "     # 17|___________________"          ,          
+%! "     M  9|         895      |"          ,
+%! "     H  5|  795         1499|   704"    ,
+%! "     1   |  150         1995|"          ,
+%! "               _______"                 ,
+%! "         ______| 1056|_______"          ,
+%! "        f| -261         2555|"          ,
+%! "         |    0            0|  out"     ,
+%! "        F|-1317         3611|"          ,
+%! "         |    0            0|  far"     ,
+%! " "                                      ,
+%! "   1 | 50"                              ,
+%! "   2 | 50"                              ,
+%! "     :"                                 ,
+%! "   6 | 88,95"                           ,
+%! "   7 | 95,95"                           ,
+%! "   8 | 95,95,95"                        ,
+%! "     :"                                 ,
+%! "  10 | 99"                              ,
+%! "  11 | 66"                              ,
+%! "     :"                                 ,
+%! "  13 | 33"                              ,
+%! "  14 | 99"                              ,
+%! "     :"                                 ,
+%! "  16 | 93,99"                           ,
+%! "  17 | 75"                              ,
+%! "     :"                                 ,
+%! "  19 | 95"                              );
+%! r = stemleaf (x, "Chevrolet Prices EDA pg.30", 1);
+%! assert (r, rexp);
+
+## Test input validation
+%!error stemleaf ()
+%!error stemleaf (1, 2, 3, 4)
+%!error <X must be a vector> stemleaf (ones (2,2), "")
+%!warning <X truncated to integer values> tmp = stemleaf ([0 0.5 1],"");
+%!error <X must be a numeric vector> stemleaf ("Hello World", "data")
+%!error <CAPTION must be a character array> stemleaf (1, 2)
+%!error <STEM_SZ must be a real integer> stemleaf (1, "", ones (2,2))
+%!error <STEM_SZ must be a real integer> stemleaf (1, "", -1)
+%!error <STEM_SZ must be a real integer> stemleaf (1, "", 1+i)
+
new file mode 100644
--- /dev/null
+++ b/scripts/testfun/__have_feature__.m
@@ -0,0 +1,34 @@
+## Copyright (C) 2013 John W. Eaton
+##
+## This file is part of Octave.
+##
+## Octave is free software; you can redistribute it and/or modify it
+## under the terms of the GNU General Public License as published by
+## the Free Software Foundation; either version 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
+## <http://www.gnu.org/licenses/>.
+
+## -*- texinfo -*-
+## @deftypefn  {Function File} {} __have_feature__ (feature)
+## Undocumented internal function.
+## @end deftypefn
+
+function retval = __have_feature__ (feature)
+  features = octave_config_info ("features");
+  if (iscellstr (feature))
+    retval = (all (isfield (features, feature))
+              && cellfun (@(x) features.(x), feature));
+  elseif (ischar (feature))
+    retval = isfield (features, feature) && features.(feature);
+  else
+    retval = false;
+  endif
+endfunction
--- a/scripts/testfun/test.m
+++ b/scripts/testfun/test.m
@@ -463,15 +463,16 @@
       ## Strip comment any comment from testif line before looking for features
       __feat_line = strtok (__code(1:__e), '#%'); 
       __feat = regexp (__feat_line, '\w+', 'match');
-      __have_feat = strfind (octave_config_info ("DEFS"), __feat); 
-      if (any (cellfun ("isempty", __have_feat)))
+      __feat = strrep (__feat, "HAVE_", "");
+      __have_feat = __have_feature__ (__feat);
+      if (__have_feat)
+        __istest = 1;
+        __code = __code(__e + 1 : end);
+      else
         __xskip++;
         __istest = 0;
         __code = ""; # Skip the code.
         __msg = sprintf ("%sskipped test\n", __signal_skip);
-      else
-        __istest = 1;
-        __code = __code(__e + 1 : end);
       endif
 
 ### TEST
@@ -679,19 +680,6 @@
   endif
 endfunction
 
-### Test for test for missing features
-%!testif OCTAVE_SOURCE
-%! ## This test should be run
-%! assert (true);
-
-### Disable this test to avoid spurious skipped test for "make check"
-% !testif HAVE_FOOBAR
-% ! ## missing feature. Fail if this test is run
-% ! error ("Failed missing feature test");
-
-### Test for a known failure
-%!xtest error ("This test is known to fail")
-
 ### example from toeplitz
 %!shared msg1,msg2
 %! msg1="C must be a vector";
--- a/test/classes/classes.tst
+++ b/test/classes/classes.tst
@@ -309,13 +309,13 @@
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
 %% Test overloaded vertcat() for the Snork class
-%% See bug #38170 (http://savannah.gnu.org/bugs/?38170)
+%% See bug #38128 (http://savannah.gnu.org/bugs/?38128)
 %!test   s = [s1; s2];  assert (isa (s, 'Snork') && isequal (s.gick, [x1; x2]));
 %!xtest  s = [s1; x2];  assert (isa (s, 'Snork') && isequal (s.gick, [x1; x2]));
 %!xtest  s = [x1; s2];  assert (isa (s, 'Snork') && isequal (s.gick, [x1; x2]));
 
 %% Test overloaded horzcat() for the Snork class
-%% See bug #38170 (http://savannah.gnu.org/bugs/?38170)
+%% See bug #38128 (http://savannah.gnu.org/bugs/?38128)
 %!test   s = [s1 s2];  assert (isa (s, 'Snork') && isequal (s.gick, [x1 x2]));
 %!xtest  s = [s1 x2];  assert (isa (s, 'Snork') && isequal (s.gick, [x1 x2]));
 %!xtest  s = [x1 s2];  assert (isa (s, 'Snork') && isequal (s.gick, [x1 x2]));
--- a/test/range.tst
+++ b/test/range.tst
@@ -72,3 +72,38 @@
 %!assert ([ r ; uint32(z)          ], uint32(expect))
 %!assert ([ r ; uint64(z)          ], uint64(expect))
 
+## Test corner cases of ranges (base and limit)
+
+%!shared r, rrev, rneg
+%! r = -0:3;
+%! rrev = 3:-1:-0;
+%! rneg = -3:-0;
+
+%!assert (full (r), [-0 1 2 3])
+%!assert (signbit (full (r)), logical ([1 0 0 0]))
+%!assert (r(1), -0)
+%!assert (signbit (r(1)), true)
+%!assert (signbit (r(1:2)), logical ([1 0]))
+%!assert (signbit (r(2:-1:1)), logical ([0 1]))
+%!assert (signbit (r([2 1 1 3])), logical ([0 1 1 0]))
+
+%!assert (full (rrev), [3 2 1 -0])
+%!assert (signbit (full (rrev)), logical ([0 0 0 1]))
+%!assert (rrev(4), -0)
+%!assert (signbit (rrev(4)), true)
+%!assert (signbit (rrev(3:4)), logical ([0 1]))
+%!assert (signbit (rrev(4:-1:3)), logical ([1 0]))
+%!assert (signbit (rrev([1 4 4 2])), logical ([0 1 1 0]))
+
+%!assert (min (r), -0)
+%!assert (signbit (min (r)), true)
+%!assert (min (rrev), -0)
+%!assert (signbit (min (rrev)), true)
+
+%!assert (max (rneg), -0)
+%!assert (signbit (max (rneg)), true)
+
+%!assert (sort (r, "descend"), [3 2 1 -0])
+%!assert (signbit (sort (r, "descend")), logical ([0 0 0 1]))
+%!assert (signbit (sort (rrev, "ascend")), logical ([1 0 0 0]))
+