changeset 22156:187b6727c75e

build doc-cache without running Octave (bug #48508) * mk_doc_cache.m: Delete. * doc/interpreter/mk-doc-cache.pl: New script, replaces mk_doc_cache.m. * doc/interpreter/module.mk: Update file lists. (doc/interpreter/doc-cache): Use perl script to generate to aid in cross builds. * libinterp/op-kw-docs: New file. * libinterp/module.mk: Update. (libinterp/DOCSTRINGS): Also include info from op-kw-docs. * pt-arg-list.cc (Fend): Include info in docstring about use of end as a language keyword. (install-built-in-docstrings): Depend on libinterp/DOCSTRINGS. Simplify rule now that libinterp/DOCSTRINGS is always generated in the build directory.
author John W. Eaton <jwe@octave.org>
date Thu, 21 Jul 2016 18:11:06 -0400
parents 289409b2992d
children c5842206aaea
files doc/interpreter/mk-doc-cache.pl doc/interpreter/mk_doc_cache.m doc/interpreter/module.mk libinterp/corefcn/help.cc libinterp/module.mk libinterp/op-kw-docs libinterp/parse-tree/pt-arg-list.cc
diffstat 7 files changed, 880 insertions(+), 154 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/interpreter/mk-doc-cache.pl	Thu Jul 21 18:11:06 2016 -0400
@@ -0,0 +1,182 @@
+#!/usr/bin/perl -w
+#
+# Copyright (C) 2016 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/>.
+
+# This script is based on the old mk_doc_cache.m file.
+
+use File::Temp qw(tempfile);
+
+## Validate program call.
+
+die "usage: mk_doc_cache OUTPUT-FILE SRCDIR MACRO-FILE ... -- DOCSTRINGS-FILE ..." if (@ARGV < 3);
+
+$makeinfo_command = "makeinfo --no-headers --no-warn --force --no-validate --fill-column=1024";
+
+$output_file = shift (@ARGV);
+$top_srcdir = shift (@ARGV);
+
+## Constant patterns.
+
+$doc_delim = "\x{1d}";
+$doc_delim_pat = qr/^\x{1d}/;
+$tex_delim_pat = qr/\Q-*- texinfo -*-\E/;
+$private_name_pat = qr/^__.+__/;
+
+$text = "";
+
+$macro_file = 1;
+
+foreach $arg (@ARGV)
+{
+  if ($arg eq "--")
+    {
+      $macro_file = 0;
+      next;
+    }
+
+  $file = $arg;
+
+  ## DOCSTRINGS files may exist in the current (build) directory or in
+  ## the source directory when building from a release.
+
+  $file_srcdir = "$top_srcdir/$file";
+
+  open (FH, $file) or open (FH, $file_srcdir)
+    or die "Unable to open $file or $file_srcdir\n";
+
+  $in_header = 1;
+
+  while (<FH>)
+    {
+      if ($macro_file)
+        {
+          ## Copy contents verbatim.
+
+          $text .= $_;
+        }
+      else
+        {
+          if ($in_header && /$doc_delim_pat/)
+            {
+              $in_header = 0;
+            }
+
+          next if ($in_header);
+
+          next if (/$tex_delim_pat/);
+
+          ## Escapes for symbol names.
+
+          s/$doc_delim_pat(([#%]|)[{}]|@)/$doc_delim@$1/;
+          $text .= $_;
+        }
+    }
+}
+
+$text .= $doc_delim;
+
+($fh, $file) = tempfile (UNLINK => 1);
+print $fh "$text";
+close ($fh);
+
+$cmd = "$makeinfo_command $file";
+open (CMD, "-|", $cmd) or die "Unable to start makeinfo command $cmd\n";
+$formatted_text = "";
+while (<CMD>)
+{
+  $formatted_text .= $_;
+}
+close (CMD);
+
+if (! $formatted_text)
+{
+  die "makeinfo produced no output!\n";
+}
+
+@formatted = ();
+
+$beg_idx = index ($formatted_text, $doc_delim);
+while ($beg_idx >= 0)
+{
+  $end_idx = index ($formatted_text, $doc_delim, $beg_idx+1);
+  if ($end_idx < 1)
+    {
+      $beg_idx = -1;
+      next;
+    }
+  $block = substr ($formatted_text, $beg_idx+1, $end_idx-$beg_idx-1);
+  $beg_idx = $end_idx;
+
+  ($symbol, $doc) = split (/[\r\n]/, $block, 2);
+
+  next if (length ($symbol) > 2 && $symbol =~ m/$private_name_pat/);
+
+  $doc =~ s/^[\r\n]+//;
+  next if (! $doc);
+
+  ($tmp = $doc) =~ s/^[\r\n]*  *-- .*[\r\n]//mg;
+  next if (! $tmp);
+
+  ($first_sentence = $tmp) =~ s/(\.|[\r\n][\r\n]).*/$1/s;
+  $first_sentence =~ s/([\r\n]| {2,})/ /g;
+  $first_sentence =~ s/   *$/ /g;
+  $first_sentence =~ s/^ +//;
+
+  push (@formatted, [($symbol, $doc, $first_sentence)]);
+}
+
+$num = @formatted;
+
+print_preamble ($output_file, $num);
+
+foreach $elt (@formatted)
+{
+  $symbol = $elt->[0];
+  $doc = $elt->[1];
+  $first_sentence = $elt->[2];
+
+  print_element ($symbol);
+  print_element ($doc);
+  print_element ($first_sentence);
+  print "\n";
+}
+
+sub print_preamble
+{
+  my ($output_file, $num) = @_;
+
+  print "# $output_file created by mk-doc-cache.pl\n";
+  print "# name: cache\n";
+  print "# type: cell\n";
+  print "# rows: 3\n";
+  print "# columns: $num\n";
+}
+
+sub print_element
+{
+  my ($str) = @_;
+
+  $len = length ($str);
+
+  print "# name: <cell-element>\n";
+  print "# type: sq_string\n";
+  print "# elements: 1\n";
+  print "# length: $len\n";
+  print "$str\n\n\n";
+}
--- a/doc/interpreter/mk_doc_cache.m	Sat Jul 16 14:03:34 2016 +1000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,143 +0,0 @@
-## Copyright (C) 2009-2015 John W. Eaton
-##
-## This program 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.
-##
-## This program 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 this program; see the file COPYING.  If not, see
-## <http://www.gnu.org/licenses/>.
-
-args = argv ();
-
-if (nargin < 3)
-  error ("usage: mk_doc_cache OUTPUT-FILE SRCDIR DOCSTRINGS-FILE ...");
-endif
-
-output_file = args{1};
-top_srcdir = args{2};
-docstrings_files = args(3:end);
-
-## Special character used as break between DOCSTRINGS
-doc_delim = char (0x1d);
-
-## Read the contents of all the DOCSTRINGS files into TEXT.
-## It is more efficient to fork to shell for makeinfo only once on large data
-
-nfiles = numel (docstrings_files);
-text = cell (1, nfiles);
-for i = 1:nfiles
-  file = docstrings_files{i};
-  ## DOCSTRINGS files may exist in the current (build) directory or in the
-  ## source directory when building from a release.
-  fid = fopen (file, "r");
-  if (fid < 0)
-    fid = fopen (fullfile (top_srcdir, file), "r");
-  endif
-  if (fid < 0)
-    error ("unable to open %s for reading", file);
-  else
-    tmp = fread (fid, Inf, "*char")';
-    if (isempty (strfind (tmp, doc_delim)))
-      ## No delimiter, copy verbatim (this is the case for the file
-      ## containing macro definitions, for example).
-      text{i} = tmp;
-    else
-      ## Strip off header lines
-      [~, text{i}] = strtok (tmp, doc_delim);
-    endif
-  endif
-endfor
-text = [text{:}];
-
-## Strip Texinfo marker
-text = regexprep (text, "-\\*- texinfo -\\*-[ \t]*[\r\n]*", "");
-
-## Add keywords and operators
-other_docstrings = [__keywords__; __operators__];
-for i = 1 : numel (other_docstrings)
-  name = other_docstrings{i};
-  ## Special handling of block comment operators such as '#{'
-  esc_name = regexprep (name, '([{}])', '@$1');
-  text = [text doc_delim esc_name get_help_text(name) "\n"];
-endfor
-text(end+1) = doc_delim;
-
-## Double '@' symbol for Texinfo
-text = strrep (text, [doc_delim "@"], [doc_delim "@@"]);
-
-## Write data to temporary file for input to makeinfo
-[fid, name, msg] = mkstemp ("octave_doc_XXXXXX", true);
-if (fid < 0)
-  error ("%s: %s\n", name, msg);
-endif
-fwrite (fid, text, "char");
-fclose (fid);
-
-cmd = [makeinfo_program() " --no-headers --no-warn --force --no-validate --fill-column=1024 " name];
-
-[status, formatted_text] = system (cmd);
-
-## Did we get the help text?
-if (status != 0)
-  error ("makeinfo failed with exit status %d!", status);
-elseif (isempty (formatted_text))
-  error ("makeinfo produced no output!");
-endif
-
-## Break apart output and store in cache variable
-delim_idx = find (formatted_text == doc_delim);
-n = length (delim_idx);
-
-cache = cell (3, n);    # pre-allocate storage for efficiency
-k = 1;
-
-for i = 2:n
-
-  block = formatted_text(delim_idx(i-1)+1:delim_idx(i)-1);
-
-  [symbol, doc] = strtok (block, "\r\n");
-
-  ## Skip internal functions that start with __ as these aren't
-  ## indexed by lookfor.
-  if (length (symbol) > 2 && regexp (symbol, '^__.+__$'))
-    continue;
-  endif
-
-  doc = regexprep (doc, "^[\r\n]+", '', 'once');
-
-  if (isempty (doc))
-    continue;
-  endif
-
-  tmp = regexprep (doc, "^ -- .*$[\r\n]", '', 'lineanchors', 'dotexceptnewline');
-
-  if (isempty (tmp))
-    continue;
-  endif
-
-  end_of_first_sentence = regexp (tmp, "(\\.|[\r\n][\r\n])", "once");
-  if (isempty (end_of_first_sentence))
-    end_of_first_sentence = length (tmp);
-  endif
-
-  first_sentence = tmp(1:end_of_first_sentence);
-  first_sentence = regexprep (first_sentence, "([\r\n]| {2,})", " ");
-  first_sentence = regexprep (first_sentence, '^ +', "", 'once');
-
-  cache{1,k} = symbol;
-  cache{2,k} = doc;
-  cache{3,k} = first_sentence;
-  k++;
-endfor
-
-cache(:,k:end) = [];    # delete unused pre-allocated entries
-
-save_header_format_string (["# doc-cache created by Octave " OCTAVE_VERSION]);
-save ("-text", output_file, "cache");
--- a/doc/interpreter/module.mk	Sat Jul 16 14:03:34 2016 +1000
+++ b/doc/interpreter/module.mk	Thu Jul 21 18:11:06 2016 -0400
@@ -288,9 +288,9 @@
   doc/interpreter/doc-cache \
   doc/interpreter/macros.texi
 
-doc/interpreter/doc-cache: $(DOCSTRING_FILES) doc/interpreter/mk_doc_cache.m | $(OCTAVE_INTERPRETER_TARGETS) doc/interpreter/$(octave_dirstamp)
+doc/interpreter/doc-cache: $(DOCSTRING_FILES) doc/interpreter/mk-doc-cache.pl | $(OCTAVE_INTERPRETER_TARGETS) doc/interpreter/$(octave_dirstamp)
 	$(AM_V_GEN)rm -f $@-t $@ && \
-	$(SHELL) run-octave --norc --silent --no-history $(srcdir)/doc/interpreter/mk_doc_cache.m - $(srcdir) $(srcdir)/doc/interpreter/macros.texi $(DOCSTRING_FILES) > $@-t && \
+	$(PERL) $(srcdir)/doc/interpreter/mk-doc-cache.pl - $(srcdir) $(srcdir)/doc/interpreter/macros.texi -- $(DOCSTRING_FILES) > $@-t && \
 	mv $@-t $@
 
 $(MUNGED_TEXI_SRC): $(DOCSTRING_FILES)
@@ -342,7 +342,7 @@
   doc/interpreter/images.awk \
   doc/interpreter/images.mk \
   doc/interpreter/macros.texi \
-  doc/interpreter/mk_doc_cache.m \
+  doc/interpreter/mk-doc-cache.pl \
   doc/interpreter/mkcontrib.awk \
   doc/interpreter/munge-texi.pl \
   $(DOC_IMAGES) \
--- a/libinterp/corefcn/help.cc	Sat Jul 16 14:03:34 2016 +1000
+++ b/libinterp/corefcn/help.cc	Thu Jul 21 18:11:06 2016 -0400
@@ -104,6 +104,11 @@
   return z;
 }
 
+// FIXME: the doc strings for operators and keywords is currently
+// duplicated in op-kw-docs.  We should arrange for Octave to read the
+// info from that file (or the generated DOCSTRINGS file) at startup
+// instead and remove the data from this file.
+
 const static pair_type operators[] =
 {
   pair_type ("!",
--- a/libinterp/module.mk	Sat Jul 16 14:03:34 2016 +1000
+++ b/libinterp/module.mk	Thu Jul 21 18:11:06 2016 -0400
@@ -90,6 +90,7 @@
   libinterp/mk-errno-list \
   libinterp/mk-pkg-add \
   libinterp/mkops \
+  libinterp/op-kw-docs \
   libinterp/version.in.h \
   $(LIBINTERP_BUILT_DISTFILES)
 
@@ -278,9 +279,9 @@
 
 DOCSTRING_FILES += libinterp/DOCSTRINGS
 
-libinterp/DOCSTRINGS: $(LIBINTERP_DEFUN_FILES) | libinterp/$(octave_dirstamp)
+libinterp/DOCSTRINGS: $(LIBINTERP_DEFUN_FILES) libinterp/op-kw-docs | libinterp/$(octave_dirstamp)
 	$(AM_V_GEN)rm -f libinterp/DOCSTRINGS-t && \
-	$(PERL) $(srcdir)/libinterp/gendoc.pl "$(srcdir)" $(LIBINTERP_DEFUN_FILES) > libinterp/DOCSTRINGS-t && \
+	( $(PERL) $(srcdir)/libinterp/gendoc.pl "$(srcdir)" $(LIBINTERP_DEFUN_FILES); cat $(srcdir)/libinterp/op-kw-docs ) > libinterp/DOCSTRINGS-t && \
 	$(call move_if_change_rule,libinterp/DOCSTRINGS-t,$@)
 
 OCTAVE_INTERPRETER_TARGETS += \
@@ -323,11 +324,9 @@
 endif
 .PHONY: install-oct uninstall-oct
 
-install-built-in-docstrings:
+install-built-in-docstrings: libinterp/DOCSTRINGS
 	$(MKDIR_P) $(DESTDIR)$(octetcdir)
-	f=libinterp/DOCSTRINGS; \
-	  if test -f $$f; then d=; else d="$(srcdir)/"; fi; \
-	  $(INSTALL_DATA) "$$d$$f" $(DESTDIR)$(octetcdir)/built-in-docstrings
+	$(INSTALL_DATA) $< $(DESTDIR)$(octetcdir)/built-in-docstrings
 .PHONY: install-built-in-docstrings
 
 uninstall-built-in-docstrings:
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libinterp/op-kw-docs	Thu Jul 21 18:11:06 2016 -0400
@@ -0,0 +1,677 @@
+## Copyright (C) 1993-2015 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/>.
+
+## FIXME: the information in this file is currently duplicated in help.cc.
+
+!
+@c libinterp/parse-tree/oct-parse.in.yy
+-*- texinfo -*-
+@deftypefn {} {} !
+Logical 'not' operator.
+@seealso{~, not}
+@end deftypefn
+~
+@c libinterp/parse-tree/oct-parse.in.yy
+-*- texinfo -*-
+@deftypefn {} {} ~
+Logical 'not' operator.
+@seealso{!, not}
+@end deftypefn
+!=
+@c libinterp/parse-tree/oct-parse.in.yy
+-*- texinfo -*-
+@deftypefn {} {} !=
+Logical 'not equals' operator.
+@seealso{~=, ne}
+@end deftypefn
+~=
+@c libinterp/parse-tree/oct-parse.in.yy
+-*- texinfo -*-
+@deftypefn {} {} ~=
+Logical 'not equals' operator.
+@seealso{!=, ne}
+@end deftypefn
+"
+@c libinterp/parse-tree/oct-parse.in.yy
+-*- texinfo -*-
+@deftypefn {} {} "
+String delimiter.
+@end deftypefn
+#
+@c libinterp/parse-tree/oct-parse.in.yy
+-*- texinfo -*-
+@deftypefn {} {} #
+Begin comment character.
+@seealso{%, #@\{}
+@end deftypefn
+%
+@c libinterp/parse-tree/oct-parse.in.yy
+-*- texinfo -*-
+@deftypefn {} {} %
+Begin comment character.
+@seealso{#, %@\{}
+@end deftypefn
+#{
+@c libinterp/parse-tree/oct-parse.in.yy
+-*- texinfo -*-
+@deftypefn {} {} #@{
+Begin block comment.  There must be nothing else, other than
+whitespace, in the line both before and after @code{#@{}.
+It is possible to nest block comments.
+@seealso{%@\{, #@\}, #}
+@end deftypefn
+%{
+@c libinterp/parse-tree/oct-parse.in.yy
+-*- texinfo -*-
+@deftypefn {} {} %@{
+Begin block comment.  There must be nothing else, other than
+whitespace, in the line both before and after @code{%@{}.
+It is possible to nest block comments.
+@seealso{#@\{, %@\}, %}
+@end deftypefn
+#}
+@c libinterp/parse-tree/oct-parse.in.yy
+-*- texinfo -*-
+@deftypefn {} {} #@}
+Close block comment.  There must be nothing else, other than
+whitespace, in the line both before and after @code{#@}}.
+It is possible to nest block comments.
+@seealso{%@\}, #@\{, #}
+@end deftypefn
+%}
+@c libinterp/parse-tree/oct-parse.in.yy
+-*- texinfo -*-
+@deftypefn {} {} %@}
+Close block comment.  There must be nothing else, other than
+whitespace, in the line both before and after @code{%@}}.
+It is possible to nest block comments.
+@seealso{#@\}, %@\{, %}
+@end deftypefn
+...
+@c libinterp/parse-tree/oct-parse.in.yy
+-*- texinfo -*-
+@deftypefn {} {} ...
+Continuation marker.  Joins current line with following line.
+@end deftypefn
+&
+@c libinterp/parse-tree/oct-parse.in.yy
+-*- texinfo -*-
+@deftypefn {} {} &
+Element by element logical 'and' operator.
+@seealso{&&, and}
+@end deftypefn
+&&
+@c libinterp/parse-tree/oct-parse.in.yy
+-*- texinfo -*-
+@deftypefn {} {} &&
+Logical 'and' operator (with short-circuit evaluation).
+@seealso{&, and}
+@end deftypefn
+'
+@c libinterp/parse-tree/oct-parse.in.yy
+-*- texinfo -*-
+@deftypefn {} {} '
+Matrix transpose operator.  For complex matrices, computes the
+complex conjugate (Hermitian) transpose.
+
+The single quote character may also be used to delimit strings, but
+it is better to use the double quote character, since that is never
+ambiguous.
+@seealso{.', transpose}
+@end deftypefn
+(
+@c libinterp/parse-tree/oct-parse.in.yy
+-*- texinfo -*-
+@deftypefn {} {} (
+Array index or function argument delimiter.
+@end deftypefn
+)
+@c libinterp/parse-tree/oct-parse.in.yy
+-*- texinfo -*-
+@deftypefn {} {})
+Array index or function argument delimiter.
+@end deftypefn
+*
+@c libinterp/parse-tree/oct-parse.in.yy
+-*- texinfo -*-
+@deftypefn {} {} *
+Multiplication operator.
+@seealso{.*, times}
+@end deftypefn
+**
+@c libinterp/parse-tree/oct-parse.in.yy
+-*- texinfo -*-
+@deftypefn {} {} **
+Power operator.  This may return complex results for real inputs.  Use
+@code{realsqrt}, @code{cbrt}, @code{nthroot}, or @code{realroot} to obtain
+real results when possible.
+@seealso{power, ^, .**, .^, realpow, realsqrt, cbrt, nthroot}
+@end deftypefn
+^
+@c libinterp/parse-tree/oct-parse.in.yy
+-*- texinfo -*-
+@deftypefn {} {} ^
+Power operator.  This may return complex results for real inputs.  Use
+@code{realsqrt}, @code{cbrt}, @code{nthroot}, or @code{realroot} to obtain
+real results when possible.
+@seealso{power, **, .^, .**, realpow, realsqrt, cbrt, nthroot}
+@end deftypefn
++
+@c libinterp/parse-tree/oct-parse.in.yy
+-*- texinfo -*-
+@deftypefn {} {} +
+Addition operator.
+@seealso{plus}
+@end deftypefn
+++
+@c libinterp/parse-tree/oct-parse.in.yy
+-*- texinfo -*-
+@deftypefn {} {} ++
+Increment operator.  As in C, may be applied as a prefix or postfix
+operator.
+@seealso{--}
+@end deftypefn
+,
+@c libinterp/parse-tree/oct-parse.in.yy
+-*- texinfo -*-
+@deftypefn {} {} ,
+Array index, function argument, or command separator.
+@end deftypefn
+-
+@c libinterp/parse-tree/oct-parse.in.yy
+-*- texinfo -*-
+@deftypefn {} {} -
+Subtraction or unary negation operator.
+@seealso{minus}
+@end deftypefn
+--
+@c libinterp/parse-tree/oct-parse.in.yy
+-*- texinfo -*-
+@deftypefn {} {} --
+Decrement operator.  As in C, may be applied as a prefix or postfix
+operator.
+@seealso{++}
+@end deftypefn
+.'
+@c libinterp/parse-tree/oct-parse.in.yy
+-*- texinfo -*-
+@deftypefn {} {} .'
+Matrix transpose operator.  For complex matrices, computes the
+transpose, @emph{not} the complex conjugate transpose.
+@seealso{', transpose}
+@end deftypefn
+.*
+@c libinterp/parse-tree/oct-parse.in.yy
+-*- texinfo -*-
+@deftypefn {} {} .*
+Element by element multiplication operator.
+@seealso{*, times}
+@end deftypefn
+.**
+@c libinterp/parse-tree/oct-parse.in.yy
+-*- texinfo -*-
+@deftypefn {} {} .*
+Element by element power operator.  If several complex results are possible,
+returns the one with smallest non-negative argument (angle).  Use
+@code{realpow}, @code{realsqrt}, @code{cbrt}, or @code{nthroot} if a
+real result is preferred.
+@seealso{**, ^, .^, power, realpow, realsqrt, cbrt, nthroot}
+@end deftypefn
+.^
+@c libinterp/parse-tree/oct-parse.in.yy
+-*- texinfo -*-
+@deftypefn {} {} .^
+Element by element power operator.  If several complex results are possible,
+returns the one with smallest non-negative argument (angle).  Use
+@code{realpow}, @code{realsqrt}, @code{cbrt}, or @code{nthroot} if a
+real result is preferred.
+@seealso{.**, ^, **, power, realpow, realsqrt, cbrt, nthroot}
+@end deftypefn
+./
+@c libinterp/parse-tree/oct-parse.in.yy
+-*- texinfo -*-
+@deftypefn {} {} ./
+Element by element right division operator.
+@seealso{/, .\, rdivide, mrdivide}
+@end deftypefn
+/
+@c libinterp/parse-tree/oct-parse.in.yy
+-*- texinfo -*-
+@deftypefn {} {} /
+Right division operator.
+@seealso{./, \, rdivide, mrdivide}
+@end deftypefn
+.\
+@c libinterp/parse-tree/oct-parse.in.yy
+-*- texinfo -*-
+@deftypefn {} {} .\
+Element by element left division operator.
+@seealso{\, ./, rdivide, mrdivide}
+@end deftypefn
+\
+@c libinterp/parse-tree/oct-parse.in.yy
+-*- texinfo -*-
+@deftypefn {} {} \
+Left division operator.
+@seealso{.\, /, ldivide, mldivide}
+@end deftypefn
+:
+@c libinterp/parse-tree/oct-parse.in.yy
+-*- texinfo -*-
+@deftypefn {} {} :
+Select entire rows or columns of matrices.
+@end deftypefn
+;
+@c libinterp/parse-tree/oct-parse.in.yy
+-*- texinfo -*-
+@deftypefn {} {} ;
+Array row or command separator.
+@seealso{,}
+@end deftypefn
+<
+@c libinterp/parse-tree/oct-parse.in.yy
+-*- texinfo -*-
+@deftypefn {} {} <
+'Less than' operator.
+@seealso{lt}
+@end deftypefn
+<=
+@c libinterp/parse-tree/oct-parse.in.yy
+-*- texinfo -*-
+@deftypefn {} {} <=
+'Less than' or 'equals' operator.
+@seealso{le}
+@end deftypefn
+=
+@c libinterp/parse-tree/oct-parse.in.yy
+-*- texinfo -*-
+@deftypefn {} {} =
+Assignment operator.
+@end deftypefn
+==
+@c libinterp/parse-tree/oct-parse.in.yy
+-*- texinfo -*-
+@deftypefn {} {} ==
+Equality test operator.
+@seealso{eq}
+@end deftypefn
+>
+@c libinterp/parse-tree/oct-parse.in.yy
+-*- texinfo -*-
+@deftypefn {} {} >
+'Greater than' operator.
+@seealso{gt}
+@end deftypefn
+>=
+@c libinterp/parse-tree/oct-parse.in.yy
+-*- texinfo -*-
+@deftypefn {} {} >=
+'Greater than' or 'equals' operator.
+@seealso{ge}
+@end deftypefn
+[
+@c libinterp/parse-tree/oct-parse.in.yy
+-*- texinfo -*-
+@deftypefn {} {} [
+Return list delimiter.
+@seealso{]}
+@end deftypefn
+]
+@c libinterp/parse-tree/oct-parse.in.yy
+-*- texinfo -*-
+@deftypefn {} {} ]
+Return list delimiter.
+@seealso{[}
+@end deftypefn
+|
+@c libinterp/parse-tree/oct-parse.in.yy
+-*- texinfo -*-
+@deftypefn {} {} |
+Element by element logical 'or' operator.
+@seealso{||, or}
+@end deftypefn
+||
+@c libinterp/parse-tree/oct-parse.in.yy
+-*- texinfo -*-
+@deftypefn {} {} ||
+Logical 'or' (with short-circuit evaluation) operator.
+@seealso{|, or}
+@end deftypefn
+break
+@c libinterp/parse-tree/oct-parse.in.yy
+-*- texinfo -*-
+@deftypefn {} {} break
+Exit the innermost enclosing do, while or for loop.
+@seealso{do, while, for, parfor, continue}
+@end deftypefn
+case
+@c libinterp/parse-tree/oct-parse.in.yy
+-*- texinfo -*-
+@deftypefn  {} {} case @var{value}
+@deftypefnx {} {} case @{@var{value}, @dots{}@}
+A case statement in a switch.  Octave cases are exclusive and do not
+fall-through as do C-language cases.  A switch statement must have at least
+one case.  See @code{switch} for an example.
+@seealso{switch}
+@end deftypefn
+catch
+@c libinterp/parse-tree/oct-parse.in.yy
+-*- texinfo -*-
+@deftypefn  {} {} catch
+@deftypefnx {} {} catch @var{value}
+Begin the cleanup part of a try-catch block.
+@seealso{try}
+@end deftypefn
+continue
+@c libinterp/parse-tree/oct-parse.in.yy
+-*- texinfo -*-
+@deftypefn {} {} continue
+Jump to the end of the innermost enclosing do, while or for loop.
+@seealso{do, while, for, parfor, break}
+@end deftypefn
+do
+@c libinterp/parse-tree/oct-parse.in.yy
+-*- texinfo -*-
+@deftypefn {} {} do
+Begin a do-until loop.  This differs from a do-while loop in that the
+body of the loop is executed at least once.
+
+@example
+@group
+i = 0;
+do
+  i++
+until (i == 10)
+@end group
+@end example
+@seealso{for, until, while}
+@end deftypefn
+else
+@c libinterp/parse-tree/oct-parse.in.yy
+-*- texinfo -*-
+@deftypefn {} {} else
+Alternate action for an if block.  See @code{if} for an example.
+@seealso{if}
+@end deftypefn
+elseif
+@c libinterp/parse-tree/oct-parse.in.yy
+-*- texinfo -*-
+@deftypefn {} {} elseif (@var{condition})
+Alternate conditional test for an if block.  See @code{if} for an example.
+@seealso{if}
+@end deftypefn
+end_try_catch
+@c libinterp/parse-tree/oct-parse.in.yy
+-*- texinfo -*-
+@deftypefn {} {} end_try_catch
+Mark the end of an @code{try-catch} block.
+@seealso{try, catch}
+@end deftypefn
+end_unwind_protect
+@c libinterp/parse-tree/oct-parse.in.yy
+-*- texinfo -*-
+@deftypefn {} {} end_unwind_protect
+Mark the end of an unwind_protect block.
+@seealso{unwind_protect}
+@end deftypefn
+endfor
+@c libinterp/parse-tree/oct-parse.in.yy
+-*- texinfo -*-
+@deftypefn {} {} endfor
+Mark the end of a for loop.  See @code{for} for an example.
+@seealso{for}
+@end deftypefn
+endfunction
+@c libinterp/parse-tree/oct-parse.in.yy
+-*- texinfo -*-
+@deftypefn {} {} endfunction
+Mark the end of a function.
+@seealso{function}
+@end deftypefn
+endif
+@c libinterp/parse-tree/oct-parse.in.yy
+-*- texinfo -*-
+@deftypefn {} {} endif
+Mark the end of an if block.  See @code{if} for an example.
+@seealso{if}
+@end deftypefn
+endparfor
+@c libinterp/parse-tree/oct-parse.in.yy
+-*- texinfo -*-
+@deftypefn {} {} endparfor
+Mark the end of a parfor loop.  See @code{parfor} for an example.
+@seealso{parfor}
+@end deftypefn
+endswitch
+@c libinterp/parse-tree/oct-parse.in.yy
+-*- texinfo -*-
+@deftypefn {} {} endswitch
+Mark the end of a switch block.  See @code{switch} for an example.
+@seealso{switch}
+@end deftypefn
+endwhile
+@c libinterp/parse-tree/oct-parse.in.yy
+-*- texinfo -*-
+@deftypefn {} {} endwhile
+Mark the end of a while loop.  See @code{while} for an example.
+@seealso{do, while}
+@end deftypefn
+for
+@c libinterp/parse-tree/oct-parse.in.yy
+-*- texinfo -*-
+@deftypefn {} {} for @var{i} = @var{range}
+Begin a for loop.
+
+@example
+@group
+for i = 1:10
+  i
+endfor
+@end group
+@end example
+@seealso{do, parfor, while}
+@end deftypefn
+function
+@c libinterp/parse-tree/oct-parse.in.yy
+-*- texinfo -*-
+@deftypefn  {} {} function @var{outputs} = function (@var{input}, @dots{})
+@deftypefnx {} {} function {} function (@var{input}, @dots{})
+@deftypefnx {} {} function @var{outputs} = function
+Begin a function body with @var{outputs} as results and @var{inputs} as
+parameters.
+@seealso{return}
+@end deftypefn
+global
+@c libinterp/parse-tree/oct-parse.in.yy
+-*- texinfo -*-
+@deftypefn {} {} global @var{var}
+Declare variables to have global scope.
+
+@example
+@group
+global @var{x};
+if (isempty (@var{x}))
+  x = 1;
+endif
+@end group
+@end example
+@seealso{persistent}
+@end deftypefn
+if
+@c libinterp/parse-tree/oct-parse.in.yy
+-*- texinfo -*-
+@deftypefn  {} {} if (@var{cond}) @dots{} endif
+@deftypefnx {} {} if (@var{cond}) @dots{} else @dots{} endif
+@deftypefnx {} {} if (@var{cond}) @dots{} elseif (@var{cond}) @dots{} endif
+@deftypefnx {} {} if (@var{cond}) @dots{} elseif (@var{cond}) @dots{} else @dots{} endif
+Begin an if block.
+
+@example
+@group
+x = 1;
+if (x == 1)
+  disp ("one");
+elseif (x == 2)
+  disp ("two");
+else
+  disp ("not one or two");
+endif
+@end group
+@end example
+@seealso{switch}
+@end deftypefn
+otherwise
+@c libinterp/parse-tree/oct-parse.in.yy
+-*- texinfo -*-
+@deftypefn {} {} otherwise
+The default statement in a switch block (similar to else in an if block).
+@seealso{switch}
+@end deftypefn
+parfor
+@c libinterp/parse-tree/oct-parse.in.yy
+-*- texinfo -*-
+@deftypefn  {} {} parfor @var{i} = @var{range}
+@deftypefnx {} {} parfor (@var{i} = @var{range}, @var{maxproc})
+Begin a for loop that may execute in parallel.
+
+@example
+@group
+parfor i = 1:10
+  i
+endparfor
+@end group
+@end example
+@seealso{for, do, while}
+@end deftypefn
+persistent
+@c libinterp/parse-tree/oct-parse.in.yy
+-*- texinfo -*-
+@deftypefn {} {} persistent @var{var}
+Declare variables as persistent.  A variable that has been declared
+persistent within a function will retain its contents in memory between
+subsequent calls to the same function.  The difference between persistent
+variables and global variables is that persistent variables are local in
+scope to a particular function and are not visible elsewhere.
+@seealso{global}
+@end deftypefn
+return
+@c libinterp/parse-tree/oct-parse.in.yy
+-*- texinfo -*-
+@deftypefn {} {} return
+Return from a function.
+@seealso{function}
+@end deftypefn
+static
+@c libinterp/parse-tree/oct-parse.in.yy
+-*- texinfo -*-
+@deftypefn {} {} static
+This statement has been deprecated in favor of @code{persistent}.
+@seealso{persistent}
+@end deftypefn
+switch
+@c libinterp/parse-tree/oct-parse.in.yy
+-*- texinfo -*-
+@deftypefn {} {} switch @var{statement}
+Begin a switch block.
+
+@example
+@group
+yesno = "yes"
+
+switch yesno
+  case @{"Yes" "yes" "YES" "y" "Y"@}
+    value = 1;
+  case @{"No" "no" "NO" "n" "N"@}
+    value = 0;
+  otherwise
+    error ("invalid value");
+endswitch
+@end group
+@end example
+@seealso{if, case, otherwise}
+@end deftypefn
+try
+@c libinterp/parse-tree/oct-parse.in.yy
+-*- texinfo -*-
+@deftypefn {} {} try
+Begin a try-catch block.
+
+If an error occurs within a try block, then the catch code will be run and
+execution will proceed after the catch block (though it is often
+recommended to use the lasterr function to re-throw the error after cleanup
+is completed).
+@seealso{catch, unwind_protect}
+@end deftypefn
+until
+@c libinterp/parse-tree/oct-parse.in.yy
+-*- texinfo -*-
+@deftypefn {} {} until (@var{cond})
+End a do-until loop.  See @code{do} for an example.
+@seealso{do}
+@end deftypefn
+unwind_protect
+@c libinterp/parse-tree/oct-parse.in.yy
+-*- texinfo -*-
+@deftypefn {} {} unwind_protect
+Begin an unwind_protect block.
+
+If an error occurs within the first part of an unwind_protect block
+the commands within the unwind_protect_cleanup block are executed before
+the error is thrown.  If an error is not thrown, then the
+unwind_protect_cleanup block is still executed (in other words, the
+unwind_protect_cleanup will be run with or without an error in the
+unwind_protect block).
+@seealso{unwind_protect_cleanup, try}
+@end deftypefn
+unwind_protect_cleanup
+@c libinterp/parse-tree/oct-parse.in.yy
+-*- texinfo -*-
+@deftypefn {} {} unwind_protect_cleanup
+Begin the cleanup section of an unwind_protect block.
+@seealso{unwind_protect}
+@end deftypefn
+varargin
+@c libinterp/parse-tree/oct-parse.in.yy
+-*- texinfo -*-
+@deftypefn {} {} varargin
+Pass an arbitrary number of arguments into a function.
+@seealso{varargout, nargin, isargout, nargout, nthargout}
+@end deftypefn
+varargout
+@c libinterp/parse-tree/oct-parse.in.yy
+-*- texinfo -*-
+@deftypefn {} {} varargout
+Pass an arbitrary number of arguments out of a function.
+@seealso{varargin, nargin, isargout, nargout, nthargout}
+@end deftypefn
+while
+@c libinterp/parse-tree/oct-parse.in.yy
+-*- texinfo -*-
+@deftypefn {} {} while
+Begin a while loop.
+
+@example
+@group
+i = 0;
+while (i < 10)
+  i++
+endwhile
+@end group
+@end example
+@seealso{do, endwhile, for, until}
+@end deftypefn
--- a/libinterp/parse-tree/pt-arg-list.cc	Sat Jul 16 14:03:34 2016 +1000
+++ b/libinterp/parse-tree/pt-arg-list.cc	Thu Jul 21 18:11:06 2016 -0400
@@ -126,11 +126,16 @@
 static int index_position = 0;
 static int num_indices = 0;
 
+// END is documented in op-kw-docs.
 DEFCONSTFUN (end, , ,
              doc: /* -*- texinfo -*-
 @deftypefn {} {} end
-The magic index @qcode{"end"} refers to the last valid entry in an
-indexing operation.
+Last element of an array or the end of any @code{for}, @code{parfor},
+@code{if}, @code{do}, @code{while}, @code{function}, @code{switch},
+@code{try}, or @code{unwind_protect} block.
+
+As an index of an array, the magic index @qcode{"end"} refers to the
+last valid entry in an indexing operation.
 
 Example:
 
@@ -146,6 +151,7 @@
     @result{} 6
 @end group
 @end example
+@seealso{for, parfor, if, do, while, function, switch, try, unwind_protect}
 @end deftypefn */)
 {
   octave_value retval;