emacs-elpa-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[elpa] externals-release/wisi 6b011cf077 2/2: Resolve conflicts, finish


From: Stephen Leake
Subject: [elpa] externals-release/wisi 6b011cf077 2/2: Resolve conflicts, finish merge
Date: Wed, 11 Jan 2023 20:05:59 -0500 (EST)

branch: externals-release/wisi
commit 6b011cf077fe95f9b08ddb0f1ca1dd2dc36f0724
Merge: dd717efa4b 9ddff6cdf1
Author: Stephen Leake <stephen_leake@stephe-leake.org>
Commit: Stephen Leake <stephen_leake@stephe-leake.org>

    Resolve conflicts, finish merge
---
 .gitignore                                      |    1 +
 Alire.make                                      |   10 +
 ELPA.make                                       |   31 +
 NEWS                                            |   47 +-
 README                                          |    9 +-
 alire_rules.make                                |   16 +
 doclicense.texi                                 |    4 +-
 emacs_wisi_common_parse.adb                     |  110 +-
 emacs_wisi_common_parse.ads                     |    6 +-
 gen_emacs_wisi_lr_parse.adb                     |   29 +-
 gen_emacs_wisi_lr_parse.ads                     |   14 +-
 gen_emacs_wisi_lr_text_rep_parse.adb            |   96 +-
 gen_emacs_wisi_lr_text_rep_parse.ads            |   15 +-
 gen_emacs_wisi_packrat_parse.adb                |  180 -
 gen_emacs_wisi_packrat_parse.ads                |   42 -
 gen_run_wisi_lr_parse.adb                       |   44 +-
 gen_run_wisi_lr_parse.ads                       |   14 +-
 gen_run_wisi_lr_text_rep_parse.adb              |   49 +-
 gen_run_wisi_lr_text_rep_parse.ads              |   15 +-
 gen_run_wisi_packrat_parse.adb                  |  241 -
 gen_run_wisi_packrat_parse.ads                  |   36 -
 gnat-core.el                                    |  487 --
 install.sh                                      |   15 -
 prj-alire.el                                    |   29 +
 prj-wisi.el                                     |   30 +
 run_wisi_common_parse.adb                       |  183 +-
 run_wisi_common_parse.ads                       |    8 +-
 sal-gen_definite_doubly_linked_lists.adb        |    4 +-
 sal-gen_definite_doubly_linked_lists.ads        |    3 +-
 sal-gen_indefinite_doubly_linked_lists.adb      |   41 +-
 sal-gen_indefinite_doubly_linked_lists.ads      |    5 +-
 sal.adb                                         |    2 +-
 standard_common.gpr                             |   10 +-
 wisi-fringe.el                                  |  113 +-
 wisi-parse-common.el                            |   61 +-
 wisi-parse_context.adb                          |   87 +-
 wisi-parse_context.ads                          |   53 +-
 wisi-prj.el                                     |  315 +-
 wisi-process-parse.el                           |  299 +-
 wisi-run-indent-test.el                         |  220 +-
 wisi-skel.el                                    |   18 +-
 wisi.adb                                        |   73 +-
 wisi.ads                                        |   13 +-
 wisi.el                                         |  410 +-
 wisi.texi                                       |   28 +-
 wisitoken-bnf-generate.adb                      |   77 +-
 wisitoken-bnf-generate_packrat.adb              |   75 +-
 wisitoken-bnf-generate_utils.adb                |   18 +-
 wisitoken-bnf-output_ada.adb                    |   53 +-
 wisitoken-bnf-output_ada_common.adb             |  232 +-
 wisitoken-bnf-output_ada_common.ads             |   12 +-
 wisitoken-bnf-output_ada_emacs.adb              |   23 +-
 wisitoken-bnf.adb                               |    1 +
 wisitoken-bnf.ads                               |   16 +-
 wisitoken-generate-lr-lalr_generate.adb         |   25 +-
 wisitoken-generate-lr-lalr_generate.ads         |   19 +-
 wisitoken-generate-lr-lr1_generate.adb          |  652 +-
 wisitoken-generate-lr-lr1_generate.ads          |   24 +-
 wisitoken-lexer-re2c.adb                        |    6 +-
 wisitoken-lexer.adb                             |    4 +-
 wisitoken-parse-lr-mckenzie_recover-explore.adb |    7 +-
 wisitoken-parse-lr-mckenzie_recover.adb         |   10 +-
 wisitoken-parse-lr-parser-parse.adb             |    9 +-
 wisitoken-parse-lr-parser.adb                   |  194 +-
 wisitoken-parse-lr-parser.ads                   |   24 +-
 wisitoken-parse-lr-parser_no_recover.adb        |   72 +-
 wisitoken-parse-lr-parser_no_recover.ads        |   12 -
 wisitoken-parse-lr.adb                          |   13 +
 wisitoken-parse-lr.ads                          |    6 +-
 wisitoken-parse-packrat-generated.adb           |   43 +-
 wisitoken-parse-packrat-generated.ads           |   41 +-
 wisitoken-parse-packrat-procedural.adb          |  258 +-
 wisitoken-parse-packrat-procedural.ads          |   40 +-
 wisitoken-parse-packrat.adb                     |  212 +-
 wisitoken-parse-packrat.ads                     |  114 +-
 wisitoken-parse.adb                             |  104 +-
 wisitoken-parse.ads                             |   21 +-
 wisitoken-parse_table-mode.el                   |   13 +-
 wisitoken-productions.ads                       |    4 +-
 wisitoken-syntax_trees.adb                      |  610 +-
 wisitoken-syntax_trees.ads                      |  198 +-
 wisitoken-user_guide.texinfo                    |    4 +-
 wisitoken.ads                                   |    4 +
 wisitoken_grammar_actions.ads                   |    2 +
 wisitoken_grammar_editing.adb                   |    2 +-
 wisitoken_grammar_main.adb                      |   18 +-
 wisitoken_grammar_main.ads                      |   12 +-
 wisitoken_grammar_re2c.c                        | 9457 +++++++++++------------
 wisitoken_grammar_runtime.adb                   |    9 +-
 89 files changed, 7743 insertions(+), 8523 deletions(-)

diff --git a/.gitignore b/.gitignore
index 12798c6e35..cd54022dbd 100644
--- a/.gitignore
+++ b/.gitignore
@@ -5,3 +5,4 @@ obj/
 wisi.gpr
 wisitoken-user_guide.info
 wisitoken-bnf-generate.exe
+autoloads.el
diff --git a/Alire.make b/Alire.make
new file mode 100644
index 0000000000..74f5027966
--- /dev/null
+++ b/Alire.make
@@ -0,0 +1,10 @@
+# Build Ada parts of Emacs wisi with Alire; see build/Makefile for non-Alire 
build
+
+STEPHES_ADA_LIBRARY_ALIRE_PREFIX ?= $(CURDIR)/../org.stephe_leake.sal
+
+include $(STEPHES_ADA_LIBRARY_ALIRE_PREFIX)/build/alire_rules.make
+
+# Local Variables:
+# eval: (unless dvc-doing-ediff-p (load-file "prj-wisi.el"))
+# End:
+# end of file
diff --git a/ELPA.make b/ELPA.make
new file mode 100644
index 0000000000..566092f31a
--- /dev/null
+++ b/ELPA.make
@@ -0,0 +1,31 @@
+# For compiling wisi code in elpa worktree
+
+#export Standard_Common_Build := Debug
+
+.PHONY : all force
+
+all : build_ada byte-compile
+
+build_ada : wisi.gpr force
+       gprbuild -p -j8 wisi.gpr
+
+wisi.gpr : wisi.gpr.gp
+       gnatprep -DELPA="yes" wisi.gpr.gp wisi.gpr
+
+BYTE_COMPILE := "(progn (setq package-load-list '((wisi) (ada-mode) 
(gnat-compiler) all)) (package-initialize)(setq byte-compile-error-on-warn 
t)(batch-byte-compile))"
+byte-compile : byte-compile-clean
+       emacs -Q -batch -L . --eval $(BYTE_COMPILE) *.el
+
+byte-compile-clean :
+       rm -f *.elc
+
+clean : force
+       rm -rf wisi.gpr obj *parse_table*
+
+recursive-clean : force
+       gprclean -r -P wisi.gpr
+
+# Local Variables:
+# eval: (unless dvc-doing-ediff-p (load-file "prj-wisi.el"))
+# End:
+# end of file
diff --git a/NEWS b/NEWS
index bd2a1002b4..f99e3c21c4 100644
--- a/NEWS
+++ b/NEWS
@@ -1,11 +1,56 @@
 GNU Emacs wisi NEWS -- history of user-visible changes.
 
-Copyright (C) 2014 - 2022 Free Software Foundation, Inc.
+Copyright (C) 2014 - 2023 Free Software Foundation, Inc.
 
 Please send wisi bug reports to bug-gnu-emacs@gnu.org, with
 'wisi' in the subject. If possible, use M-x report-emacs-bug.
 
 
+* wisi 4.2.0
+3 Jan 2023
+
+** New user variables wisi-disable-completion,
+   wisi-disable-diagnostics, wisi-disable-indent, wisi-disable-parser,
+   wisi-disable-statement to control various features. Normally set by
+   the major mode when it chooses which backends to use.
+
+** New wisi project file statement; @code{import_env_var} - copies the
+   value of an environment variable from @code{process-environment} to
+   the project environment variables.
+
+** Case exception files declared in a wisi project file are now
+   searched for on the project file search path.
+
+** No longer displays right fringe marks, that were supposed to show
+   the location of erros within a file; too hard to get right and
+   maintain, not very useful.
+
+** No longer sets global value of skeleton-end-hook.
+
+** Several small bug fixes
+
+** parser process protocol version 7
+
+   Add commands dump_prev_tree, save_prev_auto; useful for debugging
+   incremental parse issues. Controlled by new user variable
+   wisi-save-text-tree.
+   
+* wisi 4.1.1
+8 Oct 2022
+
+** Ada code builds with alire.
+
+** gnat-compiler split out into separate ELPA package.
+
+** A bug in updating the fringe error marks is fixed.
+
+** Support using eglot to replace some wisi functions; new user
+   configuration variables wisi-disable-face, wisi-disable-completion,
+   wisi-disable-indent, wisi-disable-parser.
+
+** In wisi project files, import_env_var=<name> can be used to inherit
+   an environment variable from the Emacs process.
+
 * wisi 4.0.0
 22 Oct 2022 beta prompted to release
 
diff --git a/README b/README
index e8f689caca..715c4da796 100644
--- a/README
+++ b/README
@@ -1,4 +1,4 @@
-Emacs wisi package 4.0.0
+Emacs wisi package 4.2.0
 
 The wisi package provides utilities for using generalized
 error-correcting LR parsers (in external processes) to do indentation,
@@ -8,7 +8,6 @@ See ada-mode for an example of its use.
 It also provides wisitoken-parse_table-mode, for navigating the
 diagnostic parse tables output by wisitoken-bnf-generate.
 
-The generated code is in Ada; it requires the AdaCore gnat compiler
-that you may not have installed. It is available in many packaging
-systems, or as a binary download from
-https://www.adacore.com/download.
+The generated code is in Ada; it can be built via Alire
+(https://alire.ada.dev/). Normally this is done by a package that uses
+wisi, such as ada-mode.
diff --git a/alire_rules.make b/alire_rules.make
new file mode 100644
index 0000000000..e214496368
--- /dev/null
+++ b/alire_rules.make
@@ -0,0 +1,16 @@
+# gnu make rules for building with Alire.
+
+# alr must be started in the directory holding alire.toml
+alire-build : force
+       GPR_PROJECT_PATH= ; alr --no-tty --no-color $(ALIRE_ARGS) build 
$(ALIRE_BUILD_ARGS)
+
+alire-env :
+       GPR_PROJECT_PATH= ;  alr $(ALIRE_ARGS) printenv
+
+alire-clean :
+       alr clean
+       rm -rf alire build/obj/release build/obj/development
+
+.PHONY : force
+
+# end of file
diff --git a/doclicense.texi b/doclicense.texi
index a511ffcd5a..c6d1d5f52a 100644
--- a/doclicense.texi
+++ b/doclicense.texi
@@ -7,7 +7,7 @@
 
 @display
 Copyright @copyright{} 2000, 2001, 2002, 2007, 2008, 2009 Free Software 
Foundation, Inc.
-@uref{http://fsf.org/}
+@uref{https://fsf.org/}
 
 Everyone is permitted to copy and distribute verbatim copies
 of this license document, but changing it is not allowed.
@@ -415,7 +415,7 @@ The Free Software Foundation may publish new, revised 
versions
 of the GNU Free Documentation License from time to time.  Such new
 versions will be similar in spirit to the present version, but may
 differ in detail to address new problems or concerns.  See
-@uref{http://www.gnu.org/copyleft/}.
+@uref{https://www.gnu.org/copyleft/}.
 
 Each version of the License is given a distinguishing version number.
 If the Document specifies that a particular numbered version of this
diff --git a/emacs_wisi_common_parse.adb b/emacs_wisi_common_parse.adb
index fb751b3dc3..5fc3877ee7 100644
--- a/emacs_wisi_common_parse.adb
+++ b/emacs_wisi_common_parse.adb
@@ -28,7 +28,6 @@ with GNAT.Traceback.Symbolic;
 with GNATCOLL.Memory;
 with SAL;
 with System.Storage_Elements;
-with WisiToken.Lexer;
 with WisiToken.Parse.LR.Parser;
 with WisiToken.Syntax_Trees;
 package body Emacs_Wisi_Common_Parse is
@@ -249,7 +248,8 @@ package body Emacs_Wisi_Common_Parse is
      (Name                      : in String;
       Language_Protocol_Version : in String;
       Params                    : in Process_Start_Params;
-      Language                  : in Wisi.Parse_Context.Language;
+      Factory                   : in WisiToken.Parse.Factory;
+      Free_Parser               : in WisiToken.Parse.Free_Parser;
       Trace                     : in WisiToken.Trace_Access)
    is
       use Ada.Text_IO;
@@ -318,10 +318,25 @@ package body Emacs_Wisi_Common_Parse is
             end if;
 
             if Match ("create-context") then
-               Wisi.Parse_Context.Create_No_Text (Wisi.Get_String 
(Command_Line, Last), Language, Trace);
+               Wisi.Parse_Context.Create_No_Text (Wisi.Get_String 
(Command_Line, Last), Factory, Trace);
 
-            elsif Match ("kill-context") then
-               Wisi.Parse_Context.Kill (File_Name => Wisi.Get_String 
(Command_Line, Last));
+            elsif Match ("dump_prev_tree") then
+               --  Args: source_file_name save_file_root
+               --  Input: <none>
+               --  Response:
+               --  (message "prev_tree dumped")
+               --  prompt
+               declare
+                  Source_File_Name : constant String := Wisi.Get_String 
(Command_Line, Last);
+                  Save_File_Name   : constant String := Wisi.Get_String 
(Command_Line, Last);
+
+                  Parse_Context : constant 
Wisi.Parse_Context.Parse_Context_Access := Wisi.Parse_Context.Find
+                    (Source_File_Name);
+               begin
+                  Check_Command_Length (Command_Length, Last);
+
+                  Parse_Context.Dump_Prev_Tree (Save_File_Name);
+               end;
 
             elsif Match ("enable_memory_report") then
                --  Args: <none>
@@ -334,6 +349,9 @@ package body Emacs_Wisi_Common_Parse is
                   Stack_Trace_Depth     => 0,
                   Reset_Content_On_Free => False);
 
+            elsif Match ("kill-context") then
+               Wisi.Parse_Context.Kill (File_Name => Wisi.Get_String 
(Command_Line, Last), Free_Parser => Free_Parser);
+
             elsif Match ("memory_report_reset") then
                --  Args: <none>
                --  Input: <none>
@@ -368,21 +386,31 @@ package body Emacs_Wisi_Common_Parse is
                   Parse_Context : constant 
Wisi.Parse_Context.Parse_Context_Access :=
                     (case Params.Kind is
                      when Full | Partial => Wisi.Parse_Context.Find_Create
-                       (-Params.Source_File_Name, Language, Trace),
+                       (-Params.Source_File_Name, Factory, Trace),
                      when Incremental => Wisi.Parse_Context.Find
-                       (-Params.Source_File_Name, Language, Have_Text => 
True));
+                       (-Params.Source_File_Name, Have_Text => True));
 
-                  Parser     : Parse.LR.Parser.Parser renames 
Parse_Context.Parser;
+                  Parser     : WisiToken.Parse.Base_Parser'Class renames 
Parse_Context.Parser.all;
                   Parse_Data : Wisi.Parse_Data_Type'Class renames 
Wisi.Parse_Data_Type'Class (Parser.User_Data.all);
                begin
-                  if Params.Zombie_Limit > 0 then
-                     Parser.Table.McKenzie_Param.Zombie_Limit := 
Params.Zombie_Limit;
+                  if Parse_Context.Frozen then
+                     raise WisiToken.Parse_Error with "parse_context frozen";
                   end if;
-                  if Params.Enqueue_Limit > 0 then
-                     Parser.Table.McKenzie_Param.Enqueue_Limit := 
Params.Enqueue_Limit;
-                  end if;
-                  if Params.Max_Parallel > 0 then
-                     Parser.Table.Max_Parallel := SAL.Base_Peek_Type 
(Params.Max_Parallel);
+
+                  if Parser in WisiToken.Parse.LR.Parser.Parser then
+                     declare
+                        LR_Parser : WisiToken.Parse.LR.Parser.Parser renames 
WisiToken.Parse.LR.Parser.Parser (Parser);
+                     begin
+                        if Params.Zombie_Limit > 0 then
+                           LR_Parser.Table.McKenzie_Param.Zombie_Limit := 
Params.Zombie_Limit;
+                        end if;
+                        if Params.Enqueue_Limit > 0 then
+                           LR_Parser.Table.McKenzie_Param.Enqueue_Limit := 
Params.Enqueue_Limit;
+                        end if;
+                        if Params.Max_Parallel > 0 then
+                           LR_Parser.Table.Max_Parallel := SAL.Base_Peek_Type 
(Params.Max_Parallel);
+                        end if;
+                     end;
                   end if;
 
                   case Params.Kind is
@@ -439,6 +467,14 @@ package body Emacs_Wisi_Common_Parse is
                      declare
                         KMN_List : Parse.KMN_Lists.List;
                      begin
+                        if Parse_Context.Save_Prev_Text_Tree then
+                           Parse_Context.Save_Text (-Parse_Context.File_Name & 
"-wisi-prev-text");
+                           if Parser.Tree.Editable then
+                              Parser.Tree.Copy_Tree
+                                (Parse_Context.Prev_Tree, 
Syntax_Trees.User_Data_Access_Constant (Parser.User_Data));
+                           end if;
+                        end if;
+
                         Wisi.Parse_Context.Edit_Source (Trace.all, 
Parse_Context.all, Params.Changes, KMN_List);
 
                         if Ada.Strings.Unbounded.Length 
(Parse_Context.Root_Save_Edited_Name) /= 0 then
@@ -505,8 +541,20 @@ package body Emacs_Wisi_Common_Parse is
                   Wisi.Put_Errors (Parser.Tree);
                   raise;
 
+               when WisiToken.Validate_Error =>
+                  Wisi.Put_Errors (Parser.Tree);
+                  if WisiToken.Debug_Mode then
+                     --  Ensure we don't lose the debug state
+                     Parse_Context.Frozen := True;
+                  end if;
+                  raise WisiToken.Parse_Error with "validate error; 
parse_context frozen";
+
                when others =>
                   Parser.Tree.Lexer.Discard_Rest_Of_Input;
+                  if WisiToken.Debug_Mode then
+                     --  Ensure we don't lose the debug state
+                     Parse_Context.Frozen := True;
+                  end if;
                   raise;
                end;
 
@@ -521,9 +569,9 @@ package body Emacs_Wisi_Common_Parse is
                   Params : constant Post_Parse_Params := Get_Post_Parse_Params 
(Command_Line, Last);
 
                   Parse_Context : constant 
Wisi.Parse_Context.Parse_Context_Access := Wisi.Parse_Context.Find
-                    (-Params.Source_File_Name, Language, Have_Text => True);
+                    (-Params.Source_File_Name, Have_Text => True);
 
-                  Parser     : Parse.LR.Parser.Parser renames 
Parse_Context.Parser;
+                  Parser     : WisiToken.Parse.Base_Parser'Class renames 
Parse_Context.Parser.all;
                   Parse_Data : Wisi.Parse_Data_Type'Class renames 
Wisi.Parse_Data_Type'Class (Parser.User_Data.all);
                begin
                   Parse_Data.Reset_Post_Parse
@@ -550,7 +598,7 @@ package body Emacs_Wisi_Common_Parse is
                   Params : constant Refactor_Params := Get_Refactor_Params 
(Command_Line, Last);
 
                   Parse_Context : constant 
Wisi.Parse_Context.Parse_Context_Access := Wisi.Parse_Context.Find
-                    (-Params.Source_File_Name, Language);
+                    (-Params.Source_File_Name);
 
                   Parse_Data : Wisi.Parse_Data_Type'Class renames 
Wisi.Parse_Data_Type'Class
                     (Parse_Context.Parser.User_Data.all);
@@ -572,7 +620,7 @@ package body Emacs_Wisi_Common_Parse is
                   Label : constant Wisi.Query_Label := Wisi.Query_Label'Val 
(Wisi.Get_Integer (Command_Line, Last));
 
                   Parse_Context : constant 
Wisi.Parse_Context.Parse_Context_Access := Wisi.Parse_Context.Find
-                    (-Source_File_Name, Language);
+                    (-Source_File_Name);
 
                   Parse_Data : constant Wisi.Parse_Data_Access_Constant :=
                     Wisi.Parse_Data_Access_Constant 
(Parse_Context.Parser.User_Data);
@@ -627,6 +675,26 @@ package body Emacs_Wisi_Common_Parse is
                   end case;
                end;
 
+            elsif Match ("save_prev_auto") then
+               --  Args: source_file_name enable
+               --  Input: <none>
+               --  Response:
+               --  (message "save_prev_auto enabled")
+               --  prompt
+               declare
+                  Source_File_Name : constant String  := Wisi.Get_String 
(Command_Line, Last);
+                  Enable           : constant Boolean := 1 = Wisi.Get_Integer 
(Command_Line, Last);
+
+                  --  This command is often the first command for a source 
file, from
+                  --  wisi-reset-parser.
+                  Parse_Context : constant 
Wisi.Parse_Context.Parse_Context_Access := Wisi.Parse_Context.Find_Create
+                    (Source_File_Name, Factory, Trace);
+               begin
+                  Check_Command_Length (Command_Length, Last);
+
+                  Parse_Context.Save_Prev_Text_Tree := Enable;
+               end;
+
             elsif Match ("save_text") then
                --  Args: source_file_name save_file_name
                --  Input: <none>
@@ -638,7 +706,7 @@ package body Emacs_Wisi_Common_Parse is
                   Save_File_Name   : constant String := Wisi.Get_String 
(Command_Line, Last);
 
                   Parse_Context : constant 
Wisi.Parse_Context.Parse_Context_Access := Wisi.Parse_Context.Find
-                    (Source_File_Name, Language);
+                    (Source_File_Name);
                begin
                   Check_Command_Length (Command_Length, Last);
 
@@ -660,7 +728,7 @@ package body Emacs_Wisi_Common_Parse is
 
                   --  We need "create" here for partial parse.
                   Parse_Context : constant 
Wisi.Parse_Context.Parse_Context_Access := Wisi.Parse_Context.Find_Create
-                    (Source_File_Name, Language, Trace);
+                    (Source_File_Name, Factory, Trace);
                begin
                   Check_Command_Length (Command_Length, Last);
 
diff --git a/emacs_wisi_common_parse.ads b/emacs_wisi_common_parse.ads
index fb10f469a9..a5fb95840b 100644
--- a/emacs_wisi_common_parse.ads
+++ b/emacs_wisi_common_parse.ads
@@ -20,12 +20,11 @@ pragma License (GPL);
 
 with Ada.Strings.Unbounded;
 with System;
-with Wisi;
 with WisiToken.Parse;
 with Wisi.Parse_Context;
 package Emacs_Wisi_Common_Parse is
 
-   Protocol_Version : constant String := "6";
+   Protocol_Version : constant String := "7";
    --  Protocol_Version defines the data sent between elisp and the
    --  background process, except for the language-specific parameters,
    --  which are defined by the Language_Protocol_Version parameter to
@@ -67,7 +66,8 @@ package Emacs_Wisi_Common_Parse is
      (Name                      : in String;
       Language_Protocol_Version : in String;
       Params                    : in Process_Start_Params;
-      Language                  : in Wisi.Parse_Context.Language;
+      Factory                   : in WisiToken.Parse.Factory;
+      Free_Parser               : in WisiToken.Parse.Free_Parser;
       Trace                     : in WisiToken.Trace_Access);
 
    ----------
diff --git a/gen_emacs_wisi_lr_parse.adb b/gen_emacs_wisi_lr_parse.adb
index 34a83df130..b4f59111a1 100644
--- a/gen_emacs_wisi_lr_parse.adb
+++ b/gen_emacs_wisi_lr_parse.adb
@@ -23,15 +23,30 @@ with WisiToken.Parse.LR.Parser;
 with WisiToken.Text_IO_Trace;
 procedure Gen_Emacs_Wisi_LR_Parse
 is
-   Trace               : aliased WisiToken.Text_IO_Trace.Trace;
-   Parse_Data_Template : aliased Parse_Data_Type;
-
+   Trace  : aliased WisiToken.Text_IO_Trace.Trace;
    Params : constant Process_Start_Params := Get_Process_Start_Params;
+
+   function Factory return WisiToken.Parse.Base_Parser_Access
+   is begin
+      return new WisiToken.Parse.LR.Parser.Parser'
+        (Create_Parser
+           (Trace'Unrestricted_Access,
+            User_Data                      => new Parse_Data_Type,
+            Language_Fixes                 => Language_Fixes,
+            Language_Matching_Begin_Tokens => Language_Matching_Begin_Tokens,
+            Language_String_ID_Set         => Language_String_ID_Set));
+   end Factory;
+
+   procedure Free_Parser (Object : in out WisiToken.Parse.Base_Parser_Access)
+   is
+      LR_Parser : WisiToken.Parse.LR.Parser.Parser_Access := 
WisiToken.Parse.LR.Parser.Parser_Access (Object);
+   begin
+      WisiToken.Parse.LR.Parser.Free (LR_Parser);
+      Object := null;
+   end Free_Parser;
+
 begin
    Process_Stream
      (Name, Language_Protocol_Version, Params,
-      (Descriptor, Create_Lexer (Trace'Unchecked_Access), Create_Parse_Table, 
Create_Productions,
-       Partial_Parse_Active, Partial_Parse_Byte_Goal, Language_Fixes, 
Language_Matching_Begin_Tokens,
-       Language_String_ID_Set, Parse_Data_Template'Unchecked_Access),
-      Trace'Unchecked_Access);
+      Factory'Unrestricted_Access, Free_Parser'Unrestricted_Access, 
Trace'Unchecked_Access);
 end Gen_Emacs_Wisi_LR_Parse;
diff --git a/gen_emacs_wisi_lr_parse.ads b/gen_emacs_wisi_lr_parse.ads
index 71d5e8afbb..4dd3ea9575 100644
--- a/gen_emacs_wisi_lr_parse.ads
+++ b/gen_emacs_wisi_lr_parse.ads
@@ -31,7 +31,6 @@
 pragma License (GPL);
 
 with Wisi;
-with WisiToken.Lexer;
 with WisiToken.Parse.LR.Parser;
 with WisiToken.Syntax_Trees;
 generic
@@ -39,15 +38,16 @@ generic
 
    Name                           : in String; --  for Usage, error messages.
    Language_Protocol_Version      : in String; --  Defines language-specific 
parse parameters.
-   Descriptor                     : in WisiToken.Descriptor_Access_Constant;
-   Partial_Parse_Active           : in WisiToken.Boolean_Access;
-   Partial_Parse_Byte_Goal        : in WisiToken.Buffer_Pos_Access;
    Language_Fixes                 : in 
WisiToken.Parse.LR.Parser.Language_Fixes_Access;
    Language_Matching_Begin_Tokens : in 
WisiToken.Parse.LR.Parser.Language_Matching_Begin_Tokens_Access;
    Language_String_ID_Set         : in 
WisiToken.Parse.LR.Parser.Language_String_ID_Set_Access;
 
-   with function Create_Lexer (Trace : in WisiToken.Trace_Access) return 
WisiToken.Lexer.Handle;
-   with function Create_Parse_Table return WisiToken.Parse.LR.Parse_Table_Ptr;
-   with function Create_Productions return 
WisiToken.Syntax_Trees.Production_Info_Trees.Vector;
+   with function Create_Parser
+     (Trace                          : in WisiToken.Trace_Access;
+      User_Data                      : in 
WisiToken.Syntax_Trees.User_Data_Access;
+      Language_Fixes                 : in 
WisiToken.Parse.LR.Parser.Language_Fixes_Access;
+      Language_Matching_Begin_Tokens : in 
WisiToken.Parse.LR.Parser.Language_Matching_Begin_Tokens_Access;
+      Language_String_ID_Set         : in 
WisiToken.Parse.LR.Parser.Language_String_ID_Set_Access)
+     return WisiToken.Parse.LR.Parser.Parser;
 
 procedure Gen_Emacs_Wisi_LR_Parse;
diff --git a/gen_emacs_wisi_lr_text_rep_parse.adb 
b/gen_emacs_wisi_lr_text_rep_parse.adb
index f2211954ea..ac7c2117ea 100644
--- a/gen_emacs_wisi_lr_text_rep_parse.adb
+++ b/gen_emacs_wisi_lr_text_rep_parse.adb
@@ -1,39 +1,57 @@
---  Abstract :
---
---  See spec.
---
---  Copyright (C) 2014, 2017 - 2020, 2022 All Rights Reserved.
---
---  This program is free software; you can redistribute it and/or
---  modify it under terms of the GNU General Public License as
---  published by the Free Software Foundation; either version 3, 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
---  distributed with this program; see file COPYING. If not, write to
---  the Free Software Foundation, 51 Franklin Street, Suite 500, Boston,
---  MA 02110-1335, USA.
-
-pragma License (GPL);
-
-with Ada.Command_Line;
-with Ada.Directories;
-with Emacs_Wisi_Common_Parse; use Emacs_Wisi_Common_Parse;
-with WisiToken.Text_IO_Trace;
-procedure Gen_Emacs_Wisi_LR_Text_Rep_Parse
-is
-   Trace               : aliased WisiToken.Text_IO_Trace.Trace;
-   Parse_Data_Template : aliased Parse_Data_Type;
-
-   Params : constant Process_Start_Params := Get_Process_Start_Params;
-begin
-   Process_Stream
-     (Name, Language_Protocol_Version, Params,
-      (Descriptor, Create_Lexer (Trace'Unchecked_Access), Create_Parse_Table
-         (Ada.Directories.Containing_Directory (Ada.Command_Line.Command_Name) 
& "/" & Text_Rep_File_Name),
-       Create_Productions, Partial_Parse_Active, Partial_Parse_Byte_Goal, 
Language_Fixes,
-       Language_Matching_Begin_Tokens, Language_String_ID_Set, 
Parse_Data_Template'Unchecked_Access),
-     Trace'Unchecked_Access);
-end Gen_Emacs_Wisi_LR_Text_Rep_Parse;
+--  Abstract :
+--
+--  See spec.
+--
+--  Copyright (C) 2014, 2017 - 2020, 2022 All Rights Reserved.
+--
+--  This program is free software; you can redistribute it and/or
+--  modify it under terms of the GNU General Public License as
+--  published by the Free Software Foundation; either version 3, 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
+--  distributed with this program; see file COPYING. If not, write to
+--  the Free Software Foundation, 51 Franklin Street, Suite 500, Boston,
+--  MA 02110-1335, USA.
+
+pragma License (GPL);
+
+with Ada.Command_Line;
+with Ada.Directories;
+with Emacs_Wisi_Common_Parse; use Emacs_Wisi_Common_Parse;
+with WisiToken.Text_IO_Trace;
+procedure Gen_Emacs_Wisi_LR_Text_Rep_Parse
+is
+   Trace  : aliased WisiToken.Text_IO_Trace.Trace;
+   Params : constant Process_Start_Params := Get_Process_Start_Params;
+
+   Text_Rep_File_Name_Full : constant String := 
Ada.Directories.Containing_Directory
+     (Ada.Command_Line.Command_Name) & "/" & Text_Rep_File_Name;
+
+   function Factory return WisiToken.Parse.Base_Parser_Access
+   is begin
+      return new WisiToken.Parse.LR.Parser.Parser'
+        (Create_Parser
+           (Trace                          => Trace'Unchecked_Access,
+            User_Data                      => new Parse_Data_Type,
+            Language_Fixes                 => Language_Fixes,
+            Language_Matching_Begin_Tokens => Language_Matching_Begin_Tokens,
+            Language_String_ID_Set         => Language_String_ID_Set,
+            Text_Rep_File_Name             => Text_Rep_File_Name_Full));
+   end Factory;
+
+   procedure Free_Parser (Object : in out WisiToken.Parse.Base_Parser_Access)
+   is
+      LR_Parser : WisiToken.Parse.LR.Parser.Parser_Access := 
WisiToken.Parse.LR.Parser.Parser_Access (Object);
+   begin
+      WisiToken.Parse.LR.Parser.Free (LR_Parser);
+      Object := null;
+   end Free_Parser;
+
+begin
+   Process_Stream
+     (Name, Language_Protocol_Version, Params,
+      Factory'Unrestricted_Access, Free_Parser'Unrestricted_Access, 
Trace'Unchecked_Access);
+end Gen_Emacs_Wisi_LR_Text_Rep_Parse;
diff --git a/gen_emacs_wisi_lr_text_rep_parse.ads 
b/gen_emacs_wisi_lr_text_rep_parse.ads
index 83487a72d2..da0b5e07a7 100644
--- a/gen_emacs_wisi_lr_text_rep_parse.ads
+++ b/gen_emacs_wisi_lr_text_rep_parse.ads
@@ -24,7 +24,6 @@
 pragma License (GPL);
 
 with Wisi;
-with WisiToken.Lexer;
 with WisiToken.Parse.LR.Parser;
 with WisiToken.Syntax_Trees;
 generic
@@ -32,16 +31,18 @@ generic
 
    Name                           : in String; --  for Usage, error messages. 
"_wisi_parse" will be appended
    Language_Protocol_Version      : in String; --  Defines language-specific 
parse parameters.
-   Descriptor                     : in WisiToken.Descriptor_Access_Constant;
-   Partial_Parse_Active           : in WisiToken.Boolean_Access;
-   Partial_Parse_Byte_Goal        : in WisiToken.Buffer_Pos_Access;
    Language_Fixes                 : in 
WisiToken.Parse.LR.Parser.Language_Fixes_Access;
    Language_Matching_Begin_Tokens : in 
WisiToken.Parse.LR.Parser.Language_Matching_Begin_Tokens_Access;
    Language_String_ID_Set         : in 
WisiToken.Parse.LR.Parser.Language_String_ID_Set_Access;
    Text_Rep_File_Name             : in String;
 
-   with function Create_Lexer (Trace : in WisiToken.Trace_Access) return 
WisiToken.Lexer.Handle;
-   with function Create_Parse_Table (Text_Rep_File_Name : in String) return 
WisiToken.Parse.LR.Parse_Table_Ptr;
-   with function Create_Productions return 
WisiToken.Syntax_Trees.Production_Info_Trees.Vector;
+   with function Create_Parser
+     (Trace                          : in WisiToken.Trace_Access;
+      User_Data                      : in 
WisiToken.Syntax_Trees.User_Data_Access;
+      Language_Fixes                 : in 
WisiToken.Parse.LR.Parser.Language_Fixes_Access;
+      Language_Matching_Begin_Tokens : in 
WisiToken.Parse.LR.Parser.Language_Matching_Begin_Tokens_Access;
+      Language_String_ID_Set         : in 
WisiToken.Parse.LR.Parser.Language_String_ID_Set_Access;
+      Text_Rep_File_Name             : in String)
+     return WisiToken.Parse.LR.Parser.Parser;
 
 procedure Gen_Emacs_Wisi_LR_Text_Rep_Parse;
diff --git a/gen_emacs_wisi_packrat_parse.adb b/gen_emacs_wisi_packrat_parse.adb
deleted file mode 100644
index b4e95f604f..0000000000
--- a/gen_emacs_wisi_packrat_parse.adb
+++ /dev/null
@@ -1,180 +0,0 @@
---  Abstract :
---
---  See spec.
---
---  Copyright (C) 2018 All Rights Reserved.
---
---  This program is free software; you can redistribute it and/or
---  modify it under terms of the GNU General Public License as
---  published by the Free Software Foundation; either version 3, 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
---  distributed with this program; see file COPYING. If not, write to
---  the Free Software Foundation, 51 Franklin Street, Suite 500, Boston,
---  MA 02110-1335, USA.
-
-pragma License (GPL);
-
-with Ada.Command_Line;
-with Ada.Exceptions;
-with Ada.Strings.Fixed;
-with Ada.Strings.Unbounded;
-with Ada.Text_IO; use Ada.Text_IO;
-with Emacs_Wisi_Common_Parse; use Emacs_Wisi_Common_Parse;
-with GNAT.OS_Lib;
-with GNAT.Traceback.Symbolic;
-with System.Storage_Elements;
-with WisiToken.Lexer;
-with WisiToken.Parse.Packrat;
-with WisiToken.Text_IO_Trace;
-procedure Gen_Emacs_Wisi_Parse_Packrat
-is
-   use WisiToken; -- "+", "-" Unbounded_string
-
-   Trace      : aliased WisiToken.Text_IO_Trace.Trace (Descriptor'Access);
-   Parser     : WisiToken.Parse.Packrat.Parser;
-   Parse_Data : aliased Parse_Data_Type (Parser.Line_Begin_Token'Access);
-
-begin
-   Create_Parser (Parser, Trace'Unrestricted_Access, 
Parse_Data'Unchecked_Access);
-
-   declare
-      use Ada.Command_Line;
-   begin
-      case Argument_Count is
-      when 0 =>
-         null;
-
-      when others =>
-         Usage (Name);
-         raise Programmer_Error with "invalid option count: " & Integer'Image 
(Argument_Count);
-      end case;
-   end;
-
-   Put_Line (Name & " " & Version & ", protocol version " & Protocol_Version);
-
-   --  Read commands and tokens from standard_input via GNAT.OS_Lib,
-   --  send results to standard_output.
-   loop
-      Put (Prompt); Flush;
-      declare
-         Command_Length : constant Integer := Get_Command_Length;
-         Command_Line   : aliased String (1 .. Command_Length);
-         Last           : Integer;
-
-         function Match (Target : in String) return Boolean
-         is begin
-            Last := Command_Line'First + Target'Length - 1;
-            return Last <= Command_Line'Last and then Command_Line 
(Command_Line'First .. Last) = Target;
-         end Match;
-      begin
-         Read_Input (Command_Line'Address, Command_Length);
-
-         Put_Line (";; " & Command_Line);
-
-         if Match ("parse") then
-            --  Args: see Usage
-            --  Input: <source text>
-            --  Response:
-            --  [response elisp vector]...
-            --  [elisp error form]...
-            --  prompt
-            declare
-               use Wisi;
-               Cl_Params : constant Command_Line_Params := Get_Cl_Params 
(Command_Line, Last);
-               Buffer    : Ada.Strings.Unbounded.String_Access;
-
-               procedure Clean_Up
-               is begin
-                  Parser.Lexer.Discard_Rest_Of_Input;
-                  Parser.Put_Errors (-Cl_Param.Source_File_Name);
-                  Ada.Strings.Unbounded.Free (Buffer);
-               end Clean_Up;
-
-            begin
-               --  Computing Line_Count in elisp allows parsing in parallel 
with
-               --  sending source text.
-
-               Trace_Parse    := Cl_Params.Parse_Verbosity;
-               Trace_McKenzie := Cl_Params.McKenzie_Verbosity;
-               Trace_Action   := Cl_Params.Action_Verbosity;
-               Debug_Mode     := Cl_Params.Debug_Mode;
-
-               Parse_Data.Initialize
-                 (Post_Parse_Action => Cl_Params.Post_Parse_Action,
-                  Descriptor        => Descriptor'Access,
-                  Source_File_Name  => -Cl_Params.Source_File_Name,
-                  Line_Count        => Cl_Params.Line_Count,
-                  Params            => Command_Line (Last + 2 .. 
Command_Line'Last));
-
-               Buffer := new String (1 .. Cl_Params.Byte_Count);
-               Read_Input (Buffer (1)'Address, Cl_Params.Byte_Count);
-
-               Parser.Lexer.Reset_With_String_Access (Buffer);
-               Parser.Parse;
-               Parser.Execute_Actions;
-               Put (Parse_Data);
-               Clean_Up;
-
-            exception
-            when Syntax_Error =>
-               Clean_Up;
-               Put_Line ("(parse_error)");
-
-            when E : Parse_Error =>
-               Clean_Up;
-               Put_Line ("(parse_error """ & Ada.Exceptions.Exception_Message 
(E) & """)");
-
-            when E : Fatal_Error =>
-               Clean_Up;
-               Put_Line ("(error """ & Ada.Exceptions.Exception_Message (E) & 
""")");
-            end;
-
-         elsif Match ("noop") then
-            --  Args: <source byte count>
-            --  Input: <source text>
-            --  Response: prompt
-            declare
-               Byte_Count  : constant Integer                             := 
Get_Integer (Command_Line, Last);
-               Buffer      : constant Ada.Strings.Unbounded.String_Access := 
new String (1 .. Byte_Count);
-               Token       : Base_Token;
-               Lexer_Error : Boolean;
-               pragma Unreferenced (Lexer_Error);
-            begin
-               Token.ID := Invalid_Token_ID;
-               Read_Input (Buffer (1)'Address, Byte_Count);
-
-               Parser.Lexer.Reset_With_String_Access (Buffer);
-               loop
-                  exit when Token.ID = Parser.Trace.Descriptor.EOF_ID;
-                  Lexer_Error := Parser.Lexer.Find_Next (Token);
-               end loop;
-            exception
-            when Syntax_Error =>
-               Parser.Lexer.Discard_Rest_Of_Input;
-            end;
-
-         elsif Match ("quit") then
-            exit;
-
-         else
-            Put_Line ("(error ""bad command: '" & Command_Line & "'"")");
-         end if;
-      exception
-      when E : Protocol_Error =>
-         --  don't exit the loop; allow debugging bad elisp
-         Put_Line ("(error ""protocol error "": " & 
Ada.Exceptions.Exception_Message (E) & """)");
-      end;
-   end loop;
-exception
-when E : others =>
-   Ada.Command_Line.Set_Exit_Status (Ada.Command_Line.Failure);
-   New_Line (2);
-   Put_Line
-     ("(error ""unhandled exception: " & Ada.Exceptions.Exception_Name (E) & 
": " &
-        Ada.Exceptions.Exception_Message (E) & """)");
-   Put_Line (GNAT.Traceback.Symbolic.Symbolic_Traceback (E));
-end Gen_Emacs_Wisi_Parse_Packrat;
diff --git a/gen_emacs_wisi_packrat_parse.ads b/gen_emacs_wisi_packrat_parse.ads
deleted file mode 100644
index 79c69ecf89..0000000000
--- a/gen_emacs_wisi_packrat_parse.ads
+++ /dev/null
@@ -1,42 +0,0 @@
---  Abstract :
---
---  Generic Emacs background process; packrat parse token stream,
---  return parser actions.
---
---  See gen_run_wisi_parse_packrat.ads for a standalone version.
---
---  References :
---
---  See gen_emacs_wisi_parse.ads
---
---  Copyright (C) 2018 Free Software Foundation, Inc.
---
---  This program is free software; you can redistribute it and/or
---  modify it under terms of the GNU General Public License as
---  published by the Free Software Foundation; either version 3, 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
---  distributed with this program; see file COPYING. If not, write to
---  the Free Software Foundation, 51 Franklin Street, Suite 500, Boston,
---  MA 02110-1335, USA.
-
-pragma License (GPL);
-
-with WisiToken.Parse.Packrat;
-with WisiToken.Syntax_Trees;
-with WisiToken.Wisi_Runtime;
-generic
-   type Parse_Data_Type  is new WisiToken.Wisi_Runtime.Parse_Data_Type with 
private;
-
-   Name       : in String; --  for Usage, error messages. 
"_wisi_parse_packrat" will be appended
-   Descriptor : in WisiToken.Descriptor;
-
-   with procedure Create_Parser
-     (Parser    :    out          WisiToken.Parse.Packrat.Parser;
-      Trace     : not null access WisiToken.Trace'Class;
-      User_Data : in              WisiToken.Syntax_Trees.User_Data_Access);
-
-procedure Gen_Emacs_Wisi_Parse_Packrat;
diff --git a/gen_run_wisi_lr_parse.adb b/gen_run_wisi_lr_parse.adb
index 803ddb8213..c96ecc789d 100644
--- a/gen_run_wisi_lr_parse.adb
+++ b/gen_run_wisi_lr_parse.adb
@@ -18,34 +18,32 @@
 
 pragma License (GPL);
 
-with GNATCOLL.Memory;
 with Run_Wisi_Common_Parse;
 with WisiToken.Text_IO_Trace;
 procedure Gen_Run_Wisi_LR_Parse
 is
-   Trace               : aliased WisiToken.Text_IO_Trace.Trace;
-   Parse_Data_Template : aliased Parse_Data_Type;
-begin
-   --  FIXME: report memory during lexer, parser create
-   --  WisiToken.Trace_Memory            := 2;
-   --  WisiToken.Trace_Incremental_Parse := 1;
-   GNATCOLL.Memory.Configure
-     (Activate_Monitor      => True,
-      Stack_Trace_Depth     => 10,
-      Reset_Content_On_Free => False);
+   Trace : aliased WisiToken.Text_IO_Trace.Trace;
+
+   function Factory return WisiToken.Parse.Base_Parser_Access
+   is begin
+      return new WisiToken.Parse.LR.Parser.Parser'
+        (Create_Parser
+           (Trace'Unrestricted_Access,
+            User_Data                      => new Parse_Data_Type,
+            Language_Fixes                 => Language_Fixes,
+            Language_Matching_Begin_Tokens => Language_Matching_Begin_Tokens,
+            Language_String_ID_Set         => Language_String_ID_Set));
+   end Factory;
 
-   declare
-      Lexer : constant WisiToken.Lexer.Handle := Create_Lexer 
(Trace'Unchecked_Access);
-      --  No point in reporting lexer memory; it's very small
-      Parse_Table : constant WisiToken.Parse.LR.Parse_Table_Ptr := 
Create_Parse_Table;
+   procedure Free_Parser (Object : in out WisiToken.Parse.Base_Parser_Access)
+   is
+      LR_Parser : WisiToken.Parse.LR.Parser.Parser_Access := 
WisiToken.Parse.LR.Parser.Parser_Access (Object);
    begin
-      Trace.Put_Line ("parse table created");
-      WisiToken.Report_Memory (Trace, Prefix => True);
+      WisiToken.Parse.LR.Parser.Free (LR_Parser);
+      Object := null;
+   end Free_Parser;
 
-      Run_Wisi_Common_Parse.Parse_File
-        ((Descriptor, Lexer, Parse_Table, Create_Productions, 
Partial_Parse_Active,
-          Partial_Parse_Byte_Goal, Language_Fixes, 
Language_Matching_Begin_Tokens, Language_String_ID_Set,
-          Parse_Data_Template'Unchecked_Access),
-         Trace'Unchecked_Access);
-   end;
+begin
+   Run_Wisi_Common_Parse.Parse_File
+     (Factory'Unrestricted_Access, Free_Parser'Unrestricted_Access, 
Trace'Unchecked_Access);
 end Gen_Run_Wisi_LR_Parse;
diff --git a/gen_run_wisi_lr_parse.ads b/gen_run_wisi_lr_parse.ads
index 34b73fa171..65c03c337d 100644
--- a/gen_run_wisi_lr_parse.ads
+++ b/gen_run_wisi_lr_parse.ads
@@ -21,21 +21,21 @@
 pragma License (GPL);
 
 with Wisi;
-with WisiToken.Lexer;
 with WisiToken.Parse.LR.Parser;
 with WisiToken.Syntax_Trees;
 generic
    type Parse_Data_Type is new Wisi.Parse_Data_Type with private;
 
-   Descriptor                     : in WisiToken.Descriptor_Access_Constant;
-   Partial_Parse_Active           : in WisiToken.Boolean_Access;
-   Partial_Parse_Byte_Goal        : in WisiToken.Buffer_Pos_Access;
    Language_Fixes                 : in 
WisiToken.Parse.LR.Parser.Language_Fixes_Access;
    Language_Matching_Begin_Tokens : in 
WisiToken.Parse.LR.Parser.Language_Matching_Begin_Tokens_Access;
    Language_String_ID_Set         : in 
WisiToken.Parse.LR.Parser.Language_String_ID_Set_Access;
 
-   with function Create_Lexer (Trace : in WisiToken.Trace_Access) return 
WisiToken.Lexer.Handle;
-   with function Create_Parse_Table return WisiToken.Parse.LR.Parse_Table_Ptr;
-   with function Create_Productions return 
WisiToken.Syntax_Trees.Production_Info_Trees.Vector;
+   with function Create_Parser
+     (Trace                          : in WisiToken.Trace_Access;
+      User_Data                      : in 
WisiToken.Syntax_Trees.User_Data_Access;
+      Language_Fixes                 : in 
WisiToken.Parse.LR.Parser.Language_Fixes_Access;
+      Language_Matching_Begin_Tokens : in 
WisiToken.Parse.LR.Parser.Language_Matching_Begin_Tokens_Access;
+      Language_String_ID_Set         : in 
WisiToken.Parse.LR.Parser.Language_String_ID_Set_Access)
+     return WisiToken.Parse.LR.Parser.Parser;
 
 procedure Gen_Run_Wisi_LR_Parse;
diff --git a/gen_run_wisi_lr_text_rep_parse.adb 
b/gen_run_wisi_lr_text_rep_parse.adb
index 6c2196e83f..4bc934f10e 100644
--- a/gen_run_wisi_lr_text_rep_parse.adb
+++ b/gen_run_wisi_lr_text_rep_parse.adb
@@ -20,35 +20,36 @@ pragma License (GPL);
 
 with Ada.Command_Line;
 with Ada.Directories;
-with GNATCOLL.Memory;
 with Run_Wisi_Common_Parse;
 with WisiToken.Text_IO_Trace;
 procedure Gen_Run_Wisi_LR_Text_Rep_Parse
 is
-   Trace               : aliased WisiToken.Text_IO_Trace.Trace;
-   Parse_Data_Template : aliased Parse_Data_Type;
-begin
-   --  FIXME: report memory during lexer, parser create
-   --  WisiToken.Trace_Memory            := 1;
-   --  WisiToken.Trace_Incremental_Parse := 1;
-   GNATCOLL.Memory.Configure
-     (Activate_Monitor      => True,
-      Stack_Trace_Depth     => 0,
-      Reset_Content_On_Free => False);
+   Trace : aliased WisiToken.Text_IO_Trace.Trace;
+
+   Text_Rep_File_Name_Full : constant String := 
Ada.Directories.Containing_Directory
+     (Ada.Command_Line.Command_Name) & "/" & Text_Rep_File_Name;
 
-   declare
-      Lexer : constant WisiToken.Lexer.Handle := Create_Lexer 
(Trace'Unchecked_Access);
-      --  No point in reporting lexer memory; it's very small
-      Parse_Table : constant WisiToken.Parse.LR.Parse_Table_Ptr := 
Create_Parse_Table
-        (Ada.Directories.Containing_Directory (Ada.Command_Line.Command_Name) 
& "/" & Text_Rep_File_Name);
+   function Factory return WisiToken.Parse.Base_Parser_Access
+   is begin
+      return new WisiToken.Parse.LR.Parser.Parser'
+        (Create_Parser
+           (Trace'Unchecked_Access,
+            User_Data                      => new Parse_Data_Type,
+            Language_Fixes                 => Language_Fixes,
+            Language_Matching_Begin_Tokens => Language_Matching_Begin_Tokens,
+            Language_String_ID_Set         => Language_String_ID_Set,
+            Text_Rep_File_Name             => Text_Rep_File_Name_Full));
+   end Factory;
+
+   procedure Free_Parser (Object : in out WisiToken.Parse.Base_Parser_Access)
+   is
+      LR_Parser : WisiToken.Parse.LR.Parser.Parser_Access := 
WisiToken.Parse.LR.Parser.Parser_Access (Object);
    begin
-      Trace.Put_Line ("parse table created");
-      WisiToken.Report_Memory (Trace, Prefix => True);
+      WisiToken.Parse.LR.Parser.Free (LR_Parser);
+      Object := null;
+   end Free_Parser;
 
-      Run_Wisi_Common_Parse.Parse_File
-        ((Descriptor, Lexer, Parse_Table,
-          Create_Productions, Partial_Parse_Active, Partial_Parse_Byte_Goal, 
Language_Fixes,
-          Language_Matching_Begin_Tokens, Language_String_ID_Set, 
Parse_Data_Template'Unchecked_Access),
-         Trace'Unchecked_Access);
-   end;
+begin
+   Run_Wisi_Common_Parse.Parse_File
+     (Factory'Unrestricted_Access, Free_Parser'Unrestricted_Access, 
Trace'Unchecked_Access);
 end Gen_Run_Wisi_LR_Text_Rep_Parse;
diff --git a/gen_run_wisi_lr_text_rep_parse.ads 
b/gen_run_wisi_lr_text_rep_parse.ads
index dea8f54048..405013da2e 100644
--- a/gen_run_wisi_lr_text_rep_parse.ads
+++ b/gen_run_wisi_lr_text_rep_parse.ads
@@ -21,22 +21,23 @@
 pragma License (GPL);
 
 with Wisi;
-with WisiToken.Lexer;
 with WisiToken.Parse.LR.Parser;
 with WisiToken.Syntax_Trees;
 generic
    type Parse_Data_Type is new Wisi.Parse_Data_Type with private;
 
-   Descriptor                     : in WisiToken.Descriptor_Access_Constant;
-   Partial_Parse_Active           : in WisiToken.Boolean_Access;
-   Partial_Parse_Byte_Goal        : in WisiToken.Buffer_Pos_Access;
    Language_Fixes                 : in 
WisiToken.Parse.LR.Parser.Language_Fixes_Access;
    Language_Matching_Begin_Tokens : in 
WisiToken.Parse.LR.Parser.Language_Matching_Begin_Tokens_Access;
    Language_String_ID_Set         : in 
WisiToken.Parse.LR.Parser.Language_String_ID_Set_Access;
    Text_Rep_File_Name             : in String;
 
-   with function Create_Lexer (Trace : in WisiToken.Trace_Access) return 
WisiToken.Lexer.Handle;
-   with function Create_Parse_Table (Text_Rep_File_Name : in String) return 
WisiToken.Parse.LR.Parse_Table_Ptr;
-   with function Create_Productions return 
WisiToken.Syntax_Trees.Production_Info_Trees.Vector;
+   with function Create_Parser
+     (Trace                          : in WisiToken.Trace_Access;
+      User_Data                      : in 
WisiToken.Syntax_Trees.User_Data_Access;
+      Language_Fixes                 : in 
WisiToken.Parse.LR.Parser.Language_Fixes_Access;
+      Language_Matching_Begin_Tokens : in 
WisiToken.Parse.LR.Parser.Language_Matching_Begin_Tokens_Access;
+      Language_String_ID_Set         : in 
WisiToken.Parse.LR.Parser.Language_String_ID_Set_Access;
+      Text_Rep_File_Name             : in String)
+     return WisiToken.Parse.LR.Parser.Parser;
 
 procedure Gen_Run_Wisi_LR_Text_Rep_Parse;
diff --git a/gen_run_wisi_packrat_parse.adb b/gen_run_wisi_packrat_parse.adb
deleted file mode 100644
index fb3e900a09..0000000000
--- a/gen_run_wisi_packrat_parse.adb
+++ /dev/null
@@ -1,241 +0,0 @@
---  Abstract :
---
---  See spec.
---
---  Copyright (C) 2018 All Rights Reserved.
---
---  This program is free software; you can redistribute it and/or
---  modify it under terms of the GNU General Public License as
---  published by the Free Software Foundation; either version 3, 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
---  distributed with this program; see file COPYING. If not, write to
---  the Free Software Foundation, 51 Franklin Street, Suite 500, Boston,
---  MA 02110-1335, USA.
-
-pragma License (GPL);
-
-with Ada.Command_Line;
-with Ada.Exceptions;
-with Ada.IO_Exceptions;
-with Ada.Real_Time;
-with Ada.Strings.Unbounded;
-with Ada.Text_IO; use Ada.Text_IO;
-with GNAT.Traceback.Symbolic;
-with WisiToken.Lexer;
-with WisiToken.Text_IO_Trace;
-procedure Gen_Run_Wisi_Parse_Packrat
-is
-   use WisiToken; -- Token_ID, "+", "-" Unbounded_string
-
-   Trace      : aliased WisiToken.Text_IO_Trace.Trace (Descriptor'Access);
-   Parser     : WisiToken.Parse.Packrat.Parser;
-   Parse_Data : aliased Parse_Data_Type (Parser.Line_Begin_Token'Access);
-
-   procedure Put_Usage
-   is begin
-      Put_Line ("usage: " & Name & "_wisi_parse <file_name> <parse_action> 
[options]");
-      Put_Line ("parse_action: {Navigate | Face | Indent}");
-      Put_Line ("options:");
-      Put_Line ("--verbosity n m l:");
-      Put_Line ("   n: parser; m: mckenzie; l: action");
-      Put_Line ("   0 - only report parse errors");
-      Put_Line ("   1 - shows spawn/terminate parallel parsers, error recovery 
enter/exit");
-      Put_Line ("   2 - add each parser cycle, error recovery enqueue/check");
-      Put_Line ("   3 - parse stack in each cycle, error recovery parse 
actions");
-      Put_Line ("   4 - add lexer debug");
-      Put_Line ("--lang_params <language-specific params>");
-      Put_Line ("--lexer_only : only run lexer, for profiling");
-      Put_Line ("--repeat_count n : repeat parse count times, for profiling; 
default 1");
-      Put_Line ("--pause : when repeating, prompt for <enter> after each 
parse; allows seeing memory leaks");
-      New_Line;
-   end Put_Usage;
-
-   Source_File_Name  : Ada.Strings.Unbounded.Unbounded_String;
-   Post_Parse_Action : WisiToken.Wisi_Runtime.Post_Parse_Action_Type;
-
-   Line_Count   : WisiToken.Line_Number_Type := 1;
-   Lexer_Only   : Boolean                    := False;
-   Repeat_Count : Integer                    := 1;
-   Pause        : Boolean                    := False;
-   Arg          : Integer;
-   Lang_Params  : Ada.Strings.Unbounded.Unbounded_String;
-   Start        : Ada.Real_Time.Time;
-begin
-   Create_Parser (Parser, Trace'Unrestricted_Access, 
Parse_Data'Unchecked_Access);
-
-   declare
-      use Ada.Command_Line;
-   begin
-      if Argument_Count < 1 then
-         Put_Usage;
-         Set_Exit_Status (Failure);
-         return;
-      end if;
-
-      Source_File_Name  := +Ada.Command_Line.Argument (1);
-      Post_Parse_Action := WisiToken.Wisi_Runtime.Post_Parse_Action_Type'Value 
(Ada.Command_Line.Argument (2));
-      Arg               := 3;
-
-      loop
-         exit when Arg > Argument_Count;
-
-         if Argument (Arg) = "--verbosity" then
-            WisiToken.Trace_Parse    := Integer'Value (Argument (Arg + 1));
-            WisiToken.Trace_McKenzie := Integer'Value (Argument (Arg + 2));
-            WisiToken.Trace_Action   := Integer'Value (Argument (Arg + 3));
-            Arg                      := Arg + 4;
-
-         elsif Argument (Arg) = "--lang_params" then
-            Lang_Params := +Argument (Arg + 1);
-            Arg := Arg + 2;
-
-         elsif Argument (Arg) = "--lexer_only" then
-            Lexer_Only := True;
-            Arg := Arg + 1;
-
-         elsif Argument (Arg) = "--pause" then
-            Pause := True;
-            Arg := Arg + 1;
-
-         elsif Argument (Arg) = "--repeat_count" then
-            Repeat_Count := Integer'Value (Argument (Arg + 1));
-            Arg := Arg + 2;
-
-         else
-            Put_Line ("unrecognized option: '" & Argument (Arg) & "'");
-            Put_Usage;
-            return;
-         end if;
-      end loop;
-   end;
-
-   --  Do this after setting Trace_Parse so lexer verbosity is set
-   begin
-      Parser.Lexer.Reset_With_File (-Source_File_Name);
-   exception
-   when Ada.IO_Exceptions.Name_Error =>
-      Put_Line (Standard_Error, "'" & (-Source_File_Name) & "' cannot be 
opened");
-      return;
-   end;
-
-   --  See comment in wisi-wisi_runtime.ads for why we still need this.
-   declare
-      Token : Base_Token;
-      Lexer_Error : Boolean;
-      pragma Unreferenced (Lexer_Error);
-   begin
-      loop
-         begin
-            Lexer_Error := Parser.Lexer.Find_Next (Token);
-            exit when Token.ID = Descriptor.EOF_ID;
-         exception
-         when WisiToken.Syntax_Error =>
-            Parser.Lexer.Discard_Rest_Of_Input;
-            Parser.Put_Errors (-Source_File_Name);
-            Put_Line ("(lexer_error)");
-         end;
-      end loop;
-      Line_Count := Token.Line;
-   end;
-
-   if WisiToken.Trace_Action > WisiToken.Outline then
-      Put_Line ("line_count:" & Line_Number_Type'Image (Line_Count));
-   end if;
-
-   Parse_Data.Initialize
-     (Post_Parse_Action => Post_Parse_Action,
-      Descriptor        => Descriptor'Access,
-      Source_File_Name  => -Source_File_Name,
-      Line_Count        => Line_Count,
-      Params            => -Lang_Params);
-
-   if Repeat_Count > 1 then
-      Start := Ada.Real_Time.Clock;
-   end if;
-
-   for I in 1 .. Repeat_Count loop
-      declare
-         procedure Clean_Up
-         is begin
-            Parser.Lexer.Discard_Rest_Of_Input;
-            if Repeat_Count = 1 then
-               Parser.Put_Errors (-Source_File_Name);
-            end if;
-         end Clean_Up;
-
-      begin
-         Parse_Data.Reset;
-         Parser.Lexer.Reset;
-
-         if Lexer_Only then
-            declare
-               Token : Base_Token;
-               Lexer_Error : Boolean;
-               pragma Unreferenced (Lexer_Error);
-            begin
-               Parser.Lexer.Reset;
-               loop
-                  Lexer_Error := Parser.Lexer.Find_Next (Token);
-                  exit when Token.ID = Descriptor.EOF_ID;
-               end loop;
-               --  We don't handle errors here; that was done in the count 
lines loop
-               --  above.
-            end;
-         else
-            Parser.Parse;
-            Parser.Execute_Actions;
-
-            if Repeat_Count = 1 then
-               Parse_Data.Put;
-               Parser.Put_Errors (-Source_File_Name);
-            end if;
-         end if;
-      exception
-      when WisiToken.Syntax_Error =>
-         Clean_Up;
-         Put_Line ("(parse_error)");
-
-      when E : WisiToken.Parse_Error =>
-         Clean_Up;
-         Put_Line ("(parse_error """ & Ada.Exceptions.Exception_Message (E) & 
""")");
-
-      when E : WisiToken.Fatal_Error =>
-         Clean_Up;
-         Put_Line ("(error """ & Ada.Exceptions.Exception_Message (E) & """)");
-      end;
-
-      if Pause then
-         Put_Line ("Enter to continue:");
-         Flush (Standard_Output);
-         declare
-            Junk : constant String := Get_Line;
-            pragma Unreferenced (Junk);
-         begin
-            null;
-         end;
-      end if;
-   end loop;
-
-   if Repeat_Count > 1 then
-      declare
-         use Ada.Real_Time;
-         Finish : constant Time := Clock;
-      begin
-         Put_Line ("Total time:" & Duration'Image (To_Duration (Finish - 
Start)));
-         Put_Line ("per iteration:" & Duration'Image (To_Duration ((Finish - 
Start) / Repeat_Count)));
-      end;
-   end if;
-
-exception
-when E : others =>
-   Ada.Command_Line.Set_Exit_Status (Ada.Command_Line.Failure);
-   New_Line (2);
-   Put_Line
-     ("(error ""unhandled exception: " & Ada.Exceptions.Exception_Name (E) & 
": " &
-        Ada.Exceptions.Exception_Message (E) & """)");
-   Put_Line (GNAT.Traceback.Symbolic.Symbolic_Traceback (E));
-end Gen_Run_Wisi_Parse_Packrat;
diff --git a/gen_run_wisi_packrat_parse.ads b/gen_run_wisi_packrat_parse.ads
deleted file mode 100644
index 538da1d9ea..0000000000
--- a/gen_run_wisi_packrat_parse.ads
+++ /dev/null
@@ -1,36 +0,0 @@
---  Abstract :
---
---  Run an Emacs packrate parser as a standalone executable, for debugging.
---
---  See gen_emacs_wisi_parse_packrat.ads for the Emacs background process.
---
---  Copyright (C) 2018 Free Software Foundation, Inc.
---
---  This program is free software; you can redistribute it and/or
---  modify it under terms of the GNU General Public License as
---  published by the Free Software Foundation; either version 3, 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
---  distributed with this program; see file COPYING. If not, write to
---  the Free Software Foundation, 51 Franklin Street, Suite 500, Boston,
---  MA 02110-1335, USA.
-
-pragma License (GPL);
-
-with WisiToken.Parse.Packrat;
-with WisiToken.Syntax_Trees;
-with WisiToken.Wisi_Runtime;
-generic
-   type Parse_Data_Type is new WisiToken.Wisi_Runtime.Parse_Data_Type with 
private;
-
-   Descriptor : in WisiToken.Descriptor;
-
-   with procedure Create_Parser
-     (Parser    :    out          WisiToken.Parse.Packrat.Parser;
-      Trace     : not null access WisiToken.Trace'Class;
-      User_Data : in              WisiToken.Syntax_Trees.User_Data_Access);
-
-procedure Gen_Run_Wisi_Parse_Packrat;
diff --git a/gnat-core.el b/gnat-core.el
deleted file mode 100644
index cd71ed33f3..0000000000
--- a/gnat-core.el
+++ /dev/null
@@ -1,487 +0,0 @@
-;; gnat-core.el --- Support for running GNAT tools, which support multiple 
programming  -*- lexical-binding:t -*-
-;; languages.
-;;
-;; GNAT is provided by AdaCore; see http://libre.adacore.com/
-;;
-;;; Copyright (C) 2012 - 2022  Free Software Foundation, Inc.
-;;
-;; Author: Stephen Leake <stephen_leake@member.fsf.org>
-;; Maintainer: Stephen Leake <stephen_leake@member.fsf.org>
-;;
-;; This file is part of GNU Emacs.
-;;
-;; GNU Emacs 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.
-;;
-;; GNU Emacs is distributed in the hope that it will be useful,
-;; but WITHOUT ANY WARRANTY; without even the implied warranty of
-;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-;; GNU General Public License for more details.
-;;
-;; You should have received a copy of the GNU General Public License
-;; along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
-
-(require 'cl-lib)
-(require 'wisi-prj)
-
-;;;;; code
-
-(defcustom ada-gnat-debug-run nil
-  ;; Name implies Ada, which is wrong. Kept for backward compatibility.
-  "If t, compilation buffers containing a GNAT command will show
-the command.  Otherwise, they will show only the output of the
-command.  This applies e.g. to *gnatfind* buffers."
-  :type 'boolean
-  :safe  #'booleanp
-  :group 'ada)
-
-;;;; project file handling
-
-(cl-defstruct gnat-compiler
-  "Used with wisi-compiler-* generic functions."
-
-  gpr-file       ;; absolute file name of GNAT project file.
-  run-buffer-name ;; string; some compiler objects have no gpr file
-  project-path    ;; list of directories from GPR_PROJECT_PATH
-  target         ;; gnat --target argument.
-  runtime        ;; gnat --RTS argument.
-  gnat-stub-opts  ;; options for gnat stub
-  gnat-stub-cargs ;; cargs options for gnat stub
-  )
-
-;;;###autoload
-(cl-defun create-gnat-compiler
-    (&key
-     gpr-file
-     run-buffer-name
-     project-path
-     target
-     runtime
-     gnat-stub-opts
-     gnat-stub-cargs)
-  ;; See note on `create-ada-prj' for why this is not a defalias.
-  (make-gnat-compiler
-   :gpr-file gpr-file
-   :run-buffer-name run-buffer-name
-   :project-path project-path
-   :target target
-   :runtime runtime
-   :gnat-stub-opts gnat-stub-opts
-   :gnat-stub-cargs gnat-stub-cargs
-   ))
-
-(defun gnat-compiler-require-prj ()
-  "Return current `gnat-compiler' object from current project compiler.
-Throw an error if current project does not have a gnat-compiler."
-  (let* ((wisi-prj (wisi-prj-require-prj))
-        (compiler (wisi-prj-compiler wisi-prj)))
-    (if (gnat-compiler-p compiler)
-       compiler
-      (error "no gnat-compiler in current project"))))
-
-(defun gnat-prj-add-prj-dir (project compiler dir)
-  "Add DIR to COMPILER.project_path, and to GPR_PROJECT_PATH in 
PROJECT.file-env"
-  ;; We maintain two project values for this;
-  ;; project-path - a list of directories, for elisp find file
-  ;; GPR_PROJECT_PATH in environment, for gnat-run
-  (let ((process-environment (copy-sequence (wisi-prj-file-env project))))
-    (cl-pushnew dir (gnat-compiler-project-path compiler) :test #'string-equal)
-
-    (setenv "GPR_PROJECT_PATH"
-           (mapconcat 'identity
-                      (gnat-compiler-project-path compiler) path-separator))
-    (setf (wisi-prj-file-env project) (copy-sequence process-environment))
-    ))
-
-;; We need a dynamic variable for 'add-to-list
-(defvar gnat--src-dirs)
-
-(defun gnat-get-paths (project compiler)
-  "Add project and/or compiler source, project paths to PROJECT source-path"
-  (let* ((gnat--src-dirs (wisi-prj-source-path project))
-        (prj-dirs (cl-copy-list (gnat-compiler-project-path compiler))))
-
-    ;; Don't need project plist obj_dirs if using a project file, so
-    ;; not setting obj-dirs.
-    ;;
-    ;; We only need to update prj-dirs if the gpr-file is an aggregate
-    ;; project that sets the project path.
-
-    (condition-case-unless-debug nil
-       (with-current-buffer (gnat-run-buffer project 
(gnat-compiler-run-buffer-name (wisi-prj-compiler project)))
-         ;; gnat list -v -P can return status 0 or 4; always lists compiler 
dirs
-         (gnat-run-gnat project "list" (list "-v") '(0 4))
-
-         (goto-char (point-min))
-
-         ;; Source path
-         (search-forward "Source Search Path:")
-         (forward-line 1)
-         (while (not (looking-at "^$")) ;; terminate on blank line
-           (back-to-indentation) ;; skip whitespace forward
-
-           ;; we use 'add-to-list here, not 'cl-pushnew, because we
-           ;; want to use append to preserve the directory
-           ;; order. Directory order matters for extension projects,
-           ;; which can have duplicate file names.
-            (add-to-list
-            'gnat--src-dirs
-            (if (looking-at "<Current_Directory>")
-                (directory-file-name default-directory)
-              (expand-file-name ; Canonicalize path part.
-               (directory-file-name
-                (buffer-substring-no-properties (point) (point-at-eol)))))
-            t ;; append
-            #'string-equal)
-           (forward-line 1))
-
-          ;; Project path
-         ;;
-         ;; These are also added to src_dir, so compilation errors
-         ;; reported in project files are found.
-         (search-forward "Project Search Path:")
-         (forward-line 1)
-         (while (not (looking-at "^$"))
-           (back-to-indentation)
-           (if (looking-at "<Current_Directory>")
-                (cl-pushnew (directory-file-name default-directory) prj-dirs 
:test #'string-equal)
-             (let ((f (expand-file-name
-                        (buffer-substring-no-properties (point) 
(point-at-eol)))))
-                (cl-pushnew f prj-dirs :test #'string-equal)
-                (cl-pushnew f gnat--src-dirs :test #'string-equal)))
-           (forward-line 1))
-
-         )
-      (error
-       ;; search-forward failed. Possible causes:
-       ;;
-       ;; missing dirs in GPR_PROJECT_PATH => user error
-       ;; missing Object_Dir => gprbuild not run yet; it will be run soon
-       ;; some files are missing string quotes => user error
-       ;;
-       ;; We used to call gpr_query to get src-dirs, prj-dirs here; it
-       ;; is tolerant of the above errors. But ignoring the errors, to
-       ;; let gprbuild run with GPR_PROJECT_PATH set, is simpler.
-       (pop-to-buffer (gnat-run-buffer project (gnat-compiler-run-buffer-name 
(wisi-prj-compiler project))))
-       (message "project search path: %s" prj-dirs)
-       (message "parse gpr failed")
-       ))
-
-    (setf (wisi-prj-source-path project) (delete-dups gnat--src-dirs))
-    (setf (gnat-compiler-project-path compiler) nil)
-    (mapc (lambda (dir) (gnat-prj-add-prj-dir project compiler dir))
-         prj-dirs)
-    ))
-
-(defun gnat-parse-gpr (gpr-file project compiler)
-  "Parse GPR-FILE, append to PROJECT (a `wisi-prj' object).
-GPR-FILE must be absolute file name.
-source-path will include compiler runtime."
-  ;; this can take a long time; let the user know what's up
-  (if (gnat-compiler-gpr-file compiler)
-      ;; gpr-file previously set; new one must match
-      (when (not (string-equal gpr-file (gnat-compiler-gpr-file compiler)))
-       (error "project file %s defines a different GNAT project file than %s"
-              (gnat-compiler-gpr-file compiler)
-              gpr-file))
-
-    (setf (gnat-compiler-gpr-file compiler) gpr-file))
-
-  (gnat-get-paths project compiler))
-
-(defun gnat-parse-gpr-1 (gpr-file project)
-  "For `wisi-prj-parser-alist'."
-  (let ((compiler (wisi-prj-compiler project)))
-    (setf (gnat-compiler-run-buffer-name compiler) gpr-file)
-    (gnat-parse-gpr gpr-file project compiler)))
-
-;;;; command line tool interface
-
-(defun gnat-run-buffer-name (prj-file-name &optional prefix)
-  ;; We don't use (gnat-compiler-gpr-file compiler), because multiple
-  ;; wisi-prj files can use one gpr-file.
-  (concat (or prefix " *gnat-run-")
-         prj-file-name
-         "*"))
-
-(defun gnat-run-buffer (project name)
-  "Return a buffer suitable for running gnat command line tools for PROJECT"
-  (let* ((buffer (get-buffer name)))
-
-    (unless (buffer-live-p buffer)
-      (setq buffer (get-buffer-create name))
-      (when (gnat-compiler-gpr-file (wisi-prj-compiler project))
-       ;; Otherwise assume `default-directory' is already correct (or
-       ;; doesn't matter).
-       (with-current-buffer buffer
-         (setq default-directory
-               (file-name-directory
-                (gnat-compiler-gpr-file (wisi-prj-compiler project)))))
-       ))
-    buffer))
-
-(defun gnat-run (project exec command &optional err-msg expected-status)
-  "Run a gnat command line tool, as \"EXEC COMMAND\".
-PROJECT  is a `wisi-prj' object.
-EXEC must be an executable found on `exec-path'.
-COMMAND must be a list of strings.
-ERR-MSG must be nil or a string.
-EXPECTED-STATUS must be nil or a list of integers; throws an error if
-process status is not a member.
-
-Return process status.
-Assumes current buffer is (gnat-run-buffer)"
-  (set 'buffer-read-only nil)
-  (erase-buffer)
-
-  (setq command (cl-delete-if 'null command))
-
-  (let ((process-environment
-        (append
-          (wisi-prj-compile-env project)
-          (wisi-prj-file-env project)
-          (copy-sequence process-environment)))
-       status)
-
-    (when ada-gnat-debug-run
-      (insert (format "GPR_PROJECT_PATH=%s\n%s " (getenv "GPR_PROJECT_PATH") 
exec))
-      (mapc (lambda (str) (insert (concat str " "))) command)
-      (newline))
-
-    (setq status (apply 'call-process exec nil t nil command))
-    (cond
-     ((memq status (or expected-status '(0))); success
-      nil)
-
-     (t ; failure
-      (pop-to-buffer (current-buffer))
-      (if err-msg
-         (error "%s %s failed; %s" exec (car command) err-msg)
-       (error "%s %s failed" exec (car command))
-       ))
-     )))
-
-(defun gnat-run-gnat (project command &optional switches-args expected-status)
-  "Run the \"gnat\" command line tool, as \"gnat COMMAND -P<prj> 
SWITCHES-ARGS\".
-COMMAND must be a string, SWITCHES-ARGS a list of strings.
-EXPECTED-STATUS must be nil or a list of integers.
-Return process status.
-Assumes current buffer is (gnat-run-buffer)"
-  (let* ((compiler (wisi-prj-compiler project))
-        (gpr-file (gnat-compiler-gpr-file compiler))
-        (project-file-switch
-         (when gpr-file
-           (concat "-P" (file-name-nondirectory gpr-file))))
-         (target-gnat (concat (gnat-compiler-target compiler) "gnat"))
-         ;; gnat list understands --RTS without a fully qualified
-         ;; path, gnat find (in particular) doesn't (but it doesn't
-         ;; need to, it uses the ALI files found via the GPR)
-         (runtime
-          (when (and (gnat-compiler-runtime compiler) (string= command "list"))
-            (list (concat "--RTS=" (gnat-compiler-runtime compiler)))))
-        (cmd (append (list command) (list project-file-switch) runtime 
switches-args)))
-
-    (gnat-run project target-gnat cmd nil expected-status)
-    ))
-
-(defun gnat-run-no-prj (command &optional dir)
-  "Run \"gnat COMMAND\", with DIR as current directory.
-Return process status.  Process output goes to current buffer,
-which is displayed on error."
-  (set 'buffer-read-only nil)
-  (erase-buffer)
-
-  (when ada-gnat-debug-run
-    (setq command (cl-delete-if 'null command))
-    (mapc (lambda (str) (insert (concat str " "))) command)
-    (newline))
-
-  (let ((default-directory (or dir default-directory))
-       status)
-
-    (setq status (apply 'call-process "gnat" nil t nil command))
-    (cond
-     ((= status 0); success
-      nil)
-
-     (t ; failure
-      (pop-to-buffer (current-buffer))
-      (error "gnat %s failed" (car command)))
-     )))
-
-(cl-defmethod wisi-compiler-parse-one ((compiler gnat-compiler) project name 
value)
-  (cond
-   ((or
-     (string= name "ada_project_path") ;; backward compatibility
-     (string= name "gpr_project_path"))
-    (let ((process-environment
-          (append
-           (wisi-prj-compile-env project)
-           (wisi-prj-file-env project))));; reference, for 
substitute-in-file-name
-      (gnat-prj-add-prj-dir project compiler (expand-file-name 
(substitute-in-file-name value)))))
-
-   ((string= name "gnat-stub-cargs")
-    (setf (gnat-compiler-gnat-stub-cargs compiler) value))
-
-   ((string= name "gnat-stub-opts")
-    (setf (gnat-compiler-gnat-stub-opts compiler) value))
-
-   ((string= name "gpr_file")
-    ;; The gpr file is parsed in `wisi-compiler-parse-final' below, so
-    ;; it sees all file environment vars. We store the absolute gpr
-    ;; file name, so we can get the correct default-directory from
-    ;; it. Note that gprbuild requires the base name be found on
-    ;; GPR_PROJECT_PATH.
-    (let* ((process-environment
-           (append
-            (wisi-prj-compile-env project)
-            (wisi-prj-file-env project)));; reference, for 
substitute-in-file-name
-          (gpr-file (substitute-env-vars value)))
-
-      (if (= (aref gpr-file 0) ?$)
-         ;; An environment variable that was not resolved, possibly
-         ;; because the env var is later defined in the project file;
-         ;; it may be resoved in `wisi-compiler-parse-final'.
-         (setf (gnat-compiler-gpr-file compiler) gpr-file)
-
-       ;; else get the absolute path
-       (setf (gnat-compiler-gpr-file compiler)
-             (or (locate-file gpr-file (gnat-compiler-project-path compiler))
-                 (expand-file-name (substitute-env-vars gpr-file))))))
-    t)
-
-   ((string= name "runtime")
-    (setf (gnat-compiler-runtime compiler) value))
-
-   ((string= name "target")
-    (setf (gnat-compiler-target compiler) value))
-
-   ))
-
-(cl-defmethod wisi-compiler-parse-final ((compiler gnat-compiler) project 
prj-file-name)
-  (setf (gnat-compiler-run-buffer-name compiler) (gnat-run-buffer-name 
prj-file-name))
-
-  (let ((gpr-file (gnat-compiler-gpr-file compiler)))
-    (if gpr-file
-       (progn
-         (when (= (aref gpr-file 0) ?$)
-           ;; An environment variable that was not resolved earlier,
-           ;; because the env var is defined in the project file.
-           (let ((process-environment
-                  (append
-                   (wisi-prj-compile-env project)
-                   (wisi-prj-file-env project))));; reference, for 
substitute-in-file-name
-
-             (setq gpr-file
-                   (or
-                    (locate-file (substitute-env-vars gpr-file)
-                                 (gnat-compiler-project-path compiler))
-                    (expand-file-name (substitute-env-vars gpr-file))))
-
-             (setf (gnat-compiler-gpr-file compiler) gpr-file)))
-
-         (gnat-parse-gpr gpr-file project compiler)
-         )
-
-    ;; else add the compiler libraries to project.source-path
-    (gnat-get-paths project compiler)
-    )))
-
-(cl-defmethod wisi-compiler-select-prj ((_compiler gnat-compiler) _project)
-  (add-to-list 'completion-ignored-extensions ".ali") ;; gnat library files
-  (setq compilation-error-regexp-alist
-       ;; gnu matches the summary line from make:
-       ;; make: *** [rules.make:143: wisitoken-bnf-generate.exe] Error 4
-       ;; which is just annoying, but should be up to the user.
-       '(gnu)
-       )
-  )
-
-(cl-defmethod wisi-compiler-deselect-prj ((_compiler gnat-compiler) _project)
-  (setq completion-ignored-extensions (delete ".ali" 
completion-ignored-extensions))
-  (setq compilation-error-regexp-alist (mapcar #'car 
compilation-error-regexp-alist-alist))
-  )
-
-(cl-defmethod wisi-compiler-show-prj-path ((compiler gnat-compiler))
-    (if (gnat-compiler-project-path compiler)
-      (progn
-       (pop-to-buffer (get-buffer-create "*project file search path*"))
-       (erase-buffer)
-       (dolist (file (gnat-compiler-project-path compiler))
-         (insert (format "%s\n" file))))
-    (message "no project file search path set")
-    ))
-
-;;;; gnatprep utils
-
-(defun gnatprep-indent ()
-  "If point is on a gnatprep keyword, return indentation column
-for it. Otherwise return nil.  Intended to be added to
-`wisi-indent-calculate-functions' or other indentation function
-list."
-  ;; gnatprep keywords are:
-  ;;
-  ;; #if identifier [then]
-  ;; #elsif identifier [then]
-  ;; #else
-  ;; #end if;
-  ;;
-  ;; they are all indented at column 0.
-  (when (equal (char-after) ?\#) 0))
-
-(defun gnatprep-syntax-propertize (start end)
-  (goto-char start)
-  (save-match-data
-    (while (re-search-forward
-           "^[ \t]*\\(#\\(?:if\\|else\\|elsif\\|end\\)\\)"; gnatprep keywords.
-           end t)
-      (cond
-       ((match-beginning 1)
-       (put-text-property
-        (match-beginning 1) (match-end 1) 'syntax-table '(11 . ?\n)))
-       )
-      )))
-
-(defconst gnatprep-preprocessor-keywords
-   (list (list "^[ \t]*\\(#.*\n\\)"  '(1 font-lock-preprocessor-face t))))
-
-;; We assume that if this file is loaded, any ada-mode buffer may have
-;; gnatprep syntax; even with different host/target compilers, both
-;; must run gnatprep first. If support for another preprocessor is
-;; added, we'll need wisi-prj-preprocessor, along with -compiler and
-;; -xref.
-(defun gnatprep-setup ()
-  (add-to-list 'wisi-indent-calculate-functions 'gnatprep-indent)
-  (add-hook 'ada-syntax-propertize-hook #'gnatprep-syntax-propertize)
-  (font-lock-add-keywords 'ada-mode gnatprep-preprocessor-keywords)
-  ;; ada-mode calls font-lock-refresh-defaults after ada-mode-hook
-  )
-
-(add-hook 'ada-mode-hook #'gnatprep-setup)
-
-;;;; Initialization
-
-;; These are shared between ada-compiler-gnat and gpr-query.
-(add-to-list 'wisi-prj-file-extensions  "gpr")
-(add-to-list 'wisi-prj-parser-alist  '("gpr" . gnat-parse-gpr-1))
-
-(add-to-list
- 'compilation-error-regexp-alist-alist
- '(gnat
-   ;; typical:
-   ;;   cards_package.adb:45:32: expected private type "System.Address"
-   ;;
-   ;; with full path Source_Reference pragma :
-   ;;   d:/maphds/version_x/1773/sbs-abi-dll_lib.ads.gp:39:06: file 
"interfaces_c.ads" not found
-   ;;
-   ;; gnu cc1: (gnatmake can invoke the C compiler)
-   ;;   foo.c:2: `TRUE' undeclared here (not in a function)
-   ;;   foo.c:2 : `TRUE' undeclared here (not in a function)
-   ;;
-   ;; we can't handle secondary errors here, because a regexp can't 
distinquish "message" from "filename"
-   "^\\(\\(.:\\)?[^ :\n]+\\):\\([0-9]+\\)\\s-?:?\\([0-9]+\\)?" 1 3 4))
-
-(provide 'gnat-core)
-;; end of file
diff --git a/install.sh b/install.sh
deleted file mode 100644
index 886fc94eed..0000000000
--- a/install.sh
+++ /dev/null
@@ -1,15 +0,0 @@
-#!/bin/sh
-# Install executables for Ada mode.
-#
-# See build.sh for build (must be run before install).
-
-# $1 : optional --prefix=<dir>
-#
-# If you don't have write permission in the GNAT installation
-# directory, you need to use --prefix=<dir>, or run with root priviledges.
-
-WISI_DIR=`ls -d ../wisi-3.1.?`
-
-gprinstall -f -p -P ada_mode_wisi_parse.gpr -aP $WISI_DIR 
--install-name=ada_mode_wisi_parse $1 
-
-# end of file.
diff --git a/prj-alire.el b/prj-alire.el
new file mode 100644
index 0000000000..269b4d8f25
--- /dev/null
+++ b/prj-alire.el
@@ -0,0 +1,29 @@
+;; Set up building with Alire -*- no-byte-compile : t -*-
+;;
+;; Copyright (C) 2021, 2022  Free Software Foundation, Inc.
+;;
+;; This file is part of GNU Emacs.
+;;
+;; GNU Emacs 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.
+;;
+;; GNU Emacs is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
+
+
+(wisi-prj-select-cache
+ "prj-alire.el"
+ (create-alire-prj
+  :name "wisi main Alire"
+  :gpr-file gpr-file
+  :xref-label 'gpr_query)
+ "Makefile")
+
+;; end of file
diff --git a/prj-wisi.el b/prj-wisi.el
new file mode 100644
index 0000000000..f8e41afdbf
--- /dev/null
+++ b/prj-wisi.el
@@ -0,0 +1,30 @@
+;; Set up building with gprbuild in elpa -*- no-byte-compile : t -*-
+;;
+;; Copyright (C) 2021, 2022  Free Software Foundation, Inc.
+;;
+;; This file is part of GNU Emacs.
+;;
+;; GNU Emacs 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.
+;;
+;; GNU Emacs is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
+
+(wisi-prj-select-cache
+ "wisi.gpr"
+ (create-ada-prj
+  :name "wisi main"
+  :compile-env
+  (list
+   (concat "SAL="       (expand-file-name "../../org.stephe_leake.sal"))
+   (concat "WISITOKEN=" (expand-file-name "../../org.wisitoken"))
+   ))
+ "Makefile"
+ )
diff --git a/run_wisi_common_parse.adb b/run_wisi_common_parse.adb
index 88d410f6db..a3ece4cabf 100644
--- a/run_wisi_common_parse.adb
+++ b/run_wisi_common_parse.adb
@@ -30,8 +30,8 @@ with GNAT.Traceback.Symbolic;
 with GNATCOLL.Memory;
 with GNATCOLL.Mmap;
 with SAL;
+with Wisi.Parse_Context;
 with WisiToken.Lexer;
-with WisiToken.Parse.LR.McKenzie_Recover;
 with WisiToken.Parse.LR.Parser;
 with WisiToken.Syntax_Trees;
 with WisiToken.Text_IO_Trace;
@@ -46,7 +46,7 @@ package body Run_Wisi_Common_Parse is
 
       Source_File_Name : Ada.Strings.Unbounded.Unbounded_String;
       Language_Params  : Ada.Strings.Unbounded.Unbounded_String;
-      Repeat_Count     : Integer                    := 1;
+      Repeat_Count     : Integer := 1;
 
       case Command is
       when Parse_Partial =>
@@ -84,8 +84,9 @@ package body Run_Wisi_Common_Parse is
       end case;
    end record;
 
-   procedure Usage_1 (Parse_Data : in Wisi.Parse_Data_Type'Class)
+   procedure Usage (Parse_Table : in WisiToken.Parse.LR.Parse_Table_Ptr)
    is
+      use all type WisiToken.Parse.LR.Parse_Table_Ptr;
       use Ada.Text_IO;
    begin
       Put_Line ("usage: parse_partial <post_parse_action> <file_name> [partial 
parse params] [options]");
@@ -94,19 +95,8 @@ package body Run_Wisi_Common_Parse is
       Put_Line ("   or: refactor <refactor_action> <file_name> <edit_begin> 
[options]");
       Put_Line ("   or: command_file <command_file_name> [source_file_name]");
       Put_Line ("post_parse_action: {Navigate | Face | Indent}");
-      Put_Line ("refactor_action:");
-      Parse_Data.Refactor_Help;
       New_Line;
-   end Usage_1;
 
-   procedure Usage
-     (Parse_Data  : in Wisi.Parse_Data_Type'Class;
-      Parse_Table : in WisiToken.Parse.LR.Parse_Table_Ptr)
-   is
-      use all type WisiToken.Parse.LR.Parse_Table_Ptr;
-      use Ada.Text_IO;
-   begin
-      Usage_1 (Parse_Data);
       Put_Line ("partial parse params: begin_byte_pos end_byte_pos 
goal_byte_pos begin_char_pos end_char_pos" &
                   " begin_line begin_indent");
       Put_Line ("options:");
@@ -117,20 +107,10 @@ package body Run_Wisi_Common_Parse is
       Put_Line ("--max_parallel n  : set maximum count of parallel parsers" &
                   (if Parse_Table = null then ""
                    else "; default" & Parse_Table.Max_Parallel'Image));
-      Put_Line ("--mckenzie_check_limit n  : set error recover token check 
limit" &
-                  (if Parse_Table = null then ""
-                   else "; default" & 
Parse_Table.McKenzie_Param.Check_Limit'Image));
-      Put_Line ("--mckenzie_check_delta n  : set error recover delta check 
limit" &
-                  (if Parse_Table = null then ""
-                   else "; default" & 
Parse_Table.McKenzie_Param.Check_Delta_Limit'Image));
-      Put_Line ("--mckenzie_enqueue_limit n  : set error recover token enqueue 
limit" &
-                  (if Parse_Table = null then ""
-                   else "; default" & 
Parse_Table.McKenzie_Param.Enqueue_Limit'Image));
-      Put_Line ("--mckenzie_full_explore : force error recover explore all 
solutions");
-      Put_Line ("--mckenzie_high_cost : error recover report high cost 
solutions");
-      Put_Line ("--mckenzie_zombie_limit n  : set error recover token zombie 
limit" &
-                  (if Parse_Table = null then ""
-                   else "; default" & 
Parse_Table.McKenzie_Param.Zombie_Limit'Image));
+      Put_Line ("--mckenzie_options : set error recover parameters");
+      if Parse_Table /= null then
+         WisiToken.Parse.LR.Set_McKenzie_Help;
+      end if;
       Put_Line ("--repeat_count n : repeat parse count times, for profiling; 
default 1");
       Put_Line ("--log <file_name> : output verbosity trace to <file_name>");
       New_Line;
@@ -191,10 +171,7 @@ package body Run_Wisi_Common_Parse is
       Close (File);
    end Read_Source_File;
 
-   function Command_File_Name
-     (Parse_Data : in     Wisi.Parse_Data_Type'Class;
-      Next_Arg   :    out Integer)
-     return Command_Line_Params
+   function Command_File_Name (Next_Arg : out Integer) return 
Command_Line_Params
    --  Read command and source file name from command line.
    is
       use Ada.Command_Line;
@@ -202,7 +179,7 @@ package body Run_Wisi_Common_Parse is
       Command : Command_Type;
    begin
       if Argument_Count < 2 then
-         Usage (Parse_Data, null);
+         Usage (null);
          Set_Exit_Status (Failure);
          raise Finish;
       end if;
@@ -245,13 +222,13 @@ package body Run_Wisi_Common_Parse is
 
    when E : others =>
       Ada.Text_IO.Put_Line (Ada.Exceptions.Exception_Name (E) & ": " & 
Ada.Exceptions.Exception_Message (E));
-      Usage (Parse_Data, null);
+      Usage (null);
       Set_Exit_Status (Failure);
       raise SAL.Parameter_Error;
    end Command_File_Name;
 
    procedure Remaining_Command_Params
-     (Parser : in out WisiToken.Parse.LR.Parser.Parser;
+     (Parser : in out WisiToken.Parse.Base_Parser'Class;
       Params : in out Command_Line_Params;
       Arg    : in out Integer)
    --  Command_File_Name reads the first few command line arguments
@@ -260,7 +237,11 @@ package body Run_Wisi_Common_Parse is
       use WisiToken;
    begin
       if Argument_Count >= Arg and then Argument (Arg) = "--help" then
-         Usage (Wisi.Parse_Data_Type'Class (Parser.User_Data.all), 
Parser.Table);
+         Usage
+           (if Parser in WisiToken.Parse.LR.Parser.Parser
+            then WisiToken.Parse.LR.Parser.Parser (Parser).Table
+            else null);
+         Wisi.Parse_Data_Type (Parser.User_Data.all).Refactor_Help;
          raise Finish;
       end if;
 
@@ -310,18 +291,23 @@ package body Run_Wisi_Common_Parse is
 
    when E : others =>
       Ada.Text_IO.Put_Line (Ada.Exceptions.Exception_Name (E) & ": " & 
Ada.Exceptions.Exception_Message (E));
-      Usage (Wisi.Parse_Data_Type'Class (Parser.User_Data.all), Parser.Table);
+      Usage
+        (if Parser in WisiToken.Parse.LR.Parser.Parser
+         then WisiToken.Parse.LR.Parser.Parser (Parser).Table
+         else null);
+      Wisi.Parse_Data_Type (Parser.User_Data.all).Refactor_Help;
       Set_Exit_Status (Failure);
       raise SAL.Parameter_Error;
    end Remaining_Command_Params;
 
    procedure Command_Options
-     (Parser : in out WisiToken.Parse.LR.Parser.Parser;
+     (Parser : in out WisiToken.Parse.Base_Parser'Class;
       Params : in out Command_Line_Params;
       Arg    : in out Integer)
    is
       use Ada.Command_Line;
       use WisiToken;
+      use all type WisiToken.Parse.LR.Parse_Table_Ptr;
    begin
       loop
          exit when Arg > Argument_Count;
@@ -347,33 +333,14 @@ package body Run_Wisi_Common_Parse is
             Params.Language_Params := +Argument (Arg + 1);
             Arg := @ + 2;
 
-         elsif Argument (Arg) = "--max_parallel" then
-            Parser.Table.Max_Parallel := SAL.Base_Peek_Type'Value (Argument 
(Arg + 1));
-            Arg := @ + 2;
-
-         elsif Argument (Arg) = "--mckenzie_check_delta" then
-            Parser.Table.McKenzie_Param.Check_Delta_Limit := Integer'Value 
(Argument (Arg + 1));
-            Arg := @ + 2;
-
-         elsif Argument (Arg) = "--mckenzie_check_limit" then
-            Parser.Table.McKenzie_Param.Check_Limit := 
WisiToken.Syntax_Trees.Sequential_Index'Value
-              (Argument (Arg + 1));
-            Arg := @ + 2;
-
-         elsif Argument (Arg) = "--mckenzie_enqueue_limit" then
-            Parser.Table.McKenzie_Param.Enqueue_Limit := Integer'Value 
(Argument (Arg + 1));
-            Arg := @ + 2;
-
-         elsif Argument (Arg) = "--mckenzie_full_explore" then
-            WisiToken.Parse.LR.McKenzie_Recover.Force_Full_Explore := True;
-            Arg := @ + 1;
-
-         elsif Argument (Arg) = "--mckenzie_high_cost" then
-            WisiToken.Parse.LR.McKenzie_Recover.Force_High_Cost_Solutions := 
True;
-            Arg := @ + 1;
-
-         elsif Argument (Arg) = "--mckenzie_zombie_limit" then
-            Parser.Table.McKenzie_Param.Zombie_Limit := Integer'Value 
(Argument (Arg + 1));
+         elsif Argument (Arg) = "--mckenzie_options" then
+            if Parser in WisiToken.Parse.LR.Parser.Parser then
+               declare
+                  LR_Parser : WisiToken.Parse.LR.Parser.Parser renames 
WisiToken.Parse.LR.Parser.Parser (Parser);
+               begin
+                  WisiToken.Parse.LR.Set_McKenzie_Options 
(LR_Parser.Table.McKenzie_Param, Argument (Arg + 1));
+               end;
+            end if;
             Arg := @ + 2;
 
          elsif Argument (Arg) = "--repeat_count" then
@@ -391,7 +358,11 @@ package body Run_Wisi_Common_Parse is
 
          else
             Ada.Text_IO.Put_Line ("unrecognized option: '" & Argument (Arg) & 
"'");
-            Usage (Wisi.Parse_Data_Type'Class (Parser.User_Data.all), 
Parser.Table);
+            Usage
+              (if Parser in WisiToken.Parse.LR.Parser.Parser
+               then WisiToken.Parse.LR.Parser.Parser (Parser).Table
+               else null);
+            Wisi.Parse_Data_Type (Parser.User_Data.all).Refactor_Help;
             Set_Exit_Status (Failure);
             raise SAL.Parameter_Error;
          end if;
@@ -402,14 +373,23 @@ package body Run_Wisi_Common_Parse is
 
    when E : others =>
       Ada.Text_IO.Put_Line (Ada.Exceptions.Exception_Name (E) & ": " & 
Ada.Exceptions.Exception_Message (E));
-      Usage (Wisi.Parse_Data_Type'Class (Parser.User_Data.all), Parser.Table);
+      Usage
+        (if Parser in WisiToken.Parse.LR.Parser.Parser
+         then WisiToken.Parse.LR.Parser.Parser (Parser).Table
+         else null);
+      Wisi.Parse_Data_Type (Parser.User_Data.all).Refactor_Help;
       Set_Exit_Status (Failure);
       raise SAL.Parameter_Error;
    end Command_Options;
 
-   procedure Put_Errors (Parser : in WisiToken.Parse.LR.Parser.Parser)
-   is begin
-      if Parser.Tree.Stream_Count = 0 then
+   procedure Put_Errors (Parser : in WisiToken.Parse.Base_Parser_Access)
+   is
+      use all type SAL.Base_Peek_Type;
+      use WisiToken.Syntax_Trees;
+   begin
+      if Parser.Tree.Shared_Stream = Invalid_Stream_ID then
+         --  Parse completed. If Tree.Finalize raised an exception,
+         --  Tree.Stream_Count is unreliable.
          Parser.Put_Errors;
 
       elsif Parser.Tree.Stream_Count >= 2 then
@@ -423,7 +403,8 @@ package body Run_Wisi_Common_Parse is
 
    procedure Process_Command
      (Parse_Context : in out Wisi.Parse_Context.Parse_Context_Access;
-      Language      : in     Wisi.Parse_Context.Language;
+      Factory       : in     WisiToken.Parse.Factory;
+      Free_Parser   : in     WisiToken.Parse.Free_Parser;
       Line          : in     String;
       Trace         : in     WisiToken.Trace_Access)
    is
@@ -460,7 +441,7 @@ package body Run_Wisi_Common_Parse is
       when File =>
          if Ada.Strings.Unbounded.Length (Parse_Context.File_Name) > 0 then
             --  Changing files
-            Parse_Context := Wisi.Parse_Context.Create_No_File (Language, 
Trace);
+            Parse_Context := Wisi.Parse_Context.Create_No_File (Factory, 
Trace);
          end if;
 
          declare
@@ -486,7 +467,7 @@ package body Run_Wisi_Common_Parse is
             if Source_File_Name = -Parse_Context.File_Name then
                Parse_Context := null;
             end if;
-            Wisi.Parse_Context.Kill (Source_File_Name);
+            Wisi.Parse_Context.Kill (Source_File_Name, Free_Parser);
          end;
 
       when Language_Params =>
@@ -494,8 +475,15 @@ package body Run_Wisi_Common_Parse is
            (Line (Last + 1 .. Line'Last));
 
       when McKenzie_Options =>
-         WisiToken.Parse.LR.Set_McKenzie_Options
-           (Parse_Context.Parser.Table.McKenzie_Param, Line (Last + 1 .. 
Line'Last));
+         if Parse_Context.Parser.all in WisiToken.Parse.LR.Parser.Parser then
+            declare
+               LR_Parser : WisiToken.Parse.LR.Parser.Parser renames 
WisiToken.Parse.LR.Parser.Parser
+                 (Parse_Context.Parser.all);
+            begin
+               WisiToken.Parse.LR.Set_McKenzie_Options
+                 (LR_Parser.Table.McKenzie_Param, Line (Last + 1 .. 
Line'Last));
+            end;
+         end if;
 
       when Memory_Report_Reset =>
          WisiToken.Memory_Baseline := 
GNATCOLL.Memory.Get_Ada_Allocations.Current;
@@ -557,6 +545,12 @@ package body Run_Wisi_Common_Parse is
             Ada.Text_IO.Put_Line
               ("(parse_error """ & Ada.Exceptions.Exception_Name (E) & " " &
                  Ada.Exceptions.Exception_Message (E) & """)");
+
+         when WisiToken.Validate_Error =>
+            Put_Errors (Parse_Context.Parser);
+            --  Ensure we don't lose the debug state
+            Parse_Context.Frozen := True;
+            raise WisiToken.Parse_Error with "validate error; parse_context 
frozen";
          end;
 
       when Post_Parse =>
@@ -589,7 +583,7 @@ package body Run_Wisi_Common_Parse is
                Report_Memory (Trace.all, Prefix => False);
             end if;
 
-            Wisi.Parse_Data_Type'Class 
(Parse_Context.Parser.User_Data.all).Put (Parse_Context.Parser);
+            Wisi.Parse_Data_Type'Class 
(Parse_Context.Parser.User_Data.all).Put (Parse_Context.Parser.all);
          end;
 
       when Read_Tree =>
@@ -691,7 +685,10 @@ package body Run_Wisi_Common_Parse is
       end case;
    end Process_Command;
 
-   procedure Parse_File (Language : in Wisi.Parse_Context.Language; Trace : in 
WisiToken.Trace_Access)
+   procedure Parse_File
+     (Factory     : in WisiToken.Parse.Factory;
+      Free_Parser : in WisiToken.Parse.Free_Parser;
+      Trace       : in WisiToken.Trace_Access)
    is
       use Ada.Text_IO;
       use WisiToken;
@@ -702,14 +699,14 @@ package body Run_Wisi_Common_Parse is
          use all type Wisi.Base_Post_Parse_Action_Type;
 
          Arg       : Integer;
-         Cl_Params : Command_Line_Params := Command_File_Name 
(Language.Parse_Data_Template.all, Arg);
+         Cl_Params : Command_Line_Params := Command_File_Name (Arg);
 
          Parse_Context : Wisi.Parse_Context.Parse_Context_Access :=
            (if Length (Cl_Params.Source_File_Name) > 0 -- can be empty for 
Command_File
-            then Wisi.Parse_Context.Find_Create (-Cl_Params.Source_File_Name, 
Language, Trace)
-            else Wisi.Parse_Context.Create_No_File (Language, Trace));
+            then Wisi.Parse_Context.Find_Create (-Cl_Params.Source_File_Name, 
Factory, Trace)
+            else Wisi.Parse_Context.Create_No_File (Factory, Trace));
 
-         Parser : WisiToken.Parse.LR.Parser.Parser renames 
Parse_Context.Parser;
+         Parser : WisiToken.Parse.Base_Parser'Class renames 
Parse_Context.Parser.all;
 
          Parse_Data : Wisi.Parse_Data_Type'Class renames 
Wisi.Parse_Data_Type'Class (Parser.User_Data.all);
       begin
@@ -745,14 +742,19 @@ package body Run_Wisi_Common_Parse is
          case Cl_Params.Command is
          when Parse_Partial =>
             if Cl_Params.Partial_Begin_Byte_Pos = WisiToken.Invalid_Buffer_Pos 
then
+               --  Actually a full parse.
                Cl_Params.Partial_Begin_Byte_Pos := WisiToken.Buffer_Pos'First;
                Cl_Params.Partial_Begin_Char_Pos := WisiToken.Buffer_Pos'First;
                Cl_Params.Partial_End_Byte_Pos   := Base_Buffer_Pos 
(Parse_Context.Text_Buffer_Byte_Last);
                Cl_Params.Partial_End_Char_Pos   := Base_Buffer_Pos 
(Parse_Context.Text_Buffer_Char_Last);
+
+               Cl_Params.Partial_Goal_Byte_Pos := 
Cl_Params.Partial_End_Byte_Pos;
+               Cl_Params.Partial_Goal_Char_Pos := 
Cl_Params.Partial_End_Char_Pos;
             else
                Parser.Partial_Parse_Active.all    := True;
                Parser.Partial_Parse_Byte_Goal.all := 
Cl_Params.Partial_Goal_Byte_Pos;
             end if;
+
          when Parse_Incremental =>
             if Cl_Params.Inc_Begin_Byte_Pos = WisiToken.Invalid_Buffer_Pos then
                Cl_Params.Inc_Begin_Byte_Pos := WisiToken.Buffer_Pos'First;
@@ -808,18 +810,19 @@ package body Run_Wisi_Common_Parse is
                   end if;
                exception
                when WisiToken.Syntax_Error =>
-                  Put_Errors (Parser);
+                  Put_Errors (Parse_Context.Parser);
                   Put_Line ("(parse_error)");
 
                when E : WisiToken.Parse_Error =>
-                  Put_Errors (Parser);
+                  Put_Errors (Parse_Context.Parser);
                   Put_Line ("(parse_error """ & Ada.Exceptions.Exception_Name 
(E) & " " &
                               Ada.Exceptions.Exception_Message (E) & """)");
 
                when E : others => -- includes Fatal_Error
-                  Put_Errors (Parser);
+                  Put_Errors (Parse_Context.Parser);
                   Put_Line ("(error """ & Ada.Exceptions.Exception_Name (E) & 
" " &
                               Ada.Exceptions.Exception_Message (E) & """)");
+                  raise;
                end;
             end loop;
 
@@ -854,11 +857,11 @@ package body Run_Wisi_Common_Parse is
 
             exception
             when WisiToken.Syntax_Error =>
-               Put_Errors (Parser);
+               Put_Errors (Parse_Context.Parser);
                Put_Line ("(parse_error)");
 
             when E : WisiToken.Parse_Error =>
-               Put_Errors (Parser);
+               Put_Errors (Parse_Context.Parser);
                Put_Line ("(parse_error """ & Ada.Exceptions.Exception_Name (E) 
& " " &
                            Ada.Exceptions.Exception_Message (E) & """)");
             end;
@@ -890,7 +893,7 @@ package body Run_Wisi_Common_Parse is
                     (Parse_Context.Text_Buffer, 
Parse_Context.Text_Buffer_Byte_Last, Cl_Params.Source_File_Name);
 
                   Parser.Parse (Log_File, KMN_List);
-                  Wisi.Put_Errors (Parse_Context.Parser.Tree);
+                  Wisi.Put_Errors (Parser.Tree);
 
                   if Cl_Params.Inc_Post_Parse_Action /= None then
                      Parse_Data.Reset_Post_Parse
@@ -912,11 +915,11 @@ package body Run_Wisi_Common_Parse is
 
                exception
                when WisiToken.Syntax_Error =>
-                  Put_Errors (Parser);
+                  Put_Errors (Parse_Context.Parser);
                   Put_Line ("(parse_error)");
 
                when E : WisiToken.Parse_Error =>
-                  Put_Errors (Parser);
+                  Put_Errors (Parse_Context.Parser);
                   Put_Line ("(parse_error """ & Ada.Exceptions.Exception_Name 
(E) & " " &
                               Ada.Exceptions.Exception_Message (E) & """)");
                end;
@@ -954,7 +957,7 @@ package body Run_Wisi_Common_Parse is
                         if Line (1 .. 2) = "--" then
                            null;
                         else
-                           Process_Command (Parse_Context, Language, Line, 
Trace);
+                           Process_Command (Parse_Context, Factory, 
Free_Parser, Line, Trace);
                            Trace.New_Line;
                         end if;
                      end if;
diff --git a/run_wisi_common_parse.ads b/run_wisi_common_parse.ads
index b6023b04ff..d4f3cad148 100644
--- a/run_wisi_common_parse.ads
+++ b/run_wisi_common_parse.ads
@@ -19,11 +19,13 @@
 pragma License (GPL);
 
 with Wisi;
-with WisiToken;
-with Wisi.Parse_Context;
+with WisiToken.Parse;
 package Run_Wisi_Common_Parse is
 
-   procedure Parse_File (Language : in Wisi.Parse_Context.Language; Trace : in 
WisiToken.Trace_Access);
+   procedure Parse_File
+     (Factory     : in WisiToken.Parse.Factory;
+      Free_Parser : in WisiToken.Parse.Free_Parser;
+      Trace       : in WisiToken.Trace_Access);
    --  Reads command line, processes command(s).
 
 end Run_Wisi_Common_Parse;
diff --git a/sal-gen_definite_doubly_linked_lists.adb 
b/sal-gen_definite_doubly_linked_lists.adb
index a189399b79..2697aa9829 100644
--- a/sal-gen_definite_doubly_linked_lists.adb
+++ b/sal-gen_definite_doubly_linked_lists.adb
@@ -261,10 +261,10 @@ package body SAL.Gen_Definite_Doubly_Linked_Lists is
       null;
    end Insert;
 
-   function Persistent_Ref (Position : in Cursor) return access Element_Type
+   function Unchecked_Ref (Position : in Cursor) return access Element_Type
    is begin
       return Position.Ptr.Element'Access;
-   end Persistent_Ref;
+   end Unchecked_Ref;
 
    function Constant_Reference (Container : in List; Position : in Cursor) 
return Constant_Reference_Type
    is
diff --git a/sal-gen_definite_doubly_linked_lists.ads 
b/sal-gen_definite_doubly_linked_lists.ads
index 75016694f1..bf78d1b923 100644
--- a/sal-gen_definite_doubly_linked_lists.ads
+++ b/sal-gen_definite_doubly_linked_lists.ads
@@ -103,8 +103,9 @@ package SAL.Gen_Definite_Doubly_Linked_Lists is
      return Cursor;
    --  If Before is No_Element, insert after Last.
 
-   function Persistent_Ref (Position : in Cursor) return access Element_Type
+   function Unchecked_Ref (Position : in Cursor) return access Element_Type
    with Pre => Has_Element (Position);
+   --  For building higher level containers
 
    type Constant_Reference_Type (Element : not null access constant 
Element_Type) is private with
      Implicit_Dereference => Element;
diff --git a/sal-gen_indefinite_doubly_linked_lists.adb 
b/sal-gen_indefinite_doubly_linked_lists.adb
index fdfef03c33..86f0574507 100644
--- a/sal-gen_indefinite_doubly_linked_lists.adb
+++ b/sal-gen_indefinite_doubly_linked_lists.adb
@@ -24,6 +24,22 @@ pragma License (Modified_GPL);
 
 package body SAL.Gen_Indefinite_Doubly_Linked_Lists is
 
+   procedure Delete_Node (Container : in out List; Node : in out Node_Access)
+   is begin
+      if Node.Next = null then
+         Container.Tail := Node.Prev;
+      else
+         Node.Next.Prev := Node.Prev;
+      end if;
+      if Node.Prev = null then
+         Container.Head := Node.Next;
+      else
+         Node.Prev.Next := Node.Next;
+      end if;
+      Free (Node.Element);
+      Free (Node);
+   end Delete_Node;
+
    ---------
    --  Public operations, declaration order.
 
@@ -77,6 +93,14 @@ package body SAL.Gen_Indefinite_Doubly_Linked_Lists is
       return Container.Count;
    end Length;
 
+   procedure Delete_First (Container : in out List)
+   is
+      Node : Node_Access := Container.Head;
+   begin
+      Delete_Node (Container, Node);
+      Container.Count := Container.Count - 1;
+   end Delete_First;
+
    procedure Append (Container : in out List; Element : in Element_Type)
    is
       New_Node : constant Node_Access := new Node_Type'
@@ -190,21 +214,8 @@ package body SAL.Gen_Indefinite_Doubly_Linked_Lists is
    end Append;
 
    procedure Delete (Container : in out List; Position : in out Cursor)
-   is
-      Node : Node_Access renames Position.Ptr;
-   begin
-      if Node.Next = null then
-         Container.Tail := Node.Prev;
-      else
-         Node.Next.Prev := Node.Prev;
-      end if;
-      if Node.Prev = null then
-         Container.Head := Node.Next;
-      else
-         Node.Prev.Next := Node.Next;
-      end if;
-      Free (Node.Element);
-      Free (Node);
+   is begin
+      Delete_Node (Container, Position.Ptr);
       Position        := (Ptr => null);
       Container.Count := Container.Count - 1;
    end Delete;
diff --git a/sal-gen_indefinite_doubly_linked_lists.ads 
b/sal-gen_indefinite_doubly_linked_lists.ads
index b9d3022256..d8e9fad799 100644
--- a/sal-gen_indefinite_doubly_linked_lists.ads
+++ b/sal-gen_indefinite_doubly_linked_lists.ads
@@ -44,8 +44,12 @@ package SAL.Gen_Indefinite_Doubly_Linked_Lists is
    overriding procedure Finalize (Container : in out List);
    --  Free all items in List.
 
+   procedure Clear (Container : in out List) renames Finalize;
+
    function Length (Container : in List) return Base_Peek_Type;
 
+   procedure Delete_First (Container : in out List);
+
    procedure Append (Container : in out List; Element : in Element_Type);
 
    procedure Prepend (Container : in out List; Element : in Element_Type);
@@ -105,7 +109,6 @@ private
    type Node_Access is access Node_Type;
    type Element_Access is access Element_Type;
 
-
    type Node_Type is record
       Element : Element_Access;
       Prev    : Node_Access;
diff --git a/sal.adb b/sal.adb
index d90195600d..1cfe875633 100644
--- a/sal.adb
+++ b/sal.adb
@@ -28,7 +28,7 @@ package body SAL is
 
    function Version return String is
    begin
-      return "SAL 3.6";
+      return "SAL 3.7";
    end Version;
 
    function String_Compare (Left, Right : in String) return Compare_Result
diff --git a/standard_common.gpr b/standard_common.gpr
index 3d4652ee6c..6553e9559b 100644
--- a/standard_common.gpr
+++ b/standard_common.gpr
@@ -2,7 +2,7 @@
 --
 --  Standard settings for all of Stephe's Ada projects.
 --
---  Copyright (C) 2018 - 2021 Free Software Foundation, Inc.
+--  Copyright (C) 2018 - 2022 Free Software Foundation, Inc.
 --
 --  This program is free software; you can redistribute it and/or
 --  modify it under terms of the GNU General Public License as
@@ -18,6 +18,7 @@
 
 project Standard_Common is
    for Source_Dirs use ();
+   for Create_Missing_Dirs use "True";
 
    type Build_Type is ("Debug", "Normal");
    Build : Build_Type := External ("Standard_Common_Build", "Normal");
@@ -169,4 +170,11 @@ project Standard_Common is
    end Linker;
 
    --  In project files, no linker package is needed.
+
+   package Pretty_Printer is
+      --  Used by ada_language_server and gnatpp. Projects will need
+      --  to add "--dictionary=<case exceptions file>".
+      for Default_Switches ("Ada") use ("--source-line-breaks");
+   end Pretty_Printer;
+
 end Standard_Common;
diff --git a/wisi-fringe.el b/wisi-fringe.el
index 54146a577e..875d4437e8 100644
--- a/wisi-fringe.el
+++ b/wisi-fringe.el
@@ -1,4 +1,4 @@
-;;; wisi-fringe.el --- show approximate error locations in the fringe
+;;; wisi-fringe.el --- show approximate error locations in the fringe  -*- 
lexical-binding: t; -*-
 ;;
 ;; Copyright (C) 2018 - 2019, 2021 - 2022  Free Software Foundation, Inc.
 ;;
@@ -15,9 +15,9 @@
 ;; GNU General Public License for more details.
 ;;
 ;; You should have received a copy of the GNU General Public License
-;; along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+;; along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
 ;;
-;; Design:
+;;; Design:
 ;;
 ;; Bitmaps are displayed in the fringe by putting a 'display property
 ;; on buffer text. However, just doing that also hides the buffer
@@ -29,60 +29,22 @@
 ;; single-pixel lines in the right fringe, and mark error lines with
 ;; ’!!’ in the left fringe.
 
-(defun wisi-fringe-create-bitmaps ()
-  "Return an array of bitmap symbols containing the fringe bitmaps."
-  ;; First create the ’!!’ bitmap.
-  (define-fringe-bitmap 'wisi-fringe--double-exclaim-bmp
-    (vector
-     #b00000000
-     #b01100110
-     #b01100110
-     #b01100110
-     #b01100110
-     #b01100110
-     #b00000000
-     #b01100110
-     #b01010110
-     #b00000000))
+;;; Code:
 
-  ;; In condensing the entire buffer to the current window height, we
-  ;; assume a 10 point font, which allows 6 distinct line positions
-  ;; each one pixel high, with one blank pixel between.
+(require 'wisi-parse-common)            ;For `wisi-debug'
 
-  (let ((result (make-vector 64 nil))
-       (i 1))
-    (while (<= i (length result))
-      (aset result (1- i)
-           (define-fringe-bitmap (intern (format "wisi-fringe--line-%d-bmp" i))
-             (vector
-              (if (>= i 32) #b11111111 #b00000000)
-              #b00000000
-              (if (>= (% i 32) 16) #b11111111 #b00000000)
-              #b00000000
-              (if (>= (% i 16) 8) #b11111111 #b00000000)
-              #b00000000
-              (if (>= (% i 8) 4) #b11111111 #b00000000)
-              #b00000000
-              (if (>= (% i 4) 2) #b11111111 #b00000000)
-              #b00000000
-              (if (>= (% i 2) 1) #b11111111 #b00000000)
-              )))
-      (setq i (1+ i)))
-    result))
-
-(defconst wisi-fringe-bitmaps (wisi-fringe-create-bitmaps)
-  "Array of 64 bitmap symbols.")
-
-(defun wisi-fringe--put-right (line bitmap-index)
-  (save-excursion
-    (goto-char (point-min))
-    (forward-line (1- line))
-    (let* ((endpos (line-end-position))
-          (ov (make-overlay endpos (1+ endpos)))
-          (bmp (aref wisi-fringe-bitmaps bitmap-index)))
-      (overlay-put ov 'after-string (propertize "-" 'display (list 
'right-fringe bmp 'compilation-error)))
-      (overlay-put ov 'wisi-fringe t)
-      )))
+(define-fringe-bitmap 'wisi-fringe--double-exclaim-bmp
+  (vector
+   #b00000000
+   #b01100110
+   #b01100110
+   #b01100110
+   #b01100110
+   #b01100110
+   #b00000000
+   #b01100110
+   #b01010110
+   #b00000000))
 
 (defun wisi-fringe--put-left (line)
   (save-excursion
@@ -99,26 +61,6 @@
       (overlay-put ov 'wisi-fringe t)
       )))
 
-(defun wisi-fringe--scale (error-line buffer-lines window-line-first 
window-lines)
-  "Return a cons (LINE . BIN) for ERROR-LINE,
-where LINE is the line to display the error bar on, and BIN is a
-6-bit bit vector giving the relative position in that line.
-BUFFER-LINES is the count of lines in the buffer.
-WINDOW-LINE-FIRST is the first and last lines of the buffer
-visible in the window. WINDOW-LINES is the count of lines visible
-in the window."
-  ;; If the end of buffer is inside the window, and this calculation
-  ;; puts a mark after that, it will actually be put on the last real
-  ;; line. That’s good enough for our purposes.
-
-  ;; partial-lines / window-line = 6
-  ;; buffer-lines / window-line = 1/scale
-  ;; buffer-lines / partial-line  = (window-line / partial-lines) * 
(buffer-lines / window-line) = 1/6 * 1/scale
-  (let* ((scale (/ window-lines (float buffer-lines)))
-        (line (floor (* scale error-line)))
-        (rem (- error-line (floor (/ line scale)))))
-    (cons (+ window-line-first line) (lsh 1 (min 5 (floor (* rem (* 6 
scale))))))))
-
 (defun wisi-fringe-clean ()
   "Remove all wisi-fringe marks."
   (remove-overlays (point-min) (point-max) 'wisi-fringe t))
@@ -127,17 +69,10 @@ in the window."
   "Display markers in the fringe for each buffer position in POSITIONS.
 The buffer containing POSITIONS must be current, and the window
 displaying that buffer must be current."
-  ;; We don't recompute fringe display on scroll, because the user
-  ;; will probably have edited the code by then, triggering a new
-  ;; parse. FIXME: use flymake.
   (wisi-fringe-clean)
   (when positions
-    (let (scaled-posns
-         (buffer-lines (line-number-at-pos (point-max) t))
-         (window-lines (window-height))
-         (window-pos-first (window-start))
-         (window-pos-last  (window-end))
-         (window-line-first (line-number-at-pos (window-start) t)))
+    (let ((window-pos-first (window-start))
+         (window-pos-last  (window-end)))
 
       (when (< 1 wisi-debug)
        (wisi-parse-log-message wisi-parser-shared
@@ -147,19 +82,11 @@ displaying that buffer must be current."
                                        window-pos-last)))
 
       (dolist (pos positions)
-       (let* ((line (line-number-at-pos (max (point-min) (min (point-max) 
pos)) t))
-              (scaled-pos (wisi-fringe--scale line buffer-lines 
window-line-first window-lines)))
+       (let* ((line (line-number-at-pos (max (point-min) (min (point-max) 
pos)) t)))
          (when (and (>= pos window-pos-first)
                     (<= pos window-pos-last))
            (wisi-fringe--put-left line))
-         (if (and scaled-posns
-                  (= (caar scaled-posns) (car scaled-pos)))
-             (setcdr (car scaled-posns) (logior (cdar scaled-posns) (cdr 
scaled-pos)))
-           (push scaled-pos scaled-posns))
          ))
-
-      (dolist (pos scaled-posns)
-       (wisi-fringe--put-right (car pos) (1- (cdr pos))))
       )))
 
 (provide 'wisi-fringe)
diff --git a/wisi-parse-common.el b/wisi-parse-common.el
index 28df0aa01b..c78d244f70 100644
--- a/wisi-parse-common.el
+++ b/wisi-parse-common.el
@@ -17,11 +17,17 @@
 ;; GNU General Public License for more details.
 ;;
 ;; You should have received a copy of the GNU General Public License
-;; along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+;; along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
 
 ;;; Code:
 (require 'cl-lib)
 
+(defcustom wisi-incremental-parse-enable nil
+  "If non-nil, use incremental parse when possible."
+  :type 'boolean
+  :group 'wisi
+  :safe #'booleanp)
+
 (defcustom wisi-partial-parse-threshold 100001
   "Minimum size that will be parsed by each call to the parser.
 A parse is always requested at a point (or on a region); the
@@ -33,7 +39,7 @@ is properly indented. Most navigate parses ignore this setting
 and parse the whole buffer."
   :type 'integer
   :group 'wisi
-  :safe 'integerp)
+  :safe #'integerp)
 (make-variable-buffer-local 'wisi-partial-parse-threshold)
 
 (defcustom wisi-save-all-changes nil
@@ -46,6 +52,16 @@ for the changes. The filename is the visited file name with
   :group 'wisi
   :safe 'booleanp)
 
+(defcustom wisi-save-text-tree nil
+  "When non-nil, save the parser's copy of the full text and the
+current parse tree before each change, to aid in reproducing
+bugs. The full text is written to a file whose name is the
+visited file name with \"-wisi-prev-text\"' appended. The tree
+can be dumped to a file via the tree query dump-prev."
+  :type 'boolean
+  :group 'wisi
+  :safe #'booleanp)
+
 (cl-defstruct (wisi--lexer-error)
   pos ;; position (integer) in buffer where error was detected.
   message  ;; string error message
@@ -146,6 +162,9 @@ region BEGIN END that starts and ends at points the parser 
can
 handle gracefully."
   (cons begin end))
 
+(cl-defgeneric wisi-parse-save-text-tree-auto (parser enable)
+  "Implement `wisi-save-text-tree'.")
+
 (defvar-local wisi-parser-shared nil
   "The current shared wisi parser; a ‘wisi-parser-shared’ object.
 There is one parser object per language; `wisi-parser-shared' is a
@@ -154,6 +173,13 @@ buffer-local reference to that shared object.")
 (defvar-local wisi-parser-local nil
   "Buffer-local values used by the wisi parser; a ‘wisi-parser-local’ object.")
 
+(defvar-local wisi--changes nil
+  "Cached list of args to wisi-after-change, for incremental parse.
+Each element is
+(INSERT-BEGIN-BYTE-POS INSERT-BEGIN-CHAR-POS
+ INSERT-END-BYTE-POS INSERT-END-CHAR-POS
+ DELETED-BYTE-COUNT DELETED-CHAR-COUNT INSERTED-TEXT)")
+
 (defconst wisi-post-parse-actions '(navigate face indent none refactor query 
debug)
   "Actions that the parser can perform after parsing.
 Only navigate thru indent are valid for partial parse.")
@@ -240,7 +266,7 @@ have been previously parsed by `wisi-parse-current' or
     (parent                .   3)
     (child                 .   4)
     (print                 .   5)
-    (dump                  .   6)
+    (dump                  .   6) ;; dump-prev is not here because it queries 
a different tree.
     )
   "Query values for `wisi-parse-tree-query'.")
 
@@ -436,7 +462,7 @@ Assumes the buffer is fully parsed."
 1 : report parse errors (for running tests)"
   :type 'integer
   :group 'wisi
-  :safe 'integerp)
+  :safe #'integerp)
 
 ;; The following parameters are easily changeable for debugging.
 (defcustom wisi-parser-verbosity ""
@@ -446,7 +472,7 @@ Examples:
 debug=1 lexer=1 parse=2 action=3"
   :type 'string
   :group 'wisi
-  :safe 'stringp)
+  :safe #'stringp)
 (make-variable-buffer-local 'wisi-parser-verbosity)
 
 (defcustom wisi-mckenzie-zombie-limit nil
@@ -457,7 +483,7 @@ value gives better solutions, but may cause too many 
parsers to
 be active at once.  If nil, uses %mckenzie_zombie_limit value from grammar 
file."
   :type 'integer
   :group 'wisi
-  :safe 'integerp)
+  :safe #'integerp)
 (make-variable-buffer-local 'wisi-mckenzie-zombie-limit)
 
 (defcustom wisi-mckenzie-enqueue-limit nil
@@ -467,7 +493,7 @@ Higher value has more recover power, but will be slower to 
fail.
 If nil, uses %mckenzie_enqueue_limit value from grammar file."
   :type 'integer
   :group 'wisi
-  :safe 'integerp)
+  :safe #'integerp)
 (make-variable-buffer-local 'wisi-mckenzie-enqueue-limit)
 
 (defcustom wisi-parse-max-parallel nil
@@ -478,7 +504,7 @@ the grammar has excessive conflicts. If nil, uses 
%max_parallel
 value from grammar file (default 15)"
   :type 'integer
   :group 'wisi
-  :safe 'integerp)
+  :safe #'integerp)
 (make-variable-buffer-local 'wisi-parse-max-parallel)
 
 ;; end of easily changeable parameters
@@ -504,7 +530,7 @@ Normally set from a language-specific option.")
      "%s:%d:%d: %s"
        (buffer-name) ;; buffer-file-name is sometimes nil here!?
        line col
-       (apply 'format message args))))
+       (apply #'format message args))))
 
 (defvar wisi-parse-error nil)
 (put 'wisi-parse-error
@@ -591,23 +617,6 @@ Signals an error if `wisi-incremental-parse-enable' is 
nil."
     (user-error "wisi-parse-incremental-none with 
wisi-incremental-parse-enable nil"))
   (save-excursion (wisi-parse-incremental wisi-parser-shared 'none)))
 
-(defun wisi-replay-kbd-macro (macro)
-  "Replay keyboard macro MACRO into current buffer,
-with incremental parse after each key event."
-  (unless wisi-incremental-parse-enable
-    (user-error "wisi-incremental-parse-enable nil; use EMACS_SKIP_UNLESS"))
-  (let ((i 0))
-    (while (< i  (length macro))
-      (execute-kbd-macro (make-vector 1 (aref macro i)))
-      (save-excursion
-       (condition-case err
-           (wisi-parse-incremental wisi-parser-shared 'none)
-         (wisi-parse-error
-          (when (< 0 wisi-debug)
-            ;; allow continuing when parser throws parse-error
-            (signal (car err) (cdr err))))))
-      (setq i (1+ i)))))
-
 (defun wisi-replay-undo (count)
   "Execute `undo' COUNT times, delaying in between each."
   (let ((i 0))
diff --git a/wisi-parse_context.adb b/wisi-parse_context.adb
index 5a908f0599..97c13bdce3 100644
--- a/wisi-parse_context.adb
+++ b/wisi-parse_context.adb
@@ -15,7 +15,6 @@ pragma License (GPL);
 
 with Ada.Directories;
 with Ada.Exceptions;
-with Ada.Finalization;
 with Ada.Tags;
 with GNAT.OS_Lib;
 with SAL.Gen_Unbounded_Definite_Red_Black_Trees;
@@ -33,37 +32,20 @@ package body Wisi.Parse_Context is
    Map : File_Parse_Context_Maps.Tree;
 
    function Create_No_File
-     (Language : in Wisi.Parse_Context.Language;
-      Trace    : in WisiToken.Trace_Access)
+     (Factory : in WisiToken.Parse.Factory;
+      Trace   : in WisiToken.Trace_Access)
      return Parse_Context_Access
    is
       use WisiToken;
    begin
-      return Result : constant Parse_Context_Access :=
-        (new Parse_Context'
-           (File_Name                         => +"",
-            Text_Buffer                       => null,
-            Text_Buffer_Byte_Last             => 0,
-            Text_Buffer_Char_Last             => 0,
-            Parser                            => 
WisiToken.Parse.LR.Parser.Parser'
-              (Ada.Finalization.Limited_Controlled with
-               User_Data                      => Wisi.New_User_Data 
(Language.Parse_Data_Template.all),
-               Table                          => Language.Table,
-               Productions                    => Language.Productions,
-               Language_Fixes                 => Language.Fixes,
-               Language_Matching_Begin_Tokens => 
Language.Matching_Begin_Tokens,
-               Language_String_ID_Set         => Language.String_ID_Set,
-               Partial_Parse_Active           => Language.Partial_Parse_Active,
-               Partial_Parse_Byte_Goal        => 
Language.Partial_Parse_Byte_Goal,
-               others                         => <>),
-            Root_Save_Edited_Name             => <>,
-            Save_Edited_Count                 => <>))
+      return Result : constant Parse_Context_Access := new Parse_Context
       do
-         Result.Parser.Tree.Lexer := Language.Lexer;
+         Result.Parser := Factory.all;
+
          if Trace_Incremental_Parse > Outline then
             Trace.Put_Line
               ("parse_context (no file) created, language " & 
Ada.Tags.Expanded_Name
-                 (Language.Parse_Data_Template.all'Tag));
+                 (Result.Parser.User_Data'Tag));
             if Trace_Memory > Outline then
                Report_Memory (Trace.all, Prefix => True);
             end if;
@@ -73,10 +55,10 @@ package body Wisi.Parse_Context is
 
    procedure Create_No_Text
      (File_Name : in String;
-      Language  : in Wisi.Parse_Context.Language;
+      Factory   : in WisiToken.Parse.Factory;
       Trace     : in WisiToken.Trace_Access)
    is
-      Temp : constant Parse_Context_Access := Create_No_File (Language, Trace);
+      Temp : constant Parse_Context_Access := Create_No_File (Factory, Trace);
    begin
       Set_File (File_Name, Temp);
    end Create_No_Text;
@@ -97,7 +79,7 @@ package body Wisi.Parse_Context is
 
    function Find_Create
      (File_Name : in String;
-      Language  : in Wisi.Parse_Context.Language;
+      Factory   : in WisiToken.Parse.Factory;
       Trace     : in WisiToken.Trace_Access)
      return Parse_Context_Access
    is begin
@@ -113,40 +95,29 @@ package body Wisi.Parse_Context is
       begin
          if Has_Element (Found) then
             return Result : constant Parse_Context_Access := Element (Found) do
-               if Language.Descriptor /= Result.Parser.Tree.Lexer.Descriptor 
then
-                  raise WisiToken.User_Error with "language does not match for 
buffer '" & File_Name & "'";
-               end if;
                if Trace_Incremental_Parse > Outline then
                   Trace.Put_Line ("parse_context found");
                end if;
             end return;
          end if;
 
-         return Result : constant Parse_Context_Access :=
-           (new Parse_Context'
-              (File_Name                         => +File_Name,
-               Text_Buffer                       => null,
-               Text_Buffer_Byte_Last             => 0,
-               Text_Buffer_Char_Last             => 0,
-               Parser                            => 
WisiToken.Parse.LR.Parser.Parser'
-                 (Ada.Finalization.Limited_Controlled with
-                  User_Data                      => Wisi.New_User_Data 
(Language.Parse_Data_Template.all),
-                  Table                          => Language.Table,
-                  Productions                    => Language.Productions,
-                  Language_Fixes                 => Language.Fixes,
-                  Language_Matching_Begin_Tokens => 
Language.Matching_Begin_Tokens,
-                  Language_String_ID_Set         => Language.String_ID_Set,
-                  Partial_Parse_Active           => 
Language.Partial_Parse_Active,
-                  Partial_Parse_Byte_Goal        => 
Language.Partial_Parse_Byte_Goal,
-                  others                         => <>),
-               Root_Save_Edited_Name             => <>,
-               Save_Edited_Count                 => <>))
+         return Result               : constant Parse_Context_Access :=
+           new Parse_Context'
+             (File_Name             => +File_Name,
+              Text_Buffer           => null,
+              Text_Buffer_Byte_Last => 0,
+              Text_Buffer_Char_Last => 0,
+              Parser                => Factory.all,
+              Prev_Tree             => <>,
+              Save_Prev_Text_Tree   => False,
+              Root_Save_Edited_Name => <>,
+              Save_Edited_Count     => <>,
+              Frozen                => False)
          do
-            Result.Parser.Tree.Lexer := Language.Lexer;
             Map.Insert (Result);
             if Trace_Incremental_Parse > Outline then
                Trace.Put_Line
-                 ("parse_context created, language " & Ada.Tags.Expanded_Name 
(Language.Parse_Data_Template.all'Tag));
+                 ("parse_context created, language " & Ada.Tags.Expanded_Name 
(Result.Parser.User_Data'Tag));
                if Trace_Memory > Outline then
                   Report_Memory (Trace.all, Prefix => True);
                end if;
@@ -157,7 +128,6 @@ package body Wisi.Parse_Context is
 
    function Find
      (File_Name : in String;
-      Language  : in Wisi.Parse_Context.Language;
       Have_Text : in Boolean := False)
      return Parse_Context_Access
    is begin
@@ -174,9 +144,6 @@ package body Wisi.Parse_Context is
       begin
          if Has_Element (Found) then
             return Result : constant Parse_Context_Access := Element (Found) do
-               if Language.Descriptor /= Result.Parser.Tree.Lexer.Descriptor 
then
-                  raise WisiToken.User_Error with "language does not match for 
buffer '" & File_Name & "'";
-               end if;
                if Have_Text and (Result.Text_Buffer = null or else 
Result.Text_Buffer'Length = 0) then
                   if Trace_Incremental_Parse > Outline then
                      Result.Parser.Tree.Lexer.Trace.Put_Line ("parse_context 
found, but text buffer empty");
@@ -194,7 +161,7 @@ package body Wisi.Parse_Context is
       end;
    end Find;
 
-   procedure Kill (File_Name : in String)
+   procedure Kill (File_Name : in String; Free_Parser : in 
WisiToken.Parse.Free_Parser)
    is begin
       if File_Name'Length = 0 then
          raise Wisi.Protocol_Error with "no file name given";
@@ -214,6 +181,7 @@ package body Wisi.Parse_Context is
             begin
                Map.Delete (File_Name);
                Ada.Strings.Unbounded.Free (Context.Text_Buffer);
+               Free_Parser (Context.Parser);
                Free (Context);
             end;
          end if;
@@ -749,6 +717,13 @@ package body Wisi.Parse_Context is
       end if;
    end Edit_Source;
 
+   procedure Dump_Prev_Tree
+     (Context   : in Parse_Context;
+      File_Name : in String)
+   is begin
+      Context.Prev_Tree.Put_Tree (File_Name);
+   end Dump_Prev_Tree;
+
    procedure Save_Text
      (Context   : in Parse_Context;
       File_Name : in String)
diff --git a/wisi-parse_context.ads b/wisi-parse_context.ads
index d9ec6f9740..40f354ce6d 100644
--- a/wisi-parse_context.ads
+++ b/wisi-parse_context.ads
@@ -15,26 +15,11 @@ pragma License (Modified_GPL);
 
 with Ada.Strings.Unbounded;
 with Ada.Unchecked_Deallocation;
-with WisiToken.Lexer;
-with WisiToken.Parse.LR.Parser;
 with WisiToken.Syntax_Trees;
 package Wisi.Parse_Context is
 
    Not_Found : exception;
 
-   type Language is record
-      Descriptor              : WisiToken.Descriptor_Access_Constant;
-      Lexer                   : WisiToken.Lexer.Handle;
-      Table                   : WisiToken.Parse.LR.Parse_Table_Ptr;
-      Productions             : 
WisiToken.Syntax_Trees.Production_Info_Trees.Vector;
-      Partial_Parse_Active    : access Boolean;
-      Partial_Parse_Byte_Goal : access WisiToken.Buffer_Pos;
-      Fixes                   : 
WisiToken.Parse.LR.Parser.Language_Fixes_Access;
-      Matching_Begin_Tokens   : 
WisiToken.Parse.LR.Parser.Language_Matching_Begin_Tokens_Access;
-      String_ID_Set           : 
WisiToken.Parse.LR.Parser.Language_String_ID_Set_Access;
-      Parse_Data_Template     : Wisi.Parse_Data_Access;
-   end record;
-
    type Parse_Context is tagged limited record
       --  'tagged' for Object.Method notation
 
@@ -49,7 +34,13 @@ package Wisi.Parse_Context is
       --  For Incremental parse; after editing, there may be empty space at
       --  the end of Text_Buffer.
 
-      Parser : WisiToken.Parse.LR.Parser.Parser;
+      Parser : WisiToken.Parse.Base_Parser_Access;
+
+      Prev_Tree : WisiToken.Syntax_Trees.Tree;
+      --  Copy of Parser.Tree before edits applied; useful for debugging.
+
+      Save_Prev_Text_Tree : Boolean := False;
+      --  If true, save text and copy tree before each edit.
 
       Root_Save_Edited_Name : Ada.Strings.Unbounded.Unbounded_String;
       --  If not "", save source text after the edit in a parse_incremental 
command,
@@ -57,49 +48,48 @@ package Wisi.Parse_Context is
       --  increments.
 
       Save_Edited_Count : Integer := 0;
+
+      Frozen : Boolean := False;
+      --  Used by emacs_wisi_common_parse.Parse_Stream to prevent any
+      --  operations on Parse_Context.
    end record;
    type Parse_Context_Access is access all Parse_Context;
 
    function Create_No_File
-     (Language : in Wisi.Parse_Context.Language;
-      Trace    : in WisiToken.Trace_Access)
+     (Factory : in WisiToken.Parse.Factory;
+      Trace   : in WisiToken.Trace_Access)
      return Parse_Context_Access;
 
    procedure Create_No_Text
      (File_Name : in String;
-      Language  : in Wisi.Parse_Context.Language;
+      Factory   : in WisiToken.Parse.Factory;
       Trace     : in WisiToken.Trace_Access);
 
    procedure Set_File (File_Name : in String; Parse_Context : in 
Parse_Context_Access);
 
    function Find_Create
      (File_Name : in String;
-      Language  : in Wisi.Parse_Context.Language;
+      Factory   : in WisiToken.Parse.Factory;
       Trace     : in WisiToken.Trace_Access)
      return Parse_Context_Access;
-   --  If a context for File_Name exists, return it if Language matches.
+   --  If a context for File_Name exists, return it.
    --
-   --  If no context found for File_Name, create one, return it.
+   --  If no context found for File_Name, create one using Factory, return it.
    --
    --  Raise Protocol_Error if Source_File_Name is an empty string.
-   --
-   --  Raise WisiToken.User_Error if context found for File_Name, but Language 
does not match.
 
    function Find
      (File_Name : in String;
-      Language  : in Wisi.Parse_Context.Language;
       Have_Text : in Boolean := False)
      return Parse_Context_Access;
-   --  If a context for File_Name exists, return it if Language matches.
+   --  If a context for File_Name exists, return it.
    --
    --  Raise Protocol_Error if Source_File_Name is an empty string.
    --
-   --  Raise WisiToken.User_Error if context found for File_Name, but Language 
does not match.
-   --
    --  Raise Not_Found if no context found for File_Name.
    --  If Have_Text, raise Not_Found if Text_Buffer is empty.
 
-   procedure Kill (File_Name : in String);
+   procedure Kill (File_Name : in String; Free_Parser : in 
WisiToken.Parse.Free_Parser);
 
    procedure Clear;
    --  Delete all contexts.
@@ -130,6 +120,11 @@ package Wisi.Parse_Context is
       KMN_List      :    out WisiToken.Parse.KMN_Lists.List);
    --  Changes must be UTF-8.
 
+   procedure Dump_Prev_Tree
+     (Context   : in Parse_Context;
+      File_Name : in String);
+   --  Output Context.Prev_Tree text format to File_Name.
+
    procedure Save_Text
      (Context   : in Parse_Context;
       File_Name : in String);
diff --git a/wisi-prj.el b/wisi-prj.el
index 744a4ab8d3..69ecc132a2 100644
--- a/wisi-prj.el
+++ b/wisi-prj.el
@@ -17,7 +17,7 @@
 ;; GNU General Public License for more details.
 ;;
 ;; You should have received a copy of the GNU General Public License
-;; along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+;; along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
 
 ;;; Usage:
 ;;
@@ -81,6 +81,35 @@
   ;; if the file should be included in `project-files'.
   )
 
+;;;###autoload
+(cl-defun create-wisi-prj
+    (&key
+     name
+     compile-env
+     file-env
+     compiler
+     xref
+     case-exception-files
+     (case-full-exceptions '())
+     (case-partial-exceptions '())
+     source-path
+     file-pred)
+  ;; We declare and autoload this because we can't autoload
+  ;; make-wisi-prj in emacs < 27. We can't use '(defalias
+  ;; 'create-wisi-prj 'make-wisi-prj); then make-wisi-prj is not defined
+  ;; by autoload.
+  (make-wisi-prj
+   :name name
+   :compile-env compile-env
+   :file-env file-env
+   :compiler compiler
+   :xref xref
+   :case-exception-files case-exception-files
+   :case-full-exceptions case-full-exceptions
+   :case-partial-exceptions case-partial-exceptions
+   :source-path source-path
+   :file-pred file-pred))
+
 (defun wisi-prj-require-prj ()
   "Return current `wisi-prj' object.
 Throw an error if current project is not an wisi-prj."
@@ -105,9 +134,10 @@ Used when searching for project files.")
   "Alist holding currently parsed project objects.
 Indexed by absolute project file name.")
 
-(cl-defgeneric wisi-prj-default (prj)
+(cl-defgeneric wisi-prj-default (_prj)
   "Return a project with default values.
-Used to reset a project before refreshing it.")
+Used to reset a project before refreshing it."
+  (make-wisi-prj))
 
 (cl-defgeneric wisi-prj-parse-one (_project _name _value)
   "If recognized by PROJECT, set NAME, VALUE in PROJECT, return non-nil.
@@ -136,6 +166,11 @@ If NOT-FULL is non-nil, very slow refresh operations may 
be skipped.")
 ;; modes don't have a language-specific compiler (eg java-wisi) or
 ;; xref process (eg gpr-mode).
 
+;;;###autoload
+(defun wisi-prj-make-compiler (label)
+  ;; We assume the constructor is autoloaded
+  (funcall (intern (format "create-%s-compiler" (symbol-name label)))))
+
 (cl-defgeneric wisi-compiler-parse-one (compiler project name value)
   "Set NAME, VALUE in COMPILER, if recognized by COMPILER.
 PROJECT is an `wisi-prj' object; COMPILER is `wisi-prj-compiler'.")
@@ -153,14 +188,23 @@ after the project file PRJ-FILE-NAME is parsed."
   "PROJECT has been de-selected; undo any compiler-specific select actions."
   nil)
 
-(cl-defgeneric wisi-compiler-show-prj-path (compiler)
-  "Display buffer listing project file search path.")
+(cl-defgeneric wisi-compiler-prj-path (_compiler)
+  "Return the project file search path.
+Returns a list of directories, for us with `locate-file'."
+  nil)
 
 (cl-defgeneric wisi-compiler-fix-error (compiler source-buffer)
   "Attempt to fix a compilation error, return non-nil if fixed.
 Current buffer is compilation buffer; point is at an error message.
 SOURCE-BUFFER contains the source code referenced in the error message.")
 
+(cl-defgeneric wisi-compiler-root-dir (compiler)
+  "Return a meaningful root directory; nil if none.")
+
+(defun wisi-prj-make-xref (label)
+  ;; We assume the constructor is autoloaded
+  (funcall (intern (format "create-%s-xref" (symbol-name label)))))
+
 (cl-defgeneric wisi-xref-parse-one (_xref _project _name _value)
   "If recognized by XREF, set NAME, VALUE in XREF, return non-nil.
 Else return nil."
@@ -206,7 +250,7 @@ Group 1 must be the simple symbol; the rest of the item may 
be
 annotations.")
 
 (cl-defgeneric wisi-xref-completion-at-point-table (xref project)
-  "Return a completion table of names defined in PROJECT.
+  "Return a completion table of names in PROJECT that are relevant at point.
 The table is a simple list of symbols.")
 
 (cl-defgeneric wisi-xref-definitions (xref project item)
@@ -217,15 +261,17 @@ The table is a simple list of symbols.")
 
 (cl-defgeneric wisi-xref-other (project &key identifier filename line column)
   "Return cross reference information.
-PROJECT - dispatching object, normally a `wisi-prj' object.
-IDENTIFIER - an identifier or operator_symbol
+PROJECT - a `wisi-prj' object.
+IDENTIFIER - string; an identifier or operator_symbol
 FILENAME - absolute filename containing the identifier
 LINE - line number containing the identifier (may be nil)
 COLUMN - Emacs column of the start of the identifier (may be nil)
 Point is on the start of the identifier.
-Returns a list (FILE LINE COLUMN) giving the corresponding location;
-FILE is an absolute file name.  If point is at the specification, the
-corresponding location is the
+
+Returns a list (FILE LINE COLUMN) giving the corresponding
+location; FILE is an absolute file name.  If point is on a
+reference, the corresponding location is the specification. If
+point is at the specification, the corresponding location is the
 body, and vice versa.")
 
 (defvar-local wisi-xref-full-path nil
@@ -314,12 +360,25 @@ user arg limits completion to current file."
              id))))
      (t def))))
 
+(eval-and-compile
+  (when (version< emacs-version "28.0.60")
+    ;; WORKAROUND: in emacs 28 xref-location changed from defclass to
+    ;; cl-defstruct.
+    (require 'eieio)
+    (with-suppressed-warnings ;; "unknown slot" in emacs 28
+       (progn
+         (defun xref-item-summary (item) (oref item summary))
+         (defun xref-item-location (item) (oref item location))
+         (defun xref-file-location-file (location) (oref location file))
+         (defun xref-file-location-line (location) (oref location line))
+         (defun xref-file-location-column (location) (oref location column))
+         ))))
+
 (defun wisi-goto-spec/body (identifier)
   "Goto declaration or body for IDENTIFIER (default symbol at point).
 If no symbol at point, or with prefix arg, prompt for symbol, goto spec."
   (interactive (list (wisi-get-identifier "Goto spec/body of: ")))
-  (let ((prj (project-current))
-       desired-loc)
+  (let (desired-loc)
     (cond
      ((consp identifier)
       ;; alist element from wisi-xref-completion-table; desired
@@ -334,49 +393,40 @@ If no symbol at point, or with prefix arg, prompt for 
symbol, goto spec."
 
      ((stringp identifier)
       ;; from xref-backend-identifier-at-point; desired location is 'other'
-      (let ((item (wisi-xref-item identifier prj)))
-       (condition-case err
-           ;; WORKAROUND: xref 1.3.2 xref-location changed from
-           ;; defclass to cl-defstruct. If drop emacs 26, use
-           ;; 'with-suppressed-warnings'.
-           (with-no-warnings ;; "unknown slot"
-             (let ((summary (if (functionp 'xref-item-summary) 
(xref-item-summary item) (oref item summary)))
-                   (location (if (functionp 'xref-item-location) 
(xref-item-location item) (oref item location)))
-                   (eieio-skip-typecheck t)) ;; 'location' may have line, 
column nil
-               (let ((file (if (functionp 'xref-file-location-file)
-                               (xref-file-location-file location)
-                             (oref location file)))
-                     (line (if (functionp 'xref-file-location-line)
-                               (xref-file-location-line location)
-                             (oref location line)))
-                     (column (if (functionp 'xref-file-location-column)
-                                 (xref-file-location-column location)
-                               (oref location column))))
-                 (let ((target
-                        (wisi-xref-other
-                         (wisi-prj-xref prj) prj
-                         :identifier summary
-                         :filename file
-                         :line line
-                         :column column)))
-                   (setq desired-loc
-                         (xref-make summary
-                                    (xref-make-file-location
-                                     (nth 0 target) ;; file
-                                     (nth 1 target) ;; line
-                                     (nth 2 target))) ;; column
-                         )))))
-         (user-error ;; from gpr-query; current file might be new to project, 
so try wisi-names
-          (let ((item (assoc identifier (wisi-names nil t))))
-            (if item
-                (setq desired-loc
-                      (xref-make identifier
-                                 (xref-make-file-location
-                                  (nth 1 item) ;; file
-                                  (nth 2 item) ;; line
-                                  (nth 3 item))))
-              (signal (car err) (cdr err)))))
-         )))
+      (condition-case err
+         (let* ((prj (project-current))
+                (item (wisi-xref-item identifier prj)))
+           (let ((summary (xref-item-summary item))
+                 (location (xref-item-location item))
+                 (eieio-skip-typecheck t)) ;; 'location' may have line, column 
nil
+             (let ((file (xref-file-location-file location))
+                   (line (xref-file-location-line location))
+                   (column (xref-file-location-column location)))
+               (let ((target
+                      (wisi-xref-other
+                       (wisi-prj-xref prj) prj
+                       :identifier summary
+                       :filename file
+                       :line line
+                       :column column)))
+                 (setq desired-loc
+                       (xref-make summary
+                                  (xref-make-file-location
+                                   (nth 0 target) ;; file
+                                   (nth 1 target) ;; line
+                                   (nth 2 target))) ;; column
+                       )))))
+       (user-error ;; from gpr-query; current file might be new to project, so 
try wisi-names
+        (let ((item (assoc identifier (wisi-names nil t))))
+          (if item
+              (setq desired-loc
+                    (xref-make identifier
+                               (xref-make-file-location
+                                (nth 1 item) ;; file
+                                (nth 2 item) ;; line
+                                (nth 3 item))))
+            (signal (car err) (cdr err)))))
+       ))
 
      (t ;; something else
       (error "unknown case in wisi-goto-spec/body")))
@@ -563,8 +613,16 @@ COLUMN - Emacs column of the start of the identifier")
 ;;;; wisi-prj specific methods
 
 (cl-defmethod project-root ((project wisi-prj))
-   ;; Not meaningful, but some project functions insist on a valid directory
-   (car (wisi-prj-source-path project)))
+  ;; Some project functions insist on a valid directory. eglot starts
+  ;; language server in this directory; for ada_language_server it
+  ;; must be the directory containing the gnat project file.
+  (or
+   (and (wisi-prj-compiler project)
+       (wisi-compiler-root-dir (wisi-prj-compiler project)))
+   (car (wisi-prj-source-path project))))
+
+(cl-defmethod project-name ((project wisi-prj))
+  (wisi-prj-name project))
 
 (cl-defmethod project-files ((project wisi-prj) &optional dirs)
   (let (result)
@@ -677,15 +735,22 @@ absolute file name.")
 Parser is called with two arguments; the project file name and
 a project. Parser should update the project with values from the file.")
 
-(cl-defmethod wisi-prj-parse-one (project name value)
+(cl-defmethod wisi-prj-parse-one ((project wisi-prj) name value)
   "If NAME is a wisi-prj slot, set it to VALUE, return t.
 Else return nil."
   (cond
    ((string= name "casing")
-    (cl-pushnew (expand-file-name
-                 (substitute-in-file-name value))
-                (wisi-prj-case-exception-files project)
-               :test #'string-equal)
+    (let ((exp-value (substitute-in-file-name value)))
+      (if (and (wisi-prj-compiler project)
+              (not (file-name-absolute-p exp-value)))
+         (let ((found (locate-file exp-value (wisi-compiler-prj-path 
(wisi-prj-compiler project)))))
+           (setq exp-value (if found found (expand-file-name exp-value))))
+
+       (setq exp-value (expand-file-name exp-value)))
+
+      (cl-pushnew exp-value
+                  (wisi-prj-case-exception-files project)
+                 :test #'string-equal))
     t)
 
    ((string= name "src_dir")
@@ -701,6 +766,13 @@ Else return nil."
                (wisi-prj-file-env project)))
     t)
 
+   ((string= name "import_env_var")
+    ;; Copy an env var from parent.
+    (setf (wisi-prj-file-env project)
+         (cons (concat value "=" (getenv value))
+               (wisi-prj-file-env project)))
+    t)
+
    ))
 
 (defvar-local wisi-prj-parse-undefined-function nil
@@ -723,9 +795,11 @@ Called with three args: PROJECT NAME VALUE.")
              result)
 
          ;; Both compiler and xref need to see some settings; eg gpr_file, env 
vars.
-         (when (wisi-compiler-parse-one (wisi-prj-compiler project) project 
name value)
+         (when (and (wisi-prj-compiler project)
+                    (wisi-compiler-parse-one (wisi-prj-compiler project) 
project name value))
            (setq result t))
-         (when (wisi-xref-parse-one (wisi-prj-xref project) project name value)
+         (when (and (wisi-prj-xref project)
+                    (wisi-xref-parse-one (wisi-prj-xref project) project name 
value))
            (setq result t))
 
          (unless result
@@ -760,9 +834,13 @@ case, return the project."
       ;; If no parser, prj-file is just a placeholder; there is no file to 
parse.
       ;; For example, sal-android-prj has no project file.
        (funcall parser prj-file project)
-       (wisi-prj-parse-final project prj-file)
-       (wisi-compiler-parse-final (wisi-prj-compiler project) project prj-file)
-       (wisi-xref-parse-final (wisi-prj-xref project) project prj-file))
+       (wisi-prj-parse-final project prj-file))
+
+    ;; We do this even without a parser, so project builders can just
+    ;; set the compiler and xref; see gnat-alire.el
+    ;; create-alire-project.
+    (wisi-compiler-parse-final (wisi-prj-compiler project) project prj-file)
+    (wisi-xref-parse-final (wisi-prj-xref project) project prj-file)
 
     (when cache
       ;; Cache the project properties
@@ -775,7 +853,15 @@ case, return the project."
 (defun wisi-prj-show-prj-path ()
   "Show the compiler project file search path."
   (interactive)
-  (wisi-compiler-show-prj-path (wisi-prj-compiler (wisi-prj-require-prj))))
+  (let ((path (wisi-compiler-prj-path (wisi-prj-compiler 
(wisi-prj-require-prj)))))
+    (if path
+       (progn
+         (pop-to-buffer (get-buffer-create "*project file search path*"))
+         (erase-buffer)
+         (dolist (file path)
+           (insert (format "%s\n" file))))
+      (message "no project file search path set")
+      )))
 
 (defun wisi-prj-show-src-path ()
   "Show the project source file search path."
@@ -792,26 +878,26 @@ case, return the project."
 (defun wisi-fix-compiler-error ()
   "Attempt to fix the current compiler error.
 Point must be at the source location referenced in a compiler error.
-In `compilation-last-buffer', point must be at the compiler error.
+In `next-error-last-buffer', point must be at the compiler error.
 Leave point at fixed code."
   (interactive)
   (let ((source-buffer (current-buffer))
        (line-move-visual nil)); screws up next-line otherwise
 
     (cond
-     ((equal compilation-last-buffer wisi-error-buffer)
+     ((equal next-error-last-buffer wisi-error-buffer)
       (set-buffer source-buffer)
       (wisi-repair-error))
 
      (t
-      (with-current-buffer compilation-last-buffer
+      (with-current-buffer next-error-last-buffer
        (let ((comp-buf-pt (point))
              (success
               (wisi-compiler-fix-error
                (wisi-prj-compiler (wisi-prj-require-prj))
                source-buffer)))
          ;; restore compilation buffer point
-         (set-buffer compilation-last-buffer)
+         (set-buffer next-error-last-buffer)
          (goto-char comp-buf-pt)
 
          (unless success
@@ -1252,13 +1338,13 @@ with \\[universal-argument]."
 (defun wisi-case-activate-keys (map)
   "Modify the key bindings for all the keys that should adjust casing."
   (mapc (function
-        (lambda(key)
+        (lambda (key)
           (define-key
             map
-            (char-to-string key)
-            'wisi-case-adjust-interactive)))
+            (vector key)
+            #'wisi-case-adjust-interactive)))
        '( ?_ ?% ?& ?* ?\( ?\) ?- ?= ?+
-             ?| ?\; ?: ?' ?\" ?< ?, ?. ?> ?/ ?\n 32 ?\r ))
+             ?| ?\; ?: ?' ?\" ?< ?, ?. ?> ?/ ?\n ?\s ?\r ))
   )
 
 ;;;; xref backend
@@ -1288,7 +1374,8 @@ IDENTIFIER is from a user prompt with completion, or from
       (setq column (plist-get t-prop :column))
       )
 
-     ((string-match (wisi-xref-completion-regexp (wisi-prj-xref prj)) 
identifier)
+     ((and (wisi-prj-xref prj)
+          (string-match (wisi-xref-completion-regexp (wisi-prj-xref prj)) 
identifier))
       ;; IDENTIFIER is from prompt/completion on wisi-xref-completion-table
       (setq ident (match-string 1 identifier))
 
@@ -1300,7 +1387,8 @@ IDENTIFIER is from a user prompt with completion, or from
        (setq column (nth 2 loc))
        ))
 
-     ((string-match wisi-names-regexp identifier)
+     ((and (wisi-prj-xref prj)
+          (string-match wisi-names-regexp identifier))
       ;; IDENTIFIER is from prompt/completion on wisi-names.
       (setq ident (match-string 1 identifier))
       (setq file (buffer-file-name))
@@ -1346,12 +1434,18 @@ IDENTIFIER is from a user prompt with completion, or 
from
 
 ;;;###autoload
 (defun wisi-prj-xref-backend ()
-  "For `xref-backend-functions'; return the current wisi project."
+  "Return the current wisi project if it has an xref backend.
+For `xref-backend-functions'."
   ;; We return the project, not the xref object, because the
   ;; wisi-xref-* functions need the project.
   (let ((prj (project-current)))
-    (when (wisi-prj-p prj)
-      prj)))
+    (when (and (wisi-prj-p prj)
+              (wisi-prj-xref prj))
+      (cond
+       ((eq (wisi-prj-xref prj) 'eglot)
+       'eglot)
+       (t prj))
+      )))
 
 ;;;; project-find-functions alternatives
 
@@ -1401,15 +1495,16 @@ project is current."
   (when (or dominating-file (buffer-file-name))
     ;; buffer-file-name is nil in *compilation* buffer
     (let ((prj-file (cdr (assoc (or dominating-file (buffer-file-name)) 
wisi-prj--dominating-alist))))
-      (unless (string-equal prj-file wisi-prj--current-file)
-       (message "Switching to project file '%s'" prj-file)
-       (let ((old-prj (cdr (assoc  wisi-prj--current-file wisi-prj--cache)))
-             (new-prj (cdr (assoc prj-file wisi-prj--cache))))
-         (when (wisi-prj-p old-prj)
-           (wisi-prj-deselect old-prj))
-         (when (wisi-prj-p new-prj)
-           (wisi-prj-select new-prj))
-         (setq wisi-prj--current-file prj-file))))))
+      (when prj-file ;; don't switch if dominating-file not recognized.
+       (unless (string-equal prj-file wisi-prj--current-file)
+         (message "Switching to project file '%s'" prj-file)
+         (let ((old-prj (cdr (assoc  wisi-prj--current-file wisi-prj--cache)))
+               (new-prj (cdr (assoc prj-file wisi-prj--cache))))
+           (when (wisi-prj-p old-prj)
+             (wisi-prj-deselect old-prj))
+           (when (wisi-prj-p new-prj)
+             (wisi-prj-select new-prj))
+           (setq wisi-prj--current-file prj-file)))))))
 
 ;;;###autoload
 (defun wisi-prj-current-cached (_dir)
@@ -1506,10 +1601,11 @@ not the current project."
          (unless new-prj
            ;; User may have used `wisi-prj-set-dominating' instead of
            ;; `wisi-prj-cache-dominating'; parse the project file now.
-           (wisi-prj-parse-file
-            :prj-file prj-file
-            :init-prj (cdr (assoc-string prj-file wisi-prj--default))
-            :cache t))
+           (when (assoc-string prj-file wisi-prj--default)
+             (wisi-prj-parse-file
+              :prj-file prj-file
+              :init-prj (cdr (assoc-string prj-file wisi-prj--default))
+              :cache t)))
          (when new-prj (wisi-prj-select new-prj))))
       new-prj)))
 
@@ -1574,6 +1670,33 @@ Do The Right Thing to make PRJ-FILE active and selected; 
return the project."
       (memq #'wisi-prj-current-cached project-find-functions)
       (memq #'wisi-prj-current-parse project-find-functions)))
 
+(defun wisi-prompt-prj-file ()
+  "Prompt for a project file.
+Return nil if no file selected, the absolute file name
+otherwise. The file must have an extension from
+`wisi-prj-file-extensions'."
+  (let ((filename
+        (condition-case-unless-debug nil
+            (read-file-name
+             "Project file: " ; prompt
+             nil ; dir
+             "" ; default-filename
+             t   ; mustmatch
+             nil; initial
+             (lambda (name)
+               ;; this allows directories, which enables navigating
+               ;; to the desired file. We just assume the user won't
+               ;; return a directory.
+               (or (file-accessible-directory-p name)
+                   (member (file-name-extension name) 
wisi-prj-file-extensions))))
+          (error nil)
+          )))
+
+  (unless (or (null filename)
+             (file-name-absolute-p filename))
+    (setq filename (expand-file-name filename)))
+  filename))
+
 ;;;; project menu
 
 (defun wisi-prj--menu-compute ()
@@ -1620,7 +1743,7 @@ Menu displays cached wisi projects."
        ))
     ))
 
-(add-hook 'menu-bar-update-hook 'wisi-prj-menu-install)
+(add-hook 'menu-bar-update-hook #'wisi-prj-menu-install)
 
 (defun wisi-prj-completion-table ()
   "Return list of names of cached projects."
diff --git a/wisi-process-parse.el b/wisi-process-parse.el
index d00e6762fb..def4ce9c6e 100644
--- a/wisi-process-parse.el
+++ b/wisi-process-parse.el
@@ -1,6 +1,6 @@
-;;; wisi-process-parse.el --- interface to external parse program
+;;; wisi-process-parse.el --- interface to external parse program  -*- 
lexical-binding: t; -*-
 ;;
-;; Copyright (C) 2014, 2017 - 2022 Free Software Foundation, Inc.
+;; Copyright (C) 2014, 2017 - 2023 Free Software Foundation, Inc.
 ;;
 ;; Author: Stephen Leake <stephen_leake@member.fsf.org>
 ;;
@@ -17,12 +17,12 @@
 ;; GNU General Public License for more details.
 ;;
 ;; You should have received a copy of the GNU General Public License
-;; along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+;; along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
 
 (require 'cl-lib)
 (require 'wisi-parse-common)
 
-(defconst wisi-process-parse-protocol-version "6"
+(defconst wisi-process-parse-protocol-version "7"
   "Defines data exchanged between this package and the background process.
 Must match emacs_wisi_common_parse.ads Protocol_Version.")
 
@@ -83,7 +83,7 @@ Otherwise add PARSER to `wisi-process--alist', return it."
       (let ((exec-file (locate-file (wisi-process--parser-exec-file parser) 
exec-path '("" ".exe"))))
 
        (unless exec-file
-         (error "%s not found on `exec-path'; run 'build.sh' in the ELPA 
package."
+         (user-error "%s not found on `exec-path'."
                 (wisi-process--parser-exec-file parser)))
 
        (push (cons (wisi-process--parser-label parser) parser) 
wisi-process--alist)
@@ -153,10 +153,7 @@ Otherwise add PARSER to `wisi-process--alist', return it."
                (with-current-buffer (car wisi-parse-full-active)
                  (read-only-mode -1)
                  (let ((region (cdr wisi-parse-full-active)))
-                   (when (and (>= (cdr region) (car region))
-                              (>= (cdr region) (point-min))
-                              (<= (car region) (point-max)))
-                     (font-lock-flush (car region) (cdr region))))
+                   (font-lock-flush (max (point-min) (car region)) (min 
(point-max) (cdr region))))
 
                  (set-process-filter process nil)
 
@@ -172,9 +169,9 @@ Otherwise add PARSER to `wisi-process--alist', return it."
                  )
              (setq wisi-parse-full-active nil)
              ))))
-         ))))
+       ))))
 
-(cl-defmethod wisi-parse-require-process (parser &key nowait)
+(cl-defmethod wisi-parse-require-process ((parser wisi-process--parser) &key 
nowait)
   (unless (process-live-p (wisi-process--parser-process parser))
     (let ((process-connection-type nil) ;; use a pipe, not a pty; avoid 
line-by-line reads
          (process-name (format " *%s_wisi_parse*" (wisi-process--parser-label 
parser))))
@@ -192,7 +189,9 @@ Otherwise add PARSER to `wisi-process--alist', return it."
        (erase-buffer));; delete any previous messages, prompt
 
       (when (or (not nowait) (>= wisi-debug 2))
-       (message "starting parser ..."))
+       (message "starting wisi parser %s in buffer %s ..."
+                (wisi-process--parser-label parser)
+                (current-buffer)))
       (wisi-parse-log-message parser "create process")
 
       (setf (wisi-process--parser-version-checked parser) nil)
@@ -219,7 +218,7 @@ Otherwise add PARSER to `wisi-process--alist', return it."
 
       (unless nowait
        (wisi-process-parse--wait parser)
-       (message "starting parser ... done"))
+       (message "starting wisi parser ... done"))
       )))
 
 (defun wisi-process-parse--wait (parser)
@@ -232,6 +231,7 @@ Otherwise add PARSER to `wisi-process--alist', return it."
     (with-current-buffer (wisi-process--parser-buffer parser)
       (setq search-start (point-min))
       (while (if filter-active
+                ;; FIXME: if the filter is hung, this should reset it
                 (not (eq #'internal-default-process-filter (process-filter 
process)));; wait for filter to finish
 
              (and (process-live-p process)
@@ -323,6 +323,10 @@ complete. PARSE-END is end of desired parse region."
     ;; we don't log the buffer text; may be huge
     (process-send-string process (buffer-substring-no-properties begin 
send-end))
 
+    ;; We don't set wisi-process--parser-update-fringe; partial parse
+    ;; almost always has bogus errors at the start and end of the
+    ;; parse.
+    ;;
     ;; We don't wait for the send to complete here.
     ))
 
@@ -389,6 +393,8 @@ complete."
                    )))
           (process (wisi-process--parser-process parser)))
 
+      (setf (wisi-process--parser-update-fringe parser) (not 
wisi-disable-diagnostics))
+
       (with-current-buffer (wisi-process--parser-buffer parser)
        (erase-buffer))
 
@@ -515,7 +521,7 @@ PARSER will respond with one or more Query messages."
        )))
     ))
 
-(defun wisi-process-parse--Name_Property (parser sexp)
+(defun wisi-process-parse--Name_Property (_parser sexp)
   ;; sexp is [Name_Property first-pos last-pos]
   ;; see `wisi-process-parse--execute'
   ;; implements wisi-name-action
@@ -546,7 +552,7 @@ PARSER will respond with one or more Query messages."
               'fontified t)
         )))))
 
-(defun wisi-process-parse--Indent (parser sexp)
+(defun wisi-process-parse--Indent (_parser sexp)
   ;; sexp is [Indent line-number line-begin-char-pos indent]
   ;; see `wisi-process-parse--execute'
   (let ((pos (aref sexp 2)))
@@ -559,7 +565,7 @@ PARSER will respond with one or more Query messages."
         (aref sexp 3)))
       )))
 
-(defun wisi-process-parse--Lexer_Error (parser sexp)
+(defun wisi-process-parse--Lexer_Error (_parser sexp)
   ;; sexp is [Lexer_Error char-position <message> <repair-char>]
   ;; see `wisi-process-parse--execute'
   (let ((pos (min (point-max) (aref sexp 1)))
@@ -582,7 +588,7 @@ PARSER will respond with one or more Query messages."
     (push err (wisi-parser-local-lexer-errors wisi-parser-local))
     ))
 
-(defun wisi-process-parse--Parser_Error (parser sexp)
+(defun wisi-process-parse--Parser_Error (_parser sexp)
   ;; sexp is [Parser_Error char-position <string>]
   ;; see `wisi-process-parse--execute'
   (let ((pos (min (point-max) (aref sexp 1)))
@@ -611,7 +617,7 @@ PARSER will respond with one or more Query messages."
     (push err (wisi-parser-local-parse-errors wisi-parser-local))
     ))
 
-(defun wisi-process-parse--In_Parse_Action_Error (parser sexp)
+(defun wisi-process-parse--In_Parse_Action_Error (_parser sexp)
   ;; sexp is [In_Parse_Action_Error code name-1-pos name-2-pos <string>]
   ;; see `wisi-process-parse--execute'
   (let ((name-1-pos (aref sexp 2))
@@ -671,7 +677,9 @@ PARSER will respond with one or more Query messages."
              (wisi--parse-error-repair err)) ;; new
             err ;; old
             (wisi-parser-local-parse-errors wisi-parser-local) ;; tree
-            :test (lambda (old el) (= (wisi--parse-error-pos old) 
(wisi--parse-error-pos err)))))
+            :test (lambda (old _el)
+                    (= (wisi--parse-error-pos old)
+                       (wisi--parse-error-pos err)))))
           )))
     ))
 
@@ -680,7 +688,7 @@ PARSER will respond with one or more Query messages."
   ;; see `wisi-process-parse--execute'
   (setf (wisi-process--parser-end-pos parser) (1+ (aref sexp 1))))
 
-(defun wisi-process-parse--Edit (parser sexp)
+(defun wisi-process-parse--Edit (_parser sexp)
   ;; sexp is [Edit begin end text]
   (save-excursion
     (delete-region (aref sexp 1) (1+ (aref sexp 2)))
@@ -715,88 +723,91 @@ PARSER will respond with one or more Query messages."
 Source buffer is current."
   ;; sexp is [action arg ...]; an encoded instruction that we need to execute
   ;;
-  ;; Actions:
-  ;;
-  ;; [Navigate_Cache pos statement_id id length class containing_pos prev_pos 
next_pos end_pos]
-  ;;    Set a wisi-cache text-property.
-  ;;    *pos          : integer buffer position; -1 if nil (not set)
-  ;;    *id           : integer index into parser-token-table
-  ;;    length        : integer character count
-  ;;    class         : integer index into wisi-class-list
-  ;;
-  ;; [Name_Property first-pos last-pos]
-  ;;
-  ;; [Face_Property first-pos last-pos face-index]
-  ;;    Set a font-lock-face text-property
-  ;;    face-index: integer index into parser-elisp-face-table
-  ;;
-  ;; [Indent line-number indent]
-  ;;    Set an indent text property
-  ;;
-  ;; [Lexer_Error char-position <message> <repair-char>]
-  ;;    The lexer detected an error at char-position.
-  ;;
-  ;;    If <repair-char> is not ASCII NUL, it was inserted immediately
-  ;;    after char-position to fix the error.
-  ;;
-  ;; [Parser_Error char-position <message>]
-  ;;    The parser detected a syntax error; save information for later
-  ;;    reporting.
-  ;;
-  ;;    If error recovery is successful, there can be more than one
-  ;;    error reported during a parse.
-  ;;
-  ;; [In_Parse_Action_Error code name-1-pos name-2-pos <string>]
-  ;;    The parser detected an in-parse action error; save information
-  ;;    for later reporting. Either of the name-*-pos may be 0,
-  ;;    indicating a missing name.
-  ;;
-  ;;    If error recovery is successful, there can be more than one
-  ;;    error reported during a parse.
-  ;;
-  ;; [Recover [error-pos edit-pos [inserted] [deleted] deleted-region]...]
-  ;;    The parser finished a successful error recovery.
-  ;;
-  ;;    error-pos: Buffer position where error was detected
-  ;;
-  ;;    edit-pos: Buffer position of inserted/deleted tokens
-  ;;
-  ;;    inserted: Virtual tokens (terminal or non-terminal) inserted
-  ;;    before edit-pos.
-  ;;
-  ;;    deleted: Tokens deleted after edit-pos.
-  ;;
-  ;;    deleted-region: source buffer char region containing deleted tokens
-  ;;
-  ;;    Args are token ids; index into parser-token-table. Save the
-  ;;    information for later use by `wisi-repair-error'.
-  ;;
-  ;; [Edit begin end text]
-  ;;    Replace region BEGIN . END with TEXT; normally the result of a
-  ;;    refactor command.
-  ;;
-  ;; [Language ...]
-  ;;    Dispatch to a language-specific action, via
-  ;;    `wisi-process--parser-language-action-table'.
-  ;;
-  ;; [Query query-label ...]
-  ;;
-  ;; Numeric action codes are given in the case expression below
+  ;; Numeric action codes are given in the case expression below; must
+  ;; match list of *_Code in wisi.ads.
 
   (condition-case err
       (cl-ecase (aref sexp 0)
        (1  (wisi-process-parse--Navigate_Cache parser sexp))
+       ;; [Navigate_Cache pos statement_id id length class containing_pos 
prev_pos next_pos end_pos]
+       ;;    Set a wisi-cache text-property.
+       ;;    *pos          : integer buffer position; -1 if nil (not set)
+       ;;    *id           : integer index into parser-token-table
+       ;;    length        : integer character count
+       ;;    class         : integer index into wisi-class-list
+
        (2  (wisi-process-parse--Face_Property parser sexp))
+       ;; [Face_Property first-pos last-pos face-index]
+       ;;    Set a font-lock-face text-property
+       ;;    face-index: integer index into parser-elisp-face-table
+
        (3  (wisi-process-parse--Indent parser sexp))
+       ;; [Indent line-number indent]
+       ;;    Set an indent text property
+
        (4  (wisi-process-parse--Lexer_Error parser sexp))
+       ;; [Lexer_Error char-position <message> <repair-char>]
+       ;;    The lexer detected an error at char-position.
+       ;;
+       ;;    If <repair-char> is not ASCII NUL, it was inserted immediately
+       ;;    after char-position to fix the error.
+
        (5  (wisi-process-parse--Parser_Error parser sexp))
+       ;; [Parser_Error char-position <message>]
+       ;;    The parser detected a syntax error; save information for later
+       ;;    reporting.
+       ;;
+       ;;    If error recovery is successful, there can be more than one
+       ;;    error reported during a parse.
+
        (6  (wisi-process-parse--In_Parse_Action_Error parser sexp))
+       ;; [In_Parse_Action_Error code name-1-pos name-2-pos <string>]
+       ;;    The parser detected an in-parse action error; save information
+       ;;    for later reporting. Either of the name-*-pos may be 0,
+       ;;    indicating a missing name.
+       ;;
+       ;;    If error recovery is successful, there can be more than one
+       ;;    error reported during a parse.
+
        (7  (wisi-process-parse--Recover parser sexp))
+       ;; [Recover [error-pos edit-pos [inserted] [deleted] deleted-region]...]
+       ;;    The parser finished a successful error recovery.
+       ;;
+       ;;    error-pos: Buffer position where error was detected
+       ;;
+       ;;    edit-pos: Buffer position of inserted/deleted tokens
+       ;;
+       ;;    inserted: Virtual tokens (terminal or non-terminal) inserted
+       ;;    before edit-pos.
+       ;;
+       ;;    deleted: Tokens deleted after edit-pos.
+       ;;
+       ;;    deleted-region: source buffer char region containing deleted 
tokens
+       ;;
+       ;;    Args are token ids; index into parser-token-table. Save the
+       ;;    information for later use by `wisi-repair-error'.
+
        (8  (wisi-process-parse--End parser sexp))
+       ;; [End pos]
+       ;;    Record last buffer position parsed.
+
        (9  (wisi-process-parse--Name_Property parser sexp))
+       ;; [Name_Property first-pos last-pos]
+
        (10 (wisi-process-parse--Edit parser sexp))
+       ;; [Edit begin end text]
+       ;;    Replace region BEGIN . END with TEXT; normally the result of a
+       ;;    refactor command.
+
        (11 (wisi-process-parse--Language parser sexp))
+       ;; [Language ...]
+       ;;    Dispatch to a language-specific action, via
+       ;;    `wisi-process--parser-language-action-table'.
+
        (12 (wisi-process-parse--Query parser sexp))
+       ;; [Query query-label ...]
+       ;;    Query result.
+
        )
     (error
      (when (< 0 wisi-debug)
@@ -811,6 +822,7 @@ Source buffer is current."
 
 (cl-defmethod wisi-parse-reset ((parser wisi-process--parser))
   (setf (wisi-process--parser-busy parser) nil)
+  (setq wisi-parse-full-active nil)
   (wisi-parse-require-process parser)
   (wisi-process--kill-context parser)
   (wisi-process-parse--wait parser))
@@ -822,8 +834,7 @@ Source buffer is current."
     ;; executable is not reading command input.
 
     ;; Don't let font-lock start a parse for face while waiting for
-    ;; the process to die. FIXME: that just means font-lock will
-    ;; restart the process immediately; tell font-lock not to do that?
+    ;; the process to die.
     (setf (wisi-process--parser-busy parser) t)
     (wisi-parse-log-message parser "kill process")
     (kill-process (wisi-process--parser-process parser)))
@@ -831,6 +842,10 @@ Source buffer is current."
 
 (cl-defun wisi-process-parse--prepare (parser parse-action &key nowait)
   "Check for parser busy and startup, mark parser busy, require parser 
process."
+  (unless (process-live-p (wisi-process--parser-process parser))
+    (wisi-parse-log-message parser "process died")
+    (error "parser process died"))
+
   (when (wisi-process--parser-busy parser)
     (when (< 1 wisi-debug)
       (wisi-parse-log-message parser (format "parse--prepare %s in %s parser 
busy" parse-action (current-buffer))))
@@ -900,6 +915,7 @@ Source buffer is current."
   (let ((response-buffer (wisi-process--parser-buffer parser))
         (source-buffer (wisi-process--parser-source-buffer parser))
        log-start)
+    (defvar w32-pipe-read-delay)
     (condition-case err
        (let* ((process (wisi-process--parser-process parser))
               (w32-pipe-read-delay 0) ;; fastest subprocess read
@@ -1004,7 +1020,7 @@ Source buffer is current."
                     (t
                      ;; Something else
                      (condition-case-unless-debug err
-                         (eval response)
+                         (eval response t)
                        (error
                         (wisi-parse-log-message parser (cadr err))
                         (with-current-buffer source-buffer
@@ -1018,7 +1034,7 @@ Source buffer is current."
                   ((arrayp response)
                    ;; encoded action
                    (set-buffer source-buffer) ;; for put-text-property in 
actions
-                   (condition-case err
+                   (condition-case nil
                        (wisi-process-parse--execute parser response)
 
                      (t ;; error from bug in action code above, or bad data 
from parser.
@@ -1108,33 +1124,19 @@ Source buffer is current."
        (signal (car err) (cdr err)))
       )))
 
-(cl-defun wisi-process-parse--handle-messages-file-not-found (parser action 
&key no-text)
+(cl-defun wisi-process-parse--handle-messages-file-not-found (parser action)
   (funcall action)
   (condition-case _err
       (wisi-process-parse--handle-messages parser)
     ('wisi-file_not_found
-     (cond
-      (no-text
-       (let ((cmd (format "create-context \"%s\"" (if (buffer-file-name) 
(buffer-file-name) (buffer-name))))
-            (process (wisi-process--parser-process parser)))
-        (with-current-buffer (wisi-process--parser-buffer parser)
-          (erase-buffer))
-        (wisi-parse-log-message parser cmd)
-        (process-send-string process (wisi-process-parse--add-cmd-length cmd)))
-       (wisi-process-parse--wait parser)
-       (wisi-process-parse--handle-messages parser)
-       (funcall action)
-       (wisi-process-parse--handle-messages parser)
-       )
-      (t
-       (message "parsing buffer ...")
-       (wisi-process-parse--send-incremental-parse parser t)
-       (wisi-process-parse--wait parser)
-       (wisi-process-parse--handle-messages parser)
-       (message "parsing buffer ... done")
-       (funcall action)
-       (wisi-process-parse--handle-messages parser)
-       )))))
+     (message "parsing buffer ...")
+     (wisi-process-parse--send-incremental-parse parser t) ;; creates parse 
context
+     (wisi-process-parse--wait parser)
+     (wisi-process-parse--handle-messages parser)
+     (message "parsing buffer ... done")
+     (funcall action)
+     (wisi-process-parse--handle-messages parser)
+     )))
 
 (cl-defmethod wisi-parse-enable-memory-report ((parser wisi-parser))
   (wisi-process-parse--prepare parser 'debug)
@@ -1183,17 +1185,19 @@ Source buffer is current."
     ;; The parser process has not finished starting up, or has not yet
     ;; been started. If this is the very first Ada file in the current
     ;; project, and there is more text in the file than the process
-    ;; send buffer holds, w-p-p--send-* hangs waiting for the process
+    ;; send buffer holds, w-p-p--send-* waits for the process
     ;; to start reading, which is after it loads the parse table,
     ;; which can take noticeable time for Ada.
-    (message "starting parser ..."))
+    (message "waiting for wisi parser %s start in buffer %s ..."
+            (wisi-process--parser-label parser)
+            (current-buffer)))
   (wisi-process-parse--prepare parser parse-action :nowait nowait)
   (setf (wisi-parser-local-lexer-errors wisi-parser-local) nil)
   (setf (wisi-parser-local-parse-errors wisi-parser-local) nil)
   (cond
    ((and full nowait)
     (set-process-filter (wisi-process--parser-process parser) 
#'wisi-process-parse--filter)
-    (setq wisi-parse-full-active (cons (current-buffer) (cons (point-max) 
(point-min))))
+    (setq wisi-parse-full-active (cons (current-buffer) (cons (point-min) 
(point-max))))
     (read-only-mode 1)
     (wisi-process-parse--send-incremental-parse parser full))
    (t
@@ -1258,7 +1262,7 @@ Source buffer is current."
   (wisi-process-parse--handle-messages-file-not-found
    parser
    (lambda ()
-     (apply 'wisi-process-parse--send-query parser query args)))
+     (apply #'wisi-process-parse--send-query parser query args)))
   (wisi-process--parser-query-result parser))
 
 ;;;;; debugging
@@ -1277,12 +1281,25 @@ Source buffer is current."
     (process-send-string process (wisi-process-parse--add-cmd-length cmd))
     (wisi-process-parse--handle-messages parser)))
 
-(defun wisi-process-parse-dump-tree (save-file-root)
-  (interactive "Fsave-file-root: ")
+(cl-defmethod wisi-parse-save-text-tree-auto ((parser wisi-process--parser) 
enable)
+  (wisi-process-parse--prepare parser 'debug)
+  (let* ((cmd
+         (format "save_prev_auto \"%s\" %d"
+                 (if (buffer-file-name) (buffer-file-name) (buffer-name))
+                 (if enable 1 0)))
+        (process (wisi-process--parser-process parser)))
+    (with-current-buffer (wisi-process--parser-buffer parser)
+      (erase-buffer))
+
+    (wisi-parse-log-message parser cmd)
+    (process-send-string process (wisi-process-parse--add-cmd-length cmd))
+    (wisi-process-parse--handle-messages parser)))
+
+(defun wisi-process-parse-dump-tree (save-file-root prev)
+  (interactive "Fsave-file-root: \nP")
   (let ((parser wisi-parser-shared))
     (wisi-process-parse--prepare parser 'debug)
-    ;; Also save the source text, so we have a complete test case
-    ;; starting point.
+    ;; Also save the source text, so we have a complete test case.
     (let* ((cmd
            (format (concat "save_text" " \"%s\" \"%s\"")
                    (if (buffer-file-name) (buffer-file-name) (buffer-name))
@@ -1295,7 +1312,20 @@ Source buffer is current."
       (process-send-string process (wisi-process-parse--add-cmd-length cmd))
       (wisi-process-parse--handle-messages parser))
 
-    (wisi-parse-tree-query parser 'dump (concat save-file-root ".tree_text"))))
+    (if prev
+       (let ((cmd
+              (format (concat "dump_prev_tree" " \"%s\" \"%s\"")
+                      (if (buffer-file-name) (buffer-file-name) (buffer-name))
+                     (concat save-file-root ".tree_text")))
+            (process (wisi-process--parser-process parser)))
+         (with-current-buffer (wisi-process--parser-buffer parser)
+           (erase-buffer))
+
+         (wisi-parse-log-message parser cmd)
+         (process-send-string process (wisi-process-parse--add-cmd-length cmd))
+         (wisi-process-parse--handle-messages parser))
+
+       (wisi-parse-tree-query parser 'dump (concat save-file-root 
".tree_text")))))
 
 (defun wisi-process-all-changes-to-cmd (&optional cmd-buffer-name)
   "Convert wisi-parser-local-all-changes in current buffer to command file
@@ -1312,7 +1342,7 @@ in CMD-BUFFER-NAME."
        (mckenzie_zombie_limit wisi-mckenzie-zombie-limit)
        (mckenzie_enqueue_limit wisi-mckenzie-enqueue-limit)
        (language_options (wisi-parse-format-language-options 
wisi-parser-shared))
-       edit begin end)
+       begin end)
     (set-buffer cmd-buffer)
     (erase-buffer)
 
@@ -1399,7 +1429,6 @@ prompt for it."
        (let ((verbosity (match-string 2))
             (mckenzie_zombie_limit (match-string 3))
             (mckenzie_enqueue_limit (match-string 4))
-            (parse_max_parallel (match-string 5))
             (language_param (match-string 6)))
 
         (set-buffer cmd-buffer)
@@ -1575,9 +1604,6 @@ command_file command in the kill ring."
    ((looking-at "parse 2 \"\\([^\"]*\\)\" \"\\([^\"]*\\)\" \\([-0-9]+\\) 
\\([-0-9]+\\) \\([-0-9]+\\) [-0-9]+ [-0-9]+ \"\\([^\"]*\\)\"")
     (let ((source-file (match-string 1))
          (verbosity (match-string 2))
-         (mckenzie_zombie_limit (match-string 3))
-         (mckenzie_enqueue_limit (match-string 4))
-         (parse_max_parallel (match-string 5))
          (language_param (match-string 6))
          cmd)
 
@@ -1589,16 +1615,23 @@ command_file command in the kill ring."
                    ))
       (kill-new cmd)))
 
-   ((looking-at "post-parse \"\\([^\"]*\\)\" \"\\([^\"]*\\)\" \\([-0-9]+\\) 
\\([-0-9]+\\) \\([-0-9]+\\) \\([-0-9]+\\) \\([-0-9]+\\) \"\\([^\"]*\\)\"")
+    ((looking-at "parse 1 \"\\([^\"]+\\)\"")
+     (let (begin cmd)
+       (search-forward-regexp "((")
+       (setq begin (match-beginning 0))
+       (search-forward-regexp "\")) ") ;; avoid matching 'is (Float (A));'
+       (setq cmd (concat "parse_incremental "
+                        (replace-regexp-in-string "\n" "\\n"
+                                        (buffer-substring begin (match-end 
0)))))
+       (kill-new cmd)))
+
+    ((looking-at "post-parse \"\\([^\"]*\\)\" \"\\([^\"]*\\)\" \\([-0-9]+\\) 
\\([-0-9]+\\) \\([-0-9]+\\) \\([-0-9]+\\) \\([-0-9]+\\) \"\\([^\"]*\\)\"")
     ;; see wisi-process-parse--send-action above
-    (let* ((source-file (match-string 1))
-          (verbosity (match-string 2))
-          (action (string-to-number (match-string 3)))
+    (let* ((action (string-to-number (match-string 3)))
           (begin-bytes (match-string 4))
           (begin-chars (match-string 5))
           (end-bytes (match-string 6))
           (end-chars (match-string 7))
-          (language-opts (match-string 8))
           (cmd
            (concat "post_parse "
                    (cl-ecase action (0 "Navigate") (1 "Face") (2 "Indent") (3 
"None")) " "
diff --git a/wisi-run-indent-test.el b/wisi-run-indent-test.el
index 3aea39bbde..0f3090c4c0 100644
--- a/wisi-run-indent-test.el
+++ b/wisi-run-indent-test.el
@@ -1,4 +1,4 @@
-;;; wisi-run-indent-test.el --- utils for automating indentation and casing 
tests
+;;; wisi-run-indent-test.el --- utils for automating indentation and casing 
tests  -*- lexical-binding: t; -*-
 ;;
 ;; Copyright (C) 2018 - 2022  Free Software Foundation, Inc.
 ;;
@@ -15,7 +15,7 @@
 ;; GNU General Public License for more details.
 ;;
 ;; You should have received a copy of the GNU General Public License
-;; along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+;; along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
 
 (require 'wisi-prj)
 (require 'wisi-process-parse)
@@ -36,6 +36,13 @@ text, after each edit in an incremental parse, and before 
each partial parse.")
 (defun test-in-comment-p ()
   (nth 4 (syntax-ppss)))
 
+(defun wisi-wait-parser()
+  (while (wisi-process--parser-busy wisi-parser-shared)
+    (accept-process-output nil wisi-process-time-out)))
+
+(defvar test-face-wait-fn nil
+  "Function to call after `font-lock-ensure' to wait for face to actually be 
set.")
+
 (defun test-face (token face)
   "Test if all of TOKEN in next code line has FACE.
 FACE may be a list."
@@ -43,52 +50,58 @@ FACE may be a list."
     (when (test-in-comment-p)
       (beginning-of-line); forward-comment doesn't move if inside a comment!
       (forward-comment (point-max)))
-    (condition-case err
+    (condition-case nil
        (search-forward token (line-end-position 5))
       (error
        (error "can't find '%s'" token)))
 
-    (save-match-data
-      (wisi-validate-cache (line-beginning-position) (line-end-position) nil 
'face)
-      (font-lock-ensure (line-beginning-position) (line-end-position)))
+    (when (not skip-recase-test) ;; should be t when wisi-disable-face is t
+      (let ((token (match-string-no-properties 0))
+           (test-pos (match-beginning 0)))
 
-    ;; We don't use face-at-point, because it doesn't respect
-    ;; font-lock-face set by the parser! And we want to check for
-    ;; conflicts between font-lock-keywords and the parser.
+       (when wisi-parser-shared
+         ;; it may be busy doing initial parse in another file opened by an 
xref command.
+         (wisi-wait-parser)
+         (wisi-validate-cache (line-beginning-position) (line-end-position) 
nil 'face))
 
-    ;; font-lock-keywords sets 'face property, parser sets 'font-lock-face.
+       (font-lock-ensure (line-beginning-position) (line-end-position))
 
-    ;; In emacs < 27, if we use (get-text-property (point) 'face), we
-    ;; also get 'font-lock-face, but not vice-versa. So we have to use
-    ;; text-properties-at to check for both.
-    (let* ((token (match-string 0))
-          (props (text-properties-at (match-beginning 0)))
-          key
-          token-face)
+       (when test-face-wait-fn
+         (funcall test-face-wait-fn))
 
-      (cond
-       ((plist-get props 'font-lock-face)
-       (setq key 'font-lock-face)
-       (setq token-face (plist-get props 'font-lock-face)))
-
-       ((plist-get props 'face)
-       (setq key 'face)
-       (setq token-face (plist-get props 'face)))
-       )
-
-      (when (and (memq 'font-lock-face props)
-                (memq 'face props))
-       (describe-text-properties (match-beginning 0))
-       (error "mixed font-lock-keyword and parser faces for '%s'" token))
-
-      (unless (not (text-property-not-all 0 (length token) key token-face 
token))
-       (error "mixed faces, expecting %s for '%s'" face token))
-
-      (unless (or (and (listp face)
-                      (memq token-face face))
-                 (eq token-face face))
-       (error "found face %s, expecting %s for '%s'" token-face face token))
-    )))
+       ;; We don't use face-at-point, because it doesn't respect
+       ;; font-lock-face set by the parser! And we want to check for
+       ;; conflicts between font-lock-keywords and the parser.
+
+       ;; font-lock-keywords sets 'face property, parser sets 'font-lock-face.
+
+       ;; In emacs < 27, if we use (get-text-property (point) 'face), we
+       ;; also get 'font-lock-face, but not vice-versa. So we have to use
+       ;; text-properties-at to check for both.
+       (let ((props (text-properties-at test-pos))
+             key
+             token-face)
+         (cond
+          ((plist-get props 'font-lock-face)
+           (setq key 'font-lock-face)
+           (setq token-face (plist-get props 'font-lock-face)))
+
+          ((plist-get props 'face)
+           (setq key 'face)
+           (setq token-face (plist-get props 'face)))
+          )
+
+         (when (and (memq 'font-lock-face props)
+                    (memq 'face props))
+           (describe-text-properties test-pos)
+           (error "mixed font-lock-keyword and parser faces for '%s'" token))
+
+         (when (text-property-not-all test-pos (+ test-pos (length token)) key 
token-face)
+                   (error "mixed faces, expecting %s for '%s'" face token))
+
+         (unless (equal token-face face)
+           (error "found face %s, expecting %s for '%s'" token-face face 
token))
+         )))))
 
 (defun test-face-1 (search token face)
   "Move to end of comment, search for SEARCH, call `test-face'."
@@ -126,7 +139,7 @@ is not present."
     (wisi-validate-cache (line-beginning-position 0) (line-end-position 3) nil 
'navigate)
     (beginning-of-line); forward-comment doesn't move if inside a comment!
     (forward-comment (point-max))
-    (condition-case err
+    (condition-case nil
        (search-forward token (line-end-position 5))
       (error
        (error "can't find '%s'" token)))
@@ -203,22 +216,36 @@ Each item is a list (ACTION PARSE-BEGIN PARSE-END 
EDIT-BEGIN)")
       (wisi-test-save-log-1 (get-buffer (nth 0 item)) (nth 1 item))))
     ))
 
+(defvar eglot-send-changes-idle-time)
+(declare-function jsonrpc--debug "jsonrpc.el")
+
 (defun run-test-here ()
   "Run an indentation and casing test on the current buffer."
   (interactive)
-  (condition-case-unless-debug err
+  (when wisi-incremental-parse-enable
+    ;; wait for the parser to finish the initial parse
+    (wisi-wait-parser))
+
+  (condition-case err
       (progn
        (setq indent-tabs-mode nil)
-       (setq jit-lock-context-time 0.0);; for test-face
+
+       ;; for test-face
+       (setq jit-lock-context-time 0.0)
+       (setq-local font-lock-ensure-function 'jit-lock-fontify-now) ;; it's 
not at all clear what's resetting this
+       (setq-local eglot-send-changes-idle-time 0.0) ;; FIXME: did not help 
test-face
 
        ;; Test files use wisi-prj-select-cached to parse and select a project 
file.
        (setq project-find-functions (list #'wisi-prj-current-cached))
-       (setq xref-backend-functions (list #'wisi-prj-xref-backend))
+
+       (unless (memq 'eglot-xref-backend xref-backend-functions)
+         (setq xref-backend-functions (list #'wisi-prj-xref-backend)))
 
        (when (stringp save-edited-text)
          (wisi-process-parse-save-text wisi-parser-shared save-edited-text t))
 
        (let ((error-count 0)
+             (error-lines '())
              (pass-count 0)
              (test-buffer (current-buffer))
              cmd-line
@@ -252,27 +279,33 @@ Each item is a list (ACTION PARSE-BEGIN PARSE-END 
EDIT-BEGIN)")
             ((string= (match-string 1) "CMD")
              (looking-at ".*$")
              (setq cmd-line (line-number-at-pos)
-                   last-cmd (match-string 0))
+                   last-cmd (match-string-no-properties 0)
+                   force-fail nil)
              (let ((msg (format "%s:%d: test %s" (buffer-file-name) cmd-line 
last-cmd)))
-               (wisi-parse-log-message wisi-parser-shared msg)
+               (when wisi-parser-shared (wisi-parse-log-message 
wisi-parser-shared msg))
                (message "%s" msg)
+               (when (and (fboundp 'eglot-current-server) 
(eglot-current-server))
+                 (jsonrpc--debug (eglot-current-server) msg))
                (save-excursion
                  (setq last-result
                        (condition-case-unless-debug err
                            (prog1
-                             (eval (car (read-from-string last-cmd)))
+                             (eval (car (read-from-string last-cmd)) t)
                              (when (> wisi-debug 1)
                                (setq msg (concat msg " ... done"))
-                                (wisi-parse-log-message wisi-parser-shared msg)
+                                (when wisi-parser-shared 
(wisi-parse-log-message wisi-parser-shared msg))
                                 (message msg)))
                          ((error wisi-parse-error)
                           (setq error-count (1+ error-count))
+                          (push cmd-line error-lines)
                           (setq msg (concat msg " ... signaled"))
                           (setq force-fail t)
-                          (wisi-parse-log-message wisi-parser-shared msg)
+                          (when wisi-parser-shared (wisi-parse-log-message 
wisi-parser-shared msg))
                           (message msg)
                           (setq msg (format "... %s: %s" (car err) (cdr err)))
-                          (wisi-parse-log-message wisi-parser-shared msg)
+                          (when wisi-parser-shared (wisi-parse-log-message 
wisi-parser-shared msg))
+                          (when (and (fboundp 'eglot-current-server) 
(eglot-current-server))
+                            (jsonrpc--debug (eglot-current-server) msg))
                           (message msg)
                           nil)))
                  ))
@@ -284,15 +317,19 @@ Each item is a list (ACTION PARSE-BEGIN PARSE-END 
EDIT-BEGIN)")
 
             ((string= (match-string 1) "RESULT")
              (looking-at ".*$")
-             (setq expected-result (save-excursion (end-of-line 1) (eval (car 
(read-from-string (match-string 0))))))
+             (setq expected-result
+                   (save-excursion
+                     (end-of-line 1)
+                     (eval (car (read-from-string (match-string 0))) t)))
              (if (and (not force-fail)
                       (equal expected-result last-result))
                  (let ((msg (format "test passes %s:%d:\n" (buffer-file-name) 
(line-number-at-pos))))
                    (setq pass-count (1+ pass-count))
-                   (wisi-parse-log-message wisi-parser-shared msg)
+                   (when wisi-parser-shared (wisi-parse-log-message 
wisi-parser-shared msg))
                    (message msg))
 
                (setq error-count (1+ error-count))
+               (push (line-number-at-pos) error-lines)
 
                (let ((msg (concat
                            (format "error: %s:%d:\n" (buffer-file-name) 
(line-number-at-pos))
@@ -302,25 +339,29 @@ Each item is a list (ACTION PARSE-BEGIN PARSE-END 
EDIT-BEGIN)")
                                      last-cmd
                                      last-result
                                      expected-result)))))
-                 (wisi-parse-log-message wisi-parser-shared msg)
-                 (message "%s" msg))
-               (setq force-fail nil)))
+                 (when wisi-parser-shared (wisi-parse-log-message 
wisi-parser-shared msg))
+                 (message "%s" msg))))
 
             ((string= (match-string 1) "RESULT_START")
              (looking-at ".*$")
-             (setq expected-result
-                   (list (save-excursion (end-of-line 1) (eval (car 
(read-from-string (match-string 0))))))))
+             (let ((val (save-excursion
+                         (end-of-line 1)
+                         (eval (car (read-from-string (match-string 0))) t))))
+               (when val
+                 (setq expected-result (list val)))))
 
             ((string= (match-string 1) "RESULT_ADD")
              (looking-at ".*$")
-             (let ((val (save-excursion (end-of-line 1)
-                                        (eval (car (read-from-string 
(match-string 0)))))))
+             (let ((val (save-excursion
+                          (end-of-line 1)
+                          (eval (car (read-from-string (match-string 0))) t))))
                (when val
                  (setq expected-result (append expected-result (list val))))))
 
             ((string= (match-string 1) "RESULT_FINISH")
              (unless (equal (length expected-result) (length last-result))
                (setq error-count (1+ error-count))
+               (push (line-number-at-pos) error-lines)
                ;; this is used for gpr-query tests, not parser tests,
                ;; so we don't write to the parser log.
                (message
@@ -335,6 +376,7 @@ Each item is a list (ACTION PARSE-BEGIN PARSE-END 
EDIT-BEGIN)")
                (while (< i (length expected-result))
                  (unless (equal (nth i expected-result) (nth i last-result))
                    (setq error-count (1+ error-count))
+                   (push (line-number-at-pos) error-lines)
                    (message
                     (concat
                      (format "error: %s:%d:\n" (buffer-file-name) 
(line-number-at-pos))
@@ -348,7 +390,7 @@ Each item is a list (ACTION PARSE-BEGIN PARSE-END 
EDIT-BEGIN)")
 
             ((string= (match-string 1) "_SKIP_UNLESS")
              (looking-at ".*$")
-             (unless (eval (car (read-from-string (match-string 0))))
+             (unless (eval (car (read-from-string (match-string 0))) t)
                (setq skip-cmds t)
                (setq skip-reindent-test t)
                (setq skip-recase-test t)
@@ -361,18 +403,20 @@ Each item is a list (ACTION PARSE-BEGIN PARSE-END 
EDIT-BEGIN)")
                       (current-buffer)
                       (line-number-at-pos)
                       (save-excursion
-                        (eval (car (read-from-string (match-string 0)))))))
+                        (eval (car (read-from-string (match-string 0))) t))))
 
             (t
              (setq error-count (1+ error-count))
+             (push (line-number-at-pos) error-lines)
              (error (concat "Unexpected EMACS test command " (match-string 
1))))))
 
          (let ((msg (format "%s:%d tests passed %d"
                             (buffer-file-name) (line-number-at-pos (point)) 
pass-count)))
-           (wisi-parse-log-message wisi-parser-shared msg)
+           (when wisi-parser-shared (wisi-parse-log-message wisi-parser-shared 
msg))
            (message msg))
 
          (when (> error-count 0)
+           (message "errors on lines: %s" error-lines)
            (error
             "%s:%d: aborting due to previous errors (%d)"
             (buffer-file-name) (line-number-at-pos (point)) error-count))
@@ -406,27 +450,52 @@ Each item is a list (ACTION PARSE-BEGIN PARSE-END 
EDIT-BEGIN)")
      (signal (car err) (cdr err)))
     ))
 
-(defvar cl-print-readably); cl-print.el, used by edebug
+;; Let edebug display strings full-length, and show internals of records
+(defvar cl-print-readably t); cl-print.el, used by edebug
+(setq read-buffer-completion-ignore-case t) ;; for "*Messages*"
 
-(defun large-frame ()
+(defun wisi-half-screen ()
   (interactive)
   (modify-frame-parameters
-      nil
+   nil
+   (cl-case system-type
+     (gnu/linux
+      (list
+       (cons 'font "DejaVu Sans Mono-11")
+       (cons 'width 120) ;; characters; fringe extra
+       (cons 'height 73) ;; characters
+       (cons 'left 0)
+       (cons 'top 0)))
+     (windows-nt
       (list
+       (cons 'font "DejaVu Sans Mono-8")
        (cons 'width 120) ;; characters; fringe extra
-       (cons 'height 71) ;; characters
-       (cons 'left 0) ;; pixels
-       (cons 'top 0))))
-(define-key global-map "\C-cp" 'large-frame)
+       (cons 'height 103) ;; characters
+       (cons 'left 0)
+       (cons 'top 0))))))
+(define-key global-map "\C-cp" 'wisi-half-screen)
+
+(defun wisi-first-error ()
+  (interactive)
+  (pop-to-buffer "*Messages*")
+  (goto-char (point-min))
+  (search-forward "error:"))
+(define-key global-map [f6] 'wisi-first-error)
+
+(defun wisi-prev-window ()
+  "move to previous window"
+  (interactive)
+  (other-window -1))
+(define-key global-map [M-C-up] 'wisi-prev-window)
+(define-key global-map [M-C-down] 'other-window)
+(define-key global-map [f11] 'switch-to-buffer)
 
 (defun run-test (file-name)
   "Run an indentation and casing test on FILE-NAME."
   (interactive "f")
 
   (setq-default indent-tabs-mode nil) ;; no tab chars in files
-
-  ;; Let edebug display strings full-length, and show internals of records
-  (setq cl-print-readably t)
+  (setq message-log-max most-positive-fixnum)
 
   ;; we'd like to run emacs from a makefile as:
   ;;
@@ -442,12 +511,7 @@ Each item is a list (ACTION PARSE-BEGIN PARSE-END 
EDIT-BEGIN)")
   ;;
   ;; emacs -Q -l runtest.el --eval '(progn (run-test 
"<filename>")(kill-emacs))'
   ;;
-  ;; Then we have problems with font lock defaulting to jit-lock; that
-  ;; screws up font-lock tests because the test runs before jit-lock
-  ;; does. This forces default font-lock, which fontifies the whole
-  ;; buffer when (font-lock-fontify-buffer) is called, which tests
-  ;; that rely on font-lock do explicitly.
-  (setq font-lock-support-mode nil)
+  ;; Then we must use (font-lock-ensure) to force immediate fontification.
 
   (setq xref-prompt-for-identifier nil)
 
diff --git a/wisi-skel.el b/wisi-skel.el
index 4bfdb88715..79e9a65a12 100644
--- a/wisi-skel.el
+++ b/wisi-skel.el
@@ -1,6 +1,6 @@
 ;;; wisi-skel.el --- Extensions skeleton  -*- lexical-binding:t -*-
 
-;; Copyright (C) 1987, 1993, 1994, 1996-2021  Free Software Foundation, Inc.
+;; Copyright (C) 1987, 1993, 1994, 1996-2022  Free Software Foundation, Inc.
 
 ;; Authors: Stephen Leake <stephen_leake@stephe-leake.org>
 
@@ -17,7 +17,7 @@
 ;; GNU General Public License for more details.
 
 ;; You should have received a copy of the GNU General Public License
-;; along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+;; along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
 
 ;;; Design:
 ;;
@@ -26,6 +26,8 @@
 ;; name).
 
 (require 'skeleton)
+(require 'wisi)     ;For `wisi-inhibit-parse'.
+(require 'wisi-prj) ;For `wisi-auto-case' and `wisi-case-adjust-region'.
 
 (defvar-local wisi-skel-token-alist nil
   "Alist of (STRING . ELEMENT), used by `wisi-skel-expand'.
@@ -65,9 +67,9 @@ after AFTER-1. If AFTER-1 is a nested alist, add the new 
entry after AFTER-2."
 The prompt consists of the first COUNT keys from the alist,
 separated by `|', with trailing `...' if there are more keys."
   (if (>= count (length alist))
-      (concat (mapconcat 'car alist " | ") " : ")
+      (concat (mapconcat #'car alist " | ") " : ")
     (let ((alist-1 (butlast alist (- (length alist) count))))
-      (concat (mapconcat 'car alist-1 " | ") " | ... : "))
+      (concat (mapconcat #'car alist-1 " | ") " | ... : "))
   ))
 
 (defvar wisi-skel-test-input nil
@@ -76,7 +78,8 @@ separated by `|', with trailing `...' if there are more keys."
   )
 
 (defun wisi-skel-enable-parse ()
-  (setq wisi-inhibit-parse nil));
+  (setq wisi-inhibit-parse nil)
+  (remove-hook 'skeleton-end-hook #'wisi-skel-enable-parse t));
 
 (defun wisi-skel-expand (&optional name)
   "Expand the token or placeholder before point to a skeleton.
@@ -104,6 +107,8 @@ before that as the token."
         (skel (assoc-string token wisi-skel-token-alist))
         (handled nil))
 
+    (add-hook 'skeleton-end-hook #'wisi-skel-enable-parse 90 t)
+
     (if skel
        (progn
          (when (listp (cdr skel))
@@ -191,8 +196,5 @@ before that as the token."
   (interactive)
   (skip-syntax-backward "^!"))
 
-;;;###autoload
-(add-hook 'skeleton-end-hook #'wisi-skel-enable-parse 90)
-
 (provide 'wisi-skel)
 ;;; wisi-skel.el ends here
diff --git a/wisi.adb b/wisi.adb
index 2b16301271..e75d4dcba7 100644
--- a/wisi.adb
+++ b/wisi.adb
@@ -523,10 +523,11 @@ package body Wisi is
                --  We get here in partial_parse when there is no action to set 
indent
                --  for the first few lines; they are comments or low-level 
statements
                --  or declarations. ada_mode-recover_partial_28.adb
-               Data.Indents.Replace_Element (Line, (Int, Invalid_Line_Number, 
Data.Begin_Indent));
+               Data.Indents.Replace_Element (Line, (Int, 
Data.Action_Region_Lines.First, Data.Begin_Indent));
 
             when Int =>
-               Data.Indents.Replace_Element (Line, (Int, Invalid_Line_Number, 
Indent.Int_Indent + Begin_Indent));
+               Data.Indents.Replace_Element
+                 (Line, (Int, Data.Action_Region_Lines.First, 
Indent.Int_Indent + Begin_Indent));
 
             when Anchored =>
                declare
@@ -541,7 +542,8 @@ package body Wisi is
 
                   when Int =>
                      Data.Indents.Replace_Element
-                       (Line, (Int, Invalid_Line_Number, 
Anchor_Line_Indent.Int_Indent + Indent.Anchor_Delta));
+                       (Line,
+                        (Int, Data.Action_Region_Lines.First, 
Anchor_Line_Indent.Int_Indent + Indent.Anchor_Delta));
                   end case;
                end;
 
@@ -603,8 +605,8 @@ package body Wisi is
          Simple_Delta           =>
            (case Indent.Label is
             when Not_Set  => (None, Invalid_Line_Number),
-            when Int      => (Int, Invalid_Line_Number, Indent.Int_Indent),
-            when Anchored => (Anchored, Invalid_Line_Number, 
Indent.Anchor_Line, Indent.Anchor_Delta)));
+            when Int      => (Int, Indent.Controlling_Token_Line, 
Indent.Int_Indent),
+            when Anchored => (Anchored, Indent.Controlling_Token_Line, 
Indent.Anchor_Line, Indent.Anchor_Delta)));
    end To_Delta;
 
    ----------
@@ -797,7 +799,7 @@ package body Wisi is
       Action_Region_Chars : in     WisiToken.Buffer_Region;
       Begin_Indent        : in     Integer)
    is begin
-      if not Tree.Editable then
+      if Tree.Root = Syntax_Trees.Invalid_Node_Access then
          raise Parse_Error with "previous parse failed; can't execute 
post_parse action.";
       end if;
 
@@ -1811,16 +1813,13 @@ package body Wisi is
                           (Data, Tree,
                            Line_Region       => Indenting.Comment,
                            Delta_Indent      => Comment_Delta,
-                           Controlling_Delta => To_Delta
-                             (Data.Indents
-                                (Line_Number_Type'
-                                   (if Params (I).Comment_Present
-                                    then -- 
ada_mode-conditional_expressions.adb case expression for K, if
-                                          --  expression blank line.
-                                       Tree.Line_Region (Controlling_Token, 
Trailing_Non_Grammar => True).Last
-
-                                    else --  
ada_mode-conditional_expressions.adb case expression for K.
-                                       Tree.Line_Region (Controlling_Token, 
Trailing_Non_Grammar => True).First))),
+                           Controlling_Delta =>
+                             (if Params (I).Comment_Present
+                              then Null_Delta --  test_select.adb accept E2
+
+                              else To_Delta --  
ada_mode-conditional_expressions.adb case expression for K.
+                                (Data.Indents
+                                   (Tree.Line_Region (Controlling_Token, 
Trailing_Non_Grammar => True).First))),
                            Indenting_Comment => (if Params (I).Comment_Present 
then Trailing else Leading));
                      end if;
                   end if;
@@ -2012,8 +2011,15 @@ package body Wisi is
               (if Query.Label = Parent
                then Tree.Parent (Query.Node, Query.N)
                else Tree.Child (Query.Node, Positive_Index_Type (Query.N)));
-            Char_Region : constant Buffer_Region := Tree.Char_Region (Result, 
Trailing_Non_Grammar => False);
+            Char_Region : constant Buffer_Region :=
+              (if Result = Invalid_Node_Access
+               then Null_Buffer_Region
+               else Tree.Char_Region (Result, Trailing_Non_Grammar => False));
          begin
+            if Result = Invalid_Node_Access then
+               raise Parse_Error with "previous parse failed; can't execute 
post_parse action.";
+            end if;
+
             Ada.Text_IO.Put_Line
               ("[" & Query_Tree_Code &
                  Query_Label'Pos (Query.Label)'Image & " " &
@@ -2040,21 +2046,23 @@ package body Wisi is
          end if;
 
       when Dump =>
-         declare
-            use Ada.Directories;
-            File_Name : constant String := -Query.File_Name;
-            Normalized_Tree : WisiToken.Syntax_Trees.Tree;
-         begin
-            if Exists (File_Name) then
-               Delete_File (File_Name);
-            end if;
+         if Tree.Parents_Set then
+            declare
+               use Ada.Directories;
+               File_Name : constant String := -Query.File_Name;
+               Normalized_Tree : WisiToken.Syntax_Trees.Tree;
+            begin
+               if Exists (File_Name) then
+                  Delete_File (File_Name);
+               end if;
 
-            WisiToken.Syntax_Trees.Copy_Tree
-              (Source      => Tree,
-               Destination => Normalized_Tree,
-               User_Data   => Syntax_Trees.User_Data_Access_Constant (Data));
-            Normalized_Tree.Put_Tree (-Query.File_Name);
-         end;
+               WisiToken.Syntax_Trees.Copy_Tree
+                 (Source      => Tree,
+                  Destination => Normalized_Tree,
+                  User_Data   => Syntax_Trees.User_Data_Access_Constant 
(Data));
+               Normalized_Tree.Put_Tree (-Query.File_Name);
+            end;
+         end if;
       end case;
    end Query_Tree;
 
@@ -2127,6 +2135,7 @@ package body Wisi is
 
    procedure Put_Errors (Tree : in Syntax_Trees.Tree)
    is
+      use all type SAL.Base_Peek_Type;
       use Ada.Text_IO;
       Descriptor  : WisiToken.Descriptor renames Tree.Lexer.Descriptor.all;
 
@@ -2537,7 +2546,7 @@ package body Wisi is
             return
               (Simple,
                (Int,
-                Tree.Line_Region (Indenting_Token, Trailing_Non_Grammar => 
True).First,
+                Tree.Line_At_Node (Indenting_Token),
                 Param.Param.Int_Delta));
 
          when Simple_Param_Anchored =>
diff --git a/wisi.ads b/wisi.ads
index 28827cfd5d..cd0c689695 100644
--- a/wisi.ads
+++ b/wisi.ads
@@ -554,6 +554,8 @@ private
 
       Controlling_Token_Line : WisiToken.Base_Line_Number_Type := 
WisiToken.Invalid_Line_Number;
       --  See [2] Indent actions for description of controlling token.
+      --  Invalid when Label is Not_Set; see Delta_Indent for description of
+      --  other cases when it is invalid.
 
       case Label is
       when Not_Set =>
@@ -610,7 +612,9 @@ private
    type Simple_Delta_Type (Label : Simple_Delta_Labels := None) is
    record
       Controlling_Token_Line : WisiToken.Base_Line_Number_Type;
-      --  If Invalid_Line_Number, delta should not be ignored.
+      --  If Invalid_Line_Number, delta should not be ignored. Invalid when
+      --  Label is None, and when Delta is from wisi-block,
+      --  ada-indent-aggregate or similar indent function.
 
       case Label is
       when None =>
@@ -664,8 +668,7 @@ private
       Tree : in WisiToken.Syntax_Trees.Tree;
       Node : in WisiToken.Syntax_Trees.Valid_Node_Access)
      return Wisi.Indenting
-   with Pre => Tree.Line_Region (Node, Trailing_Non_Grammar => False) /= 
WisiToken.Null_Line_Region and
-               Tree.SOI /= Node and Tree.EOI /= Node;
+   with Pre => Tree.SOI /= Node and Tree.EOI /= Node;
    --  Return Node.Augmented.Indenting, computing it first if needed.
 
    function Current_Indent_Offset
@@ -703,7 +706,7 @@ private
       Indenting_Token   : in     WisiToken.Syntax_Trees.Valid_Node_Access;
       Indenting_Comment : in     Boolean)
      return Delta_Type;
-   --  Return indent defined by Param for Tree_Indenting in Nonterm.
+   --  Return indent defined by Param for Indenting_Token (a child of Nonterm).
 
    procedure Indent_Token_1
      (Data              : in out Parse_Data_Type;
@@ -717,7 +720,7 @@ private
    --  Controlling_Delta should be Null_Delta if Indenting_Comment is
    --  None; it should be any existing indent for
    --  Controlling_Token.Line_Region.[First | Last] if Indenting_Comment
-   --  is Leading | Trailing. This allows adding previously computed
+   --  is Trailing | Leading. This allows adding previously computed
    --  indents for the token controlling a comment line to the comment
    --  line indent.
    --
diff --git a/wisi.el b/wisi.el
index 28e20daca5..ff517456a6 100644
--- a/wisi.el
+++ b/wisi.el
@@ -1,15 +1,15 @@
 ;;; wisi.el --- Utilities for implementing an indentation/navigation engine 
using a generalized LR parser -*- lexical-binding:t -*-
 ;;
-;; Copyright (C) 2012 - 2022  Free Software Foundation, Inc.
+;; Copyright (C) 2012 - 2023  Free Software Foundation, Inc.
 ;;
 ;; Author: Stephen Leake <stephen_leake@stephe-leake.org>
 ;; Maintainer: Stephen Leake <stephen_leake@stephe-leake.org>
 ;; Keywords: parser
 ;;  indentation
 ;;  navigation
-;; Version: 4.0.0
+;; Version: 4.2.0
 ;; package-requires: ((emacs "25.3") (seq "2.20"))
-;; URL: http://stephe-leake.org/ada/wisitoken.html
+;; URL: https://stephe-leake.org/ada/wisitoken.html
 ;;
 ;; This file is part of GNU Emacs.
 ;;
@@ -24,7 +24,7 @@
 ;; GNU General Public License for more details.
 ;;
 ;; You should have received a copy of the GNU General Public License
-;; along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+;; along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
 ;;
 
 ;;; Commentary:
@@ -127,14 +127,13 @@
   is no response from the parser after waiting this amount (in
   seconds)."
   :type 'float
-  :safe 'numberp)
+  :safe #'numberp)
 (make-variable-buffer-local 'wisi-process-time-out)
 
 (defcustom wisi-size-threshold most-positive-fixnum
   "Max size (in characters) for using wisi parser results for anything."
   :type 'integer
-  :group 'wisi
-  :safe 'integerp)
+  :safe #'integerp)
 (make-variable-buffer-local 'wisi-size-threshold)
 
 (defcustom wisi-indent-context-lines 0
@@ -142,27 +141,52 @@
 Increasing this will give better results when in the middle of a
 deeply nested statement, but worse in some situations."
   :type 'integer
-  :group 'wisi
-  :safe 'integerp)
+  :safe #'integerp)
+(make-variable-buffer-local 'wisi-indent-context-lines)
+
+(defcustom wisi-disable-completion nil
+  "When non-nil, `wisi-setup' does not enable use of wisi xref for completion.
+Useful when using wisi in parallel with eglot."
+  :type 'boolean
+  :safe #'booleanp)
+(make-variable-buffer-local 'wisi-disable-completion)
+
+(defcustom wisi-disable-diagnostics nil
+  "When non-nil, `wisi-setup' does not enable reporting diagnostics.
+Useful when using wisi in parallel with eglot."
+  :type 'boolean
+  :safe #'booleanp)
+(make-variable-buffer-local 'wisi-disable-diagnostics)
 
 (defcustom wisi-disable-face nil
-  "When non-nil, `wisi-setup' does not enable use of parser for font-lock.
-Useful when debugging parser or parser actions."
+  "When non-nil, `wisi-setup' does not enable use of parser for font-lock."
   :type 'boolean
-  :group 'wisi
-  :safe 'booleanp)
+  :safe #'booleanp)
+(make-variable-buffer-local 'wisi-disable-face)
 
-(defcustom wisi-incremental-parse-enable nil
-  "If non-nil, use incremental parse when possible."
+(defcustom wisi-disable-indent nil
+  "When non-nil, `wisi-setup' does not enable use of parser for indent."
   :type 'boolean
-  :group 'wisi
-  :safe 'booleanp)
+  :safe #'booleanp)
+(make-variable-buffer-local 'wisi-disable-indent)
+
+(defcustom wisi-disable-parser nil
+  "When non-nil, `wisi-setup' does not enable use of parser for any purpose."
+  :type 'boolean
+  :safe #'booleanp)
+(make-variable-buffer-local 'wisi-disable-parser)
+
+(defcustom wisi-disable-statement nil
+  "When non-nil, the wisi parser should not be enabled for statement motion."
+  :type 'boolean
+  :safe #'booleanp)
+(make-variable-buffer-local 'wisi-disable-statement)
 
 (defcustom wisi-parse-full-background t
   "If non-nil, do initial full parse in background."
   :type 'boolean
-  :group 'wisi
-  :safe 'booleanp)
+  :safe #'booleanp)
+(make-variable-buffer-local 'wisi-parse-full-background)
 
 (defconst wisi-error-buffer-name "*wisi syntax errors*"
   "Name of buffer for displaying syntax errors.")
@@ -175,6 +199,29 @@ Useful when debugging parser or parser actions."
 Language code can set this non-nil when syntax is known to be
 invalid temporarily, or when making lots of changes.")
 
+;; wisi--change-* keep track of buffer modifications.
+;; If wisi--change-end comes before wisi--change-beg, it means there were
+;; no modifications.
+(defvar-local wisi--change-beg most-positive-fixnum
+  "First position where a change may have taken place.")
+
+(defvar-local wisi--change-end nil
+  "Marker pointing to the last position where a change may have taken place.")
+
+(defvar-local wisi--deleted-syntax nil
+  "Worst syntax class of characters deleted in changes.
+One of:
+nil - no deletions since reset
+0   - only whitespace or comment deleted
+2   - some other syntax deleted
+
+Set by `wisi-before-change', used and reset by `wisi--post-change'.")
+
+(defvar-local wisi--affected-text 0
+  "Cached text of range passed to `wisi-before-change',
+used by `wisi-after-change' to get byte count of actual
+deleted range.")
+
 (defun wisi-safe-marker-pos (pos)
   "Return an integer buffer position from POS, an integer or marker"
   (cond
@@ -462,7 +509,6 @@ For debugging."
   (setq wisi--change-beg most-positive-fixnum)
   (setq wisi--change-end nil)
   (setq wisi--deleted-syntax nil)
-  (setq wisi-indenting-p nil)
 
   (setq wisi--cached-regions ;; necessary instead of wisi-invalidate after 
ediff-regions
        (list
@@ -488,41 +534,9 @@ For debugging."
   (interactive)
   (wisi-force-parse)
   (when wisi-parser-shared
-    (wisi-parse-reset wisi-parser-shared)))
-
-;; wisi--change-* keep track of buffer modifications.
-;; If wisi--change-end comes before wisi--change-beg, it means there were
-;; no modifications.
-(defvar-local wisi--change-beg most-positive-fixnum
-  "First position where a change may have taken place.")
-
-(defvar-local wisi--change-end nil
-  "Marker pointing to the last position where a change may have taken place.")
-
-(defvar-local wisi--deleted-syntax nil
-  "Worst syntax class of characters deleted in changes.
-One of:
-nil - no deletions since reset
-0   - only whitespace or comment deleted
-2   - some other syntax deleted
-
-Set by `wisi-before-change', used and reset by `wisi--post-change'.")
-
-(defvar-local wisi-indenting-p nil
-  "Non-nil when `wisi-indent-region' is actively indenting.
-Used to ignore whitespace changes in before/after change hooks.")
-
-(defvar-local wisi--changes nil
-  "Cached list of args to wisi-after-change, for incremental parse.
-Each element is
-(INSERT-BEGIN-BYTE-POS INSERT-BEGIN-CHAR-POS
- INSERT-END-BYTE-POS INSERT-END-CHAR-POS
- DELETED-BYTE-COUNT DELETED-CHAR-COUNT INSERTED-TEXT)")
-
-(defvar-local wisi--affected-text 0
-  "Cached text of range passed to `wisi-before-change',
-used by `wisi-after-change' to get byte count of actual
-deleted range.")
+    (wisi-parse-reset wisi-parser-shared)
+    (when wisi-save-text-tree
+      (wisi-parse-save-text-tree-auto wisi-parser-shared t))))
 
 (defun wisi-before-change (begin end)
   "For `before-change-functions'."
@@ -531,37 +545,34 @@ deleted range.")
     (when wisi-incremental-parse-enable
       (setq wisi--affected-text (buffer-substring-no-properties begin end)))
 
-    (unless wisi-indenting-p
-      ;; We set wisi--change-beg, -end even if only inserting, so we
-      ;; don't have to do it again in wisi-after-change.
-      (setq wisi--change-beg (min wisi--change-beg begin))
+    (setq wisi--change-beg (min wisi--change-beg begin))
 
-      ;; `buffer-base-buffer' deals with edits in indirect buffers
-      ;; created by ediff-regions-*
+    ;; `buffer-base-buffer' deals with edits in indirect buffers
+    ;; created by ediff-regions-*
 
-      (cond
-       ((null wisi--change-end)
-       (setq wisi--change-end (make-marker))
-       (set-marker wisi--change-end end (or (buffer-base-buffer) 
(current-buffer))))
+    (cond
+     ((null wisi--change-end)
+      (setq wisi--change-end (make-marker))
+      (set-marker wisi--change-end end (or (buffer-base-buffer) 
(current-buffer))))
 
-       ((> end wisi--change-end)
-       (set-marker wisi--change-end end (or (buffer-base-buffer) 
(current-buffer))))
-       )
+     ((> end wisi--change-end)
+      (set-marker wisi--change-end end (or (buffer-base-buffer) 
(current-buffer))))
+     )
 
-      (unless (= begin end)
-       (cond
-        ((or (null wisi--deleted-syntax)
-             (= 0 wisi--deleted-syntax))
-         (save-excursion
-           (if (or (nth 4 (syntax-ppss begin)) ; in comment, moves point to 
begin
-                   (= end (skip-syntax-forward " " end)));; whitespace
-               (setq wisi--deleted-syntax 0)
-             (setq wisi--deleted-syntax 2))))
+    (unless (= begin end)
+      (cond
+       ((or (null wisi--deleted-syntax)
+           (= 0 wisi--deleted-syntax))
+       (save-excursion
+         (if (or (nth 4 (syntax-ppss begin)) ; in comment, moves point to begin
+                 (= end (skip-syntax-forward " " end)));; whitespace
+             (setq wisi--deleted-syntax 0)
+           (setq wisi--deleted-syntax 2))))
 
-        (t
-         ;; wisi--deleted-syntax is 2; no change.
-         )
-        )))
+       (t
+       ;; wisi--deleted-syntax is 2; no change.
+       )
+       ))
     ))
 
 (defun wisi-after-change (begin end length)
@@ -864,14 +875,13 @@ Run the parser first if needed."
 
       (wisi-set-last-parse-region begin parse-end parse-action)
 
-      (unless (eq parse-action 'face)
-       (when (buffer-live-p wisi-error-buffer)
-         (with-current-buffer wisi-error-buffer
-           (setq buffer-read-only nil)
-           (erase-buffer)
-           (setq buffer-read-only t)
-           (when (get-buffer-window wisi-error-buffer)
-             (delete-window (get-buffer-window wisi-error-buffer))))))
+      (when (buffer-live-p wisi-error-buffer)
+       (with-current-buffer wisi-error-buffer
+         (setq buffer-read-only nil)
+         (erase-buffer)
+         (setq buffer-read-only t)
+         (when (get-buffer-window wisi-error-buffer)
+           (delete-window (get-buffer-window wisi-error-buffer)))))
 
       (condition-case err
          (save-excursion
@@ -903,10 +913,7 @@ Run the parser first if needed."
        (wisi-parse-error
         (cl-ecase parse-action
           (face
-           ;; Caches set by failed elisp parse are ok, but some parse
-           ;; failures return 'nil' in parse-region.
-           (when (cdr parsed-region)
-             (wisi--delete-face-cache (cdr parsed-region))))
+           (wisi--delete-face-cache (car parsed-region)))
 
           (navigate
            ;; don't trust parse result
@@ -1049,10 +1056,9 @@ fails."
 
     (wisi-validate-cache parse-begin parse-end error-on-fail parse-action)))
 
-(defun wisi-fontify-region (begin end)
-  "For `jit-lock-functions'."
-  (with-silent-modifications
-    (remove-text-properties begin end '(font-lock-face nil)))
+(defun wisi-fontify-region (begin end &optional _contextual)
+  "For `jit-lock-register'."
+  (remove-text-properties begin end '(font-lock-face nil))
 
   (if wisi-parse-full-active
       ;; Record region to fontify when full parse is done.
@@ -1226,7 +1232,7 @@ Return start cache."
 
 (defun wisi-goto-statement-start ()
   "Move point to token at start of statement point is in or after.
-Return start cache."
+Return start cache (nil if point is before first statement)."
   (interactive)
   (wisi-validate-cache-current-statement t 'navigate)
   (wisi-goto-start (or (wisi-get-cache (point))
@@ -1509,30 +1515,28 @@ If INDENT-BLANK-LINES is non-nil, also indent blank 
lines (for use as
          ;; wisi--get-cached-indent.
          (goto-char (1- end)) ;; end is exclusive
          (goto-char (line-beginning-position))
-         (let ((wisi-indenting-p t))
-           (while (and (not (bobp))
-                       (or (and (= begin end) (= (point) end))
-                           (>= (point) begin)))
-             (when (or indent-blank-lines (not (eolp)))
-               ;; ’indent-region’ doesn’t indent an empty line; ’indent-line’ 
does
-               (let ((indent (if (bobp) 0 (wisi--get-cached-indent begin 
end))))
-                 (indent-line-to indent))
-               )
-             (forward-line -1))
-
-           ;; Run wisi-indent-calculate-functions
-           (when wisi-indent-calculate-functions
-             (goto-char begin)
-             (while (and (not (eobp))
-                         (< (point) end-mark))
-               (back-to-indentation)
-               (let ((indent
-                      (run-hook-with-args-until-success 
'wisi-indent-calculate-functions)))
-                 (when indent
-                   (indent-line-to indent)))
-
-               (forward-line 1)))
-           )
+         (while (and (not (bobp))
+                     (or (and (= begin end) (= (point) end))
+                         (>= (point) begin)))
+           (when (or indent-blank-lines (not (eolp)))
+             ;; ’indent-region’ doesn’t indent an empty line; ’indent-line’ 
does
+             (let ((indent (if (bobp) 0 (wisi--get-cached-indent begin end))))
+               (indent-line-to indent))
+             )
+           (forward-line -1))
+
+         ;; Run wisi-indent-calculate-functions
+         (when wisi-indent-calculate-functions
+           (goto-char begin)
+           (while (and (not (eobp))
+                       (< (point) end-mark))
+             (back-to-indentation)
+             (let ((indent
+                    (run-hook-with-args-until-success 
'wisi-indent-calculate-functions)))
+               (when indent
+                 (indent-line-to indent)))
+
+             (forward-line 1)))
 
          (when
              (and prev-indent-failed
@@ -1557,8 +1561,6 @@ If INDENT-BLANK-LINES is non-nil, also indent blank lines 
(for use as
     ;; (1+ line-end-pos) is needed to compute indent for a line. It
     ;; can exceed (point-max); the parser must be able to handle that.
     ;;
-    ;; IMPROVEME: change parser 'indent' action to take lines, not
-    ;; buffer positions.
     (wisi-indent-region (line-beginning-position (1+ (- 
wisi-indent-context-lines))) (1+ (line-end-position)) t)
 
     (goto-char savep)
@@ -1740,9 +1742,9 @@ where the car is a list (FILE LINE COL)."
 (defun wisi-debug-keys ()
   "Add debug key definitions to `global-map'."
   (interactive)
-  (define-key global-map "\M-h" 'wisi-show-containing-or-previous-cache)
-  (define-key global-map "\M-i" 'wisi-show-indent)
-  (define-key global-map "\M-j" 'wisi-show-cache)
+  (define-key global-map "\M-h" #'wisi-show-containing-or-previous-cache)
+  (define-key global-map "\M-i" #'wisi-show-indent)
+  (define-key global-map "\M-j" #'wisi-show-cache)
   )
 
 (defun wisi-parse-buffer (&optional parse-action begin end)
@@ -1802,67 +1804,109 @@ where the car is a list (FILE LINE COL)."
       (message "previous %s" (wisi-backward-cache)))
     ))
 
+(defun wisi-replay-kbd-macro (macro)
+  "Replay keyboard macro MACRO into current buffer,
+with incremental parse after each key event."
+  (unless wisi-incremental-parse-enable
+    (user-error "wisi-incremental-parse-enable nil; use EMACS_SKIP_UNLESS"))
+  (let ((i 0))
+    (while (< i  (length macro))
+      (execute-kbd-macro (make-vector 1 (aref macro i)))
+      (save-excursion
+       (condition-case err
+           (progn
+             (wisi--check-change)
+             (when wisi--changes
+               (wisi-parse-incremental wisi-parser-shared 'none)))
+         (wisi-parse-error
+          (when (< 0 wisi-debug)
+            ;; allow continuing when parser throws parse-error
+            (signal (car err) (cdr err))))))
+      (setq i (1+ i)))))
+
 ;;;;; setup
 
 (cl-defun wisi-setup (&key indent-calculate post-indent-fail parser)
   "Set up a buffer for parsing files with wisi."
-  (setq wisi-parser-shared parser)
-  (setq wisi-parser-local (make-wisi-parser-local))
-  (setq wisi--cached-regions
-       (list
-        (cons 'face nil)
-        (cons 'navigate nil)
-        (cons 'indent nil)))
-
-  (setq wisi--parse-try
-       (list
-        (cons 'face t)
-        (cons 'navigate t)
-        (cons 'indent t)))
-
-  (setq wisi--last-parse-region
-       (list
-        (cons 'face nil)
-        (cons 'navigate nil)
-        (cons 'indent nil)))
+  ;; wisi-disable-* should be set in a find-file-hook such as
+  ;; ada-eglot-setup, not in local variables.
+  (when (and (not wisi-disable-parser)
+            parser
+            ;; indirect buffers handled below.
+            ;; We don't insist on (null wisi-parser-shared), so we can re-run 
ada-mode
+            )
+    (setq wisi-parser-shared parser)
+    (setq wisi-parser-local (make-wisi-parser-local))
+
+    (setq wisi--cached-regions
+         (list
+          (cons 'face nil)
+          (cons 'navigate nil)
+          (cons 'indent nil)))
+
+    (setq wisi--parse-try
+         (list
+          (cons 'face t)
+          (cons 'navigate t)
+          (cons 'indent t)))
+
+    (setq wisi--last-parse-region
+         (list
+          (cons 'face nil)
+          (cons 'navigate nil)
+          (cons 'indent nil)))
+
+    (setq wisi-post-indent-fail-hook post-indent-fail)
+    (setq wisi-indent-failed nil)
+    (setq wisi-indent-calculate-functions (append 
wisi-indent-calculate-functions indent-calculate))
+
+    (add-hook 'before-change-functions #'wisi-before-change 'append t)
+    (add-hook 'after-change-functions #'wisi-after-change nil t)
+    (setq wisi--change-end (copy-marker (point-min) t))
+
+    (add-hook 'kill-buffer-hook #'wisi-parse-kill-buf 90 t)
+
+    (when (not wisi-disable-completion)
+      (add-hook 'completion-at-point-functions #'wisi-completion-at-point -90 
t))
+
+    ;; wisi-disable-diagnostics is handled in wisi-process-parse.el
+
+    (when (not wisi-disable-face)
+      ;; font-lock complains about not working in indirect buffers,
+      ;; but we need to set all the local variables for mmm-mode.
+      (jit-lock-register #'wisi-fontify-region))
+
+    (when (not wisi-disable-indent)
+      (setq-local indent-line-function #'wisi-indent-line)
+      (setq-local indent-region-function #'wisi-indent-region)
+      (setq-local comment-indent-function #'wisi-comment-indent))
+
+    ;; wisi-disable-statement just affects whether to start the
+    ;; parser.
+
+    (setq-local forward-sexp-function #'wisi-forward-sexp)
 
-  (setq wisi-indent-calculate-functions (append 
wisi-indent-calculate-functions indent-calculate))
-  (set (make-local-variable 'indent-line-function) #'wisi-indent-line)
-  (set (make-local-variable 'indent-region-function) #'wisi-indent-region)
-  (set (make-local-variable 'forward-sexp-function) #'wisi-forward-sexp)
-
-  (setq wisi-post-indent-fail-hook post-indent-fail)
-  (setq wisi-indent-failed nil)
-
-  (add-hook 'before-change-functions #'wisi-before-change 'append t)
-  (add-hook 'after-change-functions #'wisi-after-change nil t)
-  (setq wisi--change-end (copy-marker (point-min) t))
-
-  (add-hook 'kill-buffer-hook 'wisi-parse-kill-buf 90 t)
-
-  (set (make-local-variable 'comment-indent-function) 'wisi-comment-indent)
-
-  (add-hook 'completion-at-point-functions #'wisi-completion-at-point -90 t)
-
-  (add-hook 'hack-local-variables-hook 'wisi-post-local-vars nil t)
-  )
-
-(defun wisi-post-local-vars ()
-  "See wisi-setup."
-  (remove-hook 'hack-local-variables-hook #'wisi-post-local-vars)
-
-  (unless wisi-disable-face
-    (jit-lock-register #'wisi-fontify-region))
-
-  (when wisi-incremental-parse-enable
-    (when wisi-save-all-changes
-      (setf (wisi-parser-local-all-changes wisi-parser-local) nil))
-
-    ;; We don't wait for this to complete here, so users can scroll
-    ;; around while the initial parse runs. font-lock will not work
-    ;; during that time (the parser is busy, the buffer is read-only).
-    (when (< 0 wisi-debug) (message "start initial full parse in %s" 
(current-buffer)))
-    (wisi-parse-incremental wisi-parser-shared 'none :full t :nowait 
wisi-parse-full-background)))
+    (when wisi-incremental-parse-enable
+      (when wisi-save-all-changes
+       (setf (wisi-parser-local-all-changes wisi-parser-local) nil))
+
+      (unless (buffer-base-buffer)
+       ;; If are in an indirect buffer (ie mmm-temp-buffer), We need
+       ;; to set all the local variables above, but _not_ start a
+       ;; parse; that would duplicate and conflict with the parse in
+       ;; the main buffer.
+
+       ;; We don't wait for this to complete here, so users can scroll
+       ;; around while the initial parse runs. font-lock will not work
+       ;; during that time (the parser is busy, the buffer is read-only).
+       (when (< 0 wisi-debug) (message "starting initial full parse; parser %s 
buffer %s"
+                                       (wisi-process--parser-label parser)
+                                       (current-buffer)))
+       (wisi-parse-incremental wisi-parser-shared 'none :full t :nowait 
wisi-parse-full-background))
+
+      (when wisi-save-text-tree
+       (wisi-parse-save-text-tree-auto wisi-parser-shared t))
+      )))
 
 (provide 'wisi)
 ;;; wisi.el ends here
diff --git a/wisi.texi b/wisi.texi
index 5250d4fb77..9949c5b1e1 100644
--- a/wisi.texi
+++ b/wisi.texi
@@ -2,7 +2,7 @@
 @settitle Wisi
 
 @copying
-Copyright @copyright{} 1999 - 2022  Free Software Foundation, Inc.
+Copyright @copyright{} 1999 - 2023  Free Software Foundation, Inc.
 
 @quotation
 Permission is granted to copy, distribute and/or modify this document
@@ -25,7 +25,7 @@ developing GNU and promoting software freedom.''
 
 @titlepage
 @sp 10
-@title Wisi Version 4.0.0
+@title Wisi Version 4.2.0
 @page
 @vskip 0pt plus 1filll
 @insertcopying
@@ -37,7 +37,7 @@ developing GNU and promoting software freedom.''
 @node Top
 @top Top
 
-Wisi Version 4.0.0
+Wisi Version 4.2.0
 @end ifnottex
 
 @menu
@@ -54,7 +54,7 @@ Wisi Version 4.0.0
 
 The wisi package provides an elisp interface to an external parser. It
 assumes the parser generator package WisiToken
-(@url{http://stephe-leake.org/ada/wisitoken.html}, implemented in
+(@url{https://stephe-leake.org/ada/wisitoken.html}, implemented in
 Ada), but can use any parser that meets the same API. wisi provides
 several grammar actions, to implement indentation, navigating, and
 syntax highlighting (fontification).
@@ -828,10 +828,10 @@ indenting the comment with the last line of the 
expression.
 
 @item statements: [(wisi-block ada-indent) ada-indent]
 Applies a delta indent of 3 to the code and comment on lines 5 thru
-10, and 3 to the trailing comment on lines 11 and
-12. @code{wisi-block} says to ignore the controlling token line; that
-is 5, so this would be ignored for line 6; this is why we need
-@code{wisi-block}. The delta is ignored for the Anchored line 7.
+10, and 3 to the trailing comment on lines 11 and 12. The controlling
+token line is 5, so this delta would be ignored for line 6; this is
+why we need @code{wisi-block}, which sets controlling token line to
+invalid. The delta is ignored for the Anchored line 7.
 
 Note that the indent for comments after statements is given here, not
 at a lower level; it would be tedious to add it to each statement.
@@ -957,11 +957,21 @@ add more.
 
 @table @asis
 @item @code{casing}         [slot: @code{case-exception-files}]
-List of files containing casing exceptions. @xref{Casing exception files}.
+List of files containing casing exceptions, either absolute, relative
+to the project file directory, or found on the project file
+path. @xref{Casing exception files}.
+
+@item @code{import_env_var} [slot: @code{file-env}]
+Copies an environment variable from @code{process-environment}.
 
 @item @code{src_dir}        [slot: @code{source-path}]
 A list of directories to search for source files.
 
+@item @code{$<name>}        [slot: @code{file-env}]
+Set an environment variable @code{name} in the local @code{file-env};
+it may be referenced in subsequent project file statements, and in
+processes spawned by the project.
+
 @end table
 
 @node Selecting projects
diff --git a/wisitoken-bnf-generate.adb b/wisitoken-bnf-generate.adb
index 19b6ab37c4..9c45c28e41 100644
--- a/wisitoken-bnf-generate.adb
+++ b/wisitoken-bnf-generate.adb
@@ -3,7 +3,7 @@
 --  Parser for Wisi grammar files, producing Ada source
 --  files for a parser.
 --
---  Copyright (C) 2012 - 2015, 2017 - 2022 Free Software Foundation, Inc.
+--  Copyright (C) 2012 - 2015, 2017 - 2023 Free Software Foundation, Inc.
 --
 --  The WisiToken package is free software; you can redistribute it
 --  and/or modify it under terms of the GNU General Public License as
@@ -29,7 +29,6 @@ with Ada.Strings.Maps;
 with Ada.Strings.Unbounded;
 with Ada.Text_IO;
 with GNAT.Traceback.Symbolic;
-with System.Multiprocessors;
 with WisiToken.BNF.Generate_Utils;
 with WisiToken.BNF.Output_Ada;
 with WisiToken.BNF.Output_Ada_Common;
@@ -37,7 +36,6 @@ with WisiToken.BNF.Output_Ada_Emacs;
 with WisiToken.BNF.Output_Elisp_Common;
 with WisiToken.Generate.LR.LALR_Generate;
 with WisiToken.Generate.LR.LR1_Generate;
-with WisiToken.Generate.LR1_Items;
 with WisiToken.Generate.Packrat;
 with WisiToken.Parse.LR.Parser_No_Recover; -- for reading BNF file
 with WisiToken.Productions;
@@ -49,12 +47,14 @@ with WisiToken_Grammar_Runtime;
 with Wisitoken_Grammar_Main;
 procedure WisiToken.BNF.Generate
 is
+   use all type SAL.Base_Peek_Type;
+
    procedure Put_Usage
    is
       use Ada.Text_IO;
       First : Boolean := True;
    begin
-      Put_Line (Standard_Error, "version 3.0"); -- matches release version in 
Docs/wisitoken.html
+      Put_Line (Standard_Error, "version 4.1"); -- matches release version in 
Docs/wisitoken.html
       Put_Line (Standard_Error, "wisitoken-bnf-generate [options] {wisi 
grammar file}");
       Put_Line (Standard_Error, "Generate source code implementing a parser 
for the grammar.");
       New_Line (Standard_Error);
@@ -120,10 +120,6 @@ is
       Put_Line (Standard_Error, "  --ignore_conflicts; ignore excess/unknown 
conflicts");
       Put_Line (Standard_Error,
                 "  --test_main; generate standalone main program for running 
the generated parser, modify file names");
-      Put_Line (Standard_Error,
-                "  --task_count n; number of tasks used to compute LR1 items; 
0 means CPU count." &
-                  " Default 1 unless %lr1_hash_table_size specified; then 0.");
-      Put_Line (Standard_Error, "  --lr1_hash_table_size n; default 113; 
bigger should be faster");
       Put_Line (Standard_Error, "verbosity keys:");
       Enable_Trace_Help;
    end Put_Usage;
@@ -134,14 +130,13 @@ is
    Output_BNF              : Boolean                          := False;
    Ignore_Conflicts        : Boolean                          := False;
    Test_Main               : Boolean                          := False;
-   Generate_Task_Count     : System.Multiprocessors.CPU_Range := 1;
-   Generate_Task_Count_Set : Boolean                          := False;
 
    Command_Generate_Set : Generate_Set_Access; -- override grammar file 
declarations
 
    Trace          : aliased WisiToken.Text_IO_Trace.Trace;
    Input_Data     : aliased WisiToken_Grammar_Runtime.User_Data_Type;
-   Grammar_Parser : WisiToken.Parse.LR.Parser_No_Recover.Parser;
+   Grammar_Parser : WisiToken.Parse.LR.Parser_No_Recover.Parser := 
Wisitoken_Grammar_Main.Create_Parser
+     (Trace'Unchecked_Access, Input_Data'Unchecked_Access);
    Log_File       : Ada.Text_IO.File_Type; -- not used
 
    procedure Use_Input_File (File_Name : in String)
@@ -151,11 +146,6 @@ is
    begin
       Output_File_Name_Root := +Ada.Directories.Base_Name (File_Name) & Suffix;
 
-      WisiToken.Parse.LR.Parser_No_Recover.New_Parser
-        (Grammar_Parser, Wisitoken_Grammar_Main.Create_Lexer 
(Trace'Unchecked_Access),
-         Wisitoken_Grammar_Main.Create_Parse_Table, 
Wisitoken_Grammar_Main.Create_Productions,
-         Input_Data'Unchecked_Access);
-
       Grammar_Parser.Tree.Lexer.Reset_With_File (File_Name);
 
       declare
@@ -245,16 +235,6 @@ begin
                Add (Command_Generate_Set, Tuple);
             end;
 
-         elsif Argument (Arg_Next) = "--lr1_hash_table_size" then
-            Arg_Next := Arg_Next + 1;
-
-            Input_Data.Language_Params.LR1_Hash_Table_Size := Positive'Value 
(Argument (Arg_Next));
-            if not Generate_Task_Count_Set then
-               Generate_Task_Count := 0;
-            end if;
-
-            Arg_Next := Arg_Next + 1;
-
          elsif Argument (Arg_Next) = "--output_bnf" then
             Output_BNF := True;
             Arg_Next   := Arg_Next + 1;
@@ -264,19 +244,6 @@ begin
             Suffix   := +Argument (Arg_Next);
             Arg_Next := Arg_Next + 1;
 
-         elsif Argument (Arg_Next) = "--task_count" then
-            Arg_Next   := @ + 1;
-            Generate_Task_Count_Set := True;
-            declare
-               use System.Multiprocessors;
-            begin
-               Generate_Task_Count := CPU_Range'Value (Argument (Arg_Next));
-               if Generate_Task_Count = 0 then
-                  Generate_Task_Count := Number_Of_CPUs;
-               end if;
-            end;
-            Arg_Next   := @ + 1;
-
          elsif Argument (Arg_Next) = "--test_main" then
             Arg_Next  := Arg_Next + 1;
             Test_Main := True;
@@ -299,7 +266,7 @@ begin
    end if;
 
    begin
-      Grammar_Parser.Parse (Log_File); -- Execute_Actions only does meta phase
+      Grammar_Parser.Parse (Log_File);
    exception
    when WisiToken.Syntax_Error =>
       if Grammar_Parser.Tree.Parents_Set then
@@ -434,7 +401,7 @@ begin
                      Trace.Put_Line ("post-parse grammar file OTHER, bnf 
tree");
                   end if;
 
-                  WisiToken.Parse.LR.Parser_No_Recover.Execute_Actions
+                  WisiToken.Parse.Execute_Actions
                     (BNF_Tree, Grammar_Parser.Productions, 
Input_Data'Unchecked_Access);
                end if;
 
@@ -536,14 +503,8 @@ begin
                Parser => Tuple.Gen_Alg,
                Phase  => WisiToken_Grammar_Runtime.Other);
 
-            if Input_Data.Language_Params.LR1_Hash_Table_Size /=
-              WisiToken.Generate.LR1_Items.Item_Set_Trees.Default_Rows and
-              not Generate_Task_Count_Set
-            then
-               Generate_Task_Count := System.Multiprocessors.Number_Of_CPUs;
-            end if;
-
             declare
+               use all type WisiToken.Parse.LR.Parse_Table_Ptr;
                use Ada.Real_Time;
 
                Time_Start : Time;
@@ -564,9 +525,6 @@ begin
                Parse_Table_File_Name : constant String :=
                  (if Tuple.Gen_Alg in LALR .. Packrat_Proc
                   then -Output_File_Name_Root & "_" & To_Lower 
(Tuple.Gen_Alg'Image) &
-                    (if Tuple.Gen_Alg = LR1 and Test_Main
-                     then "_t" & Ada.Strings.Fixed.Trim 
(Generate_Task_Count'Image, Ada.Strings.Both)
-                     else "") &
                     (if Input_Data.If_Lexer_Present
                      then "_" & Lexer_Image (Input_Data.User_Lexer).all
                      else "") &
@@ -617,13 +575,14 @@ begin
                        (Generate_Data.Grammar,
                         Generate_Data.Descriptor.all,
                         Grammar_Parser.Tree.Lexer.File_Name,
+                        Input_Data.Language_Params.Error_Recover,
                         Generate_Data.Conflicts,
                         Generate_Utils.To_McKenzie_Param (Generate_Data, 
Input_Data.McKenzie_Recover),
                         Input_Data.Max_Parallel,
                         Parse_Table_File_Name,
                         Include_Extra         => Test_Main,
                         Ignore_Conflicts      => Ignore_Conflicts,
-                        Partial_Recursion     => 
Input_Data.Language_Params.Partial_Recursion,
+                        Recursion_Strategy    => 
Input_Data.Language_Params.Recursion_Strategy,
                         Use_Cached_Recursions => not 
(Input_Data.If_Lexer_Present or Input_Data.If_Parser_Present),
                         Recursions            => Cached_Recursions);
 
@@ -658,15 +617,14 @@ begin
                        (Generate_Data.Grammar,
                         Generate_Data.Descriptor.all,
                         Grammar_Parser.Tree.Lexer.File_Name,
+                        Input_Data.Language_Params.Error_Recover,
                         Generate_Data.Conflicts,
                         Generate_Utils.To_McKenzie_Param (Generate_Data, 
Input_Data.McKenzie_Recover),
                         Input_Data.Max_Parallel,
                         Parse_Table_File_Name,
                         Include_Extra         => Test_Main,
                         Ignore_Conflicts      => Ignore_Conflicts,
-                        Partial_Recursion     => 
Input_Data.Language_Params.Partial_Recursion,
-                        Task_Count            => Generate_Task_Count,
-                        Hash_Table_Size       => 
Input_Data.Language_Params.LR1_Hash_Table_Size,
+                        Recursion_Strategy    => 
Input_Data.Language_Params.Recursion_Strategy,
                         Use_Cached_Recursions => not 
(Input_Data.If_Lexer_Present or Input_Data.If_Parser_Present),
                         Recursions            => Cached_Recursions);
 
@@ -721,11 +679,14 @@ begin
 
                case Tuple.Gen_Alg is
                when LR_Generate_Algorithm =>
+                  pragma Assert
+                    (Generate_Data.LR_Parse_Table /= null and then
+                     Generate_Data.LR_Parse_Table.Error_Recover_Enabled = 
Input_Data.Language_Params.Error_Recover);
+
                   if Tuple.Text_Rep then
                      WisiToken.Generate.LR.Put_Text_Rep
                        (Generate_Data.LR_Parse_Table.all,
-                        Text_Rep_File_Name
-                          (-Output_File_Name_Root, Tuple, Generate_Task_Count, 
Input_Data.If_Lexer_Present, Test_Main));
+                        Text_Rep_File_Name (-Output_File_Name_Root, Tuple, 
Input_Data.If_Lexer_Present));
                   end if;
 
                when others =>
@@ -740,7 +701,7 @@ begin
 
                   WisiToken.BNF.Output_Ada
                     (Input_Data, Grammar_Parser.Tree.Lexer.File_Name, 
-Output_File_Name_Root, Generate_Data,
-                     Packrat_Data, Tuple, Test_Main, Multiple_Tuples, 
Generate_Task_Count);
+                     Packrat_Data, Tuple, Test_Main, Multiple_Tuples);
 
                when Ada_Emacs_Lang =>
                   if Trace_Generate > Outline then
diff --git a/wisitoken-bnf-generate_packrat.adb 
b/wisitoken-bnf-generate_packrat.adb
index ec0216487a..2bc59eb3d3 100644
--- a/wisitoken-bnf-generate_packrat.adb
+++ b/wisitoken-bnf-generate_packrat.adb
@@ -56,6 +56,7 @@ is
    end Var_Suffix;
 
    procedure Generate_Parser_Body (Prod : in Productions.Instance)
+   --  Generate the parser function for one production.
    is
       use all type Ada.Containers.Count_Type;
 
@@ -72,10 +73,11 @@ is
       Indent_Line ("Descriptor : WisiToken.Descriptor renames 
Tree.Lexer.Descriptor.all;");
       Indent_Line
         ("Start_Pos  : constant Syntax_Trees.Stream_Index := Tree.Stream_Next 
(Tree.Shared_Stream, Last_Pos);");
-      Indent_Line ("Start_Pos_Index : constant Syntax_Trees.Node_Index :=");
+      Indent_Line ("Start_Pos_Index  : constant Syntax_Trees.Node_Index :=");
       Indent_Line ("  Tree.Get_Node_Index (Tree.Shared_Stream, Start_Pos);");
-      Indent_Line ("Pos        : Syntax_Trees.Stream_Index := Last_Pos; --  
last token parsed.");
-      Indent_Line ("Next_Pos   : Syntax_Trees.Stream_Index := Start_Pos;");
+      Indent_Line ("Pos              : Syntax_Trees.Stream_Index := Last_Pos; 
--  last token parsed.");
+      Indent_Line ("Next_Pos         : Syntax_Trees.Stream_Index := 
Start_Pos;");
+      Indent_Line ("Max_Examined_Pos : Syntax_Trees.Stream_Index := 
Last_Pos;");
 
       for RHS_Index in Prod.RHSs.First_Index .. Prod.RHSs.Last_Index loop
          declare
@@ -101,11 +103,11 @@ is
       Indent := Indent + 3;
 
       Indent_Line ("if Next_Pos = Syntax_Trees.Invalid_Stream_Index then");
-      Indent_Line ("   return (State => Failure);");
+      Indent_Line ("   return (State => Failure, Max_Examined_Pos => 
Next_Pos);");
       Indent_Line ("end if;");
       Indent_Line ("declare");
       Indent_Line
-        ("   Memo : Memo_Entry renames Parser.Derivs (" & Result_ID & 
")(Start_Pos_Index);");
+        ("   Memo : Memo_Entry := Get_Deriv (Parser.Derivs, " & Result_ID & ", 
Start_Pos_Index);");
       Indent_Line ("begin");
       Indent := Indent + 3;
       Indent_Line ("case Memo.State is");
@@ -128,7 +130,9 @@ is
 
       if Data.Direct_Left_Recursive (Prod.LHS) then
          --  This is the top of the 'while' loop in [warth 2008] figure 3 
Grow-LR.
-         Indent_Line ("Parser.Derivs (" & Result_ID & ").Replace_Element 
(Start_Pos_Index, (State => Failure));");
+         Indent_Line
+           ("Set_Deriv (Parser.Derivs, " & Result_ID &
+              ", Start_Pos_Index, (State => Failure, Max_Examined_Pos => 
Next_Pos));");
          Indent_Line ("<<Recurse_Start>>");
       end if;
 
@@ -142,11 +146,12 @@ is
                   Indent_Line ("Result_Recurse :=");
                   Indent := Indent + 2;
                else
-                  Indent_Line ("Parser.Derivs (" & Result_ID & 
").Replace_Element");
-                  Indent_Line ("  (Start_Pos_Index,");
+                  Indent_Line ("Set_Deriv");
+                  Indent_Line ("  (Parser.Derivs, " & Result_ID & ", 
Start_Pos_Index,");
                   Indent := Indent + 3;
                end if;
                Indent_Line ("(State            => Success,");
+               Indent_Line (" Max_Examined_Pos => Max_Examined_Pos,");
                Indent_Line (" Result           => Parser.Tree.Add_Nonterm");
 
                Indent := Indent + 3;
@@ -218,10 +223,12 @@ is
                for Token_Index in RHS.Tokens.First_Index .. 
RHS.Tokens.Last_Index loop
                   declare
                      ID      : constant String := Trimmed_Image (RHS.Tokens 
(Token_Index));
+                     ID_Name : constant String := Image (RHS.Tokens 
(Token_Index), Descriptor);
                      Var_Suf : constant String := Var_Suffix (RHS_Index, 
Token_Index);
                   begin
                      if RHS.Tokens (Token_Index) in Terminal then
-                        Indent_Line ("if Tree.ID (Tree.Shared_Stream, 
Next_Pos) = " & ID & " then");
+                        Indent_Line ("Update (Parser, """ & ID_Name & """, 
Next_Pos, Max_Examined_Pos);");
+                        Indent_Line ("if Tree.ID (Next_Pos) = " & ID & " 
then");
                         Indent := Indent + 3;
                         Indent_Line ("Pos := Next_Pos;");
                         Indent_Line ("Next_Pos := Tree.Stream_Next 
(Tree.Shared_Stream, Pos);");
@@ -238,6 +245,9 @@ is
                         Indent_Line
                           ("Memo_" & Var_Suf & " := Parse_" & Image 
(RHS.Tokens (Token_Index), Descriptor) &
                              " (Parser, Pos);");
+                        Indent_Line
+                          ("Update (Parser, """ & ID_Name & """, Memo_" & 
Var_Suf &
+                             ".Max_Examined_Pos, Max_Examined_Pos);");
                         Indent_Line ("case Result_States'(Memo_" & Var_Suf & 
".State) is");
                         Indent_Line ("when Success =>");
                         Indent := Indent + 3;
@@ -255,16 +265,18 @@ is
                end loop;
             end if;
 
-            Indent_Line ("<<RHS_" & Trimmed_Image (RHS_Index) & "_Fail>>");
             New_Line;
+            Indent_Line ("<<RHS_" & Trimmed_Image (RHS_Index) & "_Fail>>");
          end;
       end loop;
 
       --  We get here if the last alternative fails.
       if Data.Direct_Left_Recursive (Prod.LHS) then
-         Indent_Line ("Result_Recurse := (State => Failure);");
+         Indent_Line ("Result_Recurse := (State => Failure, Max_Examined_Pos 
=> Max_Examined_Pos);");
       else
-         Indent_Line ("Parser.Derivs (" & Result_ID & ").Replace_Element 
(Start_Pos_Index, (State => Failure));");
+         Indent_Line ("Set_Deriv");
+         Indent_Line ("   (Parser.Derivs, " & Result_ID & ", 
Start_Pos_Index,");
+         Indent_Line ("    (State => Failure, Max_Examined_Pos => 
Max_Examined_Pos));");
          Indent_Line ("return Parser.Derivs (" & Result_ID & 
")(Start_Pos_Index);");
       end if;
 
@@ -277,12 +289,12 @@ is
          Indent_Line ("then");
          --  made progress, try again
          Indent := Indent + 3;
-         Indent_Line ("Parser.Derivs (" & Result_ID & ").Replace_Element 
(Start_Pos_Index, Result_Recurse);");
+         Indent_Line ("Set_Deriv (Parser.Derivs, " & Result_ID & ", 
Start_Pos_Index, Result_Recurse);");
          Indent_Line ("Pos_Recurse_Last := Pos;");
          Indent_Line ("if WisiToken.Trace_Parse > Detail then");
          Indent_Line ("   Tree.Lexer.Trace.Put_Line");
          Indent_Line ("     (Parser.Tree.Image (Result_Recurse.Result,");
-         Indent_Line ("      Children => True, Terminal_Node_Numbers => 
True));");
+         Indent_Line ("      Children => True, Terminal_Node_Numbers => True, 
RHS_Index => True));");
          Indent_Line ("end if;");
          Indent_Line ("goto Recurse_Start;");
          Indent := Indent - 3;
@@ -291,7 +303,7 @@ is
               "Parser.Tree.Is_Empty_Nonterm (Result_Recurse.Result) then");
          --  Parse succeeded producing an empty nonterm; don't try again. This
          --  special case is not in [warth 2008].
-         Indent_Line ("   Parser.Derivs (" & Result_ID & ").Replace_Element 
(Start_Pos_Index, Result_Recurse);");
+         Indent_Line ("   Set_Deriv (Parser.Derivs, " & Result_ID & ", 
Start_Pos_Index, Result_Recurse);");
          Indent_Line ("end if;");
          Indent := Indent - 3;
          Indent_Line ("end if;");
@@ -305,7 +317,7 @@ is
          Indent_Line ("Tree.Lexer.Trace.Put_Line");
          Indent_Line ("  (Parser.Tree.Image");
          Indent_Line ("    (Parser.Derivs (" & Result_ID & 
")(Start_Pos_Index).Result,");
-         Indent_Line ("     Children => True, Terminal_Node_Numbers => 
True));");
+         Indent_Line ("     Children => True, Terminal_Node_Numbers => True, 
RHS_Index => True));");
          Indent := Indent - 3;
          Indent_Line ("end if;");
       end if;
@@ -328,17 +340,30 @@ begin
    end loop;
    New_Line;
 
+   Indent_Line ("procedure Update");
+   Indent_Line ("  (Parser           : in out Generated.Parser;");
+   Indent_Line ("   Nonterm          : in     String;");
+   Indent_Line ("   New_Pos          : in     Syntax_Trees.Stream_Index;");
+   Indent_Line ("   Max_Examined_Pos : in out Syntax_Trees.Stream_Index)");
+   Indent_Line ("is");
+   Indent_Line ("   Tree : Syntax_Trees.Tree renames Parser.Tree;");
+   Indent_Line ("begin");
+   Indent_Line ("   if Tree.Byte_Region");
+   Indent_Line ("     (Tree.Get_Node (Tree.Shared_Stream, New_Pos), 
Trailing_Non_Grammar => False).First >");
+   Indent_Line ("     Tree.Byte_Region");
+   Indent_Line ("       (Tree.Get_Node (Tree.Shared_Stream, Max_Examined_Pos), 
Trailing_Non_Grammar => False).First");
+   Indent_Line ("   then");
+   Indent_Line ("      Max_Examined_Pos := New_Pos;");
+   Indent_Line ("   end if;");
+   Indent_Line ("   if Trace_Parse > Extra then");
+   Indent_Line ("      Tree.Lexer.Trace.Put_Line");
+   Indent_Line ("        (Nonterm & "": max_examined_pos "" & Tree.Image");
+   Indent_Line ("          (Tree.Get_Node (Tree.Shared_Stream, 
Max_Examined_Pos), Node_Numbers => True));");
+   Indent_Line ("   end if;");
+   Indent_Line ("end Update;");
+
    for Prod of Data.Grammar loop
       Generate_Parser_Body (Prod);
    end loop;
 
-   Indent_Line ("function Parse_wisitoken_accept_1");
-   --  WORKAROUND: using Parse.Packrat.Parser'Class here generates GNAT bug 
box with GPL 2018
-   Indent_Line ("  (Parser   : in out WisiToken.Parse.Base_Parser'Class;");
-   Indent_Line ("   Last_Pos : in Syntax_Trees.Stream_Index) return 
Result_Type");
-   Indent_Line ("is begin");
-   Indent_Line ("   return Parse_wisitoken_accept (Generated.Parser (Parser), 
Last_Pos);");
-   Indent_Line ("end Parse_wisitoken_accept_1;");
-   New_Line;
-
 end WisiToken.BNF.Generate_Packrat;
diff --git a/wisitoken-bnf-generate_utils.adb b/wisitoken-bnf-generate_utils.adb
index a9eccb2132..3b089c1b98 100644
--- a/wisitoken-bnf-generate_utils.adb
+++ b/wisitoken-bnf-generate_utils.adb
@@ -22,7 +22,6 @@ with Ada.Exceptions;
 with Ada.Text_IO;
 with WisiToken.Generate; use WisiToken.Generate;
 with WisiToken.Syntax_Trees;
-with WisiToken.Text_IO_Trace;
 with WisiToken.Wisi_Ada;
 with WisiToken_Grammar_Editing;
 with Wisitoken_Grammar_Main;
@@ -308,15 +307,8 @@ package body WisiToken.BNF.Generate_Utils is
      (Grammar_Parser    : in out WisiToken.Parse.LR.Parser_No_Recover.Parser;
       Grammar_File_Name : in     String)
    is
-      Trace      : aliased WisiToken.Text_IO_Trace.Trace;
-      Input_Data : aliased WisiToken_Grammar_Runtime.User_Data_Type;
-      Log_File   : Ada.Text_IO.File_Type;
+      Log_File : Ada.Text_IO.File_Type;
    begin
-      WisiToken.Parse.LR.Parser_No_Recover.New_Parser
-        (Grammar_Parser, Wisitoken_Grammar_Main.Create_Lexer 
(Trace'Unchecked_Access),
-         Wisitoken_Grammar_Main.Create_Parse_Table, 
Wisitoken_Grammar_Main.Create_Productions,
-         Input_Data'Unchecked_Access);
-
       Grammar_Parser.Tree.Lexer.Reset_With_File (Grammar_File_Name);
 
       Grammar_Parser.Parse (Log_File);
@@ -340,14 +332,10 @@ package body WisiToken.BNF.Generate_Utils is
      return Generate_Data
    is
       use all type WisiToken_Grammar_Runtime.Meta_Syntax;
-      Grammar_Parser : WisiToken.Parse.LR.Parser_No_Recover.Parser;
+      Grammar_Parser : WisiToken.Parse.LR.Parser_No_Recover.Parser := 
Wisitoken_Grammar_Main.Create_Parser
+        (Trace'Unchecked_Access, Syntax_Trees.User_Data_Access (Input_Data));
       Log_File       : Ada.Text_IO.File_Type;
    begin
-      WisiToken.Parse.LR.Parser_No_Recover.New_Parser
-        (Grammar_Parser, Wisitoken_Grammar_Main.Create_Lexer 
(Trace'Unchecked_Access),
-         Wisitoken_Grammar_Main.Create_Parse_Table, 
Wisitoken_Grammar_Main.Create_Productions,
-         Syntax_Trees.User_Data_Access (Input_Data));
-
       Grammar_Parser.Tree.Lexer.Reset_With_File (Grammar_File_Name);
 
       Grammar_Parser.Parse (Log_File);
diff --git a/wisitoken-bnf-output_ada.adb b/wisitoken-bnf-output_ada.adb
index 0b727b1504..6069c84291 100644
--- a/wisitoken-bnf-output_ada.adb
+++ b/wisitoken-bnf-output_ada.adb
@@ -23,7 +23,6 @@ pragma License (Modified_GPL);
 with Ada.Strings.Fixed;
 with Ada.Text_IO; use Ada.Text_IO;
 with GNAT.Regexp;
-with System.Multiprocessors;
 with WisiToken.BNF.Generate_Packrat;
 with WisiToken.BNF.Generate_Utils;
 with WisiToken.BNF.Output_Ada_Common; use WisiToken.BNF.Output_Ada_Common;
@@ -37,18 +36,14 @@ procedure WisiToken.BNF.Output_Ada
    Packrat_Data          :         in WisiToken.Generate.Packrat.Data;
    Tuple                 :         in Generate_Tuple;
    Test_Main             :         in Boolean;
-   Multiple_Tuples       :         in Boolean;
-   Generate_Task_Count   :         in System.Multiprocessors.CPU_Range)
+   Multiple_Tuples       :         in Boolean)
 is
    Common_Data : Output_Ada_Common.Common_Data := 
WisiToken.BNF.Output_Ada_Common.Initialize
      (Input_Data, Tuple, Grammar_File_Name, Output_File_Name_Root, 
Check_Interface => False);
 
    Gen_Alg_Name : constant String :=
      (if Test_Main or Multiple_Tuples
-      then "_" & Generate_Algorithm_Image (Common_Data.Generate_Algorithm).all 
&
-         (if Common_Data.Generate_Algorithm = LR1
-         then "_t" & Ada.Strings.Fixed.Trim (Generate_Task_Count'Image, 
Ada.Strings.Both)
-         else "")
+      then "_" & Generate_Algorithm_Image (Common_Data.Generate_Algorithm).all
       else "");
 
    function Symbol_Regexp (Item : in String) return String
@@ -287,7 +282,8 @@ is
 
    procedure Create_Ada_Main_Body
      (Actions_Package_Name : in String;
-      Main_Package_Name    : in String)
+      Main_Package_Name    : in String;
+      Input_Data           : in WisiToken_Grammar_Runtime.User_Data_Type)
    is
       use WisiToken.Generate;
 
@@ -314,23 +310,25 @@ is
          Put_Line ("with " & re2c_Package_Name & ";");
       end case;
 
-      Put_Line ("with " & Actions_Package_Name & "; use " & 
Actions_Package_Name & ";");
-
       case Common_Data.Generate_Algorithm is
-      when LR_Generate_Algorithm | Tree_Sitter =>
-         null;
-
-      when Packrat_Gen =>
-         Put_Line ("with WisiToken.Parse.Packrat.Generated;");
+      when LR_Generate_Algorithm =>
+         if not Input_Data.Language_Params.Error_Recover then
+            Put_Line ("with WisiToken.Parse.LR;");
+         end if;
 
       when Packrat_Proc =>
-         Put_Line ("with WisiToken.Parse.Packrat.Procedural;");
          Put_Line ("with WisiToken.Productions;");
 
-      when External =>
+      when Packrat_Gen =>
+         null;
+
+      when External | Tree_Sitter =>
          null;
+
       end case;
 
+      Put_Line ("with " & Actions_Package_Name & "; use " & 
Actions_Package_Name & ";");
+
       Put_Line ("package body " & Main_Package_Name & " is");
       Indent := Indent + 3;
       New_Line;
@@ -345,8 +343,9 @@ is
 
       case Common_Data.Generate_Algorithm is
       when LR_Generate_Algorithm =>
-         LR_Create_Create_Parse_Table (Input_Data, Common_Data, Generate_Data, 
Actions_Package_Name);
+         LR_Create_Create_Parse_Table (Input_Data, Common_Data, Generate_Data);
          Create_Create_Productions (Generate_Data);
+         LR_Create_Create_Parser (Actions_Package_Name, Common_Data, 
Generate_Data);
 
       when Packrat_Gen =>
          WisiToken.BNF.Generate_Packrat (Packrat_Data, Generate_Data);
@@ -385,9 +384,10 @@ is
                then "Gen_LR_Text_Rep_Parser_No_Recover_Run"
                else "Gen_LR_Parser_No_Recover_Run")),
 
-         when Packrat_Generate_Algorithm => "Gen_Packrat_Parser_Run",
-         when External => raise SAL.Programmer_Error,
-         when Tree_Sitter => "Gen_Tree_Sitter_Parser_Run");
+         when Packrat_Proc          => "Gen_Packrat_Proc_Parser_Run",
+         when Packrat_Gen           => "Gen_Packrat_Gen_Parser_Run",
+         when External              => raise SAL.Programmer_Error,
+         when Tree_Sitter           => "Gen_Tree_Sitter_Parser_Run");
 
       Unit_Name : constant String := File_Name_To_Ada (Output_File_Name_Root) 
& Gen_Alg_Name & "_Run";
 
@@ -431,8 +431,7 @@ is
          if Common_Data.Text_Rep then
             Put_Line
               ("   """ &
-                 Text_Rep_File_Name
-                   (Output_File_Name_Root, Tuple, Generate_Task_Count, 
Input_Data.If_Lexer_Present, Test_Main) & """,");
+                 Text_Rep_File_Name (Output_File_Name_Root, Tuple, 
Input_Data.If_Lexer_Present) & """,");
          end if;
          if Input_Data.Language_Params.Error_Recover then
             if Input_Data.Language_Params.Use_Language_Runtime then
@@ -441,9 +440,7 @@ is
                Put_Line ("   null, null, null,");
             end if;
          end if;
-         Put_Line ("   " & Main_Package_Name & ".Create_Parse_Table,");
-         Put_Line ("   " & Main_Package_Name & ".Create_Productions,");
-         Put_Line ("   " & Main_Package_Name & ".Create_Lexer);");
+         Put_Line ("   " & Main_Package_Name & ".Create_Parser);");
 
       when Packrat_Generate_Algorithm | Tree_Sitter =>
          Put_Line ("   " & Main_Package_Name & ".Create_Parser);");
@@ -480,9 +477,9 @@ begin
 
       if Tuple.Gen_Alg = External then
          Create_External_Main_Spec (Main_Package_Name, Tuple, Input_Data);
-         Create_Ada_Main_Body (Actions_Package_Name, Main_Package_Name);
+         Create_Ada_Main_Body (Actions_Package_Name, Main_Package_Name, 
Input_Data);
       else
-         Create_Ada_Main_Body (Actions_Package_Name, Main_Package_Name);
+         Create_Ada_Main_Body (Actions_Package_Name, Main_Package_Name, 
Input_Data);
 
          Create_Ada_Main_Spec (To_Lower (Main_Package_Name) & ".ads", 
Main_Package_Name, Input_Data, Common_Data);
 
diff --git a/wisitoken-bnf-output_ada_common.adb 
b/wisitoken-bnf-output_ada_common.adb
index ffd61d4698..853b690022 100644
--- a/wisitoken-bnf-output_ada_common.adb
+++ b/wisitoken-bnf-output_ada_common.adb
@@ -228,6 +228,9 @@ package body WisiToken.BNF.Output_Ada_Common is
          end if;
       end loop;
 
+      Indent_Line ("Partial_Parse_Active    : aliased Boolean := False;");
+      Indent_Line ("Partial_Parse_Byte_Goal : aliased WisiToken.Buffer_Pos := 
WisiToken.Buffer_Pos'Last;");
+
       Put_Raw_Code (Ada_Comment, Input_Data.Raw_Code (Actions_Spec_Post));
 
       Put_Line ("end " & Package_Name & ";");
@@ -248,25 +251,49 @@ package body WisiToken.BNF.Output_Ada_Common is
 
       procedure LR_Process
       is begin
-         Indent_Line ("function Create_Parse_Table");
+         Indent_Line ("function Create_Parser");
+         Indent_Line ("  (Trace      : in WisiToken.Trace_Access;");
+         Indent_Start   ("   User_Data  : in 
WisiToken.Syntax_Trees.User_Data_Access");
+         if Input_Data.Language_Params.Error_Recover then
+            Put_Line (";");
+            Indent_Line ("   Language_Fixes                 : in 
WisiToken.Parse.LR.Parser.Language_Fixes_Access;");
+            Indent_Line
+              ("   Language_Matching_Begin_Tokens : in " &
+                 
"WisiToken.Parse.LR.Parser.Language_Matching_Begin_Tokens_Access;");
+            Indent_Start
+              ("   Language_String_ID_Set         : in 
WisiToken.Parse.LR.Parser.Language_String_ID_Set_Access");
+         end if;
          if Common_Data.Text_Rep then
-            Indent_Line ("  (Text_Rep_File_Name : in String)");
+            Put_Line (";");
+            Indent_Start ("   Text_Rep_File_Name : in String");
          end if;
-         Indent_Line ("  return WisiToken.Parse.LR.Parse_Table_Ptr;");
-         New_Line;
-         Indent_Line ("function Create_Productions return 
WisiToken.Syntax_Trees.Production_Info_Trees.Vector;");
+         Put_Line (")");
+         Indent_Line
+           ("  return WisiToken.Parse.LR.Parser"  &
+              (if Input_Data.Language_Params.Error_Recover
+               then ""
+               else "_No_Recover") &
+              ".Parser;");
          New_Line;
-         Indent_Line ("function Create_Lexer (Trace : in 
WisiToken.Trace_Access) return WisiToken.Lexer.Handle;");
       end LR_Process;
 
-      procedure Packrat_Process
+      procedure Packrat_Procedural_Process
+      is begin
+         Indent_Line ("function Create_Parser");
+         Indent_Line ("  (Trace      : in WisiToken.Trace_Access;");
+         Indent_Line ("   User_Data  : in 
WisiToken.Syntax_Trees.User_Data_Access)");
+         Indent_Line ("  return WisiToken.Parse.Packrat.Procedural.Parser;");
+         New_Line;
+      end Packrat_Procedural_Process;
+
+      procedure Packrat_Generated_Process
       is begin
          Indent_Line ("function Create_Parser");
          Indent_Line ("  (Trace      : in WisiToken.Trace_Access;");
          Indent_Line ("   User_Data  : in 
WisiToken.Syntax_Trees.User_Data_Access)");
-         Indent_Line ("  return WisiToken.Parse.Base_Parser'Class;");
+         Indent_Line ("  return WisiToken.Parse.Packrat.Generated.Parser;");
          New_Line;
-      end Packrat_Process;
+      end Packrat_Generated_Process;
 
    begin
       if Common_Data.Generate_Algorithm = External then
@@ -288,11 +315,18 @@ package body WisiToken.BNF.Output_Ada_Common is
 
       case Common_Data.Generate_Algorithm is
       when LR_Generate_Algorithm =>
-         Put_Line ("with WisiToken.Lexer;");
-         Put_Line ("with WisiToken.Parse.LR;");
+         Put_Line
+           ("with WisiToken.Parse.LR.Parser"  &
+              (if Input_Data.Language_Params.Error_Recover
+               then ""
+               else "_No_Recover") &
+              ";");
 
-      when Packrat_Generate_Algorithm =>
-         Put_Line ("with WisiToken.Parse;");
+      when Packrat_Proc =>
+         Put_Line ("with WisiToken.Parse.Packrat.Procedural;");
+
+      when Packrat_Gen =>
+         Put_Line ("with WisiToken.Parse.Packrat.Generated;");
 
       when External | Tree_Sitter =>
          null;
@@ -307,8 +341,10 @@ package body WisiToken.BNF.Output_Ada_Common is
          case Common_Data.Generate_Algorithm is
          when LR_Generate_Algorithm =>
             LR_Process;
-         when Packrat_Generate_Algorithm =>
-            Packrat_Process;
+         when Packrat_Proc =>
+            Packrat_Procedural_Process;
+         when Packrat_Gen =>
+            Packrat_Generated_Process;
          when External | Tree_Sitter =>
             null;
          end case;
@@ -319,8 +355,10 @@ package body WisiToken.BNF.Output_Ada_Common is
             case Common_Data.Generate_Algorithm is
             when LR_Generate_Algorithm =>
                LR_Process;
-            when Packrat_Generate_Algorithm =>
-               Packrat_Process;
+            when Packrat_Proc =>
+               Packrat_Procedural_Process;
+            when Packrat_Gen =>
+               Packrat_Generated_Process;
             when External | Tree_Sitter =>
                null;
             end case;
@@ -610,10 +648,9 @@ package body WisiToken.BNF.Output_Ada_Common is
    end Create_LR_Parser_Table;
 
    procedure LR_Create_Create_Parse_Table
-     (Input_Data           :         in     
WisiToken_Grammar_Runtime.User_Data_Type;
-      Common_Data          :         in out Output_Ada_Common.Common_Data;
-      Generate_Data        : aliased in     
WisiToken.BNF.Generate_Utils.Generate_Data;
-      Actions_Package_Name :         in     String)
+     (Input_Data    :         in     WisiToken_Grammar_Runtime.User_Data_Type;
+      Common_Data   :         in out Output_Ada_Common.Common_Data;
+      Generate_Data : aliased in     
WisiToken.BNF.Generate_Utils.Generate_Data)
    is
       Table : WisiToken.Parse.LR.Parse_Table_Ptr renames 
Generate_Data.LR_Parse_Table;
    begin
@@ -666,13 +703,66 @@ package body WisiToken.BNF.Output_Ada_Common is
       Indent := Indent - 3;
       Indent_Line ("end Create_Parse_Table;");
       New_Line;
+   end LR_Create_Create_Parse_Table;
+
+   procedure LR_Create_Create_Parser
+     (Actions_Package_Name :         in     String;
+      Common_Data          :         in out Output_Ada_Common.Common_Data;
+      Generate_Data        : aliased in     
WisiToken.BNF.Generate_Utils.Generate_Data)
+   is
+      Parser_Type : constant String :=
+        "WisiToken.Parse.LR.Parser" &
+        (if Generate_Data.LR_Parse_Table.Error_Recover_Enabled
+         then ""
+         else "_No_Recover") &
+        ".Parser";
+   begin
+      Indent_Line ("function Create_Parser");
+      Indent_Line    ("  (Trace      : in WisiToken.Trace_Access;");
+      Indent_Start   ("   User_Data  : in 
WisiToken.Syntax_Trees.User_Data_Access");
+      if Generate_Data.LR_Parse_Table.Error_Recover_Enabled then
+         Put_Line (";");
+         Indent_Line
+           ("   Language_Fixes                 : in 
WisiToken.Parse.LR.Parser.Language_Fixes_Access;");
+         Indent_Line
+           ("   Language_Matching_Begin_Tokens : in 
WisiToken.Parse.LR.Parser.Language_Matching_Begin_Tokens_Access;");
+         Indent_Start
+           ("   Language_String_ID_Set         : in 
WisiToken.Parse.LR.Parser.Language_String_ID_Set_Access");
+      end if;
+      if Common_Data.Text_Rep then
+         Put_Line (";");
+         Indent_Start ("   Text_Rep_File_Name : in String");
+      end if;
+      Put_Line (")");
+      Indent_Line ("  return " & Parser_Type);
 
-      Indent_Line ("function Create_Lexer (Trace : in WisiToken.Trace_Access) 
return WisiToken.Lexer.Handle");
       Indent_Line ("is begin");
-      Indent_Line ("   return Lexer.New_Lexer (Trace, " & Actions_Package_Name 
& ".Descriptor'Access);");
-      Indent_Line ("end Create_Lexer;");
-      New_Line;
-   end LR_Create_Create_Parse_Table;
+      Indent := Indent + 3;
+      Indent_Line ("return Parser : " & Parser_Type & " do");
+      Indent := Indent + 3;
+      Indent_Line ("Parser.Tree.Lexer := Lexer.New_Lexer (Trace, " & 
Actions_Package_Name & ".Descriptor'Access);");
+      Indent_Line ("Parser.Productions := Create_Productions;");
+      Indent_Line ("Parser.User_Data := User_Data;");
+      if Generate_Data.LR_Parse_Table.Error_Recover_Enabled then
+         Indent_Line ("Parser.Partial_Parse_Active := " & Actions_Package_Name 
& ".Partial_Parse_Active'Access;");
+         Indent_Line ("Parser.Partial_Parse_Byte_Goal := " & 
Actions_Package_Name & ".Partial_Parse_Byte_Goal'Access;");
+      end if;
+
+      if Common_Data.Text_Rep then
+         Indent_Line ("Parser.Table := Create_Parse_Table 
(Text_Rep_File_Name);");
+      else
+         Indent_Line ("Parser.Table := Create_Parse_Table;");
+      end if;
+      if Generate_Data.LR_Parse_Table.Error_Recover_Enabled then
+         Indent_Line ("Parser.Language_Fixes                 := 
Language_Fixes;");
+         Indent_Line ("Parser.Language_Matching_Begin_Tokens := 
Language_Matching_Begin_Tokens;");
+         Indent_Line ("Parser.Language_String_ID_Set         := 
Language_String_ID_Set;");
+      end if;
+      Indent := Indent - 3;
+      Indent_Line ("end return;");
+      Indent := Indent - 3;
+      Indent_Line ("end Create_Parser;");
+   end LR_Create_Create_Parser;
 
    procedure Packrat_Create_Create_Parser
      (Actions_Package_Name :         in     String;
@@ -680,41 +770,19 @@ package body WisiToken.BNF.Output_Ada_Common is
       Generate_Data        : aliased in     
WisiToken.BNF.Generate_Utils.Generate_Data;
       Packrat_Data         :         in     WisiToken.Generate.Packrat.Data)
    is
-      use Ada.Strings.Unbounded;
-
-      Text     : Unbounded_String;
-      Need_Bar : Boolean := True;
-   begin
-      Indent_Line ("function Create_Parser");
-      Indent_Line ("  (Trace      : in WisiToken.Trace_Access;");
-      Indent_Line ("   User_Data  : in 
WisiToken.Syntax_Trees.User_Data_Access)");
-      Indent_Line ("  return WisiToken.Parse.Base_Parser'Class");
-
-      case Packrat_Generate_Algorithm'(Common_Data.Generate_Algorithm) is
-      when Packrat_Gen =>
-         Indent_Line ("is begin");
-         Indent := Indent + 3;
-         Indent_Line ("return Parser : 
WisiToken.Parse.Packrat.Generated.Parser do");
-         Indent := Indent + 3;
-         Indent_Line ("Parser.Tree.Lexer := Lexer.New_Lexer (Trace, " & 
Actions_Package_Name & ".Descriptor'Access);");
-         Indent_Line ("Parser.Productions := Create_Productions;");
-         Indent_Line ("Parser.User_Data := User_Data;");
-         Indent_Line ("Parser.Parse_WisiToken_Accept := 
Parse_wisitoken_accept_1'Access;");
-         Indent := Indent - 3;
-         Indent_Line ("end return;");
+      Descriptor : WisiToken.Descriptor renames Generate_Data.Descriptor.all;
 
-      when Packrat_Proc =>
-         Indent_Line ("is");
-         Indent := Indent + 3;
-         Indent_Line ("use WisiToken;");
-         Indent_Line ("use WisiToken.Productions;");
-         Indent_Line ("Grammar               : Prod_Arrays.Vector;");
+      procedure Put_Direct_Left_Recursive
+      is
+         use Ada.Strings.Unbounded;
+         Text     : Unbounded_String;
+         Need_Bar : Boolean := False;
+      begin
          Indent_Line
            ("Direct_Left_Recursive : constant WisiToken.Token_ID_Set (" &
               Trimmed_Image (Generate_Data.Grammar.First_Index) & " .. " &
               Trimmed_Image (Generate_Data.Grammar.Last_Index) & ") :=");
 
-         Need_Bar := False;
          if Any (Packrat_Data.Direct_Left_Recursive) then
             for I in Packrat_Data.Direct_Left_Recursive'Range loop
                if Packrat_Data.Direct_Left_Recursive (I) then
@@ -734,16 +802,60 @@ package body WisiToken.BNF.Output_Ada_Common is
          else
             Indent_Line ("  (others => False);");
          end if;
+      end Put_Direct_Left_Recursive;
+
+   begin
+      Indent_Line ("function Create_Parser");
+      Indent_Line ("  (Trace      : in WisiToken.Trace_Access;");
+      Indent_Line ("   User_Data  : in 
WisiToken.Syntax_Trees.User_Data_Access)");
+
+      case Packrat_Generate_Algorithm'(Common_Data.Generate_Algorithm) is
+      when Packrat_Gen =>
+         Indent_Line ("  return WisiToken.Parse.Packrat.Generated.Parser");
+         Indent_Line ("is");
+         Indent := @ + 3;
+         Indent := @ - 3;
+         Indent_Line ("begin");
+         Indent := Indent + 3;
+         Indent_Line
+           ("return Parser : WisiToken.Parse.Packrat.Generated.Parser (" &
+              Trimmed_Image (Descriptor.First_Nonterminal) & ", " &
+              Trimmed_Image (Descriptor.Last_Nonterminal) & ") do");
+         Indent := Indent + 3;
+         Indent_Line ("Parser.Tree.Lexer := Lexer.New_Lexer (Trace, " & 
Actions_Package_Name & ".Descriptor'Access);");
+         Indent_Line ("Parser.Productions := Create_Productions;");
+         Indent_Line ("Parser.User_Data := User_Data;");
+         Indent_Line ("Parser.Parse_WisiToken_Accept := 
Parse_wisitoken_accept'Access;");
+         Indent := Indent - 3;
+         Indent_Line ("end return;");
+
+      when Packrat_Proc =>
+         Indent_Line
+           ("  return WisiToken.Parse.Packrat.Procedural.Parser");
+         Indent_Line ("is");
+         Indent := Indent + 3;
+         Indent_Line ("use WisiToken;");
+         Indent_Line ("use WisiToken.Productions;");
+         Indent_Line ("Grammar               : Prod_Arrays.Vector;");
+         Put_Direct_Left_Recursive;
          Indent := Indent - 3;
          Indent_Line ("begin");
          Indent := Indent + 3;
          WisiToken.BNF.Generate_Grammar (Generate_Data.Grammar, 
Generate_Data.Action_Names.all);
 
-         Indent_Line ("return WisiToken.Parse.Packrat.Procedural.Create");
-         Indent_Line ("  (Grammar, Direct_Left_Recursive, " & Trimmed_Image 
(Generate_Data.Descriptor.Accept_ID) &
-                        ", Lexer.New_Lexer");
-         Indent_Line ("     (Trace, " & Actions_Package_Name & 
".Descriptor'Access),");
-         Indent_Line ("   Create_Productions, User_Data);");
+         Indent_Line
+           ("return Parser : WisiToken.Parse.Packrat.Procedural.Parser (" &
+              Trimmed_Image (Descriptor.First_Nonterminal) & ", " &
+              Trimmed_Image (Descriptor.Last_Nonterminal) & ") do");
+         Indent := Indent + 3;
+         Indent_Line ("Parser.Tree.Lexer := Lexer.New_Lexer (Trace, " & 
Actions_Package_Name & ".Descriptor'Access);");
+         Indent_Line ("Parser.Productions := Create_Productions;");
+         Indent_Line ("Parser.User_Data := User_Data;");
+         Indent_Line ("Parser.Grammar := Grammar;");
+         Indent_Line ("Parser.Direct_Left_Recursive := 
Direct_Left_Recursive;");
+         Indent_Line ("Parser.Start_ID := " & Trimmed_Image 
(Generate_Data.Descriptor.Accept_ID) & ";");
+         Indent := Indent - 3;
+         Indent_Line ("end return;");
       end case;
       Indent := Indent - 3;
       Indent_Line ("end Create_Parser;");
diff --git a/wisitoken-bnf-output_ada_common.ads 
b/wisitoken-bnf-output_ada_common.ads
index fd8eb284c2..005cfdcc94 100644
--- a/wisitoken-bnf-output_ada_common.ads
+++ b/wisitoken-bnf-output_ada_common.ads
@@ -65,14 +65,18 @@ package WisiToken.BNF.Output_Ada_Common is
       Input_Data           : in WisiToken_Grammar_Runtime.User_Data_Type);
 
    procedure LR_Create_Create_Parse_Table
-     (Input_Data           :         in     
WisiToken_Grammar_Runtime.User_Data_Type;
-      Common_Data          :         in out Output_Ada_Common.Common_Data;
-      Generate_Data        : aliased in     
WisiToken.BNF.Generate_Utils.Generate_Data;
-      Actions_Package_Name :         in     String);
+     (Input_Data    :         in     WisiToken_Grammar_Runtime.User_Data_Type;
+      Common_Data   :         in out Output_Ada_Common.Common_Data;
+      Generate_Data : aliased in     
WisiToken.BNF.Generate_Utils.Generate_Data);
    --  If not Common_Data.Text_Rep, includes LR parse table in generated
    --  source. Otherwise, includes call to LR.Get_Text_Rep; caller must
    --  call Put_Text_Rep to create file.
 
+   procedure LR_Create_Create_Parser
+     (Actions_Package_Name :         in     String;
+      Common_Data          :         in out Output_Ada_Common.Common_Data;
+      Generate_Data        : aliased in     
WisiToken.BNF.Generate_Utils.Generate_Data);
+
    procedure Packrat_Create_Create_Parser
      (Actions_Package_Name :         in     String;
       Common_Data          :         in out Output_Ada_Common.Common_Data;
diff --git a/wisitoken-bnf-output_ada_emacs.adb 
b/wisitoken-bnf-output_ada_emacs.adb
index 76357dfc79..7d386ae2e7 100644
--- a/wisitoken-bnf-output_ada_emacs.adb
+++ b/wisitoken-bnf-output_ada_emacs.adb
@@ -1655,14 +1655,11 @@ is
       Create (Body_File, Out_File, File_Name);
       Set_Output (Body_File);
       Indent := 1;
+
       Put_File_Header (Ada_Comment, Use_Tuple => True, Tuple => Tuple);
       Put_Raw_Code (Ada_Comment, Input_Data.Raw_Code (Copyright_License));
       New_Line;
 
-      if Input_Data.Action_Count > 0 or Input_Data.Check_Count > 0 then
-         Put_Line ("with " & Actions_Package_Name & "; use " & 
Actions_Package_Name & ";");
-      end if;
-
       case Common_Data.Lexer is
       when None | Tree_Sitter_Lexer =>
          null;
@@ -1676,15 +1673,22 @@ is
 
       case Common_Data.Generate_Algorithm is
       when LR_Generate_Algorithm =>
-         null;
+         if not Input_Data.Language_Params.Error_Recover then
+            Put_Line ("with WisiToken.Parse.LR;");
+         end if;
 
-      when Packrat_Generate_Algorithm =>
-         Put_Line ("with WisiToken.Parse;");
+      when Packrat_Proc =>
+         Put_Line ("with WisiToken.Productions;");
+
+      when Packrat_Gen =>
+         Put_Line ("with WisiToken.Parse.Packrat.Parser;");
 
       when External | Tree_Sitter =>
          null;
       end case;
 
+      Put_Line ("with " & Actions_Package_Name & "; use " & 
Actions_Package_Name & ";");
+
       Put_Line ("package body " & Main_Package_Name & " is");
       Indent := Indent + 3;
       New_Line;
@@ -1699,8 +1703,9 @@ is
 
       case Common_Data.Generate_Algorithm is
       when LR_Generate_Algorithm =>
-         LR_Create_Create_Parse_Table (Input_Data, Common_Data, Generate_Data, 
Actions_Package_Name);
+         LR_Create_Create_Parse_Table (Input_Data, Common_Data, Generate_Data);
          Create_Create_Productions (Generate_Data);
+         LR_Create_Create_Parser (Actions_Package_Name, Common_Data, 
Generate_Data);
 
       when Packrat_Gen =>
          WisiToken.BNF.Generate_Packrat (Packrat_Data, Generate_Data);
@@ -1713,6 +1718,7 @@ is
 
       when External =>
          External_Create_Create_Grammar (Generate_Data);
+
       when Tree_Sitter =>
          null;
       end case;
@@ -1720,6 +1726,7 @@ is
       case Common_Data.Interface_Kind is
       when Process =>
          null;
+
       when Module =>
          Indent_Line ("Parser : LR_Parser.Instance;");
          New_Line;
diff --git a/wisitoken-bnf.adb b/wisitoken-bnf.adb
index c5157ebf59..ee98bf4dbf 100644
--- a/wisitoken-bnf.adb
+++ b/wisitoken-bnf.adb
@@ -21,6 +21,7 @@ pragma License (GPL);
 with Ada.Command_Line;
 with Ada.Directories;
 with Ada.Environment_Variables;
+with Ada.Strings.Fixed;
 with Ada.Text_IO;
 package body WisiToken.BNF is
 
diff --git a/wisitoken-bnf.ads b/wisitoken-bnf.ads
index f7ccdb43f3..5275e2cc95 100644
--- a/wisitoken-bnf.ads
+++ b/wisitoken-bnf.ads
@@ -31,10 +31,8 @@ with Ada.Containers.Doubly_Linked_Lists;
 with Ada.Containers.Indefinite_Doubly_Linked_Lists;
 with Ada.Containers.Ordered_Maps;
 with Ada.Containers.Vectors;
-with Ada.Strings.Fixed;
 with Ada.Strings.Unbounded;
 with Ada.Unchecked_Deallocation;
-with System.Multiprocessors;
 with WisiToken.Parse.LR;
 with WisiToken.Syntax_Trees;
 package WisiToken.BNF is
@@ -129,17 +127,12 @@ package WisiToken.BNF is
       Tuple : in     Generate_Tuple);
 
    function Text_Rep_File_Name
-     (File_Name_Root      : in String;
-      Tuple               : in Generate_Tuple;
-      Generate_Task_Count : in System.Multiprocessors.CPU_Range;
-      If_Lexer_Present    : in Boolean;
-      Test_Main           : in Boolean)
+     (File_Name_Root   : in String;
+      Tuple            : in Generate_Tuple;
+      If_Lexer_Present : in Boolean)
      return String
    is (File_Name_Root & "_" &
          Ada.Characters.Handling.To_Lower (Generate_Algorithm_Image 
(Tuple.Gen_Alg).all) &
-         (if Tuple.Gen_Alg = LR1 and Test_Main
-          then "_t" & Ada.Strings.Fixed.Trim (Generate_Task_Count'Image, 
Ada.Strings.Both)
-          else "") &
          (if If_Lexer_Present
           then "_" & Lexer_Image (Tuple.Lexer).all
           else "") &
@@ -158,9 +151,8 @@ package WisiToken.BNF is
       Declare_Enums             : Boolean  := True;
       End_Names_Optional_Option : Ada.Strings.Unbounded.Unbounded_String;
       Error_Recover             : Boolean  := False; -- True if grammar 
specifies error recover parameters.
-      LR1_Hash_Table_Size       : Positive := 113; --  Should match 
sal-gen_unbounded_definite_hash_tables.ads
       Language_Runtime_Name     : Ada.Strings.Unbounded.Unbounded_String;
-      Partial_Recursion         : Boolean  := False;
+      Recursion_Strategy        : WisiToken.Recursion_Strategy := Full;
       Start_Token               : Ada.Strings.Unbounded.Unbounded_String;
       Use_Language_Runtime      : Boolean  := True;
    end record;
diff --git a/wisitoken-generate-lr-lalr_generate.adb 
b/wisitoken-generate-lr-lalr_generate.adb
index 5f971dd103..358ab85d33 100644
--- a/wisitoken-generate-lr-lalr_generate.adb
+++ b/wisitoken-generate-lr-lalr_generate.adb
@@ -479,13 +479,14 @@ package body WisiToken.Generate.LR.LALR_Generate is
      (Grammar               : in out WisiToken.Productions.Prod_Arrays.Vector;
       Descriptor            : in     WisiToken.Descriptor;
       Grammar_File_Name     : in     String;
+      Error_Recover         : in     Boolean;
       Known_Conflicts       : in     Conflict_Lists.Tree := 
Conflict_Lists.Empty_Tree;
       McKenzie_Param        : in     McKenzie_Param_Type := 
Default_McKenzie_Param;
       Max_Parallel          : in     SAL.Base_Peek_Type  := 15;
       Parse_Table_File_Name : in     String              := "";
       Include_Extra         : in     Boolean             := False;
       Ignore_Conflicts      : in     Boolean             := False;
-      Partial_Recursion     : in     Boolean             := True;
+      Recursion_Strategy    : in     WisiToken.Recursion_Strategy := Full;
       Use_Cached_Recursions : in     Boolean             := False;
       Recursions            : in out WisiToken.Generate.Recursions)
      return Parse_Table_Ptr
@@ -524,10 +525,17 @@ package body WisiToken.Generate.LR.LALR_Generate is
 
    begin
       if not Use_Cached_Recursions or Recursions = Empty_Recursions then
-         Recursions :=
-           (if Partial_Recursion
-            then WisiToken.Generate.Compute_Partial_Recursion (Grammar, 
Descriptor)
-            else WisiToken.Generate.Compute_Full_Recursion (Grammar, 
Descriptor));
+         case Recursion_Strategy is
+         when None =>
+            null;
+
+         when Partial =>
+            Recursions := WisiToken.Generate.Compute_Partial_Recursion 
(Grammar, Descriptor);
+
+         when Full =>
+            Recursions := WisiToken.Generate.Compute_Full_Recursion (Grammar, 
Descriptor);
+
+         end case;
       end if;
       Set_Grammar_Recursions (Recursions, Grammar);
       Recursions_Time := Ada.Calendar.Clock;
@@ -566,6 +574,8 @@ package body WisiToken.Generate.LR.LALR_Generate is
          First_Nonterminal => Descriptor.First_Nonterminal,
          Last_Nonterminal  => Descriptor.Last_Nonterminal);
 
+      Table.Error_Recover_Enabled := Error_Recover;
+
       if McKenzie_Param = Default_McKenzie_Param then
          --  Descriminants in Default are wrong
          Table.McKenzie_Param :=
@@ -586,11 +596,8 @@ package body WisiToken.Generate.LR.LALR_Generate is
             Check_Delta_Limit           => 
Default_McKenzie_Param.Check_Delta_Limit,
             Enqueue_Limit               => 
Default_McKenzie_Param.Enqueue_Limit);
 
-         Table.Error_Recover_Enabled := False;
-
       else
-         Table.McKenzie_Param        := McKenzie_Param;
-         Table.Error_Recover_Enabled := True;
+         Table.McKenzie_Param := McKenzie_Param;
       end if;
 
       Table.Max_Parallel := Max_Parallel;
diff --git a/wisitoken-generate-lr-lalr_generate.ads 
b/wisitoken-generate-lr-lalr_generate.ads
index b2b3fef5a0..ce4115b7c4 100644
--- a/wisitoken-generate-lr-lalr_generate.ads
+++ b/wisitoken-generate-lr-lalr_generate.ads
@@ -2,7 +2,7 @@
 --
 --  Generalized LALR parse table generator.
 --
---  Copyright (C) 2002 - 2003, 2009 - 2010, 2013 - 2015, 2017 - 2020 Free 
Software Foundation, Inc.
+--  Copyright (C) 2002 - 2003, 2009 - 2010, 2013 - 2015, 2017 - 2020, 2022 
Free Software Foundation, Inc.
 --
 --  This file is part of the WisiToken package.
 --
@@ -28,14 +28,15 @@ package WisiToken.Generate.LR.LALR_Generate is
      (Grammar               : in out WisiToken.Productions.Prod_Arrays.Vector;
       Descriptor            : in     WisiToken.Descriptor;
       Grammar_File_Name     : in     String;
-      Known_Conflicts       : in     Conflict_Lists.Tree := 
Conflict_Lists.Empty_Tree;
-      McKenzie_Param        : in     McKenzie_Param_Type := 
Default_McKenzie_Param;
-      Max_Parallel          : in     SAL.Base_Peek_Type  := 15;
-      Parse_Table_File_Name : in     String              := "";
-      Include_Extra         : in     Boolean             := False;
-      Ignore_Conflicts      : in     Boolean             := False;
-      Partial_Recursion     : in     Boolean             := True;
-      Use_Cached_Recursions : in     Boolean             := False;
+      Error_Recover         : in     Boolean;
+      Known_Conflicts       : in     Conflict_Lists.Tree          := 
Conflict_Lists.Empty_Tree;
+      McKenzie_Param        : in     McKenzie_Param_Type          := 
Default_McKenzie_Param;
+      Max_Parallel          : in     SAL.Base_Peek_Type           := 15;
+      Parse_Table_File_Name : in     String                       := "";
+      Include_Extra         : in     Boolean                      := False;
+      Ignore_Conflicts      : in     Boolean                      := False;
+      Recursion_Strategy    : in     WisiToken.Recursion_Strategy := Full;
+      Use_Cached_Recursions : in     Boolean                      := False;
       Recursions            : in out WisiToken.Generate.Recursions)
      return Parse_Table_Ptr
    with Pre =>
diff --git a/wisitoken-generate-lr-lr1_generate.adb 
b/wisitoken-generate-lr-lr1_generate.adb
index bba1176feb..2226fc2d25 100644
--- a/wisitoken-generate-lr-lr1_generate.adb
+++ b/wisitoken-generate-lr-lr1_generate.adb
@@ -22,9 +22,8 @@ pragma License (Modified_GPL);
 
 with Ada.Calendar;
 with Ada.Containers;
-with Ada.Exceptions;
 with Ada.Text_IO;
-with System.Address_To_Access_Conversions;
+with WisiToken.Generate.LR1_Items;
 package body WisiToken.Generate.LR.LR1_Generate is
 
    function LR1_Goto_Transitions
@@ -68,7 +67,7 @@ package body WisiToken.Generate.LR.LR1_Generate is
       return Closure (Goto_Set, Has_Empty_Production, First_Terminal_Sequence, 
Grammar, Descriptor);
    end LR1_Goto_Transitions;
 
-   function LR1_Item_Sets_Single
+   function LR1_Item_Sets
      (Has_Empty_Production    : in Token_ID_Set;
       First_Terminal_Sequence : in Token_Sequence_Arrays.Vector;
       Grammar                 : in WisiToken.Productions.Prod_Arrays.Vector;
@@ -197,618 +196,7 @@ package body WisiToken.Generate.LR.LR1_Generate is
       end if;
 
       return C;
-   end LR1_Item_Sets_Single;
-
-   function LR1_Item_Sets_Parallel
-     (Has_Empty_Production    : in Token_ID_Set;
-      First_Terminal_Sequence : in Token_Sequence_Arrays.Vector;
-      Grammar                 : in WisiToken.Productions.Prod_Arrays.Vector;
-      Descriptor              : in WisiToken.Descriptor;
-      Task_Count              : in System.Multiprocessors.CPU_Range;
-      Hash_Table_Size         : in Positive := 
LR1_Items.Item_Set_Trees.Default_Rows)
-     return LR1_Items.Item_Set_List
-   is
-      use LR1_Items;
-      use all type Ada.Containers.Count_Type;
-      use all type SAL.Base_Peek_Type;
-      use all type System.Multiprocessors.CPU_Range;
-
-      --  [dragon] algorithm 4.9 pg 231; figure 4.38 pg 232; procedure
-      --  "items", with some optimizations.
-
-      type Base_Worker_ID is range 0 .. Positive'Last;
-      subtype Worker_ID is Base_Worker_ID range 1 .. Base_Worker_ID'Last;
-
-      package Item_Set_Tree_Node_Arrays is new 
SAL.Gen_Unbounded_Definite_Vectors
-        (Positive, Item_Set_Tree_Node, (others => <>));
-
-      package Worker_Array_State_Index_Arrays is new 
SAL.Gen_Unbounded_Definite_Vectors
-        (Worker_ID, State_Index_Arrays.Vector, 
State_Index_Arrays.Empty_Vector);
-
-      type Worker_Data is record
-         --  All data produced by one worker from one state, except New_C,
-         --  which doesn't need to be split by supervisor state.
-         From_State          : State_Index := State_Index'Last;
-         New_States          : State_Index_Arrays.Vector;
-         Existing_Goto_Items : Goto_Item_Arrays.Vector;
-         New_Goto_Items      : Goto_Item_Arrays.Vector;
-      end record;
-
-      package State_Array_Worker_Data is new SAL.Gen_Unbounded_Definite_Vectors
-        (State_Index, Worker_Data, (others => <>));
-
-      protected Supervisor is
-
-         procedure Initialize
-           (Worker_Count   : in     LR1_Item_Sets_Parallel.Worker_ID;
-            First_Item_Set : in out Item_Set);
-
-         entry Get
-           (Worker_ID     : in     LR1_Item_Sets_Parallel.Worker_ID;
-            Sets_To_Check :    out Item_Set_List;
-            Keys_To_Store :    out Item_Set_Tree_Node_Arrays.Vector)
-         with Pre => Sets_To_Check.Is_Empty and Keys_To_Store.Is_Empty;
-         --  Set Sets_To_Check to new states to check, _not_ indexed by state;
-         --  they may be discontinuous. Available when there are states to
-         --  check, or when all states have been checked and all workers are
-         --  inactive; then Sets_To_Check is empty.
-         --
-         --  If Sets_To_Check is not empty, Keys_To_Store contains keys from
-         --  other workers to store in worker's C_Tree; increment active worker
-         --  count.
-
-         procedure Update
-           (Worker_ID   : in     LR1_Item_Sets_Parallel.Worker_ID;
-            New_C       : in out Item_Set_Arrays.Vector;
-            Worker_Data : in out State_Array_Worker_Data.Vector);
-         --  New_C: New states found by worker, indexed by worker new state
-         --  number (1 origin); add to supervisor C. States are updated to 
supervisor
-         --  state numbers; worker should add those to worker's C_Tree.
-         --
-         --  Worker_Data : Indexed by supervisor state number I. Contains:
-         --
-         --     New_States: Worker new state numbers for states derived from C 
(I);
-         --  sets are in New_C.
-         --
-         --     Existing_Goto_Items: Gotos from C (I) to some state in 
supervisor
-         --  C (which worker found in C_Tree); add to supervisor C (I).
-         --
-         --     New_Goto_Items: From C (I) to some state in New_C (given by
-         --  worker new state number). Add to supervisor C (I).
-         --
-         --  Decrement active worker count.
-
-         procedure Fatal_Error
-           (Exception_ID : in Ada.Exceptions.Exception_Id;
-            Message      : in String);
-         --  Worker encountered an exception; record it for Done, decrement
-         --  active worker count.
-
-         entry Done
-           (ID      : out Ada.Exceptions.Exception_Id;
-            Message : out Ada.Strings.Unbounded.Unbounded_String);
-         --  Available when all states have been checked, and all workers
-         --  inactive.
-
-         function Get_C return Item_Set_List;
-
-      private
-         C               : Item_Set_List; -- result
-         C_Tree          : Item_Set_Tree; -- for fast find
-         States_To_Check : State_Index_Queues.Queue;
-         --  [dragon] specifies 'until no more items can be added', but we use
-         --  a queue to avoid checking unecessary states. Ada LR1 has over
-         --  100,000 states, so this is a significant gain (reduced time from
-         --  600 seconds to 40).
-
-         Worker_Count   : LR1_Item_Sets_Parallel.Worker_ID;
-         Active_Workers : Natural := 0;
-         Fatal          : Boolean := False;
-
-         New_States_For_Worker : Worker_Array_State_Index_Arrays.Vector;
-         --  Indexed by worker ID
-
-         Error_ID       : Ada.Exceptions.Exception_Id := 
Ada.Exceptions.Null_Id;
-         Error_Message  : Ada.Strings.Unbounded.Unbounded_String;
-
-         Min_States_Get      : SAL.Peek_Type := 10;
-
-         Net_Time            : Duration    := 0.0; -- Time spent in Get, 
Update.
-         Found_States        : Integer     := 0;   -- States found in Update; 
counts duplicate states found by workers
-         Summary_Last_Output : State_Index := 0;
-      end Supervisor;
-
-      function Image (Node_Ref : Item_Set_Trees.Variable_Reference_Type) 
return String
-      is
-         package Convert is new System.Address_To_Access_Conversions 
(Item_Set_Tree_Node);
-      begin
-         return Convert.To_Address (Convert.Object_Pointer (Node_Ref))'Image & 
":" &
-           Node_Ref.Hash'Image & ":" & Node_Ref.State'Image;
-      end Image;
-
-      protected body Supervisor is
-
-         procedure Initialize
-           (Worker_Count   : in     LR1_Item_Sets_Parallel.Worker_ID;
-            First_Item_Set : in out Item_Set)
-         is
-            First_State_Index : constant State_Index       := 
First_Item_Set.Tree_Node.State;
-         begin
-            Supervisor.Worker_Count := Worker_Count;
-
-            New_States_For_Worker.Set_First_Last (1, Worker_Count);
-
-            C.Set_First_Last (First_State_Index, First_State_Index - 1);
-            C_Tree.Set_Rows (Hash_Table_Size);
-
-            First_Item_Set.Dot_IDs := Get_Dot_IDs (Grammar, 
First_Item_Set.Set, Descriptor);
-            Compute_Key_Hash (First_Item_Set, C_Tree.Rows, Grammar, 
Descriptor, True);
-
-            C.Append (First_Item_Set);
-            C_Tree.Insert (First_Item_Set.Tree_Node, Duplicate => SAL.Error);
-
-            States_To_Check.Put (First_State_Index);
-         end Initialize;
-
-         entry Get
-           (Worker_ID     : in     LR1_Item_Sets_Parallel.Worker_ID;
-            Sets_To_Check :    out Item_Set_List;
-            Keys_To_Store :    out Item_Set_Tree_Node_Arrays.Vector)
-         when Fatal or States_To_Check.Length > 0 or Active_Workers = 0
-         is
-            use all type Ada.Calendar.Time;
-
-            Time_Start : constant Ada.Calendar.Time := Ada.Calendar.Clock;
-         begin
-            if States_To_Check.Length > 0 then
-               for I in 1 ..
-                 (if States_To_Check.Length / SAL.Peek_Type (Worker_Count) < 
Min_States_Get
-                  then States_To_Check.Length
-                  else States_To_Check.Length / SAL.Peek_Type (Worker_Count))
-               loop
-                  Sets_To_Check.Append (C (States_To_Check.Get));
-               end loop;
-
-               if not New_States_For_Worker (Worker_ID).Is_Empty then
-                  Keys_To_Store.Set_Capacity
-                    (New_States_For_Worker (Worker_ID).First_Index, 
New_States_For_Worker (Worker_ID).Last_Index);
-                  for State of New_States_For_Worker (Worker_ID) loop
-                     pragma Assert (C (State).Tree_Node.State = State);
-                     Keys_To_Store.Append (C (State).Tree_Node);
-                  end loop;
-                  New_States_For_Worker (Worker_ID).Clear;
-               end if;
-
-               if Trace_Generate_Table > Detail then
-                  Ada.Text_IO.Put
-                    ("(worker" & Worker_ID'Image & ") Checking" & 
Sets_To_Check.Length'Image & " states");
-                  for Set of Sets_To_Check loop
-                     Ada.Text_IO.Put (Set.Tree_Node.State'Image);
-                  end loop;
-                  Ada.Text_IO.New_Line;
-                  if Trace_Generate_Table > Extra then
-                     for Set of Sets_To_Check loop
-                        Put (Grammar, Descriptor, Set, Show_Lookaheads => 
False, Kernel_Only => True);
-                     end loop;
-                  end if;
-
-                  Ada.Text_IO.Put
-                    ("(worker" & Worker_ID'Image & ") storing" & 
Keys_To_Store.Length'Image & " states");
-                  for Node of Keys_To_Store loop
-                     Ada.Text_IO.Put (Node.State'Image);
-                  end loop;
-                  Ada.Text_IO.New_Line;
-               end if;
-
-               Active_Workers := @ + 1;
-
-               Net_Time := @ + (Ada.Calendar.Clock - Time_Start);
-            end if;
-
-            if Trace_Time and C.Last_Index > Summary_Last_Output +
-              (if C_Tree.Rows < 15_053 then 500 else 10_000) --  500 for 
ada_lite.wy, 10_000 for ada.wy
-            then
-               Ada.Text_IO.Put_Line
-                 ("(super) time:" & Net_Time'Image &
-                    " states:" & C.Last_Index'Image &
-                    " States_To_Check:" & States_To_Check.Length'Image &
-                    " Found_States:" & Found_States'Image);
-               Summary_Last_Output := C.Last_Index;
-            end if;
-         end Get;
-
-         procedure Update
-           (Worker_ID   : in     LR1_Item_Sets_Parallel.Worker_ID;
-            New_C       : in out Item_Set_Arrays.Vector;
-            Worker_Data : in out State_Array_Worker_Data.Vector)
-         is
-            use all type Ada.Calendar.Time;
-            Time_Start : constant Ada.Calendar.Time := Ada.Calendar.Clock;
-
-            State_Map : array (New_C.First_Index .. New_C.Last_Index) of 
State_Index;
-            --  Indexed by worker new state number, contains super state number
-         begin
-            if Trace_Generate_Table > Detail then
-               Ada.Text_IO.Put ("(super) Update from worker" & Worker_ID'Image 
& "; new states:");
-               for Data of Worker_Data loop
-                  for Node of Data.New_Goto_Items loop
-                     Ada.Text_IO.Put
-                       (Data.From_State'Image & "." & Image (Node.Symbol, 
Descriptor) & "." &
-                          Trimmed_Image (Node.State));
-                  end loop;
-                  Ada.Text_IO.Put (" | ");
-               end loop;
-               Ada.Text_IO.New_Line;
-            end if;
-
-            for Worker_Data of Update.Worker_Data loop
-               for Worker_New_State of Worker_Data.New_States loop
-                  declare
-                     use Item_Set_Trees;
-
-                     Super_New_State  : constant State_Index := C.Last_Index + 
1;
-
-                     Found      : Boolean;
-                     Found_Ref  : constant 
Item_Set_Trees.Variable_Reference_Type := C_Tree.Find_Or_Insert_Var
-                       (New_C (Worker_New_State).Tree_Node, Found);
-                  begin
-                     if Found then
-                        State_Map (Worker_New_State) := Found_Ref.State;
-                        Found_States := @ + 1;
-                        New_C (Worker_New_State).Tree_Node.State := 
Found_Ref.State;
-
-                     else
-                        Found_Ref.State := Super_New_State;
-                        New_C (Worker_New_State).Tree_Node.State := 
Super_New_State;
-
-                        States_To_Check.Put (Super_New_State);
-
-                        State_Map (Worker_New_State) := Super_New_State;
-
-                        C.Append (New_C (Worker_New_State));
-                        pragma Assert (C.Last_Index = Super_New_State);
-
-                        for ID in New_States_For_Worker.First_Index .. 
New_States_For_Worker.Last_Index  loop
-                           if ID /= Worker_ID then
-                              New_States_For_Worker (ID).Append 
(Super_New_State);
-                           end if;
-                        end loop;
-
-                        if Trace_Generate_Table > Extra then
-                           Ada.Text_IO.Put_Line
-                             ("from state" & Worker_Data.From_State'Image & 
"." & Trimmed_Image (Worker_New_State));
-                           Put (Grammar, Descriptor, New_C (Worker_New_State),
-                                Show_Lookaheads => False,
-                                Kernel_Only  => True);
-                        end if;
-                     end if;
-                  end;
-               end loop;
-
-               --  Now we have State_Map, we can process the gotos.
-               declare
-                  use Goto_Item_Lists;
-                  From_State : constant State_Index := Worker_Data.From_State;
-               begin
-                  for Item of Worker_Data.Existing_Goto_Items loop
-                     if Trace_Generate_Table > Extra and then
-                       not Has_Element (C (From_State).Goto_List.Find 
(Item.Symbol))
-                     then
-                        Ada.Text_IO.Put_Line
-                          ("    state" & From_State'Image & " adding goto on " 
&
-                             Image (Item.Symbol, Descriptor) & " to existing 
state" & Item.State'Image);
-                     end if;
-
-                     C (From_State).Goto_List.Insert (Item, Duplicate => 
SAL.Ignore);
-                  end loop;
-
-                  for Item of Worker_Data.New_Goto_Items loop
-                     Item.State := State_Map (Item.State);
-
-                     if Trace_Generate_Table > Extra and then
-                       not Goto_Item_Lists.Has_Element
-                         (C (From_State).Goto_List.Find (Item.Symbol))
-                     then
-                        Ada.Text_IO.Put_Line
-                          ("    state" & From_State'Image & " adding goto on " 
&
-                             Image (Item.Symbol, Descriptor) & " to new state" 
& Item.State'Image);
-                     end if;
-
-                     C (From_State).Goto_List.Insert (Item, Duplicate => 
SAL.Ignore);
-                  end loop;
-               end;
-            end loop;
-
-            Active_Workers := @ - 1;
-
-            Net_Time := @ + (Ada.Calendar.Clock - Time_Start);
-         exception
-         when E : others =>
-
-            Active_Workers := @ - 1;
-            Fatal          := True;
-            States_To_Check.Clear; -- force an early end.
-            declare
-               use Ada.Text_IO;
-               use Ada.Exceptions;
-            begin
-               Error_ID       := Exception_Identity (E);
-               Error_Message  := +Exception_Message (E);
-               Put_Line
-                 (Standard_Error, "(super) Update exception: " & 
Exception_Name (E) & ": " & Exception_Message (E));
-            end;
-         end Update;
-
-         procedure Fatal_Error
-           (Exception_ID : in Ada.Exceptions.Exception_Id;
-            Message      : in String)
-         is begin
-            Supervisor.Error_ID      := Exception_ID;
-            Supervisor.Error_Message := +Message;
-
-            States_To_Check.Clear; -- force an early end.
-            Fatal          := True;
-            Active_Workers := @ - 1;
-         end Fatal_Error;
-
-         entry Done
-           (ID      : out Ada.Exceptions.Exception_Id;
-            Message : out Ada.Strings.Unbounded.Unbounded_String)
-         when Fatal or (Active_Workers = 0 and States_To_Check.Is_Empty)
-         is begin
-            if Trace_Time then
-               Ada.Text_IO.Put_Line
-                 ("(super) net time:" & Net_Time'Image &
-                    " states:" & C.Last_Index'Image &
-                    " States_To_Check:" & States_To_Check.Length'Image &
-                    " Found_States:" & Found_States'Image);
-            end if;
-
-            ID      := Supervisor.Error_ID;
-            Message := Supervisor.Error_Message;
-         end Done;
-
-         function Get_C return Item_Set_List
-         is begin
-            return C;
-         end Get_C;
-
-      end Supervisor;
-
-      task type Worker_Task
-      is
-         entry Start (ID : in LR1_Item_Sets_Parallel.Worker_ID);
-         --  Start states from Supervisor. Stop when Supervisor returns
-         --  Invalid_State_Index;
-      end Worker_Task;
-
-      task body Worker_Task
-      is
-         use all type Ada.Calendar.Time;
-
-         ID : LR1_Item_Sets_Parallel.Worker_ID;
-
-         Time_Start     : Ada.Calendar.Time;
-         Net_Time       : Duration := 0.0; --  Time spent outside Supervisor
-         States_Checked : Integer  := 0;
-         States_Found   : Integer  := 0;
-
-         C_Tree : Item_Set_Tree;          -- Local copy for fast find
-         C      : Item_Set_Arrays.Vector; -- Local copy of subset of C to 
search; from Supervisor
-
-         Local_New_State : State_Index := 1;
-
-         --  See Supervisor Get, Update for definitions of these.
-         New_C       : Item_Set_Arrays.Vector;
-         New_C_Tree  : Item_Set_Tree;
-         Worker_Data : State_Array_Worker_Data.Vector;
-
-         procedure Check_State (C_Index : in State_Index)
-         is
-            C_I : Item_Set renames C (C_Index);
-            Worker_Data : LR1_Item_Sets_Parallel.Worker_Data renames 
Worker_Task.Worker_Data (C_Index);
-         begin
-            States_Checked := @ + 1;
-            Worker_Data.From_State := C_I.Tree_Node.State;
-            Worker_Data.New_States.Clear;
-            Worker_Data.Existing_Goto_Items.Clear;
-            Worker_Data.New_Goto_Items.Clear;
-
-            for Dot_ID_I in C_I.Dot_IDs.First_Index .. C_I.Dot_IDs.Last_Index 
loop
-               --  [dragon] has 'for each grammar symbol X', but 
LR1_Goto_Transitions
-               --  rejects Symbol that is not in Dot_IDs, so we iterate over 
that.
-
-               declare
-                  Symbol       : Token_ID renames C_I.Dot_IDs (Dot_ID_I);
-                  New_Item_Set : Item_Set := LR1_Goto_Transitions
-                    (C_I, Symbol, Has_Empty_Production, 
First_Terminal_Sequence, Grammar, Descriptor);
-               begin
-                  Compute_Key_Hash (New_Item_Set, C_Tree.Rows, Grammar, 
Descriptor, True);
-                  declare
-                     use Item_Set_Trees;
-
-                     --  First search in Worker.C_Tree
-                     Found_Cur : Cursor := C_Tree.Find 
(New_Item_Set.Tree_Node);
-
-                     Found_State : constant Unknown_State_Index :=
-                       (if Has_Element (Found_Cur)
-                        then C_Tree.Constant_Ref (Found_Cur).State
-                        else Unknown_State);
-                  begin
-                     if Found_State = Unknown_State then
-                        Found_Cur := New_C_Tree.Find (New_Item_Set.Tree_Node);
-
-                        if Has_Element (Found_Cur) then
-                           --  Local_New_State was previously generated from 
some other state we
-                           --  are checking.
-                           Worker_Data.New_Goto_Items.Append ((Symbol, 
C_Tree.Constant_Ref (Found_Cur).State));
-
-                        else
-                           Worker_Data.New_Goto_Items.Append ((Symbol, 
Local_New_State));
-
-                           New_Item_Set.Tree_Node.State := Local_New_State;
-                           New_Item_Set.Dot_IDs := Get_Dot_IDs (Grammar, 
New_Item_Set.Set, Descriptor);
-                           New_C.Append (New_Item_Set);
-                           pragma Assert (New_C.Last_Index = Local_New_State);
-                           Worker_Data.New_States.Append (Local_New_State);
-
-                           New_C_Tree.Insert (New_Item_Set.Tree_Node, 
Duplicate => SAL.Error);
-
-                           Local_New_State := Local_New_State + 1;
-                        end if;
-                     else
-                        States_Found := @ + 1;
-                        pragma Assert (C_I.Goto_List.Count = 0);
-                        Worker_Data.Existing_Goto_Items.Append ((Symbol, 
Found_State));
-                        if Trace_Generate_Table > Extra then
-                           Ada.Text_IO.Put_Line
-                             ("(worker" & ID'Image & ")  state" & 
Worker_Data.From_State'Image & " adding goto on " &
-                                Image (Symbol, Descriptor) & " to existing 
state" & Image
-                                  (C_Tree.Variable_Ref (Found_Cur)));
-                        end if;
-                     end if;
-                  end;
-               end;
-            end loop;
-         end Check_State;
-      begin
-         select
-            accept Start (ID : in LR1_Item_Sets_Parallel.Worker_ID)
-
-            do
-               Worker_Task.ID := ID;
-            end Start;
-         or
-            terminate;
-         end select;
-
-         C_Tree.Set_Rows (Hash_Table_Size);
-         New_C_Tree.Set_Rows (Hash_Table_Size);
-
-         loop
-            declare
-               Keys_To_Store : Item_Set_Tree_Node_Arrays.Vector;
-            begin
-               Supervisor.Get (ID, C, Keys_To_Store);
-               exit when C.Length = 0;
-
-               Time_Start := Ada.Calendar.Clock;
-
-               for Set of C loop
-                  --  C are all new states to check, but they may
-                  --  have been in a previous Keys_To_Store.
-                  C_Tree.Insert (Set.Tree_Node, Duplicate => SAL.Ignore);
-               end loop;
-               for Node of Keys_To_Store loop
-                  --  States are added to Keys_To_Store when they are new in
-                  --  Supervisor.C_Tree, before they are given to any worker 
to check;
-                  --  they may also be in C
-                  C_Tree.Insert (Node, Duplicate => SAL.Ignore);
-               end loop;
-            end;
-
-            Local_New_State := 1;
-            New_C.Set_First_Last (First => Local_New_State, Last => 
Local_New_State - 1);
-            New_C_Tree.Clear; -- IMPROVEME: new_c_tree red_black should use 
vector store, not allocate each node
-
-            Worker_Data.Set_First_Last (C.First_Index, C.Last_Index);
-
-            for I in C.First_Index .. C.Last_Index loop
-               Check_State (I);
-            end loop;
-            C.Clear;
-
-            Net_Time := @ + (Ada.Calendar.Clock - Time_Start);
-            Supervisor.Update (ID, New_C, Worker_Data);
-            Time_Start := Ada.Calendar.Clock;
-
-            --  New_C.Tree_Node.State updated; insert into C_Tree.
-            for Item of New_C loop
-               C_Tree.Insert (Item.Tree_Node, Duplicate => SAL.Error);
-            end loop;
-            Net_Time := @ + (Ada.Calendar.Clock - Time_Start);
-         end loop;
-
-         if Trace_Time then
-            declare
-               Elements, Max_Row_Depth, Average_Row_Depth : 
Ada.Containers.Count_Type;
-               Rows, Empty_Rows : Integer;
-            begin
-               C_Tree.Sizes (Elements, Rows, Max_Row_Depth, Average_Row_Depth, 
Empty_Rows);
-
-               Ada.Text_IO.Put_Line
-                 ("(worker" & ID'Image & ") net time" & Net_Time'Image &
-                    " states checked:" & States_Checked'Image & " states 
found:" & States_Found'Image &
-                    " hash table states:" & Elements'Image &
-                    " rows:" & Rows'Image &
-                    " max_row_depth:" & Max_Row_Depth'Image &
-                    " average_row_depth:" & Average_Row_Depth'Image &
-                    " empty_rows:" & Empty_Rows'Image);
-            end;
-         end if;
-
-         if Trace_Generate_Table > Outline then
-            Ada.Text_IO.Put_Line ("(worker" & ID'Image & ") terminate");
-         end if;
-      exception
-      when E : others =>
-         Supervisor.Fatal_Error (Ada.Exceptions.Exception_Identity (E), 
Ada.Exceptions.Exception_Message (E));
-         if Trace_Generate_Table > Outline then
-            Ada.Text_IO.Put_Line ("(worker" & ID'Image & ") terminate on 
exception");
-         end if;
-      end Worker_Task;
-
-      Worker_Tasks : array
-        (1 .. System.Multiprocessors.CPU_Range'Min
-         (Task_Count,
-         System.Multiprocessors.CPU_Range'Max (1, 
System.Multiprocessors.Number_Of_CPUs)))
-        of Worker_Task;
-
-      First_State_Index : constant State_Index := 0;
-
-      First_Item_Set : Item_Set := Closure
-        ((Set            => Item_Lists.To_List
-            ((Prod       => (Grammar.First_Index, 0),
-              Dot        => Grammar (Grammar.First_Index).RHSs 
(0).Tokens.First_Index,
-              Lookaheads => To_Lookahead (Descriptor.EOI_ID))),
-          Tree_Node      =>
-            (State       => First_State_Index,
-             others      => <>),
-          others         => <>),
-         Has_Empty_Production, First_Terminal_Sequence, Grammar, Descriptor);
-   begin
-      Supervisor.Initialize (LR1_Item_Sets_Parallel.Worker_ID 
(Worker_Tasks'Last), First_Item_Set);
-
-      if Trace_Generate_Table > Outline then
-         Ada.Text_IO.Put_Line (Worker_Tasks'Length'Image & " lr1_items worker 
tasks");
-      end if;
-
-      for I in Worker_Tasks'Range loop
-         Worker_Tasks (I).Start (LR1_Item_Sets_Parallel.Worker_ID (I));
-      end loop;
-
-      declare
-         use Ada.Exceptions;
-         ID      : Exception_Id;
-         Message : Ada.Strings.Unbounded.Unbounded_String;
-      begin
-         Supervisor.Done (ID, Message); -- Wait for all states to be checked
-
-         if ID /= Null_Id then
-            for I in Worker_Tasks'Range loop
-               if not Worker_Tasks (I)'Terminated then
-                  abort Worker_Tasks (I);
-               end if;
-            end loop;
-            Raise_Exception (ID, -Message);
-         else
-            if Trace_Generate_Table > Outline then
-               Ada.Text_IO.Put_Line ("super reports done");
-            end if;
-         end if;
-      end;
-      return Supervisor.Get_C;
-   end LR1_Item_Sets_Parallel;
+   end LR1_Item_Sets;
 
    procedure Add_Actions
      (Item_Sets          : in     LR1_Items.Item_Set_List;
@@ -838,21 +226,18 @@ package body WisiToken.Generate.LR.LR1_Generate is
      (Grammar               : in out WisiToken.Productions.Prod_Arrays.Vector;
       Descriptor            : in     WisiToken.Descriptor;
       Grammar_File_Name     : in     String;
+      Error_Recover         : in     Boolean;
       Known_Conflicts       : in     Conflict_Lists.Tree              := 
Conflict_Lists.Empty_Tree;
       McKenzie_Param        : in     McKenzie_Param_Type              := 
Default_McKenzie_Param;
       Max_Parallel          : in     SAL.Base_Peek_Type               := 15;
       Parse_Table_File_Name : in     String                           := "";
       Include_Extra         : in     Boolean                          := False;
       Ignore_Conflicts      : in     Boolean                          := False;
-      Partial_Recursion     : in     Boolean                          := True;
-      Task_Count            : in     System.Multiprocessors.CPU_Range := 1;
-      Hash_Table_Size       : in     Positive                         := 
LR1_Items.Item_Set_Trees.Default_Rows;
+      Recursion_Strategy    : in     WisiToken.Recursion_Strategy     := Full;
       Use_Cached_Recursions : in     Boolean                          := False;
       Recursions            : in out WisiToken.Generate.Recursions)
      return Parse_Table_Ptr
    is
-      use all type System.Multiprocessors.CPU_Range;
-
       Time_Start            : constant Ada.Calendar.Time := Ada.Calendar.Clock;
       Add_Actions_Time      : Ada.Calendar.Time;
       Minimal_Actions_Time  : Ada.Calendar.Time;
@@ -881,13 +266,8 @@ package body WisiToken.Generate.LR.LR1_Generate is
       First_Terminal_Sequence : constant Token_Sequence_Arrays.Vector :=
         WisiToken.Generate.To_Terminal_Sequence_Array (First_Nonterm_Set, 
Descriptor);
 
-      Item_Sets : constant LR1_Items.Item_Set_List :=
-        (if Task_Count = 1
-         then LR1_Item_Sets_Single
-           (Has_Empty_Production, First_Terminal_Sequence, Grammar, 
Descriptor, Hash_Table_Size)
-        else LR1_Item_Sets_Parallel
-           (Has_Empty_Production, First_Terminal_Sequence, Grammar, 
Descriptor, Task_Count,
-            Hash_Table_Size));
+      Item_Sets : constant LR1_Items.Item_Set_List := LR1_Item_Sets
+           (Has_Empty_Production, First_Terminal_Sequence, Grammar, 
Descriptor);
 
       Unknown_Conflicts    : Conflict_Lists.Tree;
       Known_Conflicts_Edit : Conflict_Lists.Tree := Known_Conflicts;
@@ -896,11 +276,18 @@ package body WisiToken.Generate.LR.LR1_Generate is
 
    begin
       if not Use_Cached_Recursions or Recursions = Empty_Recursions then
-         Recursions :=
-           (if Partial_Recursion
-            then WisiToken.Generate.Compute_Partial_Recursion (Grammar, 
Descriptor)
-            else WisiToken.Generate.Compute_Full_Recursion (Grammar, 
Descriptor));
+         case Recursion_Strategy is
+         when None =>
+            null;
+
+         when Partial =>
+            Recursions := WisiToken.Generate.Compute_Partial_Recursion 
(Grammar, Descriptor);
+
+         when Full =>
+            Recursions := WisiToken.Generate.Compute_Full_Recursion (Grammar, 
Descriptor);
+         end case;
       end if;
+
       Set_Grammar_Recursions (Recursions, Grammar);
       Recursions_Time := Ada.Calendar.Clock;
 
@@ -929,6 +316,8 @@ package body WisiToken.Generate.LR.LR1_Generate is
          First_Nonterminal => Descriptor.First_Nonterminal,
          Last_Nonterminal  => Descriptor.Last_Nonterminal);
 
+      Table.Error_Recover_Enabled := Error_Recover;
+
       if McKenzie_Param = Default_McKenzie_Param then
          --  Descriminants in Default are wrong
          Table.McKenzie_Param :=
@@ -948,6 +337,7 @@ package body WisiToken.Generate.LR.LR1_Generate is
             Check_Limit                 => Default_McKenzie_Param.Check_Limit,
             Check_Delta_Limit           => 
Default_McKenzie_Param.Check_Delta_Limit,
             Enqueue_Limit               => 
Default_McKenzie_Param.Enqueue_Limit);
+
       else
          Table.McKenzie_Param := McKenzie_Param;
       end if;
diff --git a/wisitoken-generate-lr-lr1_generate.ads 
b/wisitoken-generate-lr-lr1_generate.ads
index b37388fbc2..42004e7f2a 100644
--- a/wisitoken-generate-lr-lr1_generate.ads
+++ b/wisitoken-generate-lr-lr1_generate.ads
@@ -7,7 +7,7 @@
 --  [dragon] "Compilers Principles, Techniques, and Tools" by Aho,
 --  Sethi, and Ullman (aka: "The [Red] Dragon Book").
 --
---  Copyright (C) 2017 - 2020 Free Software Foundation, Inc.
+--  Copyright (C) 2017 - 2020, 2022 Free Software Foundation, Inc.
 --
 --  This file is part of the WisiToken package.
 --
@@ -25,8 +25,6 @@
 
 pragma License (Modified_GPL);
 
-with System.Multiprocessors;
-with WisiToken.Generate.LR1_Items;
 with WisiToken.Productions;
 package WisiToken.Generate.LR.LR1_Generate is
 
@@ -34,15 +32,14 @@ package WisiToken.Generate.LR.LR1_Generate is
      (Grammar               : in out WisiToken.Productions.Prod_Arrays.Vector;
       Descriptor            : in     WisiToken.Descriptor;
       Grammar_File_Name     : in     String;
+      Error_Recover         : in     Boolean;
       Known_Conflicts       : in     Conflict_Lists.Tree              := 
Conflict_Lists.Empty_Tree;
       McKenzie_Param        : in     McKenzie_Param_Type              := 
Default_McKenzie_Param;
       Max_Parallel          : in     SAL.Base_Peek_Type               := 15;
       Parse_Table_File_Name : in     String                           := "";
       Include_Extra         : in     Boolean                          := False;
       Ignore_Conflicts      : in     Boolean                          := False;
-      Partial_Recursion     : in     Boolean                          := True;
-      Task_Count            : in     System.Multiprocessors.CPU_Range := 1;
-      Hash_Table_Size       : in     Positive                         := 
LR1_Items.Item_Set_Trees.Default_Rows;
+      Recursion_Strategy    : in     WisiToken.Recursion_Strategy     := Full;
       Use_Cached_Recursions : in     Boolean                          := False;
       Recursions            : in out WisiToken.Generate.Recursions)
      return Parse_Table_Ptr
@@ -63,14 +60,11 @@ package WisiToken.Generate.LR.LR1_Generate is
    --
    --  Unless Ignore_Unknown_Conflicts is True, raise Grammar_Error if there
    --  are unknown conflicts.
-   --
-   --  Use Task_Count tasks in computing LR1 items. Default is 1 so unit
-   --  tests return repeatable results.
 
    ----------
    --  visible for unit test
 
-   function LR1_Item_Sets_Single
+   function LR1_Item_Sets
      (Has_Empty_Production    : in Token_ID_Set;
       First_Terminal_Sequence : in Token_Sequence_Arrays.Vector;
       Grammar                 : in WisiToken.Productions.Prod_Arrays.Vector;
@@ -79,14 +73,4 @@ package WisiToken.Generate.LR.LR1_Generate is
      return LR1_Items.Item_Set_List;
    --  [dragon] algorithm 4.9 pg 231; figure 4.38 pg 232; procedure "items", 
no tasking
 
-   function LR1_Item_Sets_Parallel
-     (Has_Empty_Production    : in Token_ID_Set;
-      First_Terminal_Sequence : in Token_Sequence_Arrays.Vector;
-      Grammar                 : in WisiToken.Productions.Prod_Arrays.Vector;
-      Descriptor              : in WisiToken.Descriptor;
-      Task_Count              : in System.Multiprocessors.CPU_Range;
-      Hash_Table_Size         : in Positive := 
LR1_Items.Item_Set_Trees.Default_Rows)
-     return LR1_Items.Item_Set_List;
-   --  With tasking; used if State_Count known.
-
 end WisiToken.Generate.LR.LR1_Generate;
diff --git a/wisitoken-lexer-re2c.adb b/wisitoken-lexer-re2c.adb
index c6b485f719..41d57e7403 100644
--- a/wisitoken-lexer-re2c.adb
+++ b/wisitoken-lexer-re2c.adb
@@ -412,7 +412,11 @@ package body WisiToken.Lexer.re2c is
       Line  : in Line_Number_Type)
      return Base_Buffer_Pos
    is begin
-      return Line_Begin_Char_Pos (Lexer.Source, Token, Line);
+      if Token.ID = Lexer.Descriptor.New_Line_ID then
+         return Token.Char_Region.First + 1;
+      else
+         return Line_Begin_Char_Pos (Lexer.Source, Token, Line);
+      end if;
    end Line_Begin_Char_Pos;
 
    overriding
diff --git a/wisitoken-lexer.adb b/wisitoken-lexer.adb
index 54f559eeee..1d0981b936 100644
--- a/wisitoken-lexer.adb
+++ b/wisitoken-lexer.adb
@@ -162,7 +162,9 @@ package body WisiToken.Lexer is
       First       : in Boolean)
      return Base_Buffer_Pos
    is begin
-      if Instance'Class (Lexer).Can_Contain_New_Line (ID) then
+      if ID = Lexer.Descriptor.New_Line_ID then
+         return Byte_Region.First;
+      elsif Instance'Class (Lexer).Can_Contain_New_Line (ID) then
          return Contains_New_Line (Lexer.Source, Byte_Region, First);
       else
          return Invalid_Buffer_Pos;
diff --git a/wisitoken-parse-lr-mckenzie_recover-explore.adb 
b/wisitoken-parse-lr-mckenzie_recover-explore.adb
index e5f116bfa0..ebc530855d 100644
--- a/wisitoken-parse-lr-mckenzie_recover-explore.adb
+++ b/wisitoken-parse-lr-mckenzie_recover-explore.adb
@@ -839,7 +839,7 @@ package body WisiToken.Parse.LR.McKenzie_Recover.Explore is
       Orig_Config       : in out Configuration;
       Local_Config_Heap : in out Config_Heaps.Heap_Type)
      return Token_ID_Arrays.Vector
-      --  Return tokens inserted (empty if none).
+   --  Return tokens inserted (empty if none).
    is
       use Ada.Containers;
 
@@ -1915,8 +1915,7 @@ package body WisiToken.Parse.LR.McKenzie_Recover.Explore 
is
                   else Invalid_Line_Number)
                elsif not Config.Error_Token.Virtual and then
                  Config.Error_Token.Node = Config.Input_Stream 
(Config.Input_Stream.First)
-               then Tree.Line_Region (Super.Stream (Parser_Index), 
Config.Error_Token).First
-               --  Null_Line_Region if unknown.
+               then Tree.Line_At_Node (Super.Stream (Parser_Index), 
Config.Error_Token)
                else Invalid_Line_Number);
 
          begin
@@ -1962,7 +1961,7 @@ package body WisiToken.Parse.LR.McKenzie_Recover.Explore 
is
                         then Tree.Lexer.Descriptor.EOI_ID
                         else Tree.Lexer.Descriptor.SOI_ID);
 
-                     exit when Tree.Line_Region (Term, Super.Stream 
(Parser_Index)).First /= Current_Line;
+                     exit when Tree.Line_At_Node (Term, Super.Stream 
(Parser_Index)) /= Current_Line;
 
                      if Forward then
                         Tree.Next_Terminal (Term, Following => True);
diff --git a/wisitoken-parse-lr-mckenzie_recover.adb 
b/wisitoken-parse-lr-mckenzie_recover.adb
index 12d6f97fb9..02356ce996 100644
--- a/wisitoken-parse-lr-mckenzie_recover.adb
+++ b/wisitoken-parse-lr-mckenzie_recover.adb
@@ -355,7 +355,8 @@ package body WisiToken.Parse.LR.McKenzie_Recover is
                      --  we've applied all of Result.Ops, to avoid copying the 
error node
                      --  for each op.
                      Error_Recover_Ops : Recover_Op_Nodes_Arrays.Vector := 
To_Recover_Op_Nodes (Result.Ops);
-                     --  WORKAROUND: GNAT Community 2021 is confused about 
this being constant
+                     --  WORKAROUND: GNAT Community 2021 is confused about 
this being
+                     --  constant. AdaCore Eurocontrol contract ticket 
V707-027.
                      pragma Warnings (Off, Error_Recover_Ops);
 
                      Op_Index : SAL.Base_Peek_Type := No_Insert_Delete;
@@ -520,7 +521,7 @@ package body WisiToken.Parse.LR.McKenzie_Recover is
                               --  Config stack, not a parser stack. So we 
duplicate part of it.
                               if Stack_Matches_Ops then
                                  if not (Nonterm = Tree.Label (Tree.Peek 
(Stack)) and
-                                           Op.Nonterm = Tree.ID 
(Parser_State.Stream, Tree.Peek (Stack)))
+                                           Op.Nonterm = Tree.ID (Tree.Peek 
(Stack)))
                                  then
                                     Raise_Bad_Config ("Undo_Reduce does not 
match stack top in apply config");
                                  end if;
@@ -540,7 +541,7 @@ package body WisiToken.Parse.LR.McKenzie_Recover is
                               --  encounter an error; 
test_mckenzie_recover.adb Error_3.
 
                               if Stack_Matches_Ops then
-                                 if not (Op.PB_ID = Tree.ID 
(Parser_State.Stream, Tree.Peek (Stack))) then
+                                 if not (Op.PB_ID = Tree.ID (Tree.Peek 
(Stack))) then
                                     Raise_Bad_Config
                                       ("Push_Back does not match stack top in 
apply config: " &
                                          Image (Op, 
Tree.Lexer.Descriptor.all));
@@ -620,7 +621,8 @@ package body WisiToken.Parse.LR.McKenzie_Recover is
 
                                     declare
                                        --  WORKAROUND: GNAT Community 2021 
reports "'Op' must be a variable"
-                                       --  if we use this expression for the 
Op parameter.
+                                       --  if we use this expression for the 
Op parameter. AdaCore
+                                       --  Eurocontrol contract ticket 
V707-027.
                                        Op : Recover_Op_Nodes renames 
Error_Recover_Ops (Op_Index);
                                     begin
                                        Parser_State.Do_Delete
diff --git a/wisitoken-parse-lr-parser-parse.adb 
b/wisitoken-parse-lr-parser-parse.adb
index 187b74ad28..e9cd8f2df9 100644
--- a/wisitoken-parse-lr-parser-parse.adb
+++ b/wisitoken-parse-lr-parser-parse.adb
@@ -84,7 +84,9 @@ begin
          if Trace_Parse > Outline then
             Trace.Put_Line ("edited tree does not need parse; no or only 
non_grammar changes");
          end if;
-         Shared_Parser.Tree.Clear_Parse_Streams;
+         Shared_Parser.Tree.Set_Root
+           (Shared_Parser.Tree.Stream_First (Shared_Parser.Tree.Shared_Stream, 
Skip_SOI => True).Node);
+         Shared_Parser.Tree.Finish_Parse;
          Shared_Parser.Parsers.Clear;
          return;
       end if;
@@ -346,7 +348,8 @@ begin
                      Recover_Duration : constant Duration := Clock - Start;
                   begin
                      Trace.Put_Clock
-                       ("post-recover" & Shared_Parser.Parsers.Count'Img & " 
active," & Recover_Duration'Image);
+                       ("post-recover" & Shared_Parser.Parsers.Count'Img & " 
parsers active," &
+                          Recover_Duration'Image & " seconds");
                   end;
                end if;
 
@@ -636,7 +639,7 @@ when Partial_Parse =>
       Trace.Put_Clock ("finish partial parse");
    end if;
 
-when Syntax_Error | WisiToken.Parse_Error =>
+when Syntax_Error | WisiToken.Parse_Error | WisiToken.Validate_Error =>
    if Trace_Time then
       Trace.Put_Clock ("finish - error");
    end if;
diff --git a/wisitoken-parse-lr-parser.adb b/wisitoken-parse-lr-parser.adb
index 2f6e4e56dd..914d08bbab 100644
--- a/wisitoken-parse-lr-parser.adb
+++ b/wisitoken-parse-lr-parser.adb
@@ -18,12 +18,9 @@
 --  see file GPL.txt. If not, write to the Free Software Foundation,
 --  59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 --
---  As a special exception, if other files instantiate generics from
---  this unit, or you link this unit with other files to produce an
---  executable, this unit does not by itself cause the resulting
---  executable to be covered by the GNU General Public License. This
---  exception does not however invalidate any other reasons why the
---  executable file might be covered by the GNU Public License.
+--  As a special exception under Section 7 of GPL version 3, you are granted
+--  additional permissions described in the GCC Runtime Library Exception,
+--  version 3.1, as published by the Free Software Foundation.
 
 pragma License (Modified_GPL);
 
@@ -386,12 +383,10 @@ package body WisiToken.Parse.LR.Parser is
                      declare
                         Current_Token : constant Syntax_Trees.Rooted_Ref := 
Shared_Parser.Tree.Current_Token
                           (Parser_State.Stream);
+                        Tree_Root : constant Syntax_Trees.Rooted_Ref := 
Shared_Parser.Tree.Stream_Prev (Current_Token);
                      begin
-
-                        --  Insert EOI on Shared_Stream
-                        if Shared_Parser.Tree.ID (Current_Token.Node) /=
-                          Shared_Parser.Tree.Lexer.Descriptor.EOI_ID
-                        then
+                        if Shared_Parser.Tree.ID (Current_Token.Node) /= 
Shared_Parser.Tree.Lexer.Descriptor.EOI_ID then
+                           --  Insert EOI on Shared_Stream
                            declare
                               Last_Token_Byte_Region_Last : constant 
Buffer_Pos := Shared_Parser.Tree.Byte_Region
                                 (Current_Token.Node, Trailing_Non_Grammar => 
False).Last;
@@ -417,6 +412,22 @@ package body WisiToken.Parse.LR.Parser is
                                  Errors   => Syntax_Trees.Null_Error_List);
                            end;
                         end if;
+
+                        if Shared_Parser.Tree.ID (Tree_Root.Node) /= 
Shared_Parser.Tree.Lexer.Descriptor.Accept_ID then
+                           --  Add Accept_ID node.
+                           declare
+                              Accept_Node : constant Syntax_Trees.Rooted_Ref 
:= Shared_Parser.Tree.Reduce
+                                (Parser_State.Stream,
+                                 Production       =>
+                                   (LHS           => 
Shared_Parser.Tree.Lexer.Descriptor.Accept_ID,
+                                    RHS           => 1),
+                                 Child_Count      => 1,
+                                 State            => Accept_State,
+                                 Recover_Conflict => False);
+                           begin
+                              Shared_Parser.Tree.Set_Root (Accept_Node.Node);
+                           end;
+                        end if;
                      end;
                      raise;
                   end if;
@@ -960,6 +971,7 @@ package body WisiToken.Parse.LR.Parser is
    procedure Finish_Parse
      (Parser            : in out LR.Parser.Parser;
       Incremental_Parse : in     Boolean)
+   with Pre => Parser.Parsers.Count = 1
    --  Final actions after LR accept state reached; call
    --  User_Data.Insert_Token, Delete_Token.
    is
@@ -969,19 +981,31 @@ package body WisiToken.Parse.LR.Parser is
 
       Last_Deleted_Node_Parent : Node_Access;
    begin
+      Parser.Tree.Set_Root (Get_Node (Parser.Tree.Peek 
(Parser.Tree.First_Parse_Stream)));
+
       --  We need parents set in the following code.
+      Parser.Tree.Finish_Parse;
       Parser_State.Clear_Stream;
-      Parser.Tree.Clear_Parse_Streams;
+
+      if Debug_Mode then
+         declare
+            I : Integer := 1;
+         begin
+            for Node of Parser_State.Recover_Insert_Delete loop
+               if not Parser.Tree.In_Tree (Node) then
+                  raise SAL.Programmer_Error with "recover_insert_delete node" 
& I'Image & " not in tree";
+               end if;
+               I := @ + 1;
+            end loop;
+         end;
+      end if;
 
       if Trace_Parse > Extra and then 
Parser_State.Recover_Insert_Delete.Length > 0 then
          Parser.Tree.Lexer.Trace.New_Line;
          Parser.Tree.Lexer.Trace.Put_Line ("before insert/delete tree:");
-         Parser.Tree.Lexer.Trace.Put_Line
-           (Parser.Tree.Image
-              (Children     => True,
-               Non_Grammar  => True,
-               Augmented    => True,
-               Line_Numbers => True));
+         Parser.Tree.Print_Tree
+           (Non_Grammar  => True,
+            Line_Numbers => True);
          Parser.Tree.Lexer.Trace.Put_Line
            ("recover_insert_delete: " & Parser_Lists.Recover_Image 
(Parser_State, Parser.Tree));
          Parser.Tree.Lexer.Trace.New_Line;
@@ -1019,7 +1043,7 @@ package body WisiToken.Parse.LR.Parser is
          end loop;
       end loop;
 
-      if Trace_Parse > Extra or Trace_Action > Extra then
+      if Trace_Parse > Extra or Trace_Action > Detail then
          Parser.Tree.Lexer.Trace.Put_Line ("post-parse tree:");
          Parser.Tree.Lexer.Trace.Put_Line
            (Parser.Tree.Image
@@ -1052,11 +1076,12 @@ package body WisiToken.Parse.LR.Parser is
                end;
                Parser.Tree.Clear_Augmented;
             else
-               Parser.Tree.Validate_Tree (Parser.User_Data.all, 
Error_Reported, Node_Index_Order => False);
+               Parser.Tree.Validate_Tree
+                 (Parser.User_Data.all, Error_Reported, Node_Index_Order => 
not Incremental_Parse);
             end if;
 
             if Error_Reported.Count /= 0 then
-               raise WisiToken.Parse_Error with "parser: validate_tree failed";
+               raise WisiToken.Validate_Error with "parser: validate_tree 
failed";
             end if;
          end;
       end if;
@@ -1065,6 +1090,12 @@ package body WisiToken.Parse.LR.Parser is
    ----------
    --  Public subprograms, declaration order
 
+   overriding
+   procedure Finalize (Object : in out Parser)
+   is begin
+      Free_Table (Object.Table);
+   end Finalize;
+
    procedure New_Parser
      (Parser                         :    out LR.Parser.Parser;
       Lexer                          : in     WisiToken.Lexer.Handle;
@@ -1742,7 +1773,7 @@ package body WisiToken.Parse.LR.Parser is
                                           Inserted  => True,
                                           Start     => True);
 
-                                       if Tree.ID (Prev_Terminal) = Tree.ID 
(Node) and then
+                                       if Tree.ID (Prev_Terminal.Node) = 
Tree.ID (Node) and then
                                          Tree.Byte_Region (Prev_Terminal, 
Trailing_Non_Grammar => False).Last + 1 =
                                          Node_Byte_Region.First and then
                                          Tree.Lexer.Escape_Delimiter_Doubled 
(Node_ID)
@@ -1861,7 +1892,7 @@ package body WisiToken.Parse.LR.Parser is
                      --  partly past or adjacent to Stable_Region.Last. Also 
exit when last
                      --  KMN is done.
                      exit Unchanged_Loop when
-                       Tree.ID (Terminal) /= Tree.Lexer.Descriptor.SOI_ID and 
then
+                       Tree.ID (Terminal.Node) /= Tree.Lexer.Descriptor.SOI_ID 
and then
                        (if Length (Inserted_Region) = 0 and Length 
(Deleted_Region) = 0
                         then Tree.Byte_Region (Terminal.Node, 
Trailing_Non_Grammar => False).Last >
                           Stable_Region.Last -- Last KMN
@@ -2180,7 +2211,7 @@ package body WisiToken.Parse.LR.Parser is
 
                               if Trace_Incremental_Parse > Detail then
                                  Tree.Lexer.Trace.Put_Line
-                                   ("float non_grammar " & Lexer.Full_Image 
(Token, Tree.Lexer.Descriptor.all));
+                                   ("float non_grammar.1 " & Lexer.Full_Image 
(Token, Tree.Lexer.Descriptor.all));
                               end if;
                            end case;
                         end;
@@ -2490,13 +2521,13 @@ package body WisiToken.Parse.LR.Parser is
                               Do_Scan        := True;
                               Lex_Start_Byte := Inserted_Region.First;
                               Lex_Start_Char := Inserted_Region_Chars.First;
-                              Lex_Start_Line := Tree.Line_Region (Terminal, 
Trailing_Non_Grammar => False).First;
+                              Lex_Start_Line := Tree.Line_At_Node (Terminal, 
Tree.Shared_Stream);
                               Scan_End       := Data.Scan_End;
                            else
                               Do_Scan        := True;
                               Lex_Start_Byte := Terminal_Byte_Region.First;
                               Lex_Start_Char := Tree.Char_Region (Data.Node, 
Trailing_Non_Grammar => False).First;
-                              Lex_Start_Line := Tree.Line_Region (Terminal, 
Trailing_Non_Grammar => False).First;
+                              Lex_Start_Line := Tree.Line_At_Node (Terminal, 
Tree.Shared_Stream);
                               Scan_End       := Data.Scan_End;
                            end if;
                         end;
@@ -2520,7 +2551,7 @@ package body WisiToken.Parse.LR.Parser is
                         Do_Scan        := True;
                         Lex_Start_Byte := Tree.Byte_Region (Data.Node, 
Trailing_Non_Grammar => False).First;
                         Lex_Start_Char := Tree.Char_Region (Data.Node, 
Trailing_Non_Grammar => False).First;
-                        Lex_Start_Line := Tree.Line_Region (Ref, 
Trailing_Non_Grammar => False).First;
+                        Lex_Start_Line := Tree.Line_At_Node (Ref, 
Tree.Shared_Stream);
                         Scan_End       := Data.Scan_End;
 
                         if Terminal_Non_Grammar_Next /= 
Lexer.Token_Arrays.No_Index then
@@ -2616,9 +2647,7 @@ package body WisiToken.Parse.LR.Parser is
                               Lex_Start_Line :=
                                 (if Terminal_Non_Grammar_Next > 
Non_Grammar.First_Index
                                  then Non_Grammar (Terminal_Non_Grammar_Next - 
1).Line_Region.Last
-                                 else Tree.Line_Region
-                                   (Tree.Prev_Source_Terminal (Terminal, 
Trailing_Non_Grammar => True),
-                                    Trailing_Non_Grammar => True).Last);
+                                 else Tree.Line_At_Node (Terminal, 
Tree.Shared_Stream));
                               Do_Scan := True;
                            else
                               --  Edit start is in or just after Token
@@ -2663,13 +2692,13 @@ package body WisiToken.Parse.LR.Parser is
                                     Delayed_Lex_Start_Line := Lex_Start_Line;
                                     if Trace_Incremental_Parse > Detail then
                                        Tree.Lexer.Trace.Put_Line
-                                         ("scan delayed" & 
Lex_Start_Byte'Image &
+                                         ("scan delayed 1" & 
Lex_Start_Byte'Image &
                                             (if Scan_End /= Invalid_Buffer_Pos
                                              then " .." & Scan_End'Image
                                              else ""));
                                        if Trace_Incremental_Parse > Extra then
                                           Tree.Lexer.Trace.Put_Line
-                                            ("float non_grammar" & I'Image & 
":" &
+                                            ("float non_grammar.2" & I'Image & 
":" &
                                                Lexer.Full_Image (Non_Grammar 
(I), Tree.Lexer.Descriptor.all));
                                        end if;
                                     end if;
@@ -2695,7 +2724,7 @@ package body WisiToken.Parse.LR.Parser is
                                  Floating_Non_Grammar.Append (Non_Grammar (I));
                                  if Trace_Incremental_Parse > Extra then
                                     Tree.Lexer.Trace.Put_Line
-                                      ("float non_grammar" & I'Image & ":" &
+                                      ("float non_grammar.3" & I'Image & ":" &
                                          Lexer.Full_Image (Non_Grammar (I), 
Tree.Lexer.Descriptor.all));
                                  end if;
                                  Last_Floated := I;
@@ -2712,7 +2741,7 @@ package body WisiToken.Parse.LR.Parser is
                         if Trace_Incremental_Parse > Detail then
                            if Last_Floated /= Lexer.Token_Arrays.No_Index then
                               Tree.Lexer.Trace.Put_Line
-                                ("float non_grammar" & 
Terminal_Non_Grammar_Next'Image & " .." &
+                                ("float non_grammar.4" & 
Terminal_Non_Grammar_Next'Image & " .." &
                                    Last_Floated'Image);
                            end if;
                         end if;
@@ -2734,8 +2763,7 @@ package body WisiToken.Parse.LR.Parser is
                            Lex_Start_Char := Tree.Char_Region (Terminal.Node, 
Trailing_Non_Grammar => False).First +
                              Shift_Chars;
 
-                           --  Line_Region.First is from 
prev_terminal.non_grammar, which is shifted
-                           Lex_Start_Line := Tree.Line_Region (Terminal, 
Trailing_Non_Grammar => False).First;
+                           Lex_Start_Line := Tree.Line_At_Node (Terminal, 
Tree.Shared_Stream);
                         else
                            --  We never re-scan eoi; we just shift it.
                            null;
@@ -2746,8 +2774,7 @@ package body WisiToken.Parse.LR.Parser is
                         Lex_Start_Char := Tree.Char_Region (Terminal.Node, 
Trailing_Non_Grammar => False).First +
                           Shift_Chars;
 
-                        --  Line_Region.First is from 
prev_terminal.non_grammar, which is shifted
-                        Lex_Start_Line := Tree.Line_Region (Terminal, 
Trailing_Non_Grammar => False).First;
+                        Lex_Start_Line := Tree.Line_At_Node (Terminal, 
Tree.Shared_Stream);
 
                         if Tree.Lexer.Is_Block_Delimited (Tree.ID 
(Terminal.Node)) then
                            Check_Scan_End (Terminal.Node);
@@ -2980,7 +3007,7 @@ package body WisiToken.Parse.LR.Parser is
                      Delayed_Lex_Start_Line := Lex_Start_Line;
 
                      if Trace_Incremental_Parse > Detail then
-                        Tree.Lexer.Trace.Put_Line ("scan delayed");
+                        Tree.Lexer.Trace.Put_Line ("scan delayed 2");
                      end if;
                   end if;
                end if;
@@ -3167,7 +3194,7 @@ package body WisiToken.Parse.LR.Parser is
                        (if Tree.Byte_Region (Terminal.Node, 
Trailing_Non_Grammar => False).First <= Stable_Region.Last
                         then -KMN.Deleted_Bytes + KMN.Inserted_Bytes else 0) > 
Scanned_Byte_Pos;
 
-                     if Tree.ID (Terminal) = Tree.Lexer.Descriptor.SOI_ID then
+                     if Tree.ID (Terminal.Node) = Tree.Lexer.Descriptor.SOI_ID 
then
                         Tree.Next_Terminal (Terminal);
 
                      else
@@ -3203,7 +3230,7 @@ package body WisiToken.Parse.LR.Parser is
                               else
                                  if Trace_Incremental_Parse > Detail then
                                     Tree.Lexer.Trace.Put_Line
-                                      ("float non_grammar " & Lexer.Full_Image 
(Token, Tree.Lexer.Descriptor.all));
+                                      ("float non_grammar.5 " & 
Lexer.Full_Image (Token, Tree.Lexer.Descriptor.all));
                                  end if;
                                  Floating_Non_Grammar.Append (Token);
                               end if;
@@ -3251,7 +3278,7 @@ package body WisiToken.Parse.LR.Parser is
                   begin
                      loop
                         if Searching_Back then
-                           if Tree.ID (Terminal) = 
Tree.Lexer.Descriptor.SOI_ID then
+                           if Tree.ID (Terminal.Node) = 
Tree.Lexer.Descriptor.SOI_ID then
                               return Terminal;
                            end if;
 
@@ -3435,87 +3462,4 @@ package body WisiToken.Parse.LR.Parser is
       Pre_Edited       : in     Boolean        := False)
    is separate;
 
-   overriding procedure Execute_Actions
-     (Parser              : in out LR.Parser.Parser;
-      Action_Region_Bytes : in     WisiToken.Buffer_Region)
-   is
-      use all type Syntax_Trees.Post_Parse_Action;
-      use all type Syntax_Trees.User_Data_Access;
-
-      procedure Process_Node
-        (Tree : in out Syntax_Trees.Tree;
-         Node : in     Syntax_Trees.Valid_Node_Access)
-      is
-         use all type Syntax_Trees.Node_Label;
-         Node_Byte_Region : constant Buffer_Region := Tree.Byte_Region
-           (Node, Trailing_Non_Grammar => True);
-      begin
-         if Tree.Label (Node) /= Nonterm or else
-           not (Node_Byte_Region = Null_Buffer_Region or
-                  Overlaps (Node_Byte_Region, Action_Region_Bytes))
-         then
-            return;
-         end if;
-
-         for Child of Tree.Children (Node) loop
-            if Child /= Syntax_Trees.Invalid_Node_Access then
-               --  Child can be null in an edited tree
-               Process_Node (Tree, Child);
-            end if;
-         end loop;
-
-         Parser.User_Data.Reduce (Tree, Node);
-         declare
-            Post_Parse_Action : constant Syntax_Trees.Post_Parse_Action := 
Parser.Get_Post_Parse_Action
-              (Tree.Production_ID (Node));
-         begin
-            if Post_Parse_Action /= null then
-               begin
-                  Post_Parse_Action (Parser.User_Data.all, Tree, Node);
-               exception
-               when E : others =>
-                  if WisiToken.Debug_Mode then
-                     Parser.Tree.Lexer.Trace.Put_Line
-                       (Ada.Exceptions.Exception_Name (E) & ": " & 
Ada.Exceptions.Exception_Message (E));
-                     Parser.Tree.Lexer.Trace.Put_Line 
(GNAT.Traceback.Symbolic.Symbolic_Traceback (E));
-                     Parser.Tree.Lexer.Trace.New_Line;
-                  end if;
-
-                  raise WisiToken.Parse_Error with Tree.Error_Message
-                    (Node,
-                     "action raised exception " & 
Ada.Exceptions.Exception_Name (E) & ": " &
-                       Ada.Exceptions.Exception_Message (E));
-               end;
-            end if;
-         end;
-      end Process_Node;
-
-   begin
-      if Parser.User_Data = null then
-         return;
-      end if;
-
-      if Parser.Tree.Root = Syntax_Trees.Invalid_Node_Access then
-         --  No code in file, and error recovery failed to insert valid code.
-         --  Or ambiguous parse; Finish_Parse not called.
-         return;
-      end if;
-
-      Parser.User_Data.Initialize_Actions (Parser.Tree);
-
-      Process_Node (Parser.Tree, Parser.Tree.Root);
-   exception
-   when WisiToken.Parse_Error =>
-      raise;
-
-   when E : others =>
-      if Debug_Mode then
-         Parser.Tree.Lexer.Trace.Put_Line
-           (Ada.Exceptions.Exception_Name (E) & ": " & 
Ada.Exceptions.Exception_Message (E));
-         Parser.Tree.Lexer.Trace.Put_Line 
(GNAT.Traceback.Symbolic.Symbolic_Traceback (E));
-         Parser.Tree.Lexer.Trace.New_Line;
-      end if;
-      raise;
-   end Execute_Actions;
-
 end WisiToken.Parse.LR.Parser;
diff --git a/wisitoken-parse-lr-parser.ads b/wisitoken-parse-lr-parser.ads
index 1aafb8a2c6..eb0a1ea164 100644
--- a/wisitoken-parse-lr-parser.ads
+++ b/wisitoken-parse-lr-parser.ads
@@ -23,6 +23,7 @@
 
 pragma License (Modified_GPL);
 
+with Ada.Unchecked_Deallocation;
 with WisiToken.Parse.LR.Parser_Lists;
 with WisiToken.Lexer;
 with WisiToken.Syntax_Trees;
@@ -92,16 +93,12 @@ package WisiToken.Parse.LR.Parser is
       Max_Sequential_Index : Syntax_Trees.Sequential_Index := 
Syntax_Trees.Sequential_Index'First;
 
       Parsers : aliased Parser_Lists.List;
-
-      Partial_Parse_Active    : access Boolean;
-      Partial_Parse_Byte_Goal : access WisiToken.Buffer_Pos;
-      --  Used by In_Parse_Actions to terminate Partial_Parse.
    end record;
 
-   --  It is tempting to declare Finalize here, to free Parser.Table. But
-   --  Wisi.Parse_Context reuses the table between parser instances, so
-   --  we can't do that. Other applications must explicitly free
-   --  Parser.Table if they care.
+   type Parser_Access is access all Parser;
+
+   overriding procedure Finalize (Object : in out Parser);
+   --  Free Table.
 
    procedure New_Parser
      (Parser                         :    out LR.Parser.Parser;
@@ -129,14 +126,7 @@ package WisiToken.Parse.LR.Parser is
       Edits            : in     KMN_Lists.List := KMN_Lists.Empty_List;
       Pre_Edited       : in     Boolean        := False);
 
-   overriding procedure Execute_Actions
-     (Parser              : in out LR.Parser.Parser;
-      Action_Region_Bytes : in     WisiToken.Buffer_Region);
-   --  Call Parser.User_Data.Insert_Token, Parser.User_Data.Delete_Token
-   --  on any tokens inserted/deleted by error recovery. Update
-   --  Parser.Line_Begin_Tokens to reflect error recovery. Then call
-   --  User_Data.Reduce and the grammar post parse actions on all
-   --  nonterms in the syntax tree that overlap Action_Region_Bytes, by
-   --  traversing the tree in depth-first order.
+   procedure Free is new Ada.Unchecked_Deallocation (Parser, Parser_Access);
+   --  Declared last to avoid freezing rules.
 
 end WisiToken.Parse.LR.Parser;
diff --git a/wisitoken-parse-lr-parser_no_recover.adb 
b/wisitoken-parse-lr-parser_no_recover.adb
index 035ad13eb5..d1296e94ef 100644
--- a/wisitoken-parse-lr-parser_no_recover.adb
+++ b/wisitoken-parse-lr-parser_no_recover.adb
@@ -27,8 +27,6 @@
 
 pragma License (Modified_GPL);
 
-with Ada.Exceptions;
-with GNAT.Traceback.Symbolic;
 package body WisiToken.Parse.LR.Parser_No_Recover is
 
    procedure Reduce_Stack_1
@@ -419,7 +417,9 @@ package body WisiToken.Parse.LR.Parser_No_Recover is
          end;
       end loop Main_Loop;
 
-      Shared_Parser.Tree.Clear_Parse_Streams;
+      Shared_Parser.Tree.Set_Root
+        (Syntax_Trees.Get_Node (Shared_Parser.Tree.Peek 
(Shared_Parser.Tree.First_Parse_Stream)));
+      Shared_Parser.Tree.Finish_Parse;
 
       if Trace_Action > Extra then
          Trace.Put_Line
@@ -436,70 +436,4 @@ package body WisiToken.Parse.LR.Parser_No_Recover is
       --  character.
    end Parse;
 
-   procedure Execute_Actions
-     (Tree        : in out Syntax_Trees.Tree;
-      Productions : in     Syntax_Trees.Production_Info_Trees.Vector;
-      User_Data   : in     Syntax_Trees.User_Data_Access)
-   is
-      use all type Syntax_Trees.User_Data_Access;
-      procedure Process_Node
-        (Tree : in out Syntax_Trees.Tree;
-         Node : in     Syntax_Trees.Valid_Node_Access)
-      is
-         use Syntax_Trees;
-      begin
-         if Tree.Label (Node) /= Nonterm then
-            return;
-         end if;
-
-         User_Data.Reduce (Tree, Node);
-
-         declare
-            Action : constant Syntax_Trees.Post_Parse_Action := 
Get_Post_Parse_Action
-              (Productions, Tree.Production_ID (Node));
-         begin
-            if Action /= null then
-               begin
-                  Action (User_Data.all, Tree, Node);
-               exception
-               when E : others =>
-                  if Trace_Tests > Outline then
-                     --  running a unit test; exception may be AUnit assert 
fail
-                     raise;
-
-                  elsif WisiToken.Debug_Mode then
-                     Tree.Lexer.Trace.Put_Line
-                       (GNAT.Traceback.Symbolic.Symbolic_Traceback (E)); -- 
includes Prefix
-                     Tree.Lexer.Trace.New_Line;
-                  end if;
-
-                  raise WisiToken.Parse_Error with Tree.Error_Message
-                    (Node, "action raised exception " & 
Ada.Exceptions.Exception_Name (E) & ": " &
-                       Ada.Exceptions.Exception_Message (E));
-               end;
-            end if;
-         end;
-      end Process_Node;
-
-   begin
-      User_Data.Initialize_Actions (Tree);
-      Tree.Process_Tree (Process_Node'Access);
-   end Execute_Actions;
-
-   overriding procedure Execute_Actions
-     (Parser              : in out LR.Parser_No_Recover.Parser;
-      Action_Region_Bytes : in     WisiToken.Buffer_Region := 
WisiToken.Null_Buffer_Region)
-   is
-      use all type WisiToken.Syntax_Trees.User_Data_Access;
-      pragma Unreferenced (Action_Region_Bytes);
-   begin
-      if Parser.User_Data /= null then
-         if Parser.Parsers.Count > 1 then
-            raise Syntax_Error with "ambiguous parse; can't execute actions";
-         end if;
-      end if;
-
-      Execute_Actions (Parser.Tree, Parser.Productions, Parser.User_Data);
-   end Execute_Actions;
-
 end WisiToken.Parse.LR.Parser_No_Recover;
diff --git a/wisitoken-parse-lr-parser_no_recover.ads 
b/wisitoken-parse-lr-parser_no_recover.ads
index ac5169d8b1..cea1eba955 100644
--- a/wisitoken-parse-lr-parser_no_recover.ads
+++ b/wisitoken-parse-lr-parser_no_recover.ads
@@ -53,16 +53,4 @@ package WisiToken.Parse.LR.Parser_No_Recover is
    --  Raises SAL.Programmer_Error if Edits is not empty. Pre_Edited and
    --  Log_File are ignored.
 
-   overriding procedure Execute_Actions
-     (Parser              : in out LR.Parser_No_Recover.Parser;
-      Action_Region_Bytes : in     WisiToken.Buffer_Region := 
WisiToken.Null_Buffer_Region);
-   --  Action_Region_Bytes is ignored (all nodes always processed).
-
-   procedure Execute_Actions
-     (Tree        : in out Syntax_Trees.Tree;
-      Productions : in     Syntax_Trees.Production_Info_Trees.Vector;
-      User_Data   : in     Syntax_Trees.User_Data_Access);
-   --  Implements Execute_Actions, allows specifying different tree
-   --  (needed by wisitoken-bnf-generate).
-
 end WisiToken.Parse.LR.Parser_No_Recover;
diff --git a/wisitoken-parse-lr.adb b/wisitoken-parse-lr.adb
index 7c82f23144..86e230fe9c 100644
--- a/wisitoken-parse-lr.adb
+++ b/wisitoken-parse-lr.adb
@@ -335,6 +335,19 @@ package body WisiToken.Parse.LR is
       end loop;
    end Set_McKenzie_Options;
 
+   procedure Set_McKenzie_Help
+   is
+      use Ada.Text_IO;
+   begin
+      --  param alphabetical order
+      Put_Line ("check_delta_limit|check_delta");
+      Put_Line ("check_limit");
+      Put_Line ("enqueue_limit");
+      Put_Line ("full_explore");
+      Put_Line ("high_cost");
+      Put_Line ("zombie_limit");
+   end Set_McKenzie_Help;
+
    function Goto_For
      (Table : in Parse_Table;
       State : in State_Index;
diff --git a/wisitoken-parse-lr.ads b/wisitoken-parse-lr.ads
index c6bc218455..bcc4b2fd92 100644
--- a/wisitoken-parse-lr.ads
+++ b/wisitoken-parse-lr.ads
@@ -319,6 +319,10 @@ package WisiToken.Parse.LR is
    --  Set options from Config. Config contains space-separated name=value
    --  pairs. See body for exact names.
 
+   procedure Set_McKenzie_Help;
+   --  Output to Ada.Text_IO.Current_Output the list of keys for
+   --  Set_Mckenzie_Options.
+
    type Parse_Table
      (State_First       : State_Index;
       State_Last        : State_Index;
@@ -330,7 +334,7 @@ package WisiToken.Parse.LR is
    record
       States                : Parse_State_Array (State_First .. State_Last);
       Error_Action          : Parse_Action_Node_Ptr;
-      Error_Recover_Enabled : Boolean;
+      Error_Recover_Enabled : Boolean := False;
       McKenzie_Param        : McKenzie_Param_Type (First_Terminal, 
Last_Terminal, First_Nonterminal, Last_Nonterminal);
       Max_Parallel          : SAL.Base_Peek_Type := 15;
    end record;
diff --git a/wisitoken-parse-packrat-generated.adb 
b/wisitoken-parse-packrat-generated.adb
index 54ee0faf5c..81589db173 100644
--- a/wisitoken-parse-packrat-generated.adb
+++ b/wisitoken-parse-packrat-generated.adb
@@ -28,27 +28,18 @@ package body WisiToken.Parse.Packrat.Generated is
       pragma Unreferenced (Log_File, Pre_Edited);
       use all type WisiToken.Syntax_Trees.User_Data_Access;
       use all type Ada.Containers.Count_Type;
-      Descriptor : WisiToken.Descriptor renames 
Parser.Tree.Lexer.Descriptor.all;
-
-      Result : Memo_Entry;
+      Trace      : WisiToken.Trace'Class renames Parser.Tree.Lexer.Trace.all;
+      Result     : Memo_Entry;
    begin
       if Edits.Length > 0 then
          raise WisiToken.Parse_Error;
       end if;
 
-      for Deriv of Parser.Derivs loop
-         for Memo of Deriv loop
-            case Memo.State is
-            when No_Result | Failure =>
-               null;
-            when Success =>
-               Memo.Last_Pos := Syntax_Trees.Invalid_Stream_Index;
-            end case;
-         end loop;
-      end loop;
-
-      Parser.Derivs.Set_First_Last (Descriptor.First_Nonterminal, 
Descriptor.Last_Nonterminal);
+      if Trace_Time then
+         Trace.Put_Clock ("start");
+      end if;
 
+      Clear (Parser.Derivs);
       Parser.Tree.Clear;
 
       if Parser.User_Data /= null then
@@ -56,31 +47,13 @@ package body WisiToken.Parse.Packrat.Generated is
       end if;
       Parser.Lex_All; -- Creates Tree.Shared_Stream
 
-      --  WORKAROUND: there appears to be a bug in GNAT Community 2021 that 
makes
-      --  ref_count fail in this usage. May be related to AdaCore ticket 
V107-045.
+      --  FIXME: ref_count fails in this usage; works in procedural.
       Parser.Tree.Enable_Ref_Count_Check (Parser.Tree.Shared_Stream, Enable => 
False);
 
-      for Nonterm in Descriptor.First_Nonterminal .. 
Descriptor.Last_Nonterminal loop
-         Parser.Derivs (Nonterm).Clear (Free_Memory => True);
-         Parser.Derivs (Nonterm).Set_First_Last
-           (Parser.Tree.Get_Node_Index
-              (Parser.Tree.Shared_Stream, Parser.Tree.Stream_First 
(Parser.Tree.Shared_Stream, Skip_SOI => True)),
-            Parser.Tree.Get_Node_Index
-              (Parser.Tree.Shared_Stream, Parser.Tree.Stream_Last 
(Parser.Tree.Shared_Stream, Skip_EOI => False)));
-      end loop;
-
       Result := Parser.Parse_WisiToken_Accept
         (Parser, Parser.Tree.Stream_First (Parser.Tree.Shared_Stream, Skip_SOI 
=> False));
 
-      if Result.State /= Success then
-         if Trace_Parse > Outline then
-            Parser.Tree.Lexer.Trace.Put_Line ("parse failed");
-         end if;
-
-         raise Syntax_Error with "parse failed"; --  FIXME packrat: need 
better error message!
-      else
-         Parser.Tree.Set_Root (Result.Result);
-      end if;
+      Parser.Finish_Parse (Result);
 
    end Parse;
 
diff --git a/wisitoken-parse-packrat-generated.ads 
b/wisitoken-parse-packrat-generated.ads
index fe4153a851..d36600dc02 100644
--- a/wisitoken-parse-packrat-generated.ads
+++ b/wisitoken-parse-packrat-generated.ads
@@ -26,44 +26,15 @@ package WisiToken.Parse.Packrat.Generated is
 
    Recursive : exception;
 
-   type Memo_State is (No_Result, Failure, Success);
-   subtype Result_States is Memo_State range Failure .. Success;
-
-   type Memo_Entry (State : Memo_State := No_Result) is record
-
-      case State is
-      when No_Result =>
-         Recursive : Boolean := False;
-
-      when Failure =>
-         null;
-
-      when Success =>
-         Result : aliased Syntax_Trees.Node_Access;
-
-         Last_Pos : Syntax_Trees.Stream_Index;
-      end case;
-   end record;
-
-   subtype Positive_Node_Index is Syntax_Trees.Node_Index range 1 .. 
Syntax_Trees.Node_Index'Last;
-   package Memos is new SAL.Gen_Unbounded_Definite_Vectors
-     (Positive_Node_Index, Memo_Entry, Default_Element => (others => <>));
-   --  Memos is indexed by Node_Index of terminals in Shared_Stream
-   --  (incremental parse is not supported).
-
-   subtype Result_Type is Memo_Entry
-   with Dynamic_Predicate => Result_Type.State in Result_States;
-
-   package Derivs is new SAL.Gen_Unbounded_Definite_Vectors
-     (Token_ID, Memos.Vector, Default_Element => Memos.Empty_Vector);
+   type Parser;
 
    type Parse_WisiToken_Accept is access
-     --  WORKAROUND: using Packrat.Parser'Class here hits a GNAT Bug box in 
GPL 2018.
-     function (Parser : in out Base_Parser'Class; Last_Pos : in 
Syntax_Trees.Stream_Index) return Result_Type;
-
-   type Parser is new Packrat.Parser with record
-      Derivs : Generated.Derivs.Vector; --  FIXME packrat: use discriminated 
array, as in procedural
+     function (Parser : in out Packrat.Generated.Parser; Last_Pos : in 
Syntax_Trees.Stream_Index) return Result_Type;
 
+   type Parser (First_Nonterminal, Last_Nonterminal : Token_ID) is new 
WisiToken.Parse.Packrat.Parser
+     (First_Nonterminal => First_Nonterminal,
+      Last_Nonterminal  => Last_Nonterminal)
+   with record
       Parse_WisiToken_Accept : Generated.Parse_WisiToken_Accept;
    end record;
 
diff --git a/wisitoken-parse-packrat-procedural.adb 
b/wisitoken-parse-packrat-procedural.adb
index 3e70804e40..be74ebe175 100644
--- a/wisitoken-parse-packrat-procedural.adb
+++ b/wisitoken-parse-packrat-procedural.adb
@@ -17,6 +17,7 @@
 
 pragma License (Modified_GPL);
 
+with WisiToken.In_Parse_Actions;
 package body WisiToken.Parse.Packrat.Procedural is
 
    function Apply_Rule
@@ -36,6 +37,31 @@ package body WisiToken.Parse.Packrat.Procedural is
    ----------
    --  bodies
 
+   procedure Trace_Deriv_Success
+     (Parser : in out Procedural.Parser;
+      Pos    : in     WisiToken.Syntax_Trees.Stream_Index;
+      Memo   : in     Success_Memo_Entry)
+   is
+      use Syntax_Trees;
+      Tree : Syntax_Trees.Tree renames Parser.Tree;
+   begin
+      --  match LR parse trace with trace_parse=2
+      Tree.Lexer.Trace.Put_Line
+        ((if Trace_Parse > Extra
+          then Node_Index'Image (Tree.Get_Node_Index (Tree.Shared_Stream, 
Pos)) & "; "
+          else "") &
+           Tree.Image
+             (Memo.Result,
+              Children              => True,
+              Node_Numbers          => Trace_Parse > Extra,
+              Terminal_Node_Numbers => True,
+              RHS_Index             => True) &
+           (if Trace_Parse > Extra
+            then " last_pos" & Node_Index'Image (Tree.Get_Node_Index 
(Tree.Shared_Stream, Memo.Last_Pos)) &
+              " max_ex_pos" & Node_Index'Image (Tree.Get_Node_Index 
(Tree.Shared_Stream, Memo.Max_Examined_Pos))
+            else ""));
+   end Trace_Deriv_Success;
+
    function Eval
      (Parser   : in out Procedural.Parser;
       R        : in     Token_ID;
@@ -46,12 +72,31 @@ package body WisiToken.Parse.Packrat.Procedural is
 
       Tree       : Syntax_Trees.Tree renames Parser.Tree;
       Descriptor : WisiToken.Descriptor renames Tree.Lexer.Descriptor.all;
+      Trace      : WisiToken.Trace'Class renames Tree.Lexer.Trace.all;
 
       subtype Terminal is Token_ID range Descriptor.First_Terminal .. 
Descriptor.Last_Terminal;
 
       Pos      : Syntax_Trees.Stream_Index := Last_Pos; --  last token parsed.
       Next_Pos : Syntax_Trees.Stream_Index := Tree.Stream_Next 
(Tree.Shared_Stream, Pos);
+
+      Max_Examined_Pos : Syntax_Trees.Stream_Index := Last_Pos;
+
+      procedure Update_Max_Examined_Pos (New_Pos : in 
Syntax_Trees.Stream_Index)
+      is begin
+         if Tree.Byte_Region
+           (Tree.Get_Node (Tree.Shared_Stream, New_Pos), Trailing_Non_Grammar 
=> False).First >
+           Tree.Byte_Region
+             (Tree.Get_Node (Tree.Shared_Stream, Max_Examined_Pos), 
Trailing_Non_Grammar => False).First
+         then
+            Max_Examined_Pos := New_Pos;
+         end if;
+      end Update_Max_Examined_Pos;
+
    begin
+      if Trace_Parse > Extra then
+         Trace.Put_Line ("eval: " & Image (R, Descriptor) & " @" & Image_Pos 
(Next_Pos));
+      end if;
+
       for RHS_Index in Parser.Grammar (R).RHSs.First_Index .. Parser.Grammar 
(R).RHSs.Last_Index loop
          declare
             use all type Ada.Containers.Count_Type;
@@ -59,40 +104,78 @@ package body WisiToken.Parse.Packrat.Procedural is
             Memo : Memo_Entry; --  for temporary or intermediate results
          begin
             if RHS.Tokens.Length = 0 then
-               return
+               return Result : constant Memo_Entry :=
                  (State            => Success,
+                  Max_Examined_Pos => Max_Examined_Pos,
                   Result           => Tree.Add_Nonterm
                     (Production    => (R, RHS_Index),
                      Children      => (1 .. 0 => 
Syntax_Trees.Invalid_Node_Access),
                      Clear_Parents => False),
-                  Last_Pos         => Pos);
+                  Last_Pos         => Pos)
+               do
+                  if Trace_Parse > Extra then
+                     Trace.Put_Line (Image (Result, R, RHS_Index, Pos, Tree));
+                  end if;
+               end return;
             else
                declare
+                  use all type 
WisiToken.Syntax_Trees.In_Parse_Actions.In_Parse_Action;
+                  use all type WisiToken.Syntax_Trees.Node_Access;
                   Children : Syntax_Trees.Node_Access_Array
                     (SAL.Base_Peek_Type (RHS.Tokens.First_Index) .. 
SAL.Base_Peek_Type (RHS.Tokens.Last_Index));
+
+                  In_Parse_Action : constant 
Syntax_Trees.In_Parse_Actions.In_Parse_Action :=
+                    Parser.Get_In_Parse_Action ((R, RHS_Index));
                begin
                   for I in RHS.Tokens.First_Index .. RHS.Tokens.Last_Index loop
+                     if Trace_Parse > Extra then
+                        Trace.Put (Image (Production_ID'(R, RHS_Index), 
Descriptor) & "," & I'Image & ": ");
+                     end if;
+
                      if RHS.Tokens (I) in Terminal then
                         if Next_Pos = Syntax_Trees.Invalid_Stream_Index then
+                           --  We don't update Max_Examined_Pos here; it must 
already be EOI
+                           pragma Assert (Tree.Get_Node (Tree.Shared_Stream, 
Max_Examined_Pos) = Tree.EOI);
                            goto Fail_RHS;
 
-                        elsif Tree.ID (Tree.Shared_Stream, Next_Pos) = 
RHS.Tokens (I) then
-                           Pos := Next_Pos;
-                           Next_Pos := Tree.Stream_Next (Tree.Shared_Stream, 
Pos);
-                           Children (SAL.Base_Peek_Type (I)) := Tree.Get_Node 
(Tree.Shared_Stream, Pos);
                         else
-                           goto Fail_RHS;
+                           if Children (SAL.Base_Peek_Type (I)) = 
Syntax_Trees.Invalid_Node_Access then
+                              if Tree.ID (Next_Pos) = RHS.Tokens (I) then
+                                 Pos := Next_Pos;
+                                 Next_Pos := Tree.Stream_Next 
(Tree.Shared_Stream, Pos);
+                                 Children (SAL.Base_Peek_Type (I)) := 
Tree.Get_Node (Tree.Shared_Stream, Pos);
+                                 --  FIXME: why not Update_Max_Examined_Pos 
here?
+
+                                 if Trace_Parse > Extra then
+                                    Trace.Put_Line
+                                      (Tree.Image (Children 
(SAL.Base_Peek_Type (I)), Node_Numbers => True));
+                                 end if;
+
+                              else
+                                 Update_Max_Examined_Pos (Next_Pos);
+                                 goto Fail_RHS;
+                              end if;
+                           end if;
                         end if;
-                     else
+
+                     else -- not Terminal
                         Memo := Apply_Rule (Parser, RHS.Tokens (I), Pos);
+                        Update_Max_Examined_Pos (Memo.Max_Examined_Pos);
+
                         case Memo.State is
                         when Success =>
+                           if Trace_Parse > Extra then
+                              Trace.Put_Line
+                                (Image (Production_ID'(R, RHS_Index), 
Descriptor) & "," & I'Image & ": " &
+                                   Tree.Image (Memo.Result, Node_Numbers => 
True, RHS_Index => True));
+                           end if;
                            Children (SAL.Base_Peek_Type (I)) := Memo.Result;
                            Pos := Memo.Last_Pos;
                            Next_Pos := Tree.Stream_Next (Tree.Shared_Stream, 
Pos);
 
                         when Failure =>
                            goto Fail_RHS;
+
                         when No_Result =>
                            raise SAL.Programmer_Error;
                         end case;
@@ -100,22 +183,63 @@ package body WisiToken.Parse.Packrat.Procedural is
                   end loop;
 
                   return Result : constant Memo_Entry :=
-                    (State              => Success,
-                     Result             => Parser.Tree.Add_Nonterm
-                       (Production      => (R, RHS_Index),
-                        Children        => Syntax_Trees.To_Valid_Node_Access 
(Children),
-                        Clear_Parents   => True),
+                    (State            => Success,
+                     Max_Examined_Pos => Max_Examined_Pos,
+                     Result           => Parser.Tree.Add_Nonterm
+                       (Production    => (R, RHS_Index),
+                        Children      => Syntax_Trees.To_Valid_Node_Access 
(Children),
+                        Clear_Parents => True),
                      --  We must be able to steal nodes from failed nonterms;
                      --  body_instantiation_conflict.wy.
-                     Last_Pos           => Pos)
+                     Last_Pos         => Pos)
                   do
                      if Trace_Parse > Extra then
-                        Parser.Tree.Lexer.Trace.Put_Line
-                          ("eval: " & Parser.Tree.Image (Root => 
Result.Result, Children => True));
+                        Trace.Put_Line (Image (Result, R, RHS_Index, Pos, 
Tree));
+                     end if;
+
+                     if In_Parse_Action = null then
+                        null;
+
+                     else
+                        declare
+                           Nonterm_Token : Syntax_Trees.Recover_Token := 
Parser.Tree.Get_Recover_Token (Result.Result);
+
+                           Children_Token : constant 
Syntax_Trees.Recover_Token_Array :=
+                             Parser.Tree.Children_Recover_Tokens 
(Result.Result);
+                           Status         : constant 
Syntax_Trees.In_Parse_Actions.Status := In_Parse_Action
+                             (Parser.Tree, Nonterm_Token, Children_Token, 
Recover_Active => False);
+                        begin
+                           if Trace_Parse > Extra then
+                              Trace.Put_Line
+                                ("in_parse_action " & 
WisiToken.In_Parse_Actions.Image
+                                   (Status, Tree, Result.Result));
+                           end if;
+
+                           case Status.Label is
+                           when Syntax_Trees.In_Parse_Actions.Ok =>
+                              null;
+
+                           when Syntax_Trees.In_Parse_Actions.Error =>
+                              raise SAL.Not_Implemented with "packrat 
in_parse_actions fail";
+                              --  FIXME: store the error somewhere, raise a 
different exception?
+                              --  Parser.Tree.Add_Error_To_Stack_Top
+                              --    (Parser_State.Stream,
+                              --     In_Parse_Action_Error'
+                              --       (Status       => Status,
+                              --        Recover_Ops  => 
Recover_Op_Arrays.Empty_Vector,
+                              --        Recover_Cost => 0),
+                              --     Parser.User_Data);
+                           end case;
+                        end;
                      end if;
                   end return;
 
                   <<Fail_RHS>>
+                  if Trace_Parse > Extra then
+                     Trace.Put_Line
+                       (Image (Production_ID'(R, RHS_Index), Descriptor) & " 
@" &
+                          Image_Pos (Next_Pos) & ": fail");
+                  end if;
                   Pos := Last_Pos;
                   Next_Pos := Tree.Stream_Next (Tree.Shared_Stream, Pos);
                end;
@@ -124,7 +248,7 @@ package body WisiToken.Parse.Packrat.Procedural is
       end loop;
       --  get here when all RHSs fail
 
-      return (State => Failure);
+      return (Failure, Max_Examined_Pos);
    end Eval;
 
    function Apply_Rule
@@ -138,47 +262,48 @@ package body WisiToken.Parse.Packrat.Procedural is
 
       Tree       : Syntax_Trees.Tree renames Parser.Tree;
       Descriptor : WisiToken.Descriptor renames Tree.Lexer.Descriptor.all;
+      Trace      : WisiToken.Trace'Class renames Parser.Tree.Lexer.Trace.all;
 
       Pos       : Syntax_Trees.Stream_Index          := Last_Pos; --  last 
token parsed.
       Start_Pos : constant Syntax_Trees.Stream_Index := Tree.Stream_Next
         (Tree.Shared_Stream, Last_Pos);                         --  first 
token in current nonterm
-      Memo      : Memo_Entry                         := Parser.Derivs (R)
-        (Tree.Get_Node_Index (Tree.Shared_Stream, Start_Pos));
+      Memo      : Memo_Entry                         := Get_Deriv
+        (Parser.Derivs, R, Tree.Get_Node_Index (Tree.Shared_Stream, 
Start_Pos));
 
       Pos_Recurse_Last : Syntax_Trees.Stream_Index := Last_Pos;
       Result_Recurse   : Memo_Entry;
    begin
       case Memo.State is
-      when Success =>
+      when Success | Failure =>
+         if Trace_Parse > Extra then
+            Trace.Put_Line ("apply memo:" & Image (Memo, R, Start_Pos, Tree));
+         end if;
          return Memo;
 
-      when Failure =>
-         return (State => Failure);
-
       when No_Result =>
          if Parser.Direct_Left_Recursive (R) then
-            Parser.Derivs (R).Replace_Element
-              (Tree.Get_Node_Index (Tree.Shared_Stream, Start_Pos), (State => 
Failure));
+            Set_Deriv
+              (Parser.Derivs, R, Tree.Get_Node_Index (Tree.Shared_Stream, 
Start_Pos),
+               (Failure, Last_Pos));
          else
             Memo := Eval (Parser, R, Last_Pos);
 
-            if (Trace_Parse > Detail and Memo.State = Success) or Trace_Parse 
> Extra then
-               case Memo.State is
-               when Success =>
-                  Parser.Tree.Lexer.Trace.Put_Line
-                    (Parser.Tree.Image (Memo.Result, Children => True, 
Terminal_Node_Numbers => True));
-               when Failure =>
-                  Parser.Tree.Lexer.Trace.Put_Line
-                    (Image (R, Descriptor) & " failed at pos " & Image_Pos 
(Tree, Tree.Shared_Stream, Last_Pos));
-               when No_Result =>
-                  raise SAL.Programmer_Error;
-               end case;
+            if Trace_Parse > Extra then
+               Trace.Put_Line ("apply memo:" & Image (Memo, R, Start_Pos, 
Tree));
+
+            elsif Trace_Parse > Detail and Memo.State = Success then
+               --  Match LR parse trace detail
+               Trace_Deriv_Success (Parser, Start_Pos, Memo);
             end if;
-            Parser.Derivs (R).Replace_Element (Tree.Get_Node_Index 
(Tree.Shared_Stream, Start_Pos), Memo);
+            Set_Deriv (Parser.Derivs, R, Tree.Get_Node_Index 
(Tree.Shared_Stream, Start_Pos), Memo);
             return Memo;
          end if;
       end case;
 
+      if Trace_Parse > Extra then
+         Trace.Put_Line ("apply recursive " & Image (R, Descriptor));
+      end if;
+
       loop
          --  Production is like: list : list element | element
          --
@@ -193,22 +318,22 @@ package body WisiToken.Parse.Packrat.Procedural is
             if Tree.Get_Node_Index (Tree.Shared_Stream, 
Result_Recurse.Last_Pos) >
               Tree.Get_Node_Index (Tree.Shared_Stream, Pos_Recurse_Last)
             then
-               Parser.Derivs (R).Replace_Element
-                 (Tree.Get_Node_Index (Tree.Shared_Stream, Start_Pos), 
Result_Recurse);
+               Set_Deriv (Parser.Derivs, R, Tree.Get_Node_Index 
(Tree.Shared_Stream, Start_Pos), Result_Recurse);
                Pos              := Result_Recurse.Last_Pos;
                Pos_Recurse_Last := Pos;
 
                if WisiToken.Trace_Parse > Detail then
-                  Parser.Tree.Lexer.Trace.Put_Line
-                    (Parser.Tree.Image
-                       (Result_Recurse.Result, Children => True, 
Terminal_Node_Numbers => True));
+                  Trace_Deriv_Success (Parser, Start_Pos, Result_Recurse);
+                  if Trace_Parse > Extra then
+                     Trace.Put_Line ("apply recursive continue");
+                  end if;
                end if;
                --  continue looping
 
             elsif Result_Recurse.Last_Pos = Pos_Recurse_Last then
                if Parser.Tree.Is_Empty_Nonterm (Result_Recurse.Result) then
-                  Parser.Derivs (R).Replace_Element
-                    (Tree.Get_Node_Index (Tree.Shared_Stream, Start_Pos), 
Result_Recurse);
+                  Set_Deriv
+                    (Parser.Derivs, R, Tree.Get_Node_Index 
(Tree.Shared_Stream, Start_Pos), Result_Recurse);
                end if;
                exit;
             else
@@ -219,7 +344,18 @@ package body WisiToken.Parse.Packrat.Procedural is
             exit;
          end if;
       end loop;
-      return Parser.Derivs (R)(Tree.Get_Node_Index (Tree.Shared_Stream, 
Start_Pos));
+
+      declare
+         Result : Memo_Entry renames Parser.Derivs (R)(Tree.Get_Node_Index 
(Tree.Shared_Stream, Start_Pos));
+      begin
+         Result.Max_Examined_Pos := Result_Recurse.Max_Examined_Pos;
+         if Trace_Parse > Extra then
+            Trace.Put_Line
+              ("apply recursive " & Image (R, Descriptor) & " end: " & Image 
(Result, R, Pos, Tree));
+         end if;
+
+         return Result;
+      end;
    end Apply_Rule;
 
    ----------
@@ -253,8 +389,7 @@ package body WisiToken.Parse.Packrat.Procedural is
       pragma Unreferenced (Log_File, Pre_Edited);
       use all type Ada.Containers.Count_Type;
       use all type WisiToken.Syntax_Trees.User_Data_Access;
-
-      Descriptor : WisiToken.Descriptor renames 
Parser.Tree.Lexer.Descriptor.all;
+      Trace      : WisiToken.Trace'Class renames Parser.Tree.Lexer.Trace.all;
 
       Result : Memo_Entry;
    begin
@@ -262,40 +397,25 @@ package body WisiToken.Parse.Packrat.Procedural is
          raise WisiToken.Parse_Error;
       end if;
 
+      if Trace_Time then
+         Trace.Put_Clock ("start");
+      end if;
+
       Parser.Tree.Clear;
       --  Creates Shared_Stream, but no parse stream; packrat does not
       --  use a parse stream.
 
+      Clear (Parser.Derivs);
+
       if Parser.User_Data /= null then
          Parser.User_Data.Reset;
       end if;
       Parser.Lex_All;
 
-      --  WORKAROUND: there appears to be a bug in GNAT Community 2021 that 
makes
-      --  ref_count fail in this usage. May be related to AdaCore ticket 
V107-045.
-      Parser.Tree.Enable_Ref_Count_Check (Parser.Tree.Shared_Stream, Enable => 
False);
-
-      for Nonterm in Descriptor.First_Nonterminal .. 
Descriptor.Last_Nonterminal loop
-         Parser.Derivs (Nonterm).Clear (Free_Memory => True);
-         Parser.Derivs (Nonterm).Set_First_Last
-           (Parser.Tree.Get_Node_Index
-              (Parser.Tree.Shared_Stream, Parser.Tree.Stream_First 
(Parser.Tree.Shared_Stream, Skip_SOI => True)),
-            Parser.Tree.Get_Node_Index
-              (Parser.Tree.Shared_Stream, Parser.Tree.Stream_Last 
(Parser.Tree.Shared_Stream, Skip_EOI => False)));
-      end loop;
-
       Result := Apply_Rule
         (Parser, Parser.Start_ID,  Parser.Tree.Stream_First 
(Parser.Tree.Shared_Stream, Skip_SOI => False));
 
-      if Result.State /= Success then
-         if Trace_Parse > Outline then
-            Parser.Tree.Lexer.Trace.Put_Line ("parse failed");
-         end if;
-
-         raise Syntax_Error with "parse failed"; --  FIXME packrat: need 
better error message!
-      else
-         Parser.Tree.Set_Root (Result.Result);
-      end if;
+      Parser.Finish_Parse (Result);
    end Parse;
 
 end WisiToken.Parse.Packrat.Procedural;
diff --git a/wisitoken-parse-packrat-procedural.ads 
b/wisitoken-parse-packrat-procedural.ads
index 9abc754ec5..aaf7f4beda 100644
--- a/wisitoken-parse-packrat-procedural.ads
+++ b/wisitoken-parse-packrat-procedural.ads
@@ -27,42 +27,12 @@ pragma License (Modified_GPL);
 with WisiToken.Productions;
 package WisiToken.Parse.Packrat.Procedural is
 
-   --  These types duplicate Packrat.Generated. We keep them separate so
-   --  we can experiment with ways of implementing indirect left
-   --  recursion.
-
-   type Memo_State is (No_Result, Failure, Success);
-   subtype Result_States is Memo_State range Failure .. Success;
-
-   type Memo_Entry (State : Memo_State := No_Result) is record
-      case State is
-      when No_Result =>
-         null;
-
-      when Failure =>
-         null;
-
-      when Success =>
-         Result   : Syntax_Trees.Node_Access;
-         Last_Pos : Syntax_Trees.Stream_Index;
-
-      end case;
-   end record;
-
-   subtype Positive_Node_Index is Syntax_Trees.Node_Index range 1 .. 
Syntax_Trees.Node_Index'Last;
-   package Memos is new SAL.Gen_Unbounded_Definite_Vectors
-     (Positive_Node_Index, Memo_Entry, Default_Element => (others => <>));
-   --  Memos is indexed by Node_Index of terminals in Shared_Stream
-   --  (incremental parse is not supported).
-
-   type Derivs is array (Token_ID range <>) of Memos.Vector;
-
-   type Parser (First_Nonterminal, Last_Nonterminal : Token_ID) is new 
Packrat.Parser
+   type Parser (First_Nonterminal, Last_Nonterminal : Token_ID) is new 
WisiToken.Parse.Packrat.Parser
+     (First_Nonterminal => First_Nonterminal,
+      Last_Nonterminal  => Last_Nonterminal)
    with record
-      Grammar               : WisiToken.Productions.Prod_Arrays.Vector;
-      Start_ID              : Token_ID;
-      Direct_Left_Recursive : Token_ID_Set (First_Nonterminal .. 
Last_Nonterminal);
-      Derivs                : Procedural.Derivs (First_Nonterminal .. 
Last_Nonterminal);
+      Grammar  : WisiToken.Productions.Prod_Arrays.Vector;
+      Start_ID : Token_ID;
    end record;
 
    function Create
diff --git a/wisitoken-parse-packrat.adb b/wisitoken-parse-packrat.adb
index b01bc0c881..982bab79ea 100644
--- a/wisitoken-parse-packrat.adb
+++ b/wisitoken-parse-packrat.adb
@@ -17,91 +17,163 @@
 
 pragma License (Modified_GPL);
 
-with Ada.Exceptions;
-with GNAT.Traceback.Symbolic;
 package body WisiToken.Parse.Packrat is
 
-   overriding
-   procedure Execute_Actions
-     (Parser              : in out Packrat.Parser;
-      Action_Region_Bytes : in     WisiToken.Buffer_Region := 
WisiToken.Null_Buffer_Region)
-   is
-      use all type WisiToken.Syntax_Trees.User_Data_Access;
-
-      procedure Process_Node
-        (Tree : in out Syntax_Trees.Tree;
-         Node : in     Syntax_Trees.Valid_Node_Access)
-      is
-         use all type Syntax_Trees.Node_Label;
-         use all type Syntax_Trees.Post_Parse_Action;
-         use all type WisiToken.Syntax_Trees.Node_Access;
-      begin
-         if Tree.Label (Node) /= Nonterm or else
-           not Overlaps (Tree.Byte_Region (Node, Trailing_Non_Grammar => 
False), Action_Region_Bytes)
-         then
-            return;
-         end if;
-
-         declare
-            Tree_Children     : constant Syntax_Trees.Node_Access_Array := 
Tree.Children (Node);
-            Post_Parse_Action : constant Syntax_Trees.Post_Parse_Action := 
Parser.Get_Post_Parse_Action
-              (Tree.Production_ID (Node));
-         begin
-            for Child of Tree_Children loop
-               if Child /= null and then Overlaps
-                 (Tree.Byte_Region (Child, Trailing_Non_Grammar => False), 
Action_Region_Bytes)
-               then
-                  Process_Node (Tree, Child);
-               end if;
-            end loop;
-
-            Parser.User_Data.Reduce (Tree, Node);
-
-            if Post_Parse_Action /= null then
-               Post_Parse_Action (Parser.User_Data.all, Tree, Node);
-            end if;
-         end;
-      end Process_Node;
+   function Image (Item : in Memo_Entry; Tree : in Syntax_Trees.Tree) return 
String
+   is begin
+      return
+        (case Item.State is
+         when No_Result => "",
+         when Failure => "fail @" & Image_Pos (Item.Max_Examined_Pos),
+         when Success => Tree.Image (Item.Result, Node_Numbers => True) &
+           " @" & Image_Pos (Item.Max_Examined_Pos) &
+           "," & Image_Pos (Item.Last_Pos));
+   end Image;
 
+   function Image
+     (Item      : in Memo_Entry;
+      Nonterm   : in Token_ID;
+      Pos       : in Syntax_Trees.Node_Index;
+      Tree      : in Syntax_Trees.Tree)
+     return String
+   is
+      Descriptor : WisiToken.Descriptor renames Tree.Lexer.Descriptor.all;
    begin
-      if Parser.User_Data = null then
-         return;
-      end if;
+      return
+        Syntax_Trees.Trimmed_Image (Pos) & ", " &
+        (case Item.State is
+         when No_Result => "",
+         when Failure => Image (Nonterm, Descriptor) & " fail @" &
+           Image_Pos (Item.Max_Examined_Pos),
+         when Success => Tree.Image (Item.Result, Node_Numbers => True, 
RHS_Index => True) &
+           "," & Image_Pos (Item.Max_Examined_Pos) &
+           "," & Image_Pos (Item.Last_Pos));
+   end Image;
 
-      if Trace_Action > Outline then
-         if Trace_Action > Extra then
-            Parser.Tree.Print_Tree (Parser.Tree.Root);
-            Parser.Tree.Lexer.Trace.New_Line;
-         end if;
-         Parser.Tree.Lexer.Trace.Put_Line ("root node: " & Parser.Tree.Image 
(Parser.Tree.Root));
-      end if;
+   function Image
+     (Item      : in Memo_Entry;
+      Nonterm   : in Token_ID;
+      RHS_Index : in Natural;
+      Pos       : in Syntax_Trees.Node_Index;
+      Tree      : in Syntax_Trees.Tree)
+     return String
+   is
+      Descriptor : WisiToken.Descriptor renames Tree.Lexer.Descriptor.all;
+   begin
+      return
+        Pos'Image & ", " &
+        (case Item.State is
+         when No_Result => "",
+         when Failure => Image (Production_ID'(Nonterm, RHS_Index), 
Descriptor) & " fail @" &
+           Image_Pos (Item.Max_Examined_Pos),
+         when Success => Tree.Image (Item.Result, Node_Numbers => True, 
RHS_Index => True) &
+           "," & Image_Pos (Item.Max_Examined_Pos) &
+           "," & Image_Pos (Item.Last_Pos));
+   end Image;
 
-      Parser.User_Data.Initialize_Actions (Parser.Tree);
-      Process_Node (Parser.Tree, Parser.Tree.Root);
-   exception
-   when E : others =>
-      if Debug_Mode then
-         Parser.Tree.Lexer.Trace.Put_Line
-           (Ada.Exceptions.Exception_Name (E) & ": " & 
Ada.Exceptions.Exception_Message (E));
-         Parser.Tree.Lexer.Trace.Put_Line 
(GNAT.Traceback.Symbolic.Symbolic_Traceback (E));
-         Parser.Tree.Lexer.Trace.New_Line;
-      end if;
-      raise;
-   end Execute_Actions;
+   function Image
+     (Item      : in Memo_Entry;
+      Nonterm   : in Token_ID;
+      Pos       : in Syntax_Trees.Stream_Index;
+      Tree      : in Syntax_Trees.Tree)
+     return String
+   is begin
+      return Image (Item, Nonterm, Tree.Get_Node_Index (Tree.Shared_Stream, 
Pos), Tree);
+   end Image;
 
-   function Image_Pos
-     (Tree    : in Syntax_Trees.Tree;
-      Stream  : in Syntax_Trees.Stream_ID;
-      Element : in Syntax_Trees.Stream_Index)
+   function Image
+     (Item      : in Memo_Entry;
+      Nonterm   : in Token_ID;
+      RHS_Index : in Natural;
+      Pos       : in Syntax_Trees.Stream_Index;
+      Tree      : in Syntax_Trees.Tree)
      return String
+   is begin
+      return Image (Item, Nonterm, RHS_Index, Tree.Get_Node_Index 
(Tree.Shared_Stream, Pos), Tree);
+   end Image;
+
+   function Image_Pos (Element : in Syntax_Trees.Stream_Index) return String
    is
       use Syntax_Trees;
    begin
       if Element = Invalid_Stream_Index then
          return "0";
       else
-         return Tree.Get_Node_Index (Stream, Element)'Image;
+         return Get_Node_Index (Element)'Image;
       end if;
    end Image_Pos;
 
+   procedure Clear (Derivs : in out Packrat.Derivs)
+   is begin
+      for D of Derivs loop
+         D.Clear (Free_Memory => True);
+      end loop;
+   end Clear;
+
+   function Get_Deriv
+     (Derivs  : in out Packrat.Derivs;
+      Nonterm : in     Token_ID;
+      Pos     : in     Positive_Node_Index)
+     return Memo_Entry
+   is begin
+      if Pos in Derivs (Nonterm).First_Index .. Derivs (Nonterm).Last_Index 
then
+         return Derivs (Nonterm)(Pos);
+      else
+         return No_Result_Memo;
+      end if;
+   end Get_Deriv;
+
+   procedure Set_Deriv
+     (Derivs  : in out Packrat.Derivs;
+      Nonterm : in     Token_ID;
+      Pos     : in     Positive_Node_Index;
+      Memo    : in     Memo_Entry)
+   is
+      use all type WisiToken.Syntax_Trees.Node_Index;
+   begin
+      if Pos < Derivs (Nonterm).First_Index then
+         Derivs (Nonterm).Set_First_Last (Pos, Derivs (Nonterm).Last_Index);
+
+      elsif Pos > Derivs (Nonterm).Last_Index then
+         Derivs (Nonterm).Set_First_Last (Derivs (Nonterm).First_Index, Pos);
+      end if;
+
+      Derivs (Nonterm).Replace_Element (Pos, Memo);
+   end Set_Deriv;
+
+   overriding procedure Finalize (Object : in out Parser)
+   is begin
+      Clear (Object.Derivs);
+   end Finalize;
+
+
+   procedure Finish_Parse
+     (Parser : in out Packrat.Parser'Class;
+      Result : in out Memo_Entry)
+   is
+      use WisiToken.Syntax_Trees;
+
+      Tree  : Syntax_Trees.Tree renames Parser.Tree;
+      Trace : WisiToken.Trace'Class renames Tree.Lexer.Trace.all;
+
+   begin
+      if Result.State = Packrat.Success then
+         Tree.Set_Root (Result.Result);
+         Result := No_Result_Memo;
+         Clear (Parser.Derivs);
+         Tree.Finish_Parse;
+
+         if Trace_Parse > Outline then
+            Trace.Put_Line ("packrat parse succeed");
+         end if;
+
+      else
+         if Trace_Parse > Outline then
+            Trace.Put_Line ("packrat parse fail @" & Image_Pos 
(Result.Max_Examined_Pos));
+         end if;
+         raise Syntax_Error with Tree.Error_Message
+           (Tree.To_Rooted_Ref (Tree.Shared_Stream, Result.Max_Examined_Pos), 
"packrat parse fail");
+      end if;
+   end Finish_Parse;
+
 end WisiToken.Parse.Packrat;
diff --git a/wisitoken-parse-packrat.ads b/wisitoken-parse-packrat.ads
index 0c59dc9746..59ec0fbaad 100644
--- a/wisitoken-parse-packrat.ads
+++ b/wisitoken-parse-packrat.ads
@@ -14,7 +14,7 @@
 --  [warth 2008]  Warth, A., Douglass, J.R. and Millstein, T.D., 2008. Packrat
 --                parsers can support left recursion. PEPM, 8, pp.103-110.
 --
---  Copyright (C) 2018, 2020 - 2021 Free Software Foundation, Inc.
+--  Copyright (C) 2018, 2020 - 2022 Free Software Foundation, Inc.
 --
 --  This library is free software;  you can redistribute it and/or modify it
 --  under terms of the  GNU General Public License  as published by the Free
@@ -47,19 +47,109 @@ pragma License (Modified_GPL);
 with WisiToken.Syntax_Trees;
 package WisiToken.Parse.Packrat is
 
-   type Parser is abstract new Base_Parser with null record;
+   type Memo_State is (No_Result, Failure, Success);
+   subtype Result_States is Memo_State range Failure .. Success;
 
-   overriding
-   procedure Execute_Actions
-     (Parser              : in out Packrat.Parser;
-      Action_Region_Bytes : in     WisiToken.Buffer_Region := 
WisiToken.Null_Buffer_Region);
+   type Memo_Entry (State : Memo_State := No_Result) is record
+      Max_Examined_Pos : Syntax_Trees.Stream_Index;
+      --  For error message.
 
-   function Image_Pos
-     (Tree    : in Syntax_Trees.Tree;
-      Stream  : in Syntax_Trees.Stream_ID;
-      Element : in Syntax_Trees.Stream_Index)
-     return String
-   with Pre => Tree.Contains (Stream, Element);
+      case State is
+      when No_Result =>
+         Recursive : Boolean := False;
+
+      when Failure =>
+         null;
+
+      when Success =>
+         Result   : Syntax_Trees.Node_Access;
+         Last_Pos : Syntax_Trees.Stream_Index; -- Last terminal in Result
+
+      end case;
+   end record;
+   subtype Success_Memo_Entry is Memo_Entry (Success);
+   subtype Result_Type is Memo_Entry with Dynamic_Predicate => 
Result_Type.State in Result_States;
+
+   No_Result_Memo : constant Memo_Entry := (No_Result, 
WisiToken.Syntax_Trees.Invalid_Stream_Index, False);
+
+   function Image_Pos (Element : in Syntax_Trees.Stream_Index) return String;
    --  "0" for Invalid_Stream_Index, Node_Index'Image otherwise.
 
+   function Image (Item : in Memo_Entry; Tree : in Syntax_Trees.Tree) return 
String;
+
+   function Image
+     (Item      : in Memo_Entry;
+      Nonterm   : in Token_ID;
+      Pos       : in Syntax_Trees.Node_Index;
+      Tree      : in Syntax_Trees.Tree)
+     return String;
+
+   function Image
+     (Item      : in Memo_Entry;
+      Nonterm   : in Token_ID;
+      RHS_Index : in Natural;
+      Pos       : in Syntax_Trees.Node_Index;
+      Tree      : in Syntax_Trees.Tree)
+     return String;
+
+   function Image
+     (Item      : in Memo_Entry;
+      Nonterm   : in Token_ID;
+      Pos       : in Syntax_Trees.Stream_Index;
+      Tree      : in Syntax_Trees.Tree)
+     return String;
+
+   function Image
+     (Item      : in Memo_Entry;
+      Nonterm   : in Token_ID;
+      RHS_Index : in Natural;
+      Pos       : in Syntax_Trees.Stream_Index;
+      Tree      : in Syntax_Trees.Tree)
+     return String;
+
+   subtype Positive_Node_Index is Syntax_Trees.Node_Index range 1 .. 
Syntax_Trees.Node_Index'Last;
+   package Memos is new SAL.Gen_Unbounded_Definite_Vectors
+     (Positive_Node_Index, Memo_Entry, Default_Element => (others => <>));
+   --  Memos is indexed by Node_Index of terminals in Shared_Stream
+   --  (incremental parse is not supported).
+
+   type Derivs is array (Token_ID range <>) of Memos.Vector;
+
+   procedure Clear (Derivs : in out Packrat.Derivs);
+   --  Free memory allocated by Derivs; set all to Empty_Vector.
+
+   function Get_Deriv
+     (Derivs  : in out Packrat.Derivs;
+      Nonterm : in     Token_ID;
+      Pos     : in     Positive_Node_Index)
+     return Memo_Entry;
+   --  Return Derivs (Nonterm)(Pos) if present; No_Result_Memo if not.
+
+   procedure Set_Deriv
+     (Derivs  : in out Packrat.Derivs;
+      Nonterm : in     Token_ID;
+      Pos     : in     Positive_Node_Index;
+      Memo    : in     Memo_Entry);
+   --  Add or replace Derivs (Nonterm)(Pos).
+
+   type Parser (First_Nonterminal, Last_Nonterminal : Token_ID) is abstract 
new WisiToken.Parse.Base_Parser with
+   record
+      Direct_Left_Recursive : Token_ID_Set (First_Nonterminal .. 
Last_Nonterminal);
+      Derivs                : Packrat.Derivs (First_Nonterminal .. 
Last_Nonterminal);
+   end record;
+
+   overriding procedure Finalize (Object : in out Parser);
+
+   procedure Finish_Parse
+     (Parser : in out Packrat.Parser'Class;
+      Result : in out Memo_Entry);
+   --  If a single parser succeeded, leaves Parser.Tree in
+   --  Fully_Parsed state.
+   --
+   --  If there were recovered errors, the error information is in
+   --  Parser.Tree.
+   --
+   --  If the parse did not succeed, raise Parse_Error with an error
+   --  message, and Parser.Parsers is left intact for error recover.
+
 end WisiToken.Parse.Packrat;
diff --git a/wisitoken-parse.adb b/wisitoken-parse.adb
index 9920d8577e..108df00749 100644
--- a/wisitoken-parse.adb
+++ b/wisitoken-parse.adb
@@ -17,6 +17,8 @@
 
 pragma License (Modified_GPL);
 
+with Ada.Exceptions;
+with GNAT.Traceback.Symbolic;
 with WisiToken.In_Parse_Actions;
 package body WisiToken.Parse is
 
@@ -85,12 +87,12 @@ package body WisiToken.Parse is
       when Insert =>
          String'Write (Stream, Item.Ins_ID'Image);
          --  Ignore Ins_Before.
-         String'Write (Stream, Syntax_Trees.Get_Node_Index 
(Item.Ins_Node)'Image);
+         String'Write (Stream, " " & Syntax_Trees.Get_Node_Index 
(Item.Ins_Node)'Image);
 
       when Delete =>
          String'Write (Stream, Item.Del_ID'Image);
          --  Ignore Del_Index.
-         String'Write (Stream, Syntax_Trees.Get_Node_Index 
(Item.Del_Node)'Image);
+         String'Write (Stream, " " & Syntax_Trees.Get_Node_Index 
(Item.Del_Node)'Image);
 
       end case;
       Character'Write (Stream, ')');
@@ -1177,4 +1179,102 @@ package body WisiToken.Parse is
       Put_Errors (Parser.Tree, Stream);
    end Put_Errors;
 
+   procedure Execute_Actions
+     (Tree                : in out Syntax_Trees.Tree;
+      Productions         : in     Syntax_Trees.Production_Info_Trees.Vector;
+      User_Data           : in     Syntax_Trees.User_Data_Access;
+      Action_Region_Bytes : in     WisiToken.Buffer_Region := 
WisiToken.Null_Buffer_Region)
+   is
+      use all type WisiToken.Syntax_Trees.Node_Access;
+      use all type Syntax_Trees.Post_Parse_Action;
+      use all type Syntax_Trees.User_Data_Access;
+
+      procedure Process_Node
+        (Tree : in out Syntax_Trees.Tree;
+         Node : in     Syntax_Trees.Valid_Node_Access)
+      is
+         use all type Syntax_Trees.Node_Label;
+         Node_Byte_Region : constant Buffer_Region := Tree.Byte_Region
+           (Node, Trailing_Non_Grammar => True);
+      begin
+         if Tree.Label (Node) /= Nonterm or else
+           not (Node_Byte_Region = Null_Buffer_Region or
+                  Action_Region_Bytes = Null_Buffer_Region or
+                  Overlaps (Node_Byte_Region, Action_Region_Bytes))
+         then
+            return;
+         end if;
+
+         for Child of Tree.Children (Node) loop
+            if Child /= Syntax_Trees.Invalid_Node_Access then
+               --  Child can be null in an edited tree
+               Process_Node (Tree, Child);
+            end if;
+         end loop;
+
+         User_Data.Reduce (Tree, Node);
+         declare
+            Post_Parse_Action : constant Syntax_Trees.Post_Parse_Action := 
Get_Post_Parse_Action
+              (Productions, Tree.Production_ID (Node));
+         begin
+            if Post_Parse_Action /= null then
+               begin
+                  Post_Parse_Action (User_Data.all, Tree, Node);
+               exception
+               when E : others =>
+                  if Trace_Tests > Outline then
+                     --  running a unit test; exception may be AUnit assert 
fail
+                     raise;
+
+                  elsif WisiToken.Debug_Mode then
+                     Tree.Lexer.Trace.Put_Line
+                       (Ada.Exceptions.Exception_Name (E) & ": " & 
Ada.Exceptions.Exception_Message (E));
+                     Tree.Lexer.Trace.Put_Line 
(GNAT.Traceback.Symbolic.Symbolic_Traceback (E));
+                     Tree.Lexer.Trace.New_Line;
+                  end if;
+
+                  raise WisiToken.Parse_Error with Tree.Error_Message
+                    (Node,
+                     "action raised exception " & 
Ada.Exceptions.Exception_Name (E) & ": " &
+                       Ada.Exceptions.Exception_Message (E));
+               end;
+            end if;
+         end;
+      end Process_Node;
+
+   begin
+      if User_Data = null then
+         return;
+      end if;
+
+      if Tree.Root = Syntax_Trees.Invalid_Node_Access then
+         --  No code in file, and error recovery failed to insert valid code.
+         --  Or ambiguous parse; Finish_Parse not called.
+         return;
+      end if;
+
+      User_Data.Initialize_Actions (Tree);
+
+      Process_Node (Tree, Tree.Root);
+   exception
+   when WisiToken.Parse_Error =>
+      raise;
+
+   when E : others =>
+      if Debug_Mode then
+         Tree.Lexer.Trace.Put_Line
+           (Ada.Exceptions.Exception_Name (E) & ": " & 
Ada.Exceptions.Exception_Message (E));
+         Tree.Lexer.Trace.Put_Line (GNAT.Traceback.Symbolic.Symbolic_Traceback 
(E));
+         Tree.Lexer.Trace.New_Line;
+      end if;
+      raise;
+   end Execute_Actions;
+
+   procedure Execute_Actions
+     (Parser              : in out WisiToken.Parse.Base_Parser'Class;
+      Action_Region_Bytes : in     WisiToken.Buffer_Region := 
WisiToken.Null_Buffer_Region)
+   is begin
+      Execute_Actions (Parser.Tree, Parser.Productions, Parser.User_Data, 
Action_Region_Bytes);
+   end Execute_Actions;
+
 end WisiToken.Parse;
diff --git a/wisitoken-parse.ads b/wisitoken-parse.ads
index fdf482f031..b9c5b54b1a 100644
--- a/wisitoken-parse.ads
+++ b/wisitoken-parse.ads
@@ -498,9 +498,17 @@ package WisiToken.Parse is
       Tree        : aliased Syntax_Trees.Tree;
       Productions : Syntax_Trees.Production_Info_Trees.Vector;
       User_Data   : Syntax_Trees.User_Data_Access;
+
+      Partial_Parse_Active    : access Boolean;
+      Partial_Parse_Byte_Goal : access WisiToken.Buffer_Pos;
+      --  Used by In_Parse_Actions to terminate Partial_Parse.
    end record;
    --  Common to all parsers. Finalize should free any allocated objects.
 
+   type Base_Parser_Access is access all Base_Parser'Class;
+   type Factory is access function return Base_Parser_Access;
+   type Free_Parser is access procedure (Object : in out Base_Parser_Access);
+
    function Source_File_Name (Item : in Base_Parser'Class) return String
    is (Item.Tree.Lexer.File_Name);
 
@@ -616,9 +624,16 @@ package WisiToken.Parse is
    --  Output Parser.Tree.Stream errors to Tree.Lexer.Trace.
 
    procedure Execute_Actions
-     (Parser              : in out Base_Parser;
-      Action_Region_Bytes : in     WisiToken.Buffer_Region := 
WisiToken.Null_Buffer_Region)
-   is abstract;
+     (Tree                : in out Syntax_Trees.Tree;
+      Productions         : in     Syntax_Trees.Production_Info_Trees.Vector;
+      User_Data           : in     Syntax_Trees.User_Data_Access;
+      Action_Region_Bytes : in     WisiToken.Buffer_Region := 
WisiToken.Null_Buffer_Region);
+   --  Implements Execute_Actions, allows specifying different tree
+   --  (needed by wisitoken-bnf-generate).
+
+   procedure Execute_Actions
+     (Parser              : in out Base_Parser'Class;
+      Action_Region_Bytes : in     WisiToken.Buffer_Region := 
WisiToken.Null_Buffer_Region);
    --  Execute all actions in Parser.Tree nodes that overlap
    --  Action_Region_Bytes; all nodes if Action_Region_Bytes =
    --  Null_Buffer_Region. See wisitoken-syntax_trees.ads for other
diff --git a/wisitoken-parse_table-mode.el b/wisitoken-parse_table-mode.el
index 5a3c712ada..7685b38fdb 100644
--- a/wisitoken-parse_table-mode.el
+++ b/wisitoken-parse_table-mode.el
@@ -7,7 +7,7 @@
 ;; Keywords: parser
 ;; Version: 1.0
 ;; package-requires: ((emacs "25.1"))
-;; URL: http://www.nongnu.org/ada-mode/wisi/wisi.html
+;; URL: https://www.nongnu.org/ada-mode/wisi/wisi.html
 ;;
 ;; This file is part of GNU Emacs.
 ;;
@@ -22,9 +22,10 @@
 ;; GNU General Public License for more details.
 ;;
 ;; You should have received a copy of the GNU General Public License
-;; along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+;; along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
 
 (require 'xref)
+(require 'wisi-prj)                     ;For `wisi-goto-source'.
 
 (defvar wisitoken-parse_table-last-buffer nil
   "Last buffer in which a wisitoken-parse_table operation was performed")
@@ -115,7 +116,8 @@ Symbol can be a nonterminal name, or a state number."
 (defun wisitok-p_t-conflict-alist ()
   (let ((conflicts nil)
        (nonterms (wisitok-p_t-nonterm-alist))
-       line)
+       line
+       (count 0))
 
     (save-excursion
       (goto-char (point-min))
@@ -147,7 +149,10 @@ Symbol can be a nonterminal name, or a state number."
          (setq conflict (concat conflict " on token " on-token))
 
          (push (cons conflict (list (buffer-file-name) line 0)) conflicts)
-         )))
+         )
+       ;; Let user know we are not hung; can take a long time in large buffers.
+       (setq count (1+ count))
+       (message "conflict %d" count)))
     conflicts))
 
 (defconst wisitok-p_t-action-nonterm-regexp "\\(?:SHIFT\\|REDUCE\\) 
[[:alnum:]_]+")
diff --git a/wisitoken-productions.ads b/wisitoken-productions.ads
index b134a50bab..f3412b209a 100644
--- a/wisitoken-productions.ads
+++ b/wisitoken-productions.ads
@@ -37,8 +37,8 @@ package WisiToken.Productions is
       --  Recursion for each token. There may be more than one recursion cycle 
for any token,
       --  but we don't track that.
 
-      Post_Parse_Action : Syntax_Trees.Post_Parse_Action;
-      In_Parse_Action   : Syntax_Trees.In_Parse_Actions.In_Parse_Action;
+      Post_Parse_Action : Syntax_Trees.Post_Parse_Action := null;
+      In_Parse_Action   : Syntax_Trees.In_Parse_Actions.In_Parse_Action := 
null;
    end record
    with Dynamic_Predicate =>
      (Tokens.Length = 0 or Tokens.First_Index = 1) and
diff --git a/wisitoken-syntax_trees.adb b/wisitoken-syntax_trees.adb
index cb90dff031..4a1e3760b1 100644
--- a/wisitoken-syntax_trees.adb
+++ b/wisitoken-syntax_trees.adb
@@ -109,7 +109,8 @@ package body WisiToken.Syntax_Trees is
    procedure Last_Source_Terminal
      (Tree                 : in     Syntax_Trees.Tree;
       Ref                  : in out Stream_Node_Parents;
-      Trailing_Non_Grammar : in     Boolean)
+      Trailing_Non_Grammar : in     Boolean;
+      Parse_Stream         : in     Stream_ID)
    with Pre => Rooted (Ref.Ref) and Ref.Parents.Depth = 0;
    --  Update Ref to last source terminal in Ref.Node, initialize Ref.Parents.
 
@@ -146,12 +147,6 @@ package body WisiToken.Syntax_Trees is
       Ref                  : in out Stream_Node_Parents;
       Trailing_Non_Grammar : in     Boolean);
 
-   function Prev_Source_Terminal
-     (Tree                 : in Syntax_Trees.Tree;
-      Node                 : in Node_Access;
-      Trailing_Non_Grammar : in Boolean)
-     return Node_Access;
-
    procedure Prev_Terminal
      (Tree    : in     Syntax_Trees.Tree;
       Node    : in out Node_Access;
@@ -1331,7 +1326,7 @@ package body WisiToken.Syntax_Trees is
          Prev_Source_Terminal := Ref;
          Tree.First_Source_Terminal (Prev_Source_Terminal, 
Trailing_Non_Grammar);
          Next_Source_Terminal := Ref;
-         Tree.Last_Source_Terminal (Next_Source_Terminal, 
Trailing_Non_Grammar);
+         Tree.Last_Source_Terminal (Next_Source_Terminal, 
Trailing_Non_Grammar, Parse_Stream);
 
          if Prev_Source_Terminal.Ref.Node = Invalid_Node_Access then
             Tree.Prev_Source_Terminal (Prev_Source_Terminal, Parse_Stream, 
Trailing_Non_Grammar);
@@ -1631,6 +1626,21 @@ package body WisiToken.Syntax_Trees is
       return Node.Children;
    end Children;
 
+   function Children_Recover_Tokens
+     (Tree : in Syntax_Trees.Tree;
+      Node : in Valid_Node_Access)
+     return Recover_Token_Array
+   is begin
+      --  WORKAROUND: GNAT Community 2020 doesn't support 'of' here, and it
+      --  hangs if there are any errors in the statement with 'in'.
+      --  return (for I in Node.Children'Range => Tree.Get_Recover_Token 
(Node.Children (I)));
+      return Result : Recover_Token_Array (1 .. Node.Child_Count) do
+         for I in Node.Children'Range loop
+            Result (I) := Tree.Get_Recover_Token (Node.Children (I));
+         end loop;
+      end return;
+   end Children_Recover_Tokens;
+
    function Children_Recover_Tokens
      (Tree    : in Syntax_Trees.Tree;
       Stream  : in Stream_ID;
@@ -1715,130 +1725,36 @@ package body WisiToken.Syntax_Trees is
       Node.Parent := Invalid_Node_Access;
    end Clear_Parent;
 
-   procedure Clear_Parse_Streams
-     (Tree       : in out Syntax_Trees.Tree;
-      Keep_Nodes : in     Valid_Node_Access_Lists.List := 
Valid_Node_Access_Lists.Empty_List)
-   is begin
-      if Tree.Root = Invalid_Node_Access then
-         Tree.Root := Syntax_Trees.Root (Tree);
-      end if;
-
-      --  Add SOI, EOI (from the parse stream, to include any
-      --  Following_Deleted and Error_Data) to Root children, so
-      --  Prev/Next_Non_Grammar can find them.
-      declare
-         Parse_Stream : Syntax_Trees.Parse_Stream renames Tree.Streams 
(Tree.Streams.Last);
-         SOI : constant Valid_Node_Access := Stream_Element_Lists.Element 
(Parse_Stream.Elements.First).Node;
-
-         Last_Node : constant Valid_Node_Access := 
Stream_Element_Lists.Element (Parse_Stream.Elements.Last).Node;
-
-         EOI : constant Valid_Node_Access :=
-           (if Tree.ID (Last_Node) = Tree.Lexer.Descriptor.EOI_ID
-            then Last_Node
-            else Tree.EOI);
-
-         New_Children : Node_Access_Array (1 .. Tree.Root.Child_Count + 2);
-      begin
-         if Tree.Streams.Last = Tree.Shared_Stream.Cur and 
Tree.Root.Child_Count = 3 then
-            --  This is a packrat parse; SOI, EOI already in tree
-            pragma Assert (Tree.Root.Children (1) = Tree.SOI and 
Tree.Root.Children (3) = EOI);
-         else
-            --  There is a parse stream, or this is an incremental parse where 
the
-            --  edit did not require a parse.
-            New_Children (1) := SOI;
-            New_Children (2 .. New_Children'Last - 1) := Tree.Root.Children;
-            New_Children (New_Children'Last) := EOI;
-
-            Tree.SOI := SOI;
-            Tree.EOI := EOI;
+   procedure Clear_Parse_Streams (Tree : in out Syntax_Trees.Tree)
+   is
+      use Parse_Stream_Lists;
+      Cur : Cursor := Tree.Streams.First;
+   begin
+      pragma Assert (Cur = Tree.Shared_Stream.Cur);
+      Next (Cur); --  first parse stream
 
-            Tree.Root.Children := (others => Invalid_Node_Access);
+      loop
+         exit when Cur = No_Element;
 
-            Tree.Root := new Node'
-              (Label       => Nonterm,
-               Copied_Node => Invalid_Node_Access,
-               Child_Count => Tree.Root.Child_Count + 2,
-               ID          => Tree.Root.ID,
-               Node_Index  => Tree.Root.Node_Index,
-               Parent      => null,
-               Augmented   => Tree.Root.Augmented,
-               Error_List  =>
-                 (if Tree.Root.Error_List = null
-                  then null
-                  else new Error_Data_Lists.List'(Tree.Root.Error_List.all)),
-               Virtual          => Tree.Root.Virtual,
-               Recover_Conflict => False,
-               RHS_Index        => Tree.Root.RHS_Index,
-               Name_Offset      => Tree.Root.Name_Offset,
-               Name_Length      => Tree.Root.Name_Length,
-               Children         => New_Children);
+         declare
+            Stream : Parse_Stream renames Tree.Streams (Cur);
+            To_Delete : Cursor := Cur;
+         begin
+            --  Clear saved element list cursors in parse streams before 
freeing
+            --  the element lists, so they don't try to decrement reference 
counts
+            --  in deallocated elements.
+            Stream.Stack_Top   := Stream_Element_Lists.No_Element;
+            Stream.Shared_Link := Stream_Element_Lists.No_Element;
 
-            for Child of New_Children loop
-               Child.Parent := Tree.Root;
-            end loop;
+            Stream.Elements.Finalize;
 
-            Tree.Nodes.Append (Tree.Root);
-         end if;
-      end;
+            Next (Cur);
+            Tree.Streams.Delete (To_Delete);
+         end;
 
-      --  Clear saved element list cursors in parse streams before freeing
-      --  the element lists, so they don't try to decrement reference counts
-      --  in deallocated elements. We can't rely on cursor Finalize for
-      --  this; that's done in arbitrary order.
-      for Stream of Tree.Streams loop
-         Stream.Stack_Top   := Stream_Element_Lists.No_Element;
-         Stream.Shared_Link := Stream_Element_Lists.No_Element;
       end loop;
 
-      Tree.Streams.Clear;
       Tree.Next_Stream_Label := Shared_Stream_Label + 1;
-
-      Tree.Shared_Stream.Cur := Parse_Stream_Lists.No_Element;
-
-      if not Tree.Parents_Set then
-         Set_Parents (Tree);
-      end if;
-
-      for Node of Tree.Nodes loop
-         --  Only nodes that have parents are part of the final parse result.
-         --  In an incremental parse, breakdown removes nodes from a parse
-         --  stream, and clears any parent pointers involved.
-         if Node.Parent = null and then
-           Node /= Tree.Root and then
-           Node /= Tree.SOI and then
-           Node /= Tree.EOI and then
-           not (for some N of Keep_Nodes => N = Node)
-         then
-            --  It is tempting to try to enforce that all deleted nonterms have
-            --  Children = (others => Invalid_Node_Access) here. However, that 
is
-            --  not true when Breakdown is called by the main parser;
-            --  Tree.Parents_Set is false, indicating there might be multiple
-            --  streams, so Breakdown does not clear children.
-            Free (Node);
-         end if;
-      end loop;
-
-      --  Compact Tree.Nodes
-      declare
-         Free : Node_Index := Tree.Nodes.First_Index - 1;
-      begin
-         for I in Tree.Nodes.First_Index .. Tree.Nodes.Last_Index loop
-            if Free < Tree.Nodes.First_Index then
-               if Tree.Nodes (I) = Invalid_Node_Access then
-                  Free := I;
-               end if;
-            else
-               if Tree.Nodes (I) /= Invalid_Node_Access then
-                  Tree.Nodes (Free) := Tree.Nodes (I);
-                  Free := @ + 1;
-               end if;
-            end if;
-         end loop;
-
-         if Free > Tree.Nodes.First_Index then
-            Tree.Nodes.Set_First_Last (First => Tree.Nodes.First_Index, Last 
=> Free - 1);
-         end if;
-      end;
    end Clear_Parse_Streams;
 
    function Column (Tree : in Syntax_Trees.Tree; Node : in Valid_Node_Access) 
return Ada.Text_IO.Count
@@ -3068,14 +2984,17 @@ package body WisiToken.Syntax_Trees is
       Non_Grammar : Node_Access := Invalid_Node_Access;
       Null_Non_Grammar : WisiToken.Lexer.Token_Arrays.Vector;
    begin
-      begin
-         --  Tolerate broken trees where Prev_Non_Grammar doesn't find SOI, or
-         --  raises an exception.
-         Non_Grammar := Tree.Prev_Non_Grammar (Node);
-      exception
-      when others =>
-         null;
-      end;
+      if Tree.Parents_Set then
+         begin
+            --  Tolerate broken trees where Prev_Non_Grammar doesn't find SOI, 
or
+            --  raises an exception.
+            Non_Grammar := Tree.Prev_Non_Grammar (Node);
+         exception
+         when others =>
+            null;
+         end;
+      end if;
+
       return Error_Message_1
         (Tree,
          (if Non_Grammar = Invalid_Node_Access then Null_Non_Grammar else 
Non_Grammar.Non_Grammar),
@@ -3853,6 +3772,65 @@ package body WisiToken.Syntax_Trees is
       end if;
    end Find_Sibling;
 
+   procedure Finish_Parse (Tree : in out Syntax_Trees.Tree)
+   is begin
+      --  Clear saved element list cursors in parse streams before freeing
+      --  the element lists, so they don't try to decrement reference counts
+      --  in deallocated elements. We can't rely on cursor Finalize for
+      --  this; that's done in arbitrary order.
+      for Stream of Tree.Streams loop
+         Stream.Stack_Top   := Stream_Element_Lists.No_Element;
+         Stream.Shared_Link := Stream_Element_Lists.No_Element;
+      end loop;
+
+      Tree.Shared_Stream.Cur := Parse_Stream_Lists.No_Element;
+
+      Tree.Streams.Clear;
+      Tree.Next_Stream_Label := Shared_Stream_Label + 1;
+
+      if not Tree.Parents_Set then
+         Set_Parents (Tree);
+      end if;
+
+      for Node of Tree.Nodes loop
+         --  Only nodes that have parents are part of the final parse result.
+         --  In an incremental parse, breakdown removes nodes from a parse
+         --  stream, and clears any parent pointers involved.
+         if Node.Parent = null and then
+           Node /= Tree.Root
+         then
+            --  It is tempting to try to enforce that all deleted nonterms have
+            --  Children = (others => Invalid_Node_Access) here. However, that 
is
+            --  not true when Breakdown is called by the main parser;
+            --  Tree.Parents_Set is false, indicating there might be multiple
+            --  streams, so Breakdown does not clear children.
+            Free (Node);
+         end if;
+      end loop;
+
+      --  Compact Tree.Nodes
+      declare
+         Free : Node_Index := Tree.Nodes.First_Index - 1;
+      begin
+         for I in Tree.Nodes.First_Index .. Tree.Nodes.Last_Index loop
+            if Free < Tree.Nodes.First_Index then
+               if Tree.Nodes (I) = Invalid_Node_Access then
+                  Free := I;
+               end if;
+            else
+               if Tree.Nodes (I) /= Invalid_Node_Access then
+                  Tree.Nodes (Free) := Tree.Nodes (I);
+                  Free := @ + 1;
+               end if;
+            end if;
+         end loop;
+
+         if Free > Tree.Nodes.First_Index then
+            Tree.Nodes.Set_First_Last (First => Tree.Nodes.First_Index, Last 
=> Free - 1);
+         end if;
+      end;
+   end Finish_Parse;
+
    overriding function First (Object : Error_Iterator) return Error_Ref
    is begin
       return First_Error (Object.Tree.all);
@@ -3959,16 +3937,17 @@ package body WisiToken.Syntax_Trees is
 
    function First_Error (Tree : in Syntax_Trees.Tree; Stream : in Stream_ID) 
return Stream_Error_Ref
    is begin
-      return Result : Stream_Error_Ref :=
-        (Ref     => Tree.To_Stream_Node_Parents
-           (Tree.To_Rooted_Ref (Stream, Tree.Stream_First (Stream, Skip_SOI => 
True))),
-         Deleted => Valid_Node_Access_Lists.No_Element,
-         Error   => Error_Data_Lists.No_Element)
+      return Result : Stream_Error_Ref := Invalid_Stream_Error_Ref
       do
-         if Result.Ref.Ref.Node.Label = Source_Terminal then
-            Result.Deleted := Result.Ref.Ref.Node.Following_Deleted.First;
+         if Tree.Streams (Stream.Cur).Elements.Length > 1 then
+            Result.Ref := Tree.To_Stream_Node_Parents
+              (Tree.To_Rooted_Ref (Stream, Tree.Stream_First (Stream, Skip_SOI 
=> True)));
+
+            if Result.Ref.Ref.Node.Label = Source_Terminal then
+               Result.Deleted := Result.Ref.Ref.Node.Following_Deleted.First;
+            end if;
+            First_Error (Tree, Result);
          end if;
-         First_Error (Tree, Result);
       end return;
    end First_Error;
 
@@ -4077,8 +4056,7 @@ package body WisiToken.Syntax_Trees is
    is begin
       Ref.Ref.Node := First_Terminal (Tree, Ref.Ref.Node, Ref.Parents);
       loop
-         exit when Ref.Ref.Node = Invalid_Node_Access;
-         exit when
+         exit when Ref.Ref.Node /= Invalid_Node_Access and then
            (if Trailing_Non_Grammar
             then (case Terminal_Label'(Ref.Ref.Node.Label) is
                   when Source_Terminal => True,
@@ -4086,7 +4064,7 @@ package body WisiToken.Syntax_Trees is
                   when Virtual_Identifier => Ref.Ref.Node.Non_Grammar.Length > 
0)
             else Ref.Ref.Node.Label = Source_Terminal);
 
-         Next_Terminal (Tree, Ref.Ref.Node, Ref.Parents);
+         Next_Terminal (Tree, Ref, Following => True);
       end loop;
    end First_Source_Terminal;
 
@@ -4340,7 +4318,7 @@ package body WisiToken.Syntax_Trees is
 
    function Fully_Parsed (Tree : in Syntax_Trees.Tree) return Boolean
    is begin
-      return Tree.Streams.Length = 2 and then Tree.Stream_Length ((Cur => 
Tree.Streams.Last)) in 2 .. 3;
+      return Tree.Root /= Invalid_Node_Access;
    end Fully_Parsed;
 
    procedure Get_IDs
@@ -4670,6 +4648,11 @@ package body WisiToken.Syntax_Trees is
                begin
                   case Terminal_Label'(Label) is
                   when Source_Terminal =>
+                     if Node_Index = 0 and ID /= Tree.Lexer.Descriptor.SOI_ID 
then
+                        raise WisiToken.User_Error with "source_terminal 
node_index 0 has id" & ID'Image &
+                          " /= SOI; probably wrong language.";
+                     end if;
+
                      pragma Assert
                        (Child_Count = 0 and
                           (Node_Index > 0 or else ID = 
Tree.Lexer.Descriptor.SOI_ID));
@@ -4964,41 +4947,18 @@ package body WisiToken.Syntax_Trees is
       return Child.Parent /= Invalid_Node_Access;
    end Has_Parent;
 
-   function ID
-     (Tree : in Syntax_Trees.Tree;
-      Node : in Valid_Node_Access)
-     return Token_ID
+   function ID (Tree : in Syntax_Trees.Tree; Node : in Valid_Node_Access) 
return Token_ID
    is
       pragma Unreferenced (Tree);
    begin
       return Node.ID;
    end ID;
 
-   function ID
-     (Tree    : in Syntax_Trees.Tree;
-      Stream  : in Stream_ID;
-      Element : in Stream_Index)
-     return Token_ID
-   is
-      pragma Unreferenced (Tree, Stream);
-   begin
-      return Stream_Element_Lists.Element (Element.Cur).Node.ID;
-   end ID;
-
-   function ID
-     (Tree : in Syntax_Trees.Tree;
-      Ref  : in Stream_Node_Ref)
-     return WisiToken.Token_ID
+   function ID (Tree : in Syntax_Trees.Tree; Element : in Stream_Index) return 
Token_ID
    is
       pragma Unreferenced (Tree);
    begin
-      if Ref.Node /= Invalid_Node_Access then
-         return Ref.Node.ID;
-      elsif Ref.Element /= Invalid_Stream_Index then
-         return Stream_Element_Lists.Element (Ref.Element.Cur).Node.ID;
-      else
-         return Invalid_Token_ID;
-      end if;
+      return Stream_Element_Lists.Element (Element.Cur).Node.ID;
    end ID;
 
    function Identifier (Tree : in Syntax_Trees.Tree; Node : in 
Valid_Node_Access) return Base_Identifier_Index
@@ -5775,12 +5735,12 @@ package body WisiToken.Syntax_Trees is
    procedure Last_Source_Terminal
      (Tree                 : in     Syntax_Trees.Tree;
       Ref                  : in out Stream_Node_Parents;
-      Trailing_Non_Grammar : in     Boolean)
+      Trailing_Non_Grammar : in     Boolean;
+      Parse_Stream         : in     Stream_ID)
    is begin
       Ref.Ref.Node := Last_Terminal (Tree, Ref.Ref.Node, Ref.Parents);
       loop
-         exit when Ref.Ref.Node = Invalid_Node_Access;
-         exit when
+         exit when Ref.Ref.Node /= Invalid_Node_Access and then
            (if Trailing_Non_Grammar
             then (case Terminal_Label'(Ref.Ref.Node.Label) is
                   when Source_Terminal => True,
@@ -5788,7 +5748,7 @@ package body WisiToken.Syntax_Trees is
                   when Virtual_Identifier => Ref.Ref.Node.Non_Grammar.Length > 
0)
             else Ref.Ref.Node.Label = Source_Terminal);
 
-         Prev_Terminal (Tree, Ref.Ref.Node, Ref.Parents);
+         Prev_Terminal (Tree, Ref, Parse_Stream, Preceding => True);
       end loop;
    end Last_Source_Terminal;
 
@@ -5966,7 +5926,13 @@ package body WisiToken.Syntax_Trees is
                   end if;
                end;
                Parse_Stream.Elements.Delete (To_Delete);
-               To_Delete := Cur;
+
+               if Element (Cur).Node.Label = Nonterm then
+                  To_Delete := Cur;
+               else
+                  --  ada_mode-interactive_04.adb
+                  To_Delete := No_Element;
+               end if;
             end if;
          end if;
 
@@ -5988,7 +5954,9 @@ package body WisiToken.Syntax_Trees is
          end;
 
          if Node.Label in Terminal_Label then
-            if To_Delete /= Cur and Next_I /= First_Child then
+            if To_Delete = No_Element or else
+              (To_Delete /= Cur and Next_I /= First_Child)
+            then
                Ref.Element.Cur := Cur;
 
             else
@@ -6003,16 +5971,18 @@ package body WisiToken.Syntax_Trees is
 
             Ref.Node := Node;
 
-            declare
-               Node : constant Valid_Node_Access := 
Stream_Element_Lists.Element (To_Delete).Node;
-            begin
-               if Node.Error_List /= null then
-                  for Err of Tree.Error_List (Node) loop
-                     New_Errors.Append (To_Message (Err, Tree, Node));
-                  end loop;
-               end if;
-            end;
-            Parse_Stream.Elements.Delete (To_Delete);
+            if To_Delete /= No_Element then
+               declare
+                  Node : constant Valid_Node_Access := 
Stream_Element_Lists.Element (To_Delete).Node;
+               begin
+                  if Node.Error_List /= null then
+                     for Err of Tree.Error_List (Node) loop
+                        New_Errors.Append (To_Message (Err, Tree, Node));
+                     end loop;
+                  end if;
+               end;
+               Parse_Stream.Elements.Delete (To_Delete);
+            end if;
             exit;
          end if;
       end loop;
@@ -6178,6 +6148,95 @@ package body WisiToken.Syntax_Trees is
       return Line_At_Byte_Pos (Tree.Root, Start_Line => Tree.SOI.Non_Grammar 
(1).Line_Region.First);
    end Line_At_Byte_Pos;
 
+   function Line_At_Node
+     (Tree   : in Syntax_Trees.Tree;
+      Stream : in Stream_ID;
+      Ref    : in Real_Recover_Token)
+     return Base_Line_Number_Type
+   is
+      function Find_Element return Stream_Index
+      is
+         use Stream_Element_Lists;
+         Parse_Stream : Syntax_Trees.Parse_Stream renames Tree.Streams 
(Stream.Cur);
+         Cur : Cursor := Parse_Stream.Stack_Top;
+      begin
+         loop
+            exit when not Has_Element (Cur);
+            if Stream_Element_Lists.Element (Cur).Node = Ref.Element_Node then
+               return (Cur => Cur);
+            end if;
+            Next (Cur);
+         end loop;
+
+         --  Not found in stream input; search stack.
+         Cur := Parse_Stream.Stack_Top;
+         loop
+            Previous (Cur);
+            exit when not Has_Element (Cur);
+            if Stream_Element_Lists.Element (Cur).Node = Ref.Element_Node then
+               return (Cur => Cur);
+            end if;
+         end loop;
+         return Invalid_Stream_Index;
+      end Find_Element;
+
+      Element : constant Stream_Index := Find_Element;
+   begin
+      if Element = Invalid_Stream_Index then
+         --  Ref.Node is a child of some stream Element; too hard to find.
+         --  test_incremental.adb Lexer_Errors_05.
+         return Invalid_Line_Number;
+      else
+         return Line_At_Node (Tree, Tree.To_Stream_Node_Parents 
(Tree.To_Rooted_Ref (Stream, Element)), Stream);
+      end if;
+   end Line_At_Node;
+
+   function Line_At_Node
+     (Tree : in Syntax_Trees.Tree;
+      Node : in Valid_Node_Access)
+     return Line_Number_Type
+   is
+      Temp           : Valid_Node_Access   := Node;
+      New_Line_Count : Base_Line_Number_Type := 0;
+   begin
+      loop
+         Temp := Tree.Prev_Terminal (Temp);
+         exit when Temp.Non_Grammar.Length > 0;
+         if Temp.Label = Source_Terminal then
+            New_Line_Count := @ + Temp.New_Line_Count;
+         end if;
+      end loop;
+      return Temp.Non_Grammar (Temp.Non_Grammar.Last_Index).Line_Region.Last + 
New_Line_Count;
+   end Line_At_Node;
+
+   function Line_At_Node
+     (Tree         : in Syntax_Trees.Tree;
+      Ref          : in Stream_Node_Parents;
+      Parse_Stream : in Stream_ID)
+     return Line_Number_Type
+   is
+      Temp           : Stream_Node_Parents   := Ref;
+      New_Line_Count : Base_Line_Number_Type := 0;
+   begin
+      loop
+         Tree.Prev_Terminal (Temp, Parse_Stream, Preceding => True);
+         exit when Temp.Ref.Node.Non_Grammar.Length > 0;
+         if Temp.Ref.Node.Label = Source_Terminal then
+            New_Line_Count := @ + Temp.Ref.Node.New_Line_Count;
+         end if;
+      end loop;
+      return Temp.Ref.Node.Non_Grammar 
(Temp.Ref.Node.Non_Grammar.Last_Index).Line_Region.Last + New_Line_Count;
+   end Line_At_Node;
+
+   function Line_At_Node
+     (Tree         : in Syntax_Trees.Tree;
+      Ref          : in Stream_Node_Ref;
+      Parse_Stream : in Stream_ID)
+     return Line_Number_Type
+   is begin
+      return Tree.Line_At_Node (Tree.To_Stream_Node_Parents (Ref), 
Parse_Stream);
+   end Line_At_Node;
+
    function Line_Begin_Char_Pos
      (Tree : in Syntax_Trees.Tree;
       Line : in Line_Number_Type)
@@ -6326,14 +6385,15 @@ package body WisiToken.Syntax_Trees is
       end if;
    end Line_Begin_Token;
 
-   procedure  Line_Region_Internal_1
-     (Tree                    : in     Syntax_Trees.Tree;
-      Node                    : in     Node_Access;
-      Prev_Non_Grammar        : in     Valid_Node_Access;
-      Next_Non_Grammar        : in     Valid_Node_Access;
-      Trailing_Non_Grammar    : in     Boolean;
-      First_Non_Grammar_Token :    out WisiToken.Lexer.Token;
-      Last_Non_Grammar_Token  :    out WisiToken.Lexer.Token)
+   procedure Line_Region_Internal_1
+     (Tree                                 : in     Syntax_Trees.Tree;
+      Node                                 : in     Node_Access;
+      Prev_Non_Grammar                     : in     Valid_Node_Access;
+      Next_Non_Grammar                     : in     Valid_Node_Access;
+      Trailing_Non_Grammar                 : in     Boolean;
+      First_Non_Grammar_Token              :    out WisiToken.Lexer.Token;
+      Last_Non_Grammar_Token               :    out WisiToken.Lexer.Token;
+      Last_Non_Grammar_Is_Node_Non_Grammar :    out Boolean)
    is
       --  Since all non_grammar have line_region, we don't have to look for
       --  a new_line, just any non_grammar.
@@ -6374,6 +6434,8 @@ package body WisiToken.Syntax_Trees is
             --  want to include the leading non_grammar in SOI.
             Prev_Non_Grammar.Non_Grammar 
(Prev_Non_Grammar.Non_Grammar.Last_Index));
 
+      Last_Non_Grammar_Is_Node_Non_Grammar := Actual_Last_Non_Grammar = 
Last_Terminal;
+
       Last_Non_Grammar_Token := Actual_Last_Non_Grammar.Non_Grammar
         (if Trailing_Non_Grammar and Actual_Last_Non_Grammar = Last_Non_Grammar
          then Actual_Last_Non_Grammar.Non_Grammar.Last_Index
@@ -6388,16 +6450,20 @@ package body WisiToken.Syntax_Trees is
       Trailing_Non_Grammar : in Boolean)
      return WisiToken.Line_Region
    is
-      First_Non_Grammar_Token : WisiToken.Lexer.Token;
-      Last_Non_Grammar_Token  : WisiToken.Lexer.Token;
+      First_Non_Grammar_Token              : WisiToken.Lexer.Token;
+      Last_Non_Grammar_Token               : WisiToken.Lexer.Token;
+      Last_Non_Grammar_Is_Node_Non_Grammar : Boolean;
    begin
       Line_Region_Internal_1
         (Tree, Node, Prev_Non_Grammar, Next_Non_Grammar, Trailing_Non_Grammar,
-         First_Non_Grammar_Token, Last_Non_Grammar_Token);
+         First_Non_Grammar_Token, Last_Non_Grammar_Token, 
Last_Non_Grammar_Is_Node_Non_Grammar);
 
       return
         (First => First_Non_Grammar_Token.Line_Region.Last,
-         Last => Last_Non_Grammar_Token.Line_Region.First);
+         Last =>
+           (if Trailing_Non_Grammar and Last_Non_Grammar_Is_Node_Non_Grammar
+            then Last_Non_Grammar_Token.Line_Region.Last
+            else Last_Non_Grammar_Token.Line_Region.First));
    end Line_Region_Internal;
 
    function Byte_Region_Of_Line_Region_Internal
@@ -6408,16 +6474,20 @@ package body WisiToken.Syntax_Trees is
       Trailing_Non_Grammar : in     Boolean)
      return WisiToken.Buffer_Region
    is
-      First_Non_Grammar_Token : WisiToken.Lexer.Token;
-      Last_Non_Grammar_Token  : WisiToken.Lexer.Token;
+      First_Non_Grammar_Token              : WisiToken.Lexer.Token;
+      Last_Non_Grammar_Token               : WisiToken.Lexer.Token;
+      Last_Non_Grammar_Is_Node_Non_Grammar : Boolean;
    begin
       Line_Region_Internal_1
         (Tree, Node, Prev_Non_Grammar, Next_Non_Grammar, Trailing_Non_Grammar,
-         First_Non_Grammar_Token, Last_Non_Grammar_Token);
+         First_Non_Grammar_Token, Last_Non_Grammar_Token, 
Last_Non_Grammar_Is_Node_Non_Grammar);
 
       return
         (First => First_Non_Grammar_Token.Byte_Region.Last,
-         Last => Last_Non_Grammar_Token.Byte_Region.First);
+         Last =>
+           (if Last_Non_Grammar_Is_Node_Non_Grammar
+            then Last_Non_Grammar_Token.Byte_Region.Last
+            else Last_Non_Grammar_Token.Byte_Region.First));
    end Byte_Region_Of_Line_Region_Internal;
 
    function Line_Region (Tree : in Syntax_Trees.Tree) return 
WisiToken.Line_Region
@@ -6454,20 +6524,7 @@ package body WisiToken.Syntax_Trees is
       Trailing_Non_Grammar : in Boolean)
      return WisiToken.Line_Region
    is begin
-      if Tree.Parents_Set then
-         declare
-            Prev_Non_Grammar : Stream_Node_Ref := Ref;
-            Next_Non_Grammar : Stream_Node_Ref := Ref;
-         begin
-            Tree.Prev_Non_Grammar (Prev_Non_Grammar);
-            Tree.Next_Non_Grammar (Next_Non_Grammar);
-            return Line_Region_Internal
-              (Tree, Ref.Node, Prev_Non_Grammar.Node, Next_Non_Grammar.Node, 
Trailing_Non_Grammar);
-         end;
-
-      else
-         return Line_Region (Tree, To_Stream_Node_Parents (Tree, Ref), 
Ref.Stream, Trailing_Non_Grammar);
-      end if;
+      return Line_Region (Tree, To_Stream_Node_Parents (Tree, Ref), 
Ref.Stream, Trailing_Non_Grammar);
    end Line_Region;
 
    function Byte_Region_Of_Line_Region
@@ -7843,7 +7900,7 @@ package body WisiToken.Syntax_Trees is
 
    function Prev_Source_Terminal
      (Tree                 : in Syntax_Trees.Tree;
-      Node                 : in Node_Access;
+      Node                 : in Valid_Node_Access;
       Trailing_Non_Grammar : in Boolean)
      return Node_Access
    is begin
@@ -8175,9 +8232,10 @@ package body WisiToken.Syntax_Trees is
          for I in 1 .. Level loop
             Tree.Lexer.Trace.Put ("| ", Prefix => False);
          end loop;
-         Tree.Lexer.Trace.Put (Image (Tree, Node, Children => False, RHS_Index 
=> True, Node_Numbers => True,
-                           Line_Numbers => Line_Numbers, Non_Grammar => 
Non_Grammar),
-                    Prefix => False);
+         Tree.Lexer.Trace.Put
+           (Image (Tree, Node, Children => False, RHS_Index => True, 
Node_Numbers => True,
+                   Line_Numbers => Line_Numbers, Non_Grammar => Non_Grammar),
+            Prefix => False);
 
          if Node.Augmented /= null then
             Tree.Lexer.Trace.Put (Image_Augmented (Node.Augmented.all), Prefix 
=> False);
@@ -8436,9 +8494,7 @@ package body WisiToken.Syntax_Trees is
 
          --  We don't output Node.Parent; redundant with node.Children.
 
-         if Node.Augmented /= null then
-            raise SAL.Not_Implemented with "put_tree augmented";
-         end if;
+         --  FIXME: implement augmented
 
          Put_Error_List (Node.Error_List);
 
@@ -8582,29 +8638,7 @@ package body WisiToken.Syntax_Trees is
 
    function Root (Tree : in Syntax_Trees.Tree) return Node_Access
    is begin
-      if Tree.Root = Invalid_Node_Access then
-         if Tree.Streams.Length = 0 then
-            return Invalid_Node_Access;
-         else
-            declare
-               use Stream_Element_Lists;
-               Stream : Parse_Stream renames Tree.Streams (Tree.Streams.Last);
-               --  parse stream from Parse or shared_stream from Edit_Tree 
with no changes
-
-               Cur : Cursor := Stream.Elements.First; -- SOI
-            begin
-               if Has_Element (Cur) then
-                  Cur := Next (Cur); -- wisitoken_accept
-                  if Has_Element (Cur) then
-                     return Element (Cur).Node;
-                  end if;
-               end if;
-               return Invalid_Node_Access;
-            end;
-         end if;
-      else
-         return Tree.Root;
-      end if;
+      return Tree.Root;
    end Root;
 
    function Rooted (Ref : in Stream_Node_Ref) return Boolean
@@ -8831,26 +8865,43 @@ package body WisiToken.Syntax_Trees is
          Tree.Root := New_Root;
       else
          declare
+            Parse_Stream : Syntax_Trees.Parse_Stream renames Tree.Streams 
(Tree.Streams.Last);
+            --  Parse_Stream is Shared_Stream if this is a packrat parse.
+
+            SOI : constant Valid_Node_Access := Stream_Element_Lists.Element 
(Parse_Stream.Elements.First).Node;
+
+            Last_Node : constant Valid_Node_Access := 
Stream_Element_Lists.Element (Parse_Stream.Elements.Last).Node;
+
+            EOI : constant Node_Access :=
+              (if Last_Node.ID = Tree.Lexer.Descriptor.EOI_ID
+               then Last_Node
+               elsif Last_Node.Children (Last_Node.Child_Count).ID = 
Tree.Lexer.Descriptor.EOI_ID
+               then Last_Node.Children (Last_Node.Child_Count)
+               else Tree.EOI);
+
             function Create_New_Children return Node_Access_Array
             is
                Last : Positive_Index_Type := New_Root.Children'Last;
                New_Children : Node_Access_Array (1 .. New_Root.Children'Last + 
2);
             begin
-               if New_Root.Children (1) /= Tree.SOI then
-                  New_Children (1) := Tree.SOI;
+               if New_Root.Children (1).ID /= Tree.Lexer.Descriptor.SOI_ID then
+                  New_Children (1) := SOI;
                   Last := 1 + New_Root.Children'Length;
                   New_Children (2 .. Last) := New_Root.Children;
                end if;
 
-               if New_Root.Children (New_Root.Children'Last) /= Tree.EOI then
+               if New_Root.Children (New_Root.Children'Last).ID /= 
Tree.Lexer.Descriptor.EOI_ID then
                   Last := @ + 1;
-                  New_Children (Last) := Tree.EOI;
+                  New_Children (Last) := EOI;
                end if;
                return New_Children (1 .. Last);
             end Create_New_Children;
 
             New_Children : constant Node_Access_Array := Create_New_Children;
          begin
+            Tree.SOI := SOI;
+            Tree.EOI := EOI;
+
             Tree.Root := new Node'
               (Label       => Nonterm,
                Copied_Node => Invalid_Node_Access,
@@ -9029,7 +9080,7 @@ package body WisiToken.Syntax_Trees is
 
       Tree.SOI.Parent := Invalid_Node_Access;
 
-      --  Delete SOI, EOI from root children (added in Clear_Parse_Streams)
+      --  Delete SOI, EOI from root children (added in Finish_Parse)
       declare
          New_Children : Node_Access_Array (1 .. Tree.Root.Child_Count - 2);
       begin
@@ -9081,6 +9132,8 @@ package body WisiToken.Syntax_Trees is
       Begin_Char_Pos : Buffer_Pos;
       Begin_Line     : Line_Number_Type;
    begin
+      Tree.Lexer.Errors.Clear;
+
       Tree.Lexer.Begin_Pos (Begin_Byte_Pos, Begin_Char_Pos, Begin_Line);
       declare
          Token : constant Lexer.Token :=
@@ -9156,9 +9209,9 @@ package body WisiToken.Syntax_Trees is
       return Stream_Element_Lists.Element (Tree.Streams 
(Stream.Cur).Stack_Top).State;
    end State;
 
-   function Stream_Count (Tree : in Syntax_Trees.Tree) return Natural
+   function Stream_Count (Tree : in Syntax_Trees.Tree) return 
SAL.Base_Peek_Type
    is begin
-      return Natural (Tree.Streams.Length);
+      return SAL.Base_Peek_Type (Tree.Streams.Length);
    end Stream_Count;
 
    procedure Stream_Delete
@@ -9693,6 +9746,14 @@ package body WisiToken.Syntax_Trees is
               Tree.Is_Descendant_Of (Root => Tree.Get_Node (Ref.Stream, 
Ref.Element), Descendant => Ref.Node)));
    end Valid_Stream_Node;
 
+   function Valid_Stream_Node_Parents
+     (Tree : in Syntax_Trees.Tree;
+      Ref  : in Stream_Node_Parents)
+     return Boolean
+   is begin
+      return Valid_Stream_Node (Tree, Ref.Ref) and Parents_Valid (Ref);
+   end Valid_Stream_Node_Parents;
+
    procedure Validate_Tree
      (Tree              : in out Syntax_Trees.Tree;
       User_Data         : in out User_Data_Type'Class;
@@ -9705,7 +9766,9 @@ package body WisiToken.Syntax_Trees is
 
       Real_Root : Node_Access;
 
-      Last_Source_Terminal_Pos : Base_Buffer_Pos := Buffer_Pos'First;
+      Last_Source_Terminal_Pos : Base_Buffer_Pos  := Buffer_Pos'First;
+      Last_Line                : Base_Line_Number_Type :=
+        Tree.SOI.Non_Grammar (1).Line_Region.First;
 
       procedure Process_Node
         (Tree : in out Syntax_Trees.Tree;
@@ -9773,15 +9836,25 @@ package body WisiToken.Syntax_Trees is
             end if;
             case Terminal_Label'(Node.Label) is
             when Source_Terminal =>
-               if Byte_Region_Order and then Node.Byte_Region.First < 
Last_Source_Terminal_Pos then
-                  Put_Error ("byte_region out of order");
-               end if;
-               if Node.Non_Grammar.Length > 0 then
-                  Last_Source_Terminal_Pos := Node.Non_Grammar 
(Node.Non_Grammar.Last_Index).Byte_Region.Last;
-               else
-                  Last_Source_Terminal_Pos := Node.Byte_Region.Last;
+               if Byte_Region_Order then
+                  if Node.Byte_Region.First < Last_Source_Terminal_Pos then
+                     Put_Error ("byte_region out of order");
+                  end if;
+                  Last_Line := @ + Node.New_Line_Count;
+                  if Node.Non_Grammar.Length > 0 then
+                     Last_Source_Terminal_Pos := Node.Non_Grammar 
(Node.Non_Grammar.Last_Index).Byte_Region.Last;
+                     if Tree.Lexer.Descriptor.New_Line_ID /= Invalid_Token_ID 
then
+                        for Token of Node.Non_Grammar loop
+                           if Token.Line_Region.First /= Last_Line then
+                              Put_Error ("line_number missing/out of order");
+                           end if;
+                           Last_Line := Token.Line_Region.Last;
+                        end loop;
+                     end if;
+                  else
+                     Last_Source_Terminal_Pos := Node.Byte_Region.Last;
+                  end if;
                end if;
-
                for Deleted of Node.Following_Deleted loop
                   if Deleted.Parent /= Node then
                      Put_Error ("deleted.parent wrong");
@@ -9811,7 +9884,18 @@ package body WisiToken.Syntax_Trees is
 
             when Virtual_Terminal | Virtual_Identifier =>
                if Node.Non_Grammar.Length > 0 then
-                  Last_Source_Terminal_Pos := Node.Non_Grammar 
(Node.Non_Grammar.Last_Index).Byte_Region.Last;
+                  if Byte_Region_Order then
+                     Last_Source_Terminal_Pos := Node.Non_Grammar 
(Node.Non_Grammar.Last_Index).Byte_Region.Last;
+
+                     if Tree.Lexer.Descriptor.New_Line_ID /= Invalid_Token_ID 
then
+                        for Token of Node.Non_Grammar loop
+                           if Token.Line_Region.First /= Last_Line then
+                              Put_Error ("line_number missing/out of order");
+                           end if;
+                           Last_Line := Token.Line_Region.Last;
+                        end loop;
+                     end if;
+                  end if;
                end if;
             end case;
 
diff --git a/wisitoken-syntax_trees.ads b/wisitoken-syntax_trees.ads
index 8e89007b24..796af1ad60 100644
--- a/wisitoken-syntax_trees.ads
+++ b/wisitoken-syntax_trees.ads
@@ -110,6 +110,7 @@ with SAL.Gen_Unbounded_Sparse_Ordered_Sets;
 with SAL.Generic_Decimal_Image;
 with WisiToken.Lexer;
 package WisiToken.Syntax_Trees is
+   use all type Ada.Containers.Count_Type;
    use all type SAL.Base_Peek_Type;
 
    type Node (<>) is private;
@@ -404,7 +405,8 @@ package WisiToken.Syntax_Trees is
      (Tree    : in Syntax_Trees.Tree;
       Stream  : in Stream_ID;
       Element : in Stream_Index)
-     return Rooted_Ref;
+     return Rooted_Ref
+   with Pre => Element /= Invalid_Stream_Index;
 
    type Stream_Node_Parents is record
       Ref     : Stream_Node_Ref;
@@ -422,6 +424,11 @@ package WisiToken.Syntax_Trees is
    function Parents_Valid (Ref : in Stream_Node_Parents) return Boolean;
    --  True if Parents gives the path from Element.Node to Node, or Element or 
Node is invalid.
 
+   function Valid_Stream_Node_Parents
+     (Tree : in Syntax_Trees.Tree;
+      Ref  : in Stream_Node_Parents)
+     return Boolean;
+
    function To_Stream_Node_Parents (Tree : in Syntax_Trees.Tree; Ref : in 
Stream_Node_Ref) return Stream_Node_Parents
    with Pre => Ref = Invalid_Stream_Node_Ref or else Tree.Parents_Set or else
                (Rooted (Ref) or Ref.Node = Tree.First_Terminal (Get_Node 
(Ref.Element))),
@@ -558,10 +565,6 @@ package WisiToken.Syntax_Trees is
    type User_Data_Access is access all User_Data_Type'Class;
    type User_Data_Access_Constant is access constant User_Data_Type'Class;
 
-   function New_User_Data (Template : in User_Data_Type) return 
User_Data_Access
-   is (null);
-   --  Return a new empty object with the same type as Template.
-
    procedure Reset (User_Data : in out User_Data_Type) is null;
    --  Reset to start a new parse.
 
@@ -733,8 +736,8 @@ package WisiToken.Syntax_Trees is
      Post => Tree.Is_Valid (New_Stream'Result);
    --  Create a new parse stream, initially copied from Old_Stream.
 
-   function Stream_Count (Tree : in Syntax_Trees.Tree) return Natural;
-   --  Number of active streams.
+   function Stream_Count (Tree : in Syntax_Trees.Tree) return 
SAL.Base_Peek_Type;
+   --  Number of parse streams plus the shared stream.
 
    function First_Parse_Stream (Tree : in Syntax_Trees.Tree) return Stream_ID
    with Pre => Tree.Stream_Count >= 2;
@@ -893,7 +896,7 @@ package WisiToken.Syntax_Trees is
       Productions    : in     Production_Info_Trees.Vector;
       User_Data      : in     Syntax_Trees.User_Data_Access_Constant;
       First_Terminal : in     Boolean)
-   with Pre => Valid_Stream_Node (Tree, Ref.Ref) and Parents_Valid (Ref) and
+   with Pre => Tree.Valid_Stream_Node_Parents (Ref) and
                Tree.Label (Ref.Ref.Element) = Nonterm and
                (if First_Terminal
                 then not Tree.Is_Empty_Nonterm (Ref.Ref.Node)
@@ -1045,6 +1048,7 @@ package WisiToken.Syntax_Trees is
    with Pre => Element = Invalid_Stream_Index or else
                (Tree.Contains (Stream, Element) or Tree.Contains 
(Tree.Shared_Stream, Element));
    --  If Element is Invalid_Stream_Index, result is Stream_First (= SOI).
+   --  Does not follow Stream.Shared_Link
 
    function Stream_Next
      (Tree : in Syntax_Trees.Tree;
@@ -1111,7 +1115,7 @@ package WisiToken.Syntax_Trees is
      (Tree   : in     Syntax_Trees.Tree;
       Ref    : in out Stream_Node_Parents;
       Rooted : in     Boolean)
-   with Pre => Valid_Stream_Node (Tree, Ref.Ref),
+   with Pre => Valid_Stream_Node_Parents (Tree, Ref),
      Post => Correct_Stream_Node (Tree, Ref.Ref) and
              (Ref.Ref = Invalid_Stream_Node_Ref or else
                 (if Rooted
@@ -1242,17 +1246,6 @@ package WisiToken.Syntax_Trees is
    --  Delete Element from Stream. If Element = Stream.Stack_Top,
    --  Stack_Top is set to Invalid_Stream_Index.
 
-   function ID
-     (Tree    : in Syntax_Trees.Tree;
-      Stream  : in Stream_ID;
-      Element : in Stream_Index)
-     return Token_ID
-   with Pre => Tree.Contains (Stream, Element) or Tree.Contains 
(Tree.Shared_Stream, Element);
-   --  The precondition allows either stream; Current_Token is
-   --  either a Source_Terminal from Shared_Stream or a Virtual_Terminal
-   --  in Stream input from error recovery; in incremental parse, it
-   --  could be a Source_Terminal in Stream input from push_back.
-
    function Label (Tree : in Syntax_Trees.Tree; Node : in Valid_Node_Access) 
return Node_Label;
    function Label (Tree : in Syntax_Trees.Tree; Element : in Stream_Index) 
return Node_Label
    with Pre => Element /= Invalid_Stream_Index;
@@ -1316,16 +1309,8 @@ package WisiToken.Syntax_Trees is
       Region : in Buffer_Region)
    with Pre => Tree.Is_Nonterm (Node);
 
-   function ID
-     (Tree : in Syntax_Trees.Tree;
-      Node : in Valid_Node_Access)
-     return WisiToken.Token_ID;
-
-   function ID
-     (Tree : in Syntax_Trees.Tree;
-      Ref  : in Stream_Node_Ref)
-     return WisiToken.Token_ID;
-   --  One of Ref.Node.ID, Ref.Element.Node.ID, Invalid_Token_ID
+   function ID (Tree : in Syntax_Trees.Tree; Node : in Valid_Node_Access) 
return WisiToken.Token_ID;
+   function ID (Tree : in Syntax_Trees.Tree; Element : in Stream_Index) return 
Token_ID;
 
    function Production_ID
      (Tree : in Syntax_Trees.Tree;
@@ -1372,7 +1357,7 @@ package WisiToken.Syntax_Trees is
       Parse_Stream         : in Stream_ID;
       Trailing_Non_Grammar : in Boolean := False)
      return WisiToken.Buffer_Region
-   with Pre => Valid_Stream_Node (Tree, Ref.Ref) and Parents_Valid (Ref);
+   with Pre => Tree.Valid_Stream_Node_Parents (Ref);
    --  Same as Byte_Region (Stream_Node_Ref), for use when parents are
    --  not set. See Prev_Terminal (tree, stream_node_parents) for meaning
    --  of Parse_Stream.
@@ -1414,11 +1399,11 @@ package WisiToken.Syntax_Trees is
    with Pre => Tree.Editable;
    --  Lines of tokens in Node. First is the line started by the first
    --  New_Line or SOI (start of input) before the first terminal in
-   --  Node. If Trailing_Non_Grammar, Last is the line ended by the last
-   --  New_Line in the first non_grammar array after the last terminal of
-   --  Node, or EOI (end of input); if not Trailing_Non_Grammar, Last is
-   --  the line ended by the first New_Line or EOI after the last
-   --  terminal of Node.
+   --  Node. If Trailing_Non_Grammar and the last terminal of Node has
+   --  Non_Grammar, Last is the line ended by the last New_Line of
+   --  Last_Terminal (Node).Non_Grammar; if not Trailing_Non_Grammar or
+   --  Node does not have Non_Grammar, Last is the line ended by the
+   --  first New_Line or EOI after the last terminal of Node.
    --
    --  Trailing_Non_Grammar => False is used to get the line_region of a
    --  multi-line token.
@@ -1450,7 +1435,7 @@ package WisiToken.Syntax_Trees is
       Parse_Stream         : in Stream_ID;
       Trailing_Non_Grammar : in Boolean := True)
      return WisiToken.Line_Region
-   with Pre => Tree.Valid_Stream_Node (Ref.Ref) and Parents_Valid (Ref);
+   with Pre => Tree.Valid_Stream_Node_Parents (Ref);
    --  Same as Line_Region (Stream_Node_Ref), for use when parents are
    --  not set. See Prev_Terminal (tree, stream_node_parents) for meaning
    --  of Parse_Stream.
@@ -1494,6 +1479,12 @@ package WisiToken.Syntax_Trees is
      return Recover_Token;
    --  Treat Node as a stream element.
 
+   function Children_Recover_Tokens
+     (Tree : in Syntax_Trees.Tree;
+      Node : in Valid_Node_Access)
+     return Recover_Token_Array
+   with Pre => Tree.Label (Node) = Nonterm;
+
    function Children_Recover_Tokens
      (Tree    : in Syntax_Trees.Tree;
       Stream  : in Stream_ID;
@@ -1564,15 +1555,15 @@ package WisiToken.Syntax_Trees is
       Node : in Valid_Node_Access;
       ID   : in Token_ID)
      return Node_Access;
-   --  Return the descendant of Node (may be Node) whose ID is ID, or
-   --  Invalid_Node_Access if none match.
+   --  Return the descendant of Node (may be Node; depth first search)
+   --  whose ID is ID, or Invalid_Node_Access if none match.
 
    function Find_Descendant
      (Tree      : in     Syntax_Trees.Tree;
       Node      : in     Valid_Node_Access;
       Predicate : access function (Tree : in Syntax_Trees.Tree; Node : in 
Valid_Node_Access) return Boolean)
      return Node_Access;
-   --  Return the first descendant of Node (may be Node; breadth first
+   --  Return the first descendant of Node (may be Node; depth first
    --  search) for which Predicate returns True, or Invalid_Node_Access
    --  if none do.
 
@@ -1620,7 +1611,7 @@ package WisiToken.Syntax_Trees is
      (Tree         : in     Syntax_Trees.Tree;
       Ref          : in out Stream_Node_Parents;
       Parse_Stream : in     Stream_ID)
-   with Pre => Tree.Valid_Stream_Node (Ref.Ref) and Parents_Valid (Ref),
+   with Pre => Tree.Valid_Stream_Node_Parents (Ref),
      Post => Tree.Correct_Stream_Node (Ref.Ref) and Parents_Valid (Ref);
 
    function First_Non_Grammar
@@ -1650,7 +1641,7 @@ package WisiToken.Syntax_Trees is
    procedure Next_Non_Grammar
      (Tree : in     Syntax_Trees.Tree;
       Ref  : in out Stream_Node_Parents)
-   with Pre => Valid_Stream_Node (Tree, Ref.Ref) and Parents_Valid (Ref),
+   with Pre => Tree.Valid_Stream_Node_Parents (Ref),
      Post => Tree.Correct_Stream_Node (Ref.Ref) and Parents_Valid (Ref);
 
    type New_Line_Ref is record
@@ -1670,7 +1661,7 @@ package WisiToken.Syntax_Trees is
       --  new_line is the last; it was found by Prev_New_Line;
 
       Pos : Base_Buffer_Pos := Invalid_Buffer_Pos;
-      --  The buffer position of the new_line.
+      --  The byte position of the new_line.
 
       Line : Base_Line_Number_Type := Invalid_Line_Number;
       --  The line number after the new_line.
@@ -1694,13 +1685,48 @@ package WisiToken.Syntax_Trees is
    --  giving a line number, computes Start_Line, and continues as
    --  above.
 
+   function Line_At_Node
+     (Tree   : in Syntax_Trees.Tree;
+      Stream : in Stream_ID;
+      Ref    : in Real_Recover_Token)
+     return Base_Line_Number_Type;
+   --  Return line at first byte of Ref.Node; Invalid_Line_Number if too hard 
to find.
+
+   function Line_At_Node
+     (Tree : in Syntax_Trees.Tree;
+      Node : in Valid_Node_Access)
+     return Line_Number_Type
+   with Pre => Tree.Parents_Set;
+   --  Return line at first byte of Node.
+
+   function Line_At_Node
+     (Tree         : in Syntax_Trees.Tree;
+      Ref          : in Stream_Node_Ref;
+      Parse_Stream : in Stream_ID)
+     return Line_Number_Type
+   with Pre => Valid_Stream_Node (Tree, Ref);
+   --  Return line at first byte of Ref.Node.
+
+   function Line_At_Node
+     (Tree         : in Syntax_Trees.Tree;
+      Ref          : in Stream_Node_Parents;
+      Parse_Stream : in Stream_ID)
+     return Line_Number_Type
+   with Pre => Valid_Stream_Node_Parents (Tree, Ref);
+   --  Return line at first byte of Ref.Node.
+
    function First_Source_Terminal
      (Tree                 : in Syntax_Trees.Tree;
       Node                 : in Valid_Node_Access;
       Trailing_Non_Grammar : in Boolean;
       Following            : in Boolean)
      return Node_Access
-   with Pre => (if Following then Tree.Parents_Set else True);
+   with Pre => (if Following then Tree.Parents_Set else True),
+    Post =>
+       (if Following
+        then First_Source_Terminal'Result /= Invalid_Node_Access and then
+         (Tree.Label (First_Source_Terminal'Result) = Source_Terminal or
+            Tree.Non_Grammar_Const (First_Source_Terminal'Result).Length > 0));
    --  Return a terminal node that can give byte or char pos.
    --
    --  If Trailing_Non_Grammar, return first terminal in Node that is a
@@ -1738,6 +1764,13 @@ package WisiToken.Syntax_Trees is
    --  non_grammar. If not Trailing_Non_Grammar, only return a
    --  Source_Terminal.
 
+   function Prev_Source_Terminal
+     (Tree                 : in Syntax_Trees.Tree;
+      Node                 : in Valid_Node_Access;
+      Trailing_Non_Grammar : in Boolean)
+     return Node_Access
+   with Pre => Tree.Parents_Set;
+
    function Prev_Source_Terminal
      (Tree                 : in Syntax_Trees.Tree;
       Ref                  : in Stream_Node_Ref;
@@ -1757,7 +1790,7 @@ package WisiToken.Syntax_Trees is
       Ref                  : in out Stream_Node_Parents;
       Parse_Stream         : in     Stream_ID;
       Trailing_Non_Grammar : in     Boolean)
-   with Pre => Valid_Stream_Node (Tree, Ref.Ref) and not Tree.Parents_Set,
+   with Pre => Valid_Stream_Node_Parents (Tree, Ref),
      Post   => Tree.Correct_Stream_Node (Ref.Ref);
 
    function Count_Terminals (Tree : in Syntax_Trees.Tree; Node : in 
Valid_Node_Access) return Natural;
@@ -1777,16 +1810,8 @@ package WisiToken.Syntax_Trees is
       Node    : in     Valid_Node_Access;
       Parents : in out Node_Stacks.Stack)
      return Node_Access;
-   --  Same as First_Terminal (Tree, Node), also initializes Parents to
-   --  store path from Node to the first terminal, for Next_Terminal in
-   --  nodes that have unset parent links, or to limit Next_Terminal to
-   --  descendants of Node.
-   --
-   --  We don't have "Pre => Parents.Is_Empty" or "Post => Parents_Valid
-   --  (Parents, First_Terminal'Result)", because we call this function
-   --  recursively to create Parents.
-   --
-   --  Visible for use with error recovery Configuration input stream.
+   --  Same as First_Terminal (Tree, Node), also updates Parents to
+   --  store path from Node to the first terminal.
 
    procedure First_Terminal
      (Tree : in     Syntax_Trees.Tree;
@@ -1821,7 +1846,7 @@ package WisiToken.Syntax_Trees is
      (Tree      : in     Syntax_Trees.Tree;
       Ref       : in out Stream_Node_Parents;
       Following : in     Boolean)
-   with Pre => Valid_Stream_Node (Tree, Ref.Ref) and Parents_Valid (Ref),
+   with Pre => Tree.Valid_Stream_Node_Parents (Ref),
      Post => Parents_Valid (Ref);
    --  Update Ref to first terminal in Ref.Ref.Node or, if Following, a
    --  following stream element - continues search in Shared_Stream.
@@ -1857,7 +1882,7 @@ package WisiToken.Syntax_Trees is
       Ref          : in out Stream_Node_Parents;
       Parse_Stream : in     Stream_ID;
       Preceding    : in     Boolean)
-   with Pre => Valid_Stream_Node (Tree, Ref.Ref),
+   with Pre => Valid_Stream_Node_Parents (Tree, Ref),
      Post => Parents_Valid (Ref);
    --  Update Ref to last terminal of Ref.Ref.Element.Node or, if
    --  Preceding, preceding element.
@@ -1992,8 +2017,8 @@ package WisiToken.Syntax_Trees is
      (Tree      : in     Syntax_Trees.Tree;
       Ref       : in out Syntax_Trees.Stream_Node_Parents;
       Following : in     Boolean)
-   with Pre => Valid_Stream_Node (Tree, Ref.Ref) and Parents_Valid (Ref),
-     Post => Correct_Stream_Node (Tree, Ref.Ref) and Parents_Valid (Ref);
+   with Pre => Tree.Valid_Stream_Node_Parents (Ref),
+     Post => Tree.Correct_Stream_Node (Ref.Ref) and Parents_Valid (Ref);
    --  Return first terminal with valid Sequential_Index in Ref.Node or,
    --  if Following, a following stream element; continues search in
    --  Tree.Shared_Stream. Invalid_Stream_Node_Parents if none found.
@@ -2035,7 +2060,7 @@ package WisiToken.Syntax_Trees is
       Ref          : in out Syntax_Trees.Stream_Node_Parents;
       Parse_Stream : in     Stream_ID;
       Preceding    : in     Boolean)
-   with Pre => Valid_Stream_Node (Tree, Ref.Ref) and Parents_Valid (Ref),
+   with Pre => Tree.Valid_Stream_Node_Parents (Ref),
      Post => Correct_Stream_Node (Tree, Ref.Ref) and Parents_Valid (Ref);
    --  Update Ref to last terminal with valid Sequential_Index in
    --  Ref.Node or, if Preceding, a preceding stream element; if
@@ -2060,7 +2085,7 @@ package WisiToken.Syntax_Trees is
      (Tree      : in     Syntax_Trees.Tree;
       Ref       : in out Syntax_Trees.Stream_Node_Parents;
       Following : in     Boolean)
-   with Pre => Valid_Stream_Node (Tree, Ref.Ref) and Parents_Valid (Ref),
+   with Pre => Tree.Valid_Stream_Node_Parents (Ref),
      Post => Correct_Stream_Node (Tree, Ref.Ref) and Parents_Valid (Ref);
    --  Update Node to the first terminal with valid Sequential_Index
    --  succeeding Node. Can step past EOI. If not Following, do not step
@@ -2079,7 +2104,7 @@ package WisiToken.Syntax_Trees is
       Ref          : in out Stream_Node_Parents;
       Parse_Stream : in     Stream_ID;
       Preceding    : in     Boolean)
-   with Pre => Valid_Stream_Node (Tree, Ref.Ref) and Parents_Valid (Ref),
+   with Pre => Tree.Valid_Stream_Node_Parents (Ref),
      Post => Correct_Stream_Node (Tree, Ref.Ref) and Parents_Valid (Ref);
 
    function Get_IDs
@@ -2094,7 +2119,7 @@ package WisiToken.Syntax_Trees is
    --  zero streams, so these subprograms have no stream argument.
    --
    --  Some of these are also used for Packrat parsing, and don't have a
-   --  precondition of Fully_Parsed.
+   --  precondition.
 
    function Cleared (Tree : in Syntax_Trees.Tree) return Boolean;
    --  True if there are no streams and no nodes.
@@ -2107,9 +2132,11 @@ package WisiToken.Syntax_Trees is
    --  Shared_Stream holds a lexed or edited stream.
 
    function Fully_Parsed (Tree : in Syntax_Trees.Tree) return Boolean;
-   --  True if there is only one parse stream, and it has only two
-   --  elements; SOI with the start state and the tree root (EOI is only
-   --  in the shared stream).
+   --  True if Tree.Root is valid; a parse succeeded.
+   --
+   --  LR parse leaves a parse stream containing SOI and root; Packrat
+   --  parse does not use a parse stream, it just creates nonterminal
+   --  nodes.
 
    function Editable (Tree : in Syntax_Trees.Tree) return Boolean;
    --  True if Clear_Parse_Streams and Set_Parents have been called; the
@@ -2161,22 +2188,15 @@ package WisiToken.Syntax_Trees is
       File_Name : in     String);
    --  Read the output of Put_Tree from File_Name, populate Tree.
 
-   procedure Clear_Parse_Streams
-     (Tree       : in out Syntax_Trees.Tree;
-      Keep_Nodes : in     Valid_Node_Access_Lists.List := 
Valid_Node_Access_Lists.Empty_List)
-   with Pre => Tree.Fully_Parsed or Tree.Stream_Count = 1,
+   procedure Clear_Parse_Streams (Tree : in out Syntax_Trees.Tree);
+   --  Delete the parse streams, but not the nodes they reference.
+
+   procedure Finish_Parse (Tree : in out Syntax_Trees.Tree)
+   with Pre => Tree.Root /= Invalid_Node_Access,
      Post => Tree.Editable;
-   --  If Tree.Root is not set, set it to the root of the single
-   --  remaining parse stream. Delete the parse stream and shared stream.
-   --  Delete all nodes not reachable from the root, and not Tree.SOI,
-   --  Tree.EOI, or in Keep_Nodes. Also call Set_Parents if not
+   --  Delete the parse streams and shared stream. Delete all nodes
+   --  not reachable from the root. Call Set_Parents if not
    --  Tree.Parents_Set.
-   --
-   --  Keep_Nodes should be set to nodes that occur in errors, or are
-   --  deleted by error recovery; they may be referenced by post-parse
-   --  actions.
-   --
-   --  No precondition for Packrat parser.
 
    function Parents_Set (Tree : in Syntax_Trees.Tree) return Boolean;
 
@@ -2194,12 +2214,13 @@ package WisiToken.Syntax_Trees is
 
    function Root (Tree : in Syntax_Trees.Tree) return Node_Access
    with Pre => Tree.Valid_Root;
-   --  Tree.Root, or the root in the last parse stream if Tree.Root is
-   --  not set. Can be Invalid_Node_Access if input syntax does not allow
-   --  parsing to succeed.
+   --  The node set by Set_Root; Invalid_Node_Access if that has not been 
called.
 
    procedure Set_Root (Tree : in out Syntax_Trees.Tree; New_Root : in 
Valid_Node_Access)
-   with Pre => Tree.Label (New_Root) = Nonterm and then Tree.Child_Count 
(New_Root) > 0;
+   with Pre =>
+     Tree.ID (New_Root) = Tree.Lexer.Descriptor.Accept_ID and then
+     Tree.Label (New_Root) = Nonterm and then
+     Tree.Child_Count (New_Root) > 0;
    --  Set Tree.Root to Root. If New_Root.Children does not start with
    --  Tree.SOI, prepend it. If New_Root.Children does not end with
    --  Tree.EOI, append it.
@@ -2388,8 +2409,7 @@ package WisiToken.Syntax_Trees is
       User_Data     : in     User_Data_Access_Constant)
    with Pre =>
      Tree.Label (Deleted_Node) in Terminal_Label and
-     Tree.Valid_Stream_Node (Prev_Terminal.Ref) and
-     Parents_Valid (Prev_Terminal) and
+     Tree.Valid_Stream_Node_Parents (Prev_Terminal) and
      Prev_Terminal.Ref.Stream /= Tree.Shared_Stream and
      Tree.Label (Prev_Terminal.Ref.Node) = Source_Terminal;
    --  Copy Prev_Terminal.Ref.Node, add Deleted_Node to
@@ -2550,7 +2570,7 @@ package WisiToken.Syntax_Trees is
       Error_Ref : in out Stream_Node_Parents;
       Errors    : in     Error_Data_Lists.List;
       User_Data : in     User_Data_Access_Constant)
-   with Pre => Parents_Valid (Error_Ref) and
+   with Pre => Tree.Valid_Stream_Node_Parents (Error_Ref) and
      (for all Err of Errors => not Tree.Contains_Error (Error_Ref.Ref.Node, 
Err));
    --  Copy Error_Ref.Node and parents, add Errors to its error list.
    --  Update Error_Ref to point to copied node.
@@ -2682,7 +2702,7 @@ package WisiToken.Syntax_Trees is
    function Error_Deleted (Error : in Stream_Error_Ref) return 
Valid_Node_Access_Lists.Cursor;
 
    function First_Error (Tree : in Syntax_Trees.Tree) return Error_Ref
-   with Pre => Tree.Editable;
+   with Pre => Tree.Parents_Set;
    --  Return first error node in Tree.
 
    function First_Error (Tree : in Syntax_Trees.Tree; Stream : in Stream_ID) 
return Stream_Error_Ref;
@@ -2958,8 +2978,6 @@ package WisiToken.Syntax_Trees is
    --  in debugger for a stable way to access Node.
 
 private
-   use all type Ada.Containers.Count_Type;
-
    type Error_List_Access is access all Error_Data_Lists.List;
    procedure Free is new Ada.Unchecked_Deallocation (Error_Data_Lists.List, 
Error_List_Access);
 
diff --git a/wisitoken-user_guide.texinfo b/wisitoken-user_guide.texinfo
index ba59be658d..a0b41c57dc 100644
--- a/wisitoken-user_guide.texinfo
+++ b/wisitoken-user_guide.texinfo
@@ -5,7 +5,7 @@
 @settitle WisiToken User Guide
 
 @copying
-Copyright @copyright{} 2014-2015, 2017-2018, 2020-2022 Stephen Leake.
+Copyright @copyright{} 2014-2015, 2017-2018, 2020-2023 Stephen Leake.
 
 @quotation
 Permission is granted to copy, distribute and/or modify this
@@ -33,7 +33,7 @@ section entitled "GNU Free Documentation License".
 @contents
 
 @node Top
-@top WisiToken User Guide version 3.0
+@top WisiToken User Guide version 4.1
 
 @ifnottex
 @insertcopying
diff --git a/wisitoken.ads b/wisitoken.ads
index 3606c8387d..b8a4b0c8e4 100644
--- a/wisitoken.ads
+++ b/wisitoken.ads
@@ -78,6 +78,8 @@ package WisiToken is
 
    --  SAL.Programmer_Error : exception; -- a programming convention has been 
violated
 
+   Validate_Error : exception; -- A validation has failed.
+
    subtype Positive_Index_Type is SAL.Peek_Type;
    function Trimmed_Image is new SAL.Gen_Trimmed_Image (SAL.Base_Peek_Type);
 
@@ -532,4 +534,6 @@ package WisiToken is
    --  (ending delim is read from the stream but not included in result).
    --  Leading Delims are skipped.
 
+   type Recursion_Strategy is (None, Partial, Full);
+
 end WisiToken;
diff --git a/wisitoken_grammar_actions.ads b/wisitoken_grammar_actions.ads
index 4c044a5302..f8a7654b7b 100644
--- a/wisitoken_grammar_actions.ads
+++ b/wisitoken_grammar_actions.ads
@@ -283,4 +283,6 @@ package Wisitoken_Grammar_Actions is
      (User_Data : in out WisiToken.Syntax_Trees.User_Data_Type'Class;
       Tree      : in out WisiToken.Syntax_Trees.Tree;
       Nonterm   : in     WisiToken.Syntax_Trees.Valid_Node_Access);
+   Partial_Parse_Active    : aliased Boolean := False;
+   Partial_Parse_Byte_Goal : aliased WisiToken.Buffer_Pos := 
WisiToken.Buffer_Pos'Last;
 end Wisitoken_Grammar_Actions;
diff --git a/wisitoken_grammar_editing.adb b/wisitoken_grammar_editing.adb
index 81b16b1dcc..8d0ad09ed4 100644
--- a/wisitoken_grammar_editing.adb
+++ b/wisitoken_grammar_editing.adb
@@ -2937,7 +2937,7 @@ package body WisiToken_Grammar_Editing is
          if Data.Error_Reported.Count > 0 then
             Ada.Text_IO.New_Line;
             Ada.Text_IO.Put_Line ("initial invalid tree:");
-            Tree.Print_Tree;
+            Tree.Print_Tree (Line_Numbers => True, Non_Grammar => True);
          end if;
       end if;
 
diff --git a/wisitoken_grammar_main.adb b/wisitoken_grammar_main.adb
index d985bb4429..4816a20407 100644
--- a/wisitoken_grammar_main.adb
+++ b/wisitoken_grammar_main.adb
@@ -24,6 +24,7 @@
 with SAL;
 with WisiToken.Lexer.re2c;
 with wisitoken_grammar_re2c_c;
+with WisiToken.Parse.LR;
 with Wisitoken_Grammar_Actions; use Wisitoken_Grammar_Actions;
 package body Wisitoken_Grammar_Main is
 
@@ -960,11 +961,6 @@ package body Wisitoken_Grammar_Main is
       return Table;
    end Create_Parse_Table;
 
-   function Create_Lexer (Trace : in WisiToken.Trace_Access) return 
WisiToken.Lexer.Handle
-   is begin
-      return Lexer.New_Lexer (Trace, 
Wisitoken_Grammar_Actions.Descriptor'Access);
-   end Create_Lexer;
-
    function Create_Productions return 
WisiToken.Syntax_Trees.Production_Info_Trees.Vector
    is begin
       return Result : WisiToken.Syntax_Trees.Production_Info_Trees.Vector do
@@ -1032,4 +1028,16 @@ package body Wisitoken_Grammar_Main is
       end return;
    end Create_Productions;
 
+   function Create_Parser
+     (Trace      : in WisiToken.Trace_Access;
+      User_Data  : in WisiToken.Syntax_Trees.User_Data_Access)
+     return WisiToken.Parse.LR.Parser_No_Recover.Parser
+   is begin
+      return Parser : WisiToken.Parse.LR.Parser_No_Recover.Parser do
+         Parser.Tree.Lexer := Lexer.New_Lexer (Trace, 
Wisitoken_Grammar_Actions.Descriptor'Access);
+         Parser.Productions := Create_Productions;
+         Parser.User_Data := User_Data;
+         Parser.Table := Create_Parse_Table;
+      end return;
+   end Create_Parser;
 end Wisitoken_Grammar_Main;
diff --git a/wisitoken_grammar_main.ads b/wisitoken_grammar_main.ads
index 90354e3a79..1e7b6f937a 100644
--- a/wisitoken_grammar_main.ads
+++ b/wisitoken_grammar_main.ads
@@ -22,14 +22,12 @@
 --  along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
 
 with WisiToken.Syntax_Trees;
-with WisiToken.Lexer;
-with WisiToken.Parse.LR;
+with WisiToken.Parse.LR.Parser_No_Recover;
 package Wisitoken_Grammar_Main is
 
-   function Create_Parse_Table
-     return WisiToken.Parse.LR.Parse_Table_Ptr;
+   function Create_Parser
+     (Trace      : in WisiToken.Trace_Access;
+      User_Data  : in WisiToken.Syntax_Trees.User_Data_Access)
+     return WisiToken.Parse.LR.Parser_No_Recover.Parser;
 
-   function Create_Productions return 
WisiToken.Syntax_Trees.Production_Info_Trees.Vector;
-
-   function Create_Lexer (Trace : in WisiToken.Trace_Access) return 
WisiToken.Lexer.Handle;
 end Wisitoken_Grammar_Main;
diff --git a/wisitoken_grammar_re2c.c b/wisitoken_grammar_re2c.c
index 7a76ad1ae7..712d5eb487 100644
--- a/wisitoken_grammar_re2c.c
+++ b/wisitoken_grammar_re2c.c
@@ -1,4 +1,4 @@
-/* Generated by re2c 2.0.2 */
+/* Generated by re2c 3.0 */
 #line 1 "../wisitoken_grammar.re2c"
 //  generated parser support file. -*- buffer-read-only:t mode: C -*-
 //  command line: wisitoken-bnf-generate.exe  --generate LALR Ada re2c 
wisitoken_grammar.wy
@@ -207,5536 +207,5493 @@ int wisitoken_grammar_next_token
 {
        YYCTYPE yych;
        unsigned int yyaccept = 0;
-       YYDEBUG(0, *YYCURSOR);
+       YYDEBUG(0, YYPEEK());
        yych = YYPEEK();
        switch (yych) {
-       case 0x04:      goto yy4;
-       case '\t':
-       case ' ':       goto yy6;
-       case '\n':      goto yy8;
-       case '\r':      goto yy10;
-       case '"':       goto yy11;
-       case '%':       goto yy12;
-       case '\'':      goto yy14;
-       case '(':       goto yy15;
-       case ')':       goto yy17;
-       case '*':       goto yy19;
-       case '+':       goto yy21;
-       case '-':       goto yy23;
-       case '0':
-       case '1':
-       case '2':
-       case '3':
-       case '4':
-       case '5':
-       case '6':
-       case '7':
-       case '8':
-       case '9':       goto yy25;
-       case ':':       goto yy28;
-       case ';':       goto yy30;
-       case '<':       goto yy32;
-       case '=':       goto yy34;
-       case '>':       goto yy36;
-       case '?':       goto yy38;
-       case 'A':
-       case 'a':       goto yy40;
-       case 'B':
-       case 'C':
-       case 'D':
-       case 'E':
-       case 'F':
-       case 'G':
-       case 'H':
-       case 'I':
-       case 'J':
-       case 'K':
-       case 'L':
-       case 'M':
-       case 'N':
-       case 'O':
-       case 'P':
-       case 'Q':
-       case 'T':
-       case 'U':
-       case 'V':
-       case 'W':
-       case 'X':
-       case 'Y':
-       case 'Z':
-       case 'b':
-       case 'd':
-       case 'f':
-       case 'g':
-       case 'h':
-       case 'j':
-       case 'l':
-       case 'm':
-       case 'p':
-       case 'q':
-       case 'u':
-       case 'v':
-       case 'w':
-       case 'x':
-       case 'y':
-       case 'z':       goto yy42;
-       case 'R':
-       case 'r':       goto yy44;
-       case 'S':
-       case 's':       goto yy45;
-       case '[':       goto yy46;
-       case ']':       goto yy48;
-       case 'c':       goto yy50;
-       case 'e':       goto yy51;
-       case 'i':       goto yy52;
-       case 'k':       goto yy53;
-       case 'n':       goto yy54;
-       case 'o':       goto yy55;
-       case 't':       goto yy56;
-       case '{':       goto yy57;
-       case '|':       goto yy59;
-       case '}':       goto yy61;
-       case 0xC2:
-       case 0xC3:
-       case 0xC4:
-       case 0xC5:
-       case 0xC6:
-       case 0xC7:
-       case 0xC8:
-       case 0xC9:
-       case 0xCA:
-       case 0xCB:
-       case 0xCC:
-       case 0xCD:
-       case 0xCE:
-       case 0xCF:
-       case 0xD0:
-       case 0xD1:
-       case 0xD2:
-       case 0xD3:
-       case 0xD4:
-       case 0xD5:
-       case 0xD6:
-       case 0xD7:
-       case 0xD8:
-       case 0xD9:
-       case 0xDA:
-       case 0xDB:
-       case 0xDC:
-       case 0xDD:
-       case 0xDE:
-       case 0xDF:      goto yy63;
-       case 0xE0:      goto yy64;
-       case 0xE1:
-       case 0xE2:
-       case 0xE3:
-       case 0xE4:
-       case 0xE5:
-       case 0xE6:
-       case 0xE7:
-       case 0xE8:
-       case 0xE9:
-       case 0xEA:
-       case 0xEB:
-       case 0xEC:
-       case 0xED:
-       case 0xEE:
-       case 0xEF:      goto yy65;
-       case 0xF0:      goto yy66;
-       case 0xF1:
-       case 0xF2:
-       case 0xF3:      goto yy67;
-       case 0xF4:      goto yy68;
-       default:        goto yy2;
+               case 0x04: goto yy3;
+               case '\t':
+               case ' ': goto yy4;
+               case '\n': goto yy5;
+               case '\r': goto yy6;
+               case '"': goto yy7;
+               case '%': goto yy8;
+               case '\'': goto yy10;
+               case '(': goto yy11;
+               case ')': goto yy12;
+               case '*': goto yy13;
+               case '+': goto yy14;
+               case '-': goto yy15;
+               case '0':
+               case '1':
+               case '2':
+               case '3':
+               case '4':
+               case '5':
+               case '6':
+               case '7':
+               case '8':
+               case '9': goto yy17;
+               case ':': goto yy19;
+               case ';': goto yy21;
+               case '<': goto yy23;
+               case '=': goto yy24;
+               case '>': goto yy25;
+               case '?': goto yy26;
+               case 'A':
+               case 'a': goto yy27;
+               case 'B':
+               case 'C':
+               case 'D':
+               case 'E':
+               case 'F':
+               case 'G':
+               case 'H':
+               case 'I':
+               case 'J':
+               case 'K':
+               case 'L':
+               case 'M':
+               case 'N':
+               case 'O':
+               case 'P':
+               case 'Q':
+               case 'T':
+               case 'U':
+               case 'V':
+               case 'W':
+               case 'X':
+               case 'Y':
+               case 'Z':
+               case 'b':
+               case 'd':
+               case 'f':
+               case 'g':
+               case 'h':
+               case 'j':
+               case 'l':
+               case 'm':
+               case 'p':
+               case 'q':
+               case 'u':
+               case 'v':
+               case 'w':
+               case 'x':
+               case 'y':
+               case 'z': goto yy29;
+               case 'R':
+               case 'r': goto yy31;
+               case 'S':
+               case 's': goto yy32;
+               case '[': goto yy33;
+               case ']': goto yy34;
+               case 'c': goto yy35;
+               case 'e': goto yy36;
+               case 'i': goto yy37;
+               case 'k': goto yy38;
+               case 'n': goto yy39;
+               case 'o': goto yy40;
+               case 't': goto yy41;
+               case '{': goto yy42;
+               case '|': goto yy43;
+               case '}': goto yy44;
+               case 0xC2:
+               case 0xC3:
+               case 0xC4:
+               case 0xC5:
+               case 0xC6:
+               case 0xC7:
+               case 0xC8:
+               case 0xC9:
+               case 0xCA:
+               case 0xCB:
+               case 0xCC:
+               case 0xCD:
+               case 0xCE:
+               case 0xCF:
+               case 0xD0:
+               case 0xD1:
+               case 0xD2:
+               case 0xD3:
+               case 0xD4:
+               case 0xD5:
+               case 0xD6:
+               case 0xD7:
+               case 0xD8:
+               case 0xD9:
+               case 0xDA:
+               case 0xDB:
+               case 0xDC:
+               case 0xDD:
+               case 0xDE:
+               case 0xDF: goto yy45;
+               case 0xE0: goto yy46;
+               case 0xE1:
+               case 0xE2:
+               case 0xE3:
+               case 0xE4:
+               case 0xE5:
+               case 0xE6:
+               case 0xE7:
+               case 0xE8:
+               case 0xE9:
+               case 0xEA:
+               case 0xEB:
+               case 0xEC:
+               case 0xED:
+               case 0xEE:
+               case 0xEF: goto yy47;
+               case 0xF0: goto yy48;
+               case 0xF1:
+               case 0xF2:
+               case 0xF3: goto yy49;
+               case 0xF4: goto yy50;
+               default: goto yy1;
        }
+yy1:
+       YYDEBUG(1, YYPEEK());
+       YYSKIP();
 yy2:
        YYDEBUG(2, YYPEEK());
-       YYSKIP();
-yy3:
-       YYDEBUG(3, YYPEEK());
 #line 296 "../wisitoken_grammar.re2c"
        {status = ERROR_unrecognized_character; continue;}
 #line 360 "../wisitoken_grammar_re2c.c"
-yy4:
-       YYDEBUG(4, YYPEEK());
+yy3:
+       YYDEBUG(3, YYPEEK());
        YYSKIP();
-       YYDEBUG(5, YYPEEK());
 #line 294 "../wisitoken_grammar.re2c"
        {*id = 42; continue;}
-#line 367 "../wisitoken_grammar_re2c.c"
-yy6:
-       YYDEBUG(6, YYPEEK());
+#line 366 "../wisitoken_grammar_re2c.c"
+yy4:
+       YYDEBUG(4, YYPEEK());
        YYSKIP();
-       YYDEBUG(7, YYPEEK());
 #line 249 "../wisitoken_grammar.re2c"
        { lexer->byte_token_start = lexer->cursor;
           lexer->char_token_start = lexer->char_pos;
           lexer->line_token_start = lexer->line;
           continue; }
-#line 377 "../wisitoken_grammar_re2c.c"
-yy8:
-       YYDEBUG(8, YYPEEK());
+#line 375 "../wisitoken_grammar_re2c.c"
+yy5:
+       YYDEBUG(5, YYPEEK());
        YYSKIP();
-       YYDEBUG(9, YYPEEK());
 #line 253 "../wisitoken_grammar.re2c"
        {*id = 1; lexer->line++; continue;}
-#line 384 "../wisitoken_grammar_re2c.c"
-yy10:
-       YYDEBUG(10, YYPEEK());
+#line 381 "../wisitoken_grammar_re2c.c"
+yy6:
+       YYDEBUG(6, YYPEEK());
        YYSKIP();
        yych = YYPEEK();
        switch (yych) {
-       case '\n':      goto yy8;
-       default:        goto yy3;
+               case '\n': goto yy5;
+               default: goto yy2;
        }
-yy11:
-       YYDEBUG(11, YYPEEK());
+yy7:
+       YYDEBUG(7, YYPEEK());
        yyaccept = 0;
        YYSKIP();
        YYBACKUP();
        yych = YYPEEK();
        switch (yych) {
-       case ' ':
-       case '!':
-       case '"':
-       case '#':
-       case '$':
-       case '%':
-       case '&':
-       case '\'':
-       case '(':
-       case ')':
-       case '*':
-       case '+':
-       case ',':
-       case '-':
-       case '.':
-       case '/':
-       case '0':
-       case '1':
-       case '2':
-       case '3':
-       case '4':
-       case '5':
-       case '6':
-       case '7':
-       case '8':
-       case '9':
-       case ':':
-       case ';':
-       case '<':
-       case '=':
-       case '>':
-       case '?':
-       case '@':
-       case 'A':
-       case 'B':
-       case 'C':
-       case 'D':
-       case 'E':
-       case 'F':
-       case 'G':
-       case 'H':
-       case 'I':
-       case 'J':
-       case 'K':
-       case 'L':
-       case 'M':
-       case 'N':
-       case 'O':
-       case 'P':
-       case 'Q':
-       case 'R':
-       case 'S':
-       case 'T':
-       case 'U':
-       case 'V':
-       case 'W':
-       case 'X':
-       case 'Y':
-       case 'Z':
-       case '[':
-       case '\\':
-       case ']':
-       case '^':
-       case '_':
-       case '`':
-       case 'a':
-       case 'b':
-       case 'c':
-       case 'd':
-       case 'e':
-       case 'f':
-       case 'g':
-       case 'h':
-       case 'i':
-       case 'j':
-       case 'k':
-       case 'l':
-       case 'm':
-       case 'n':
-       case 'o':
-       case 'p':
-       case 'q':
-       case 'r':
-       case 's':
-       case 't':
-       case 'u':
-       case 'v':
-       case 'w':
-       case 'x':
-       case 'y':
-       case 'z':
-       case '{':
-       case '|':
-       case '}':
-       case '~':
-       case 0x7F:
-       case 0xC2:
-       case 0xC3:
-       case 0xC4:
-       case 0xC5:
-       case 0xC6:
-       case 0xC7:
-       case 0xC8:
-       case 0xC9:
-       case 0xCA:
-       case 0xCB:
-       case 0xCC:
-       case 0xCD:
-       case 0xCE:
-       case 0xCF:
-       case 0xD0:
-       case 0xD1:
-       case 0xD2:
-       case 0xD3:
-       case 0xD4:
-       case 0xD5:
-       case 0xD6:
-       case 0xD7:
-       case 0xD8:
-       case 0xD9:
-       case 0xDA:
-       case 0xDB:
-       case 0xDC:
-       case 0xDD:
-       case 0xDE:
-       case 0xDF:
-       case 0xE0:
-       case 0xE1:
-       case 0xE2:
-       case 0xE3:
-       case 0xE4:
-       case 0xE5:
-       case 0xE6:
-       case 0xE7:
-       case 0xE8:
-       case 0xE9:
-       case 0xEA:
-       case 0xEB:
-       case 0xEC:
-       case 0xED:
-       case 0xEE:
-       case 0xEF:
-       case 0xF0:
-       case 0xF1:
-       case 0xF2:
-       case 0xF3:
-       case 0xF4:      goto yy70;
-       default:        goto yy3;
+               case ' ':
+               case '!':
+               case '"':
+               case '#':
+               case '$':
+               case '%':
+               case '&':
+               case '\'':
+               case '(':
+               case ')':
+               case '*':
+               case '+':
+               case ',':
+               case '-':
+               case '.':
+               case '/':
+               case '0':
+               case '1':
+               case '2':
+               case '3':
+               case '4':
+               case '5':
+               case '6':
+               case '7':
+               case '8':
+               case '9':
+               case ':':
+               case ';':
+               case '<':
+               case '=':
+               case '>':
+               case '?':
+               case '@':
+               case 'A':
+               case 'B':
+               case 'C':
+               case 'D':
+               case 'E':
+               case 'F':
+               case 'G':
+               case 'H':
+               case 'I':
+               case 'J':
+               case 'K':
+               case 'L':
+               case 'M':
+               case 'N':
+               case 'O':
+               case 'P':
+               case 'Q':
+               case 'R':
+               case 'S':
+               case 'T':
+               case 'U':
+               case 'V':
+               case 'W':
+               case 'X':
+               case 'Y':
+               case 'Z':
+               case '[':
+               case '\\':
+               case ']':
+               case '^':
+               case '_':
+               case '`':
+               case 'a':
+               case 'b':
+               case 'c':
+               case 'd':
+               case 'e':
+               case 'f':
+               case 'g':
+               case 'h':
+               case 'i':
+               case 'j':
+               case 'k':
+               case 'l':
+               case 'm':
+               case 'n':
+               case 'o':
+               case 'p':
+               case 'q':
+               case 'r':
+               case 's':
+               case 't':
+               case 'u':
+               case 'v':
+               case 'w':
+               case 'x':
+               case 'y':
+               case 'z':
+               case '{':
+               case '|':
+               case '}':
+               case '~':
+               case 0x7F:
+               case 0xC2:
+               case 0xC3:
+               case 0xC4:
+               case 0xC5:
+               case 0xC6:
+               case 0xC7:
+               case 0xC8:
+               case 0xC9:
+               case 0xCA:
+               case 0xCB:
+               case 0xCC:
+               case 0xCD:
+               case 0xCE:
+               case 0xCF:
+               case 0xD0:
+               case 0xD1:
+               case 0xD2:
+               case 0xD3:
+               case 0xD4:
+               case 0xD5:
+               case 0xD6:
+               case 0xD7:
+               case 0xD8:
+               case 0xD9:
+               case 0xDA:
+               case 0xDB:
+               case 0xDC:
+               case 0xDD:
+               case 0xDE:
+               case 0xDF:
+               case 0xE0:
+               case 0xE1:
+               case 0xE2:
+               case 0xE3:
+               case 0xE4:
+               case 0xE5:
+               case 0xE6:
+               case 0xE7:
+               case 0xE8:
+               case 0xE9:
+               case 0xEA:
+               case 0xEB:
+               case 0xEC:
+               case 0xED:
+               case 0xEE:
+               case 0xEF:
+               case 0xF0:
+               case 0xF1:
+               case 0xF2:
+               case 0xF3:
+               case 0xF4: goto yy52;
+               default: goto yy2;
        }
-yy12:
-       YYDEBUG(12, YYPEEK());
+yy8:
+       YYDEBUG(8, YYPEEK());
        YYSKIP();
        yych = YYPEEK();
        switch (yych) {
-       case '(':       goto yy80;
-       case '[':       goto yy82;
-       case '{':       goto yy84;
-       default:        goto yy13;
+               case '(': goto yy62;
+               case '[': goto yy63;
+               case '{': goto yy64;
+               default: goto yy9;
        }
-yy13:
-       YYDEBUG(13, YYPEEK());
+yy9:
+       YYDEBUG(9, YYPEEK());
 #line 282 "../wisitoken_grammar.re2c"
        {*id = 30; continue;}
-#line 563 "../wisitoken_grammar_re2c.c"
-yy14:
-       YYDEBUG(14, YYPEEK());
+#line 560 "../wisitoken_grammar_re2c.c"
+yy10:
+       YYDEBUG(10, YYPEEK());
        yyaccept = 0;
        YYSKIP();
        YYBACKUP();
        yych = YYPEEK();
        switch (yych) {
-       case ' ':
-       case '!':
-       case '"':
-       case '#':
-       case '$':
-       case '%':
-       case '&':
-       case '\'':
-       case '(':
-       case ')':
-       case '*':
-       case '+':
-       case ',':
-       case '-':
-       case '.':
-       case '/':
-       case '0':
-       case '1':
-       case '2':
-       case '3':
-       case '4':
-       case '5':
-       case '6':
-       case '7':
-       case '8':
-       case '9':
-       case ':':
-       case ';':
-       case '<':
-       case '=':
-       case '>':
-       case '?':
-       case '@':
-       case 'A':
-       case 'B':
-       case 'C':
-       case 'D':
-       case 'E':
-       case 'F':
-       case 'G':
-       case 'H':
-       case 'I':
-       case 'J':
-       case 'K':
-       case 'L':
-       case 'M':
-       case 'N':
-       case 'O':
-       case 'P':
-       case 'Q':
-       case 'R':
-       case 'S':
-       case 'T':
-       case 'U':
-       case 'V':
-       case 'W':
-       case 'X':
-       case 'Y':
-       case 'Z':
-       case '[':
-       case '\\':
-       case ']':
-       case '^':
-       case '_':
-       case '`':
-       case 'a':
-       case 'b':
-       case 'c':
-       case 'd':
-       case 'e':
-       case 'f':
-       case 'g':
-       case 'h':
-       case 'i':
-       case 'j':
-       case 'k':
-       case 'l':
-       case 'm':
-       case 'n':
-       case 'o':
-       case 'p':
-       case 'q':
-       case 'r':
-       case 's':
-       case 't':
-       case 'u':
-       case 'v':
-       case 'w':
-       case 'x':
-       case 'y':
-       case 'z':
-       case '{':
-       case '|':
-       case '}':
-       case '~':
-       case 0x7F:
-       case 0xC2:
-       case 0xC3:
-       case 0xC4:
-       case 0xC5:
-       case 0xC6:
-       case 0xC7:
-       case 0xC8:
-       case 0xC9:
-       case 0xCA:
-       case 0xCB:
-       case 0xCC:
-       case 0xCD:
-       case 0xCE:
-       case 0xCF:
-       case 0xD0:
-       case 0xD1:
-       case 0xD2:
-       case 0xD3:
-       case 0xD4:
-       case 0xD5:
-       case 0xD6:
-       case 0xD7:
-       case 0xD8:
-       case 0xD9:
-       case 0xDA:
-       case 0xDB:
-       case 0xDC:
-       case 0xDD:
-       case 0xDE:
-       case 0xDF:
-       case 0xE0:
-       case 0xE1:
-       case 0xE2:
-       case 0xE3:
-       case 0xE4:
-       case 0xE5:
-       case 0xE6:
-       case 0xE7:
-       case 0xE8:
-       case 0xE9:
-       case 0xEA:
-       case 0xEB:
-       case 0xEC:
-       case 0xED:
-       case 0xEE:
-       case 0xEF:
-       case 0xF0:
-       case 0xF1:
-       case 0xF2:
-       case 0xF3:
-       case 0xF4:      goto yy87;
-       default:        goto yy3;
+               case ' ':
+               case '!':
+               case '"':
+               case '#':
+               case '$':
+               case '%':
+               case '&':
+               case '\'':
+               case '(':
+               case ')':
+               case '*':
+               case '+':
+               case ',':
+               case '-':
+               case '.':
+               case '/':
+               case '0':
+               case '1':
+               case '2':
+               case '3':
+               case '4':
+               case '5':
+               case '6':
+               case '7':
+               case '8':
+               case '9':
+               case ':':
+               case ';':
+               case '<':
+               case '=':
+               case '>':
+               case '?':
+               case '@':
+               case 'A':
+               case 'B':
+               case 'C':
+               case 'D':
+               case 'E':
+               case 'F':
+               case 'G':
+               case 'H':
+               case 'I':
+               case 'J':
+               case 'K':
+               case 'L':
+               case 'M':
+               case 'N':
+               case 'O':
+               case 'P':
+               case 'Q':
+               case 'R':
+               case 'S':
+               case 'T':
+               case 'U':
+               case 'V':
+               case 'W':
+               case 'X':
+               case 'Y':
+               case 'Z':
+               case '[':
+               case '\\':
+               case ']':
+               case '^':
+               case '_':
+               case '`':
+               case 'a':
+               case 'b':
+               case 'c':
+               case 'd':
+               case 'e':
+               case 'f':
+               case 'g':
+               case 'h':
+               case 'i':
+               case 'j':
+               case 'k':
+               case 'l':
+               case 'm':
+               case 'n':
+               case 'o':
+               case 'p':
+               case 'q':
+               case 'r':
+               case 's':
+               case 't':
+               case 'u':
+               case 'v':
+               case 'w':
+               case 'x':
+               case 'y':
+               case 'z':
+               case '{':
+               case '|':
+               case '}':
+               case '~':
+               case 0x7F:
+               case 0xC2:
+               case 0xC3:
+               case 0xC4:
+               case 0xC5:
+               case 0xC6:
+               case 0xC7:
+               case 0xC8:
+               case 0xC9:
+               case 0xCA:
+               case 0xCB:
+               case 0xCC:
+               case 0xCD:
+               case 0xCE:
+               case 0xCF:
+               case 0xD0:
+               case 0xD1:
+               case 0xD2:
+               case 0xD3:
+               case 0xD4:
+               case 0xD5:
+               case 0xD6:
+               case 0xD7:
+               case 0xD8:
+               case 0xD9:
+               case 0xDA:
+               case 0xDB:
+               case 0xDC:
+               case 0xDD:
+               case 0xDE:
+               case 0xDF:
+               case 0xE0:
+               case 0xE1:
+               case 0xE2:
+               case 0xE3:
+               case 0xE4:
+               case 0xE5:
+               case 0xE6:
+               case 0xE7:
+               case 0xE8:
+               case 0xE9:
+               case 0xEA:
+               case 0xEB:
+               case 0xEC:
+               case 0xED:
+               case 0xEE:
+               case 0xEF:
+               case 0xF0:
+               case 0xF1:
+               case 0xF2:
+               case 0xF3:
+               case 0xF4: goto yy66;
+               default: goto yy2;
        }
-yy15:
-       YYDEBUG(15, YYPEEK());
+yy11:
+       YYDEBUG(11, YYPEEK());
        YYSKIP();
-       YYDEBUG(16, YYPEEK());
 #line 279 "../wisitoken_grammar.re2c"
        {*id = 27; continue;}
-#line 726 "../wisitoken_grammar_re2c.c"
-yy17:
-       YYDEBUG(17, YYPEEK());
+#line 722 "../wisitoken_grammar_re2c.c"
+yy12:
+       YYDEBUG(12, YYPEEK());
        YYSKIP();
-       YYDEBUG(18, YYPEEK());
 #line 287 "../wisitoken_grammar.re2c"
        {*id = 35; continue;}
-#line 733 "../wisitoken_grammar_re2c.c"
-yy19:
-       YYDEBUG(19, YYPEEK());
+#line 728 "../wisitoken_grammar_re2c.c"
+yy13:
+       YYDEBUG(13, YYPEEK());
        YYSKIP();
-       YYDEBUG(20, YYPEEK());
 #line 289 "../wisitoken_grammar.re2c"
        {*id = 37; continue;}
-#line 740 "../wisitoken_grammar_re2c.c"
-yy21:
-       YYDEBUG(21, YYPEEK());
+#line 734 "../wisitoken_grammar_re2c.c"
+yy14:
+       YYDEBUG(14, YYPEEK());
        YYSKIP();
-       YYDEBUG(22, YYPEEK());
 #line 283 "../wisitoken_grammar.re2c"
        {*id = 31; continue;}
-#line 747 "../wisitoken_grammar_re2c.c"
-yy23:
-       YYDEBUG(23, YYPEEK());
+#line 740 "../wisitoken_grammar_re2c.c"
+yy15:
+       YYDEBUG(15, YYPEEK());
        YYSKIP();
        yych = YYPEEK();
        switch (yych) {
-       case '0':
-       case '1':
-       case '2':
-       case '3':
-       case '4':
-       case '5':
-       case '6':
-       case '7':
-       case '8':
-       case '9':
-       case '_':       goto yy25;
-       default:        goto yy24;
+               case '0':
+               case '1':
+               case '2':
+               case '3':
+               case '4':
+               case '5':
+               case '6':
+               case '7':
+               case '8':
+               case '9':
+               case '_': goto yy17;
+               default: goto yy16;
        }
-yy24:
-       YYDEBUG(24, YYPEEK());
+yy16:
+       YYDEBUG(16, YYPEEK());
 #line 281 "../wisitoken_grammar.re2c"
        {*id = 29; continue;}
-#line 770 "../wisitoken_grammar_re2c.c"
-yy25:
-       YYDEBUG(25, YYPEEK());
+#line 763 "../wisitoken_grammar_re2c.c"
+yy17:
+       YYDEBUG(17, YYPEEK());
        YYSKIP();
        yych = YYPEEK();
-       YYDEBUG(26, YYPEEK());
        switch (yych) {
-       case '0':
-       case '1':
-       case '2':
-       case '3':
-       case '4':
-       case '5':
-       case '6':
-       case '7':
-       case '8':
-       case '9':
-       case '_':       goto yy25;
-       default:        goto yy27;
+               case '0':
+               case '1':
+               case '2':
+               case '3':
+               case '4':
+               case '5':
+               case '6':
+               case '7':
+               case '8':
+               case '9':
+               case '_': goto yy17;
+               default: goto yy18;
        }
-yy27:
-       YYDEBUG(27, YYPEEK());
+yy18:
+       YYDEBUG(18, YYPEEK());
 #line 290 "../wisitoken_grammar.re2c"
        {*id = 38; continue;}
-#line 794 "../wisitoken_grammar_re2c.c"
-yy28:
-       YYDEBUG(28, YYPEEK());
+#line 786 "../wisitoken_grammar_re2c.c"
+yy19:
+       YYDEBUG(19, YYPEEK());
        yyaccept = 1;
        YYSKIP();
        YYBACKUP();
        yych = YYPEEK();
        switch (yych) {
-       case ':':       goto yy96;
-       default:        goto yy29;
+               case ':': goto yy75;
+               default: goto yy20;
        }
-yy29:
-       YYDEBUG(29, YYPEEK());
+yy20:
+       YYDEBUG(20, YYPEEK());
 #line 273 "../wisitoken_grammar.re2c"
        {*id = 21; continue;}
-#line 809 "../wisitoken_grammar_re2c.c"
-yy30:
-       YYDEBUG(30, YYPEEK());
+#line 801 "../wisitoken_grammar_re2c.c"
+yy21:
+       YYDEBUG(21, YYPEEK());
        yyaccept = 2;
        YYSKIP();
        YYBACKUP();
        yych = YYPEEK();
        switch (yych) {
-       case ';':       goto yy97;
-       default:        goto yy31;
+               case ';': goto yy76;
+               default: goto yy22;
        }
-yy31:
-       YYDEBUG(31, YYPEEK());
+yy22:
+       YYDEBUG(22, YYPEEK());
 #line 288 "../wisitoken_grammar.re2c"
        {*id = 36; continue;}
-#line 824 "../wisitoken_grammar_re2c.c"
-yy32:
-       YYDEBUG(32, YYPEEK());
+#line 816 "../wisitoken_grammar_re2c.c"
+yy23:
+       YYDEBUG(23, YYPEEK());
        YYSKIP();
-       YYDEBUG(33, YYPEEK());
 #line 280 "../wisitoken_grammar.re2c"
        {*id = 28; continue;}
-#line 831 "../wisitoken_grammar_re2c.c"
-yy34:
-       YYDEBUG(34, YYPEEK());
+#line 822 "../wisitoken_grammar_re2c.c"
+yy24:
+       YYDEBUG(24, YYPEEK());
        YYSKIP();
-       YYDEBUG(35, YYPEEK());
 #line 275 "../wisitoken_grammar.re2c"
        {*id = 23; continue;}
-#line 838 "../wisitoken_grammar_re2c.c"
-yy36:
-       YYDEBUG(36, YYPEEK());
+#line 828 "../wisitoken_grammar_re2c.c"
+yy25:
+       YYDEBUG(25, YYPEEK());
        YYSKIP();
-       YYDEBUG(37, YYPEEK());
 #line 276 "../wisitoken_grammar.re2c"
        {*id = 24; continue;}
-#line 845 "../wisitoken_grammar_re2c.c"
-yy38:
-       YYDEBUG(38, YYPEEK());
+#line 834 "../wisitoken_grammar_re2c.c"
+yy26:
+       YYDEBUG(26, YYPEEK());
        YYSKIP();
-       YYDEBUG(39, YYPEEK());
 #line 284 "../wisitoken_grammar.re2c"
        {*id = 32; continue;}
-#line 852 "../wisitoken_grammar_re2c.c"
-yy40:
-       YYDEBUG(40, YYPEEK());
+#line 840 "../wisitoken_grammar_re2c.c"
+yy27:
+       YYDEBUG(27, YYPEEK());
        yyaccept = 3;
        YYSKIP();
        YYBACKUP();
        yych = YYPEEK();
        switch (yych) {
-       case 'C':
-       case 'c':       goto yy99;
-       default:        goto yy43;
+               case 'C':
+               case 'c': goto yy77;
+               default: goto yy30;
        }
-yy41:
-       YYDEBUG(41, YYPEEK());
+yy28:
+       YYDEBUG(28, YYPEEK());
 #line 291 "../wisitoken_grammar.re2c"
        {*id = 39; continue;}
-#line 868 "../wisitoken_grammar_re2c.c"
-yy42:
-       YYDEBUG(42, YYPEEK());
+#line 856 "../wisitoken_grammar_re2c.c"
+yy29:
+       YYDEBUG(29, YYPEEK());
        yyaccept = 3;
        YYSKIP();
        YYBACKUP();
        yych = YYPEEK();
-yy43:
-       YYDEBUG(43, YYPEEK());
+yy30:
+       YYDEBUG(30, YYPEEK());
        switch (yych) {
-       case '-':
-       case '0':
-       case '1':
-       case '2':
-       case '3':
-       case '4':
-       case '5':
-       case '6':
-       case '7':
-       case '8':
-       case '9':
-       case 'A':
-       case 'B':
-       case 'C':
-       case 'D':
-       case 'E':
-       case 'F':
-       case 'G':
-       case 'H':
-       case 'I':
-       case 'J':
-       case 'K':
-       case 'L':
-       case 'M':
-       case 'N':
-       case 'O':
-       case 'P':
-       case 'Q':
-       case 'R':
-       case 'S':
-       case 'T':
-       case 'U':
-       case 'V':
-       case 'W':
-       case 'X':
-       case 'Y':
-       case 'Z':
-       case '_':
-       case 'a':
-       case 'b':
-       case 'c':
-       case 'd':
-       case 'e':
-       case 'f':
-       case 'g':
-       case 'h':
-       case 'i':
-       case 'j':
-       case 'k':
-       case 'l':
-       case 'm':
-       case 'n':
-       case 'o':
-       case 'p':
-       case 'q':
-       case 'r':
-       case 's':
-       case 't':
-       case 'u':
-       case 'v':
-       case 'w':
-       case 'x':
-       case 'y':
-       case 'z':       goto yy42;
-       case 0xC2:
-       case 0xC3:
-       case 0xC4:
-       case 0xC5:
-       case 0xC6:
-       case 0xC7:
-       case 0xC8:
-       case 0xC9:
-       case 0xCA:
-       case 0xCB:
-       case 0xCC:
-       case 0xCD:
-       case 0xCE:
-       case 0xCF:
-       case 0xD0:
-       case 0xD1:
-       case 0xD2:
-       case 0xD3:
-       case 0xD4:
-       case 0xD5:
-       case 0xD6:
-       case 0xD7:
-       case 0xD8:
-       case 0xD9:
-       case 0xDA:
-       case 0xDB:
-       case 0xDC:
-       case 0xDD:
-       case 0xDE:
-       case 0xDF:      goto yy100;
-       case 0xE0:      goto yy101;
-       case 0xE1:
-       case 0xE2:
-       case 0xE3:
-       case 0xE4:
-       case 0xE5:
-       case 0xE6:
-       case 0xE7:
-       case 0xE8:
-       case 0xE9:
-       case 0xEA:
-       case 0xEB:
-       case 0xEC:
-       case 0xED:
-       case 0xEE:
-       case 0xEF:      goto yy102;
-       case 0xF0:      goto yy103;
-       case 0xF1:
-       case 0xF2:
-       case 0xF3:      goto yy104;
-       case 0xF4:      goto yy105;
-       default:        goto yy41;
+               case '-':
+               case '0':
+               case '1':
+               case '2':
+               case '3':
+               case '4':
+               case '5':
+               case '6':
+               case '7':
+               case '8':
+               case '9':
+               case 'A':
+               case 'B':
+               case 'C':
+               case 'D':
+               case 'E':
+               case 'F':
+               case 'G':
+               case 'H':
+               case 'I':
+               case 'J':
+               case 'K':
+               case 'L':
+               case 'M':
+               case 'N':
+               case 'O':
+               case 'P':
+               case 'Q':
+               case 'R':
+               case 'S':
+               case 'T':
+               case 'U':
+               case 'V':
+               case 'W':
+               case 'X':
+               case 'Y':
+               case 'Z':
+               case '_':
+               case 'a':
+               case 'b':
+               case 'c':
+               case 'd':
+               case 'e':
+               case 'f':
+               case 'g':
+               case 'h':
+               case 'i':
+               case 'j':
+               case 'k':
+               case 'l':
+               case 'm':
+               case 'n':
+               case 'o':
+               case 'p':
+               case 'q':
+               case 'r':
+               case 's':
+               case 't':
+               case 'u':
+               case 'v':
+               case 'w':
+               case 'x':
+               case 'y':
+               case 'z': goto yy29;
+               case 0xC2:
+               case 0xC3:
+               case 0xC4:
+               case 0xC5:
+               case 0xC6:
+               case 0xC7:
+               case 0xC8:
+               case 0xC9:
+               case 0xCA:
+               case 0xCB:
+               case 0xCC:
+               case 0xCD:
+               case 0xCE:
+               case 0xCF:
+               case 0xD0:
+               case 0xD1:
+               case 0xD2:
+               case 0xD3:
+               case 0xD4:
+               case 0xD5:
+               case 0xD6:
+               case 0xD7:
+               case 0xD8:
+               case 0xD9:
+               case 0xDA:
+               case 0xDB:
+               case 0xDC:
+               case 0xDD:
+               case 0xDE:
+               case 0xDF: goto yy78;
+               case 0xE0: goto yy79;
+               case 0xE1:
+               case 0xE2:
+               case 0xE3:
+               case 0xE4:
+               case 0xE5:
+               case 0xE6:
+               case 0xE7:
+               case 0xE8:
+               case 0xE9:
+               case 0xEA:
+               case 0xEB:
+               case 0xEC:
+               case 0xED:
+               case 0xEE:
+               case 0xEF: goto yy80;
+               case 0xF0: goto yy81;
+               case 0xF1:
+               case 0xF2:
+               case 0xF3: goto yy82;
+               case 0xF4: goto yy83;
+               default: goto yy28;
        }
-yy44:
-       YYDEBUG(44, YYPEEK());
+yy31:
+       YYDEBUG(31, YYPEEK());
        yyaccept = 3;
        YYSKIP();
        YYBACKUP();
        yych = YYPEEK();
        switch (yych) {
-       case 'E':
-       case 'e':       goto yy106;
-       default:        goto yy43;
+               case 'E':
+               case 'e': goto yy84;
+               default: goto yy30;
        }
-yy45:
-       YYDEBUG(45, YYPEEK());
+yy32:
+       YYDEBUG(32, YYPEEK());
        yyaccept = 3;
        YYSKIP();
        YYBACKUP();
        yych = YYPEEK();
        switch (yych) {
-       case 'H':
-       case 'h':       goto yy107;
-       default:        goto yy43;
+               case 'H':
+               case 'h': goto yy85;
+               default: goto yy30;
        }
-yy46:
-       YYDEBUG(46, YYPEEK());
+yy33:
+       YYDEBUG(33, YYPEEK());
        YYSKIP();
-       YYDEBUG(47, YYPEEK());
 #line 278 "../wisitoken_grammar.re2c"
        {*id = 26; continue;}
-#line 1023 "../wisitoken_grammar_re2c.c"
-yy48:
-       YYDEBUG(48, YYPEEK());
+#line 1010 "../wisitoken_grammar_re2c.c"
+yy34:
+       YYDEBUG(34, YYPEEK());
        YYSKIP();
-       YYDEBUG(49, YYPEEK());
 #line 286 "../wisitoken_grammar.re2c"
        {*id = 34; continue;}
-#line 1030 "../wisitoken_grammar_re2c.c"
-yy50:
-       YYDEBUG(50, YYPEEK());
+#line 1016 "../wisitoken_grammar_re2c.c"
+yy35:
+       YYDEBUG(35, YYPEEK());
        yyaccept = 3;
        YYSKIP();
        YYBACKUP();
        yych = YYPEEK();
        switch (yych) {
-       case 'o':       goto yy108;
-       default:        goto yy43;
+               case 'o': goto yy86;
+               default: goto yy30;
        }
-yy51:
-       YYDEBUG(51, YYPEEK());
+yy36:
+       YYDEBUG(36, YYPEEK());
        yyaccept = 3;
        YYSKIP();
        YYBACKUP();
        yych = YYPEEK();
        switch (yych) {
-       case 'l':       goto yy109;
-       case 'n':       goto yy110;
-       default:        goto yy43;
+               case 'l': goto yy87;
+               case 'n': goto yy88;
+               default: goto yy30;
        }
-yy52:
-       YYDEBUG(52, YYPEEK());
+yy37:
+       YYDEBUG(37, YYPEEK());
        yyaccept = 3;
        YYSKIP();
        YYBACKUP();
        yych = YYPEEK();
        switch (yych) {
-       case 'f':       goto yy111;
-       case 'n':       goto yy113;
-       default:        goto yy43;
+               case 'f': goto yy89;
+               case 'n': goto yy91;
+               default: goto yy30;
        }
-yy53:
-       YYDEBUG(53, YYPEEK());
+yy38:
+       YYDEBUG(38, YYPEEK());
        yyaccept = 3;
        YYSKIP();
        YYBACKUP();
        yych = YYPEEK();
        switch (yych) {
-       case 'e':       goto yy115;
-       default:        goto yy43;
+               case 'e': goto yy93;
+               default: goto yy30;
        }
-yy54:
-       YYDEBUG(54, YYPEEK());
+yy39:
+       YYDEBUG(39, YYPEEK());
        yyaccept = 3;
        YYSKIP();
        YYBACKUP();
        yych = YYPEEK();
        switch (yych) {
-       case 'o':       goto yy116;
-       default:        goto yy43;
+               case 'o': goto yy94;
+               default: goto yy30;
        }
-yy55:
-       YYDEBUG(55, YYPEEK());
+yy40:
+       YYDEBUG(40, YYPEEK());
        yyaccept = 3;
        YYSKIP();
        YYBACKUP();
        yych = YYPEEK();
        switch (yych) {
-       case 'n':       goto yy117;
-       default:        goto yy43;
+               case 'n': goto yy95;
+               default: goto yy30;
        }
-yy56:
-       YYDEBUG(56, YYPEEK());
+yy41:
+       YYDEBUG(41, YYPEEK());
        yyaccept = 3;
        YYSKIP();
        YYBACKUP();
        yych = YYPEEK();
        switch (yych) {
-       case 'o':       goto yy119;
-       default:        goto yy43;
+               case 'o': goto yy97;
+               default: goto yy30;
        }
-yy57:
-       YYDEBUG(57, YYPEEK());
+yy42:
+       YYDEBUG(42, YYPEEK());
        YYSKIP();
-       YYDEBUG(58, YYPEEK());
 #line 277 "../wisitoken_grammar.re2c"
        {*id = 25; continue;}
-#line 1109 "../wisitoken_grammar_re2c.c"
-yy59:
-       YYDEBUG(59, YYPEEK());
+#line 1094 "../wisitoken_grammar_re2c.c"
+yy43:
+       YYDEBUG(43, YYPEEK());
        YYSKIP();
-       YYDEBUG(60, YYPEEK());
 #line 272 "../wisitoken_grammar.re2c"
        {*id = 20; continue;}
-#line 1116 "../wisitoken_grammar_re2c.c"
-yy61:
-       YYDEBUG(61, YYPEEK());
+#line 1100 "../wisitoken_grammar_re2c.c"
+yy44:
+       YYDEBUG(44, YYPEEK());
        YYSKIP();
-       YYDEBUG(62, YYPEEK());
 #line 285 "../wisitoken_grammar.re2c"
        {*id = 33; continue;}
-#line 1123 "../wisitoken_grammar_re2c.c"
-yy63:
-       YYDEBUG(63, YYPEEK());
+#line 1106 "../wisitoken_grammar_re2c.c"
+yy45:
+       YYDEBUG(45, YYPEEK());
        YYSKIP();
        yych = YYPEEK();
        switch (yych) {
-       case 0x80:
-       case 0x81:
-       case 0x82:
-       case 0x83:
-       case 0x84:
-       case 0x85:
-       case 0x86:
-       case 0x87:
-       case 0x88:
-       case 0x89:
-       case 0x8A:
-       case 0x8B:
-       case 0x8C:
-       case 0x8D:
-       case 0x8E:
-       case 0x8F:
-       case 0x90:
-       case 0x91:
-       case 0x92:
-       case 0x93:
-       case 0x94:
-       case 0x95:
-       case 0x96:
-       case 0x97:
-       case 0x98:
-       case 0x99:
-       case 0x9A:
-       case 0x9B:
-       case 0x9C:
-       case 0x9D:
-       case 0x9E:
-       case 0x9F:
-       case 0xA0:
-       case 0xA1:
-       case 0xA2:
-       case 0xA3:
-       case 0xA4:
-       case 0xA5:
-       case 0xA6:
-       case 0xA7:
-       case 0xA8:
-       case 0xA9:
-       case 0xAA:
-       case 0xAB:
-       case 0xAC:
-       case 0xAD:
-       case 0xAE:
-       case 0xAF:
-       case 0xB0:
-       case 0xB1:
-       case 0xB2:
-       case 0xB3:
-       case 0xB4:
-       case 0xB5:
-       case 0xB6:
-       case 0xB7:
-       case 0xB8:
-       case 0xB9:
-       case 0xBA:
-       case 0xBB:
-       case 0xBC:
-       case 0xBD:
-       case 0xBE:
-       case 0xBF:      goto yy42;
-       default:        goto yy3;
+               case 0x80:
+               case 0x81:
+               case 0x82:
+               case 0x83:
+               case 0x84:
+               case 0x85:
+               case 0x86:
+               case 0x87:
+               case 0x88:
+               case 0x89:
+               case 0x8A:
+               case 0x8B:
+               case 0x8C:
+               case 0x8D:
+               case 0x8E:
+               case 0x8F:
+               case 0x90:
+               case 0x91:
+               case 0x92:
+               case 0x93:
+               case 0x94:
+               case 0x95:
+               case 0x96:
+               case 0x97:
+               case 0x98:
+               case 0x99:
+               case 0x9A:
+               case 0x9B:
+               case 0x9C:
+               case 0x9D:
+               case 0x9E:
+               case 0x9F:
+               case 0xA0:
+               case 0xA1:
+               case 0xA2:
+               case 0xA3:
+               case 0xA4:
+               case 0xA5:
+               case 0xA6:
+               case 0xA7:
+               case 0xA8:
+               case 0xA9:
+               case 0xAA:
+               case 0xAB:
+               case 0xAC:
+               case 0xAD:
+               case 0xAE:
+               case 0xAF:
+               case 0xB0:
+               case 0xB1:
+               case 0xB2:
+               case 0xB3:
+               case 0xB4:
+               case 0xB5:
+               case 0xB6:
+               case 0xB7:
+               case 0xB8:
+               case 0xB9:
+               case 0xBA:
+               case 0xBB:
+               case 0xBC:
+               case 0xBD:
+               case 0xBE:
+               case 0xBF: goto yy29;
+               default: goto yy2;
        }
-yy64:
-       YYDEBUG(64, YYPEEK());
+yy46:
+       YYDEBUG(46, YYPEEK());
        yyaccept = 0;
        YYSKIP();
        YYBACKUP();
        yych = YYPEEK();
        switch (yych) {
-       case 0xA0:
-       case 0xA1:
-       case 0xA2:
-       case 0xA3:
-       case 0xA4:
-       case 0xA5:
-       case 0xA6:
-       case 0xA7:
-       case 0xA8:
-       case 0xA9:
-       case 0xAA:
-       case 0xAB:
-       case 0xAC:
-       case 0xAD:
-       case 0xAE:
-       case 0xAF:
-       case 0xB0:
-       case 0xB1:
-       case 0xB2:
-       case 0xB3:
-       case 0xB4:
-       case 0xB5:
-       case 0xB6:
-       case 0xB7:
-       case 0xB8:
-       case 0xB9:
-       case 0xBA:
-       case 0xBB:
-       case 0xBC:
-       case 0xBD:
-       case 0xBE:
-       case 0xBF:      goto yy100;
-       default:        goto yy3;
+               case 0xA0:
+               case 0xA1:
+               case 0xA2:
+               case 0xA3:
+               case 0xA4:
+               case 0xA5:
+               case 0xA6:
+               case 0xA7:
+               case 0xA8:
+               case 0xA9:
+               case 0xAA:
+               case 0xAB:
+               case 0xAC:
+               case 0xAD:
+               case 0xAE:
+               case 0xAF:
+               case 0xB0:
+               case 0xB1:
+               case 0xB2:
+               case 0xB3:
+               case 0xB4:
+               case 0xB5:
+               case 0xB6:
+               case 0xB7:
+               case 0xB8:
+               case 0xB9:
+               case 0xBA:
+               case 0xBB:
+               case 0xBC:
+               case 0xBD:
+               case 0xBE:
+               case 0xBF: goto yy78;
+               default: goto yy2;
        }
-yy65:
-       YYDEBUG(65, YYPEEK());
+yy47:
+       YYDEBUG(47, YYPEEK());
        yyaccept = 0;
        YYSKIP();
        YYBACKUP();
        yych = YYPEEK();
        switch (yych) {
-       case 0x80:
-       case 0x81:
-       case 0x82:
-       case 0x83:
-       case 0x84:
-       case 0x85:
-       case 0x86:
-       case 0x87:
-       case 0x88:
-       case 0x89:
-       case 0x8A:
-       case 0x8B:
-       case 0x8C:
-       case 0x8D:
-       case 0x8E:
-       case 0x8F:
-       case 0x90:
-       case 0x91:
-       case 0x92:
-       case 0x93:
-       case 0x94:
-       case 0x95:
-       case 0x96:
-       case 0x97:
-       case 0x98:
-       case 0x99:
-       case 0x9A:
-       case 0x9B:
-       case 0x9C:
-       case 0x9D:
-       case 0x9E:
-       case 0x9F:
-       case 0xA0:
-       case 0xA1:
-       case 0xA2:
-       case 0xA3:
-       case 0xA4:
-       case 0xA5:
-       case 0xA6:
-       case 0xA7:
-       case 0xA8:
-       case 0xA9:
-       case 0xAA:
-       case 0xAB:
-       case 0xAC:
-       case 0xAD:
-       case 0xAE:
-       case 0xAF:
-       case 0xB0:
-       case 0xB1:
-       case 0xB2:
-       case 0xB3:
-       case 0xB4:
-       case 0xB5:
-       case 0xB6:
-       case 0xB7:
-       case 0xB8:
-       case 0xB9:
-       case 0xBA:
-       case 0xBB:
-       case 0xBC:
-       case 0xBD:
-       case 0xBE:
-       case 0xBF:      goto yy100;
-       default:        goto yy3;
+               case 0x80:
+               case 0x81:
+               case 0x82:
+               case 0x83:
+               case 0x84:
+               case 0x85:
+               case 0x86:
+               case 0x87:
+               case 0x88:
+               case 0x89:
+               case 0x8A:
+               case 0x8B:
+               case 0x8C:
+               case 0x8D:
+               case 0x8E:
+               case 0x8F:
+               case 0x90:
+               case 0x91:
+               case 0x92:
+               case 0x93:
+               case 0x94:
+               case 0x95:
+               case 0x96:
+               case 0x97:
+               case 0x98:
+               case 0x99:
+               case 0x9A:
+               case 0x9B:
+               case 0x9C:
+               case 0x9D:
+               case 0x9E:
+               case 0x9F:
+               case 0xA0:
+               case 0xA1:
+               case 0xA2:
+               case 0xA3:
+               case 0xA4:
+               case 0xA5:
+               case 0xA6:
+               case 0xA7:
+               case 0xA8:
+               case 0xA9:
+               case 0xAA:
+               case 0xAB:
+               case 0xAC:
+               case 0xAD:
+               case 0xAE:
+               case 0xAF:
+               case 0xB0:
+               case 0xB1:
+               case 0xB2:
+               case 0xB3:
+               case 0xB4:
+               case 0xB5:
+               case 0xB6:
+               case 0xB7:
+               case 0xB8:
+               case 0xB9:
+               case 0xBA:
+               case 0xBB:
+               case 0xBC:
+               case 0xBD:
+               case 0xBE:
+               case 0xBF: goto yy78;
+               default: goto yy2;
        }
-yy66:
-       YYDEBUG(66, YYPEEK());
+yy48:
+       YYDEBUG(48, YYPEEK());
        yyaccept = 0;
        YYSKIP();
        YYBACKUP();
        yych = YYPEEK();
        switch (yych) {
-       case 0x90:
-       case 0x91:
-       case 0x92:
-       case 0x93:
-       case 0x94:
-       case 0x95:
-       case 0x96:
-       case 0x97:
-       case 0x98:
-       case 0x99:
-       case 0x9A:
-       case 0x9B:
-       case 0x9C:
-       case 0x9D:
-       case 0x9E:
-       case 0x9F:
-       case 0xA0:
-       case 0xA1:
-       case 0xA2:
-       case 0xA3:
-       case 0xA4:
-       case 0xA5:
-       case 0xA6:
-       case 0xA7:
-       case 0xA8:
-       case 0xA9:
-       case 0xAA:
-       case 0xAB:
-       case 0xAC:
-       case 0xAD:
-       case 0xAE:
-       case 0xAF:
-       case 0xB0:
-       case 0xB1:
-       case 0xB2:
-       case 0xB3:
-       case 0xB4:
-       case 0xB5:
-       case 0xB6:
-       case 0xB7:
-       case 0xB8:
-       case 0xB9:
-       case 0xBA:
-       case 0xBB:
-       case 0xBC:
-       case 0xBD:
-       case 0xBE:
-       case 0xBF:      goto yy102;
-       default:        goto yy3;
+               case 0x90:
+               case 0x91:
+               case 0x92:
+               case 0x93:
+               case 0x94:
+               case 0x95:
+               case 0x96:
+               case 0x97:
+               case 0x98:
+               case 0x99:
+               case 0x9A:
+               case 0x9B:
+               case 0x9C:
+               case 0x9D:
+               case 0x9E:
+               case 0x9F:
+               case 0xA0:
+               case 0xA1:
+               case 0xA2:
+               case 0xA3:
+               case 0xA4:
+               case 0xA5:
+               case 0xA6:
+               case 0xA7:
+               case 0xA8:
+               case 0xA9:
+               case 0xAA:
+               case 0xAB:
+               case 0xAC:
+               case 0xAD:
+               case 0xAE:
+               case 0xAF:
+               case 0xB0:
+               case 0xB1:
+               case 0xB2:
+               case 0xB3:
+               case 0xB4:
+               case 0xB5:
+               case 0xB6:
+               case 0xB7:
+               case 0xB8:
+               case 0xB9:
+               case 0xBA:
+               case 0xBB:
+               case 0xBC:
+               case 0xBD:
+               case 0xBE:
+               case 0xBF: goto yy80;
+               default: goto yy2;
        }
-yy67:
-       YYDEBUG(67, YYPEEK());
+yy49:
+       YYDEBUG(49, YYPEEK());
        yyaccept = 0;
        YYSKIP();
        YYBACKUP();
        yych = YYPEEK();
        switch (yych) {
-       case 0x80:
-       case 0x81:
-       case 0x82:
-       case 0x83:
-       case 0x84:
-       case 0x85:
-       case 0x86:
-       case 0x87:
-       case 0x88:
-       case 0x89:
-       case 0x8A:
-       case 0x8B:
-       case 0x8C:
-       case 0x8D:
-       case 0x8E:
-       case 0x8F:
-       case 0x90:
-       case 0x91:
-       case 0x92:
-       case 0x93:
-       case 0x94:
-       case 0x95:
-       case 0x96:
-       case 0x97:
-       case 0x98:
-       case 0x99:
-       case 0x9A:
-       case 0x9B:
-       case 0x9C:
-       case 0x9D:
-       case 0x9E:
-       case 0x9F:
-       case 0xA0:
-       case 0xA1:
-       case 0xA2:
-       case 0xA3:
-       case 0xA4:
-       case 0xA5:
-       case 0xA6:
-       case 0xA7:
-       case 0xA8:
-       case 0xA9:
-       case 0xAA:
-       case 0xAB:
-       case 0xAC:
-       case 0xAD:
-       case 0xAE:
-       case 0xAF:
-       case 0xB0:
-       case 0xB1:
-       case 0xB2:
-       case 0xB3:
-       case 0xB4:
-       case 0xB5:
-       case 0xB6:
-       case 0xB7:
-       case 0xB8:
-       case 0xB9:
-       case 0xBA:
-       case 0xBB:
-       case 0xBC:
-       case 0xBD:
-       case 0xBE:
-       case 0xBF:      goto yy102;
-       default:        goto yy3;
+               case 0x80:
+               case 0x81:
+               case 0x82:
+               case 0x83:
+               case 0x84:
+               case 0x85:
+               case 0x86:
+               case 0x87:
+               case 0x88:
+               case 0x89:
+               case 0x8A:
+               case 0x8B:
+               case 0x8C:
+               case 0x8D:
+               case 0x8E:
+               case 0x8F:
+               case 0x90:
+               case 0x91:
+               case 0x92:
+               case 0x93:
+               case 0x94:
+               case 0x95:
+               case 0x96:
+               case 0x97:
+               case 0x98:
+               case 0x99:
+               case 0x9A:
+               case 0x9B:
+               case 0x9C:
+               case 0x9D:
+               case 0x9E:
+               case 0x9F:
+               case 0xA0:
+               case 0xA1:
+               case 0xA2:
+               case 0xA3:
+               case 0xA4:
+               case 0xA5:
+               case 0xA6:
+               case 0xA7:
+               case 0xA8:
+               case 0xA9:
+               case 0xAA:
+               case 0xAB:
+               case 0xAC:
+               case 0xAD:
+               case 0xAE:
+               case 0xAF:
+               case 0xB0:
+               case 0xB1:
+               case 0xB2:
+               case 0xB3:
+               case 0xB4:
+               case 0xB5:
+               case 0xB6:
+               case 0xB7:
+               case 0xB8:
+               case 0xB9:
+               case 0xBA:
+               case 0xBB:
+               case 0xBC:
+               case 0xBD:
+               case 0xBE:
+               case 0xBF: goto yy80;
+               default: goto yy2;
        }
-yy68:
-       YYDEBUG(68, YYPEEK());
+yy50:
+       YYDEBUG(50, YYPEEK());
        yyaccept = 0;
        YYSKIP();
        YYBACKUP();
        yych = YYPEEK();
        switch (yych) {
-       case 0x80:
-       case 0x81:
-       case 0x82:
-       case 0x83:
-       case 0x84:
-       case 0x85:
-       case 0x86:
-       case 0x87:
-       case 0x88:
-       case 0x89:
-       case 0x8A:
-       case 0x8B:
-       case 0x8C:
-       case 0x8D:
-       case 0x8E:
-       case 0x8F:      goto yy102;
-       default:        goto yy3;
+               case 0x80:
+               case 0x81:
+               case 0x82:
+               case 0x83:
+               case 0x84:
+               case 0x85:
+               case 0x86:
+               case 0x87:
+               case 0x88:
+               case 0x89:
+               case 0x8A:
+               case 0x8B:
+               case 0x8C:
+               case 0x8D:
+               case 0x8E:
+               case 0x8F: goto yy80;
+               default: goto yy2;
        }
-yy69:
-       YYDEBUG(69, YYPEEK());
+yy51:
+       YYDEBUG(51, YYPEEK());
        YYSKIP();
        yych = YYPEEK();
-yy70:
-       YYDEBUG(70, YYPEEK());
+yy52:
+       YYDEBUG(52, YYPEEK());
        switch (yych) {
-       case ' ':
-       case '!':
-       case '#':
-       case '$':
-       case '%':
-       case '&':
-       case '\'':
-       case '(':
-       case ')':
-       case '*':
-       case '+':
-       case ',':
-       case '-':
-       case '.':
-       case '/':
-       case '0':
-       case '1':
-       case '2':
-       case '3':
-       case '4':
-       case '5':
-       case '6':
-       case '7':
-       case '8':
-       case '9':
-       case ':':
-       case ';':
-       case '<':
-       case '=':
-       case '>':
-       case '?':
-       case '@':
-       case 'A':
-       case 'B':
-       case 'C':
-       case 'D':
-       case 'E':
-       case 'F':
-       case 'G':
-       case 'H':
-       case 'I':
-       case 'J':
-       case 'K':
-       case 'L':
-       case 'M':
-       case 'N':
-       case 'O':
-       case 'P':
-       case 'Q':
-       case 'R':
-       case 'S':
-       case 'T':
-       case 'U':
-       case 'V':
-       case 'W':
-       case 'X':
-       case 'Y':
-       case 'Z':
-       case '[':
-       case '\\':
-       case ']':
-       case '^':
-       case '_':
-       case '`':
-       case 'a':
-       case 'b':
-       case 'c':
-       case 'd':
-       case 'e':
-       case 'f':
-       case 'g':
-       case 'h':
-       case 'i':
-       case 'j':
-       case 'k':
-       case 'l':
-       case 'm':
-       case 'n':
-       case 'o':
-       case 'p':
-       case 'q':
-       case 'r':
-       case 's':
-       case 't':
-       case 'u':
-       case 'v':
-       case 'w':
-       case 'x':
-       case 'y':
-       case 'z':
-       case '{':
-       case '|':
-       case '}':
-       case '~':
-       case 0x7F:      goto yy69;
-       case '"':       goto yy72;
-       case 0xC2:
-       case 0xC3:
-       case 0xC4:
-       case 0xC5:
-       case 0xC6:
-       case 0xC7:
-       case 0xC8:
-       case 0xC9:
-       case 0xCA:
-       case 0xCB:
-       case 0xCC:
-       case 0xCD:
-       case 0xCE:
-       case 0xCF:
-       case 0xD0:
-       case 0xD1:
-       case 0xD2:
-       case 0xD3:
-       case 0xD4:
-       case 0xD5:
-       case 0xD6:
-       case 0xD7:
-       case 0xD8:
-       case 0xD9:
-       case 0xDA:
-       case 0xDB:
-       case 0xDC:
-       case 0xDD:
-       case 0xDE:
-       case 0xDF:      goto yy74;
-       case 0xE0:      goto yy75;
-       case 0xE1:
-       case 0xE2:
-       case 0xE3:
-       case 0xE4:
-       case 0xE5:
-       case 0xE6:
-       case 0xE7:
-       case 0xE8:
-       case 0xE9:
-       case 0xEA:
-       case 0xEB:
-       case 0xEC:
-       case 0xED:
-       case 0xEE:
-       case 0xEF:      goto yy76;
-       case 0xF0:      goto yy77;
-       case 0xF1:
-       case 0xF2:
-       case 0xF3:      goto yy78;
-       case 0xF4:      goto yy79;
-       default:        goto yy71;
+               case ' ':
+               case '!':
+               case '#':
+               case '$':
+               case '%':
+               case '&':
+               case '\'':
+               case '(':
+               case ')':
+               case '*':
+               case '+':
+               case ',':
+               case '-':
+               case '.':
+               case '/':
+               case '0':
+               case '1':
+               case '2':
+               case '3':
+               case '4':
+               case '5':
+               case '6':
+               case '7':
+               case '8':
+               case '9':
+               case ':':
+               case ';':
+               case '<':
+               case '=':
+               case '>':
+               case '?':
+               case '@':
+               case 'A':
+               case 'B':
+               case 'C':
+               case 'D':
+               case 'E':
+               case 'F':
+               case 'G':
+               case 'H':
+               case 'I':
+               case 'J':
+               case 'K':
+               case 'L':
+               case 'M':
+               case 'N':
+               case 'O':
+               case 'P':
+               case 'Q':
+               case 'R':
+               case 'S':
+               case 'T':
+               case 'U':
+               case 'V':
+               case 'W':
+               case 'X':
+               case 'Y':
+               case 'Z':
+               case '[':
+               case '\\':
+               case ']':
+               case '^':
+               case '_':
+               case '`':
+               case 'a':
+               case 'b':
+               case 'c':
+               case 'd':
+               case 'e':
+               case 'f':
+               case 'g':
+               case 'h':
+               case 'i':
+               case 'j':
+               case 'k':
+               case 'l':
+               case 'm':
+               case 'n':
+               case 'o':
+               case 'p':
+               case 'q':
+               case 'r':
+               case 's':
+               case 't':
+               case 'u':
+               case 'v':
+               case 'w':
+               case 'x':
+               case 'y':
+               case 'z':
+               case '{':
+               case '|':
+               case '}':
+               case '~':
+               case 0x7F: goto yy51;
+               case '"': goto yy54;
+               case 0xC2:
+               case 0xC3:
+               case 0xC4:
+               case 0xC5:
+               case 0xC6:
+               case 0xC7:
+               case 0xC8:
+               case 0xC9:
+               case 0xCA:
+               case 0xCB:
+               case 0xCC:
+               case 0xCD:
+               case 0xCE:
+               case 0xCF:
+               case 0xD0:
+               case 0xD1:
+               case 0xD2:
+               case 0xD3:
+               case 0xD4:
+               case 0xD5:
+               case 0xD6:
+               case 0xD7:
+               case 0xD8:
+               case 0xD9:
+               case 0xDA:
+               case 0xDB:
+               case 0xDC:
+               case 0xDD:
+               case 0xDE:
+               case 0xDF: goto yy56;
+               case 0xE0: goto yy57;
+               case 0xE1:
+               case 0xE2:
+               case 0xE3:
+               case 0xE4:
+               case 0xE5:
+               case 0xE6:
+               case 0xE7:
+               case 0xE8:
+               case 0xE9:
+               case 0xEA:
+               case 0xEB:
+               case 0xEC:
+               case 0xED:
+               case 0xEE:
+               case 0xEF: goto yy58;
+               case 0xF0: goto yy59;
+               case 0xF1:
+               case 0xF2:
+               case 0xF3: goto yy60;
+               case 0xF4: goto yy61;
+               default: goto yy53;
        }
-yy71:
-       YYDEBUG(71, YYPEEK());
+yy53:
+       YYDEBUG(53, YYPEEK());
        YYRESTORE();
        switch (yyaccept) {
-       case 0:
-               goto yy3;
-       case 1:
-               goto yy29;
-       case 2:
-               goto yy31;
-       case 3:
-               goto yy41;
-       case 4:
-               goto yy73;
-       case 5:
-               goto yy89;
-       case 6:
-               goto yy112;
-       case 7:
-               goto yy114;
-       case 8:
-               goto yy118;
-       case 9:
-               goto yy137;
-       case 10:
-               goto yy145;
-       case 11:
-               goto yy154;
-       case 12:
-               goto yy157;
-       case 13:
-               goto yy161;
-       case 14:
-               goto yy164;
-       case 15:
-               goto yy171;
-       case 16:
-               goto yy175;
-       case 17:
-               goto yy178;
-       case 18:
-               goto yy185;
-       default:
-               goto yy194;
+               case 0: goto yy2;
+               case 1: goto yy20;
+               case 2: goto yy22;
+               case 3: goto yy28;
+               case 4: goto yy55;
+               case 5: goto yy68;
+               case 6: goto yy90;
+               case 7: goto yy92;
+               case 8: goto yy96;
+               case 9: goto yy113;
+               case 10: goto yy121;
+               case 11: goto yy130;
+               case 12: goto yy133;
+               case 13: goto yy137;
+               case 14: goto yy140;
+               case 15: goto yy147;
+               case 16: goto yy151;
+               case 17: goto yy154;
+               case 18: goto yy161;
+               default: goto yy170;
        }
-yy72:
-       YYDEBUG(72, YYPEEK());
+yy54:
+       YYDEBUG(54, YYPEEK());
        yyaccept = 4;
        YYSKIP();
        YYBACKUP();
        yych = YYPEEK();
        switch (yych) {
-       case '"':       goto yy69;
-       default:        goto yy73;
+               case '"': goto yy51;
+               default: goto yy55;
        }
-yy73:
-       YYDEBUG(73, YYPEEK());
+yy55:
+       YYDEBUG(55, YYPEEK());
 #line 292 "../wisitoken_grammar.re2c"
        {*id = 40; continue;}
-#line 1679 "../wisitoken_grammar_re2c.c"
-yy74:
-       YYDEBUG(74, YYPEEK());
+#line 1642 "../wisitoken_grammar_re2c.c"
+yy56:
+       YYDEBUG(56, YYPEEK());
        YYSKIP();
        yych = YYPEEK();
        switch (yych) {
-       case 0x80:
-       case 0x81:
-       case 0x82:
-       case 0x83:
-       case 0x84:
-       case 0x85:
-       case 0x86:
-       case 0x87:
-       case 0x88:
-       case 0x89:
-       case 0x8A:
-       case 0x8B:
-       case 0x8C:
-       case 0x8D:
-       case 0x8E:
-       case 0x8F:
-       case 0x90:
-       case 0x91:
-       case 0x92:
-       case 0x93:
-       case 0x94:
-       case 0x95:
-       case 0x96:
-       case 0x97:
-       case 0x98:
-       case 0x99:
-       case 0x9A:
-       case 0x9B:
-       case 0x9C:
-       case 0x9D:
-       case 0x9E:
-       case 0x9F:
-       case 0xA0:
-       case 0xA1:
-       case 0xA2:
-       case 0xA3:
-       case 0xA4:
-       case 0xA5:
-       case 0xA6:
-       case 0xA7:
-       case 0xA8:
-       case 0xA9:
-       case 0xAA:
-       case 0xAB:
-       case 0xAC:
-       case 0xAD:
-       case 0xAE:
-       case 0xAF:
-       case 0xB0:
-       case 0xB1:
-       case 0xB2:
-       case 0xB3:
-       case 0xB4:
-       case 0xB5:
-       case 0xB6:
-       case 0xB7:
-       case 0xB8:
-       case 0xB9:
-       case 0xBA:
-       case 0xBB:
-       case 0xBC:
-       case 0xBD:
-       case 0xBE:
-       case 0xBF:      goto yy69;
-       default:        goto yy71;
+               case 0x80:
+               case 0x81:
+               case 0x82:
+               case 0x83:
+               case 0x84:
+               case 0x85:
+               case 0x86:
+               case 0x87:
+               case 0x88:
+               case 0x89:
+               case 0x8A:
+               case 0x8B:
+               case 0x8C:
+               case 0x8D:
+               case 0x8E:
+               case 0x8F:
+               case 0x90:
+               case 0x91:
+               case 0x92:
+               case 0x93:
+               case 0x94:
+               case 0x95:
+               case 0x96:
+               case 0x97:
+               case 0x98:
+               case 0x99:
+               case 0x9A:
+               case 0x9B:
+               case 0x9C:
+               case 0x9D:
+               case 0x9E:
+               case 0x9F:
+               case 0xA0:
+               case 0xA1:
+               case 0xA2:
+               case 0xA3:
+               case 0xA4:
+               case 0xA5:
+               case 0xA6:
+               case 0xA7:
+               case 0xA8:
+               case 0xA9:
+               case 0xAA:
+               case 0xAB:
+               case 0xAC:
+               case 0xAD:
+               case 0xAE:
+               case 0xAF:
+               case 0xB0:
+               case 0xB1:
+               case 0xB2:
+               case 0xB3:
+               case 0xB4:
+               case 0xB5:
+               case 0xB6:
+               case 0xB7:
+               case 0xB8:
+               case 0xB9:
+               case 0xBA:
+               case 0xBB:
+               case 0xBC:
+               case 0xBD:
+               case 0xBE:
+               case 0xBF: goto yy51;
+               default: goto yy53;
        }
-yy75:
-       YYDEBUG(75, YYPEEK());
+yy57:
+       YYDEBUG(57, YYPEEK());
        YYSKIP();
        yych = YYPEEK();
        switch (yych) {
-       case 0xA0:
-       case 0xA1:
-       case 0xA2:
-       case 0xA3:
-       case 0xA4:
-       case 0xA5:
-       case 0xA6:
-       case 0xA7:
-       case 0xA8:
-       case 0xA9:
-       case 0xAA:
-       case 0xAB:
-       case 0xAC:
-       case 0xAD:
-       case 0xAE:
-       case 0xAF:
-       case 0xB0:
-       case 0xB1:
-       case 0xB2:
-       case 0xB3:
-       case 0xB4:
-       case 0xB5:
-       case 0xB6:
-       case 0xB7:
-       case 0xB8:
-       case 0xB9:
-       case 0xBA:
-       case 0xBB:
-       case 0xBC:
-       case 0xBD:
-       case 0xBE:
-       case 0xBF:      goto yy74;
-       default:        goto yy71;
+               case 0xA0:
+               case 0xA1:
+               case 0xA2:
+               case 0xA3:
+               case 0xA4:
+               case 0xA5:
+               case 0xA6:
+               case 0xA7:
+               case 0xA8:
+               case 0xA9:
+               case 0xAA:
+               case 0xAB:
+               case 0xAC:
+               case 0xAD:
+               case 0xAE:
+               case 0xAF:
+               case 0xB0:
+               case 0xB1:
+               case 0xB2:
+               case 0xB3:
+               case 0xB4:
+               case 0xB5:
+               case 0xB6:
+               case 0xB7:
+               case 0xB8:
+               case 0xB9:
+               case 0xBA:
+               case 0xBB:
+               case 0xBC:
+               case 0xBD:
+               case 0xBE:
+               case 0xBF: goto yy56;
+               default: goto yy53;
        }
-yy76:
-       YYDEBUG(76, YYPEEK());
+yy58:
+       YYDEBUG(58, YYPEEK());
        YYSKIP();
        yych = YYPEEK();
        switch (yych) {
-       case 0x80:
-       case 0x81:
-       case 0x82:
-       case 0x83:
-       case 0x84:
-       case 0x85:
-       case 0x86:
-       case 0x87:
-       case 0x88:
-       case 0x89:
-       case 0x8A:
-       case 0x8B:
-       case 0x8C:
-       case 0x8D:
-       case 0x8E:
-       case 0x8F:
-       case 0x90:
-       case 0x91:
-       case 0x92:
-       case 0x93:
-       case 0x94:
-       case 0x95:
-       case 0x96:
-       case 0x97:
-       case 0x98:
-       case 0x99:
-       case 0x9A:
-       case 0x9B:
-       case 0x9C:
-       case 0x9D:
-       case 0x9E:
-       case 0x9F:
-       case 0xA0:
-       case 0xA1:
-       case 0xA2:
-       case 0xA3:
-       case 0xA4:
-       case 0xA5:
-       case 0xA6:
-       case 0xA7:
-       case 0xA8:
-       case 0xA9:
-       case 0xAA:
-       case 0xAB:
-       case 0xAC:
-       case 0xAD:
-       case 0xAE:
-       case 0xAF:
-       case 0xB0:
-       case 0xB1:
-       case 0xB2:
-       case 0xB3:
-       case 0xB4:
-       case 0xB5:
-       case 0xB6:
-       case 0xB7:
-       case 0xB8:
-       case 0xB9:
-       case 0xBA:
-       case 0xBB:
-       case 0xBC:
-       case 0xBD:
-       case 0xBE:
-       case 0xBF:      goto yy74;
-       default:        goto yy71;
+               case 0x80:
+               case 0x81:
+               case 0x82:
+               case 0x83:
+               case 0x84:
+               case 0x85:
+               case 0x86:
+               case 0x87:
+               case 0x88:
+               case 0x89:
+               case 0x8A:
+               case 0x8B:
+               case 0x8C:
+               case 0x8D:
+               case 0x8E:
+               case 0x8F:
+               case 0x90:
+               case 0x91:
+               case 0x92:
+               case 0x93:
+               case 0x94:
+               case 0x95:
+               case 0x96:
+               case 0x97:
+               case 0x98:
+               case 0x99:
+               case 0x9A:
+               case 0x9B:
+               case 0x9C:
+               case 0x9D:
+               case 0x9E:
+               case 0x9F:
+               case 0xA0:
+               case 0xA1:
+               case 0xA2:
+               case 0xA3:
+               case 0xA4:
+               case 0xA5:
+               case 0xA6:
+               case 0xA7:
+               case 0xA8:
+               case 0xA9:
+               case 0xAA:
+               case 0xAB:
+               case 0xAC:
+               case 0xAD:
+               case 0xAE:
+               case 0xAF:
+               case 0xB0:
+               case 0xB1:
+               case 0xB2:
+               case 0xB3:
+               case 0xB4:
+               case 0xB5:
+               case 0xB6:
+               case 0xB7:
+               case 0xB8:
+               case 0xB9:
+               case 0xBA:
+               case 0xBB:
+               case 0xBC:
+               case 0xBD:
+               case 0xBE:
+               case 0xBF: goto yy56;
+               default: goto yy53;
        }
-yy77:
-       YYDEBUG(77, YYPEEK());
+yy59:
+       YYDEBUG(59, YYPEEK());
        YYSKIP();
        yych = YYPEEK();
        switch (yych) {
-       case 0x90:
-       case 0x91:
-       case 0x92:
-       case 0x93:
-       case 0x94:
-       case 0x95:
-       case 0x96:
-       case 0x97:
-       case 0x98:
-       case 0x99:
-       case 0x9A:
-       case 0x9B:
-       case 0x9C:
-       case 0x9D:
-       case 0x9E:
-       case 0x9F:
-       case 0xA0:
-       case 0xA1:
-       case 0xA2:
-       case 0xA3:
-       case 0xA4:
-       case 0xA5:
-       case 0xA6:
-       case 0xA7:
-       case 0xA8:
-       case 0xA9:
-       case 0xAA:
-       case 0xAB:
-       case 0xAC:
-       case 0xAD:
-       case 0xAE:
-       case 0xAF:
-       case 0xB0:
-       case 0xB1:
-       case 0xB2:
-       case 0xB3:
-       case 0xB4:
-       case 0xB5:
-       case 0xB6:
-       case 0xB7:
-       case 0xB8:
-       case 0xB9:
-       case 0xBA:
-       case 0xBB:
-       case 0xBC:
-       case 0xBD:
-       case 0xBE:
-       case 0xBF:      goto yy76;
-       default:        goto yy71;
+               case 0x90:
+               case 0x91:
+               case 0x92:
+               case 0x93:
+               case 0x94:
+               case 0x95:
+               case 0x96:
+               case 0x97:
+               case 0x98:
+               case 0x99:
+               case 0x9A:
+               case 0x9B:
+               case 0x9C:
+               case 0x9D:
+               case 0x9E:
+               case 0x9F:
+               case 0xA0:
+               case 0xA1:
+               case 0xA2:
+               case 0xA3:
+               case 0xA4:
+               case 0xA5:
+               case 0xA6:
+               case 0xA7:
+               case 0xA8:
+               case 0xA9:
+               case 0xAA:
+               case 0xAB:
+               case 0xAC:
+               case 0xAD:
+               case 0xAE:
+               case 0xAF:
+               case 0xB0:
+               case 0xB1:
+               case 0xB2:
+               case 0xB3:
+               case 0xB4:
+               case 0xB5:
+               case 0xB6:
+               case 0xB7:
+               case 0xB8:
+               case 0xB9:
+               case 0xBA:
+               case 0xBB:
+               case 0xBC:
+               case 0xBD:
+               case 0xBE:
+               case 0xBF: goto yy58;
+               default: goto yy53;
        }
-yy78:
-       YYDEBUG(78, YYPEEK());
+yy60:
+       YYDEBUG(60, YYPEEK());
        YYSKIP();
        yych = YYPEEK();
        switch (yych) {
-       case 0x80:
-       case 0x81:
-       case 0x82:
-       case 0x83:
-       case 0x84:
-       case 0x85:
-       case 0x86:
-       case 0x87:
-       case 0x88:
-       case 0x89:
-       case 0x8A:
-       case 0x8B:
-       case 0x8C:
-       case 0x8D:
-       case 0x8E:
-       case 0x8F:
-       case 0x90:
-       case 0x91:
-       case 0x92:
-       case 0x93:
-       case 0x94:
-       case 0x95:
-       case 0x96:
-       case 0x97:
-       case 0x98:
-       case 0x99:
-       case 0x9A:
-       case 0x9B:
-       case 0x9C:
-       case 0x9D:
-       case 0x9E:
-       case 0x9F:
-       case 0xA0:
-       case 0xA1:
-       case 0xA2:
-       case 0xA3:
-       case 0xA4:
-       case 0xA5:
-       case 0xA6:
-       case 0xA7:
-       case 0xA8:
-       case 0xA9:
-       case 0xAA:
-       case 0xAB:
-       case 0xAC:
-       case 0xAD:
-       case 0xAE:
-       case 0xAF:
-       case 0xB0:
-       case 0xB1:
-       case 0xB2:
-       case 0xB3:
-       case 0xB4:
-       case 0xB5:
-       case 0xB6:
-       case 0xB7:
-       case 0xB8:
-       case 0xB9:
-       case 0xBA:
-       case 0xBB:
-       case 0xBC:
-       case 0xBD:
-       case 0xBE:
-       case 0xBF:      goto yy76;
-       default:        goto yy71;
+               case 0x80:
+               case 0x81:
+               case 0x82:
+               case 0x83:
+               case 0x84:
+               case 0x85:
+               case 0x86:
+               case 0x87:
+               case 0x88:
+               case 0x89:
+               case 0x8A:
+               case 0x8B:
+               case 0x8C:
+               case 0x8D:
+               case 0x8E:
+               case 0x8F:
+               case 0x90:
+               case 0x91:
+               case 0x92:
+               case 0x93:
+               case 0x94:
+               case 0x95:
+               case 0x96:
+               case 0x97:
+               case 0x98:
+               case 0x99:
+               case 0x9A:
+               case 0x9B:
+               case 0x9C:
+               case 0x9D:
+               case 0x9E:
+               case 0x9F:
+               case 0xA0:
+               case 0xA1:
+               case 0xA2:
+               case 0xA3:
+               case 0xA4:
+               case 0xA5:
+               case 0xA6:
+               case 0xA7:
+               case 0xA8:
+               case 0xA9:
+               case 0xAA:
+               case 0xAB:
+               case 0xAC:
+               case 0xAD:
+               case 0xAE:
+               case 0xAF:
+               case 0xB0:
+               case 0xB1:
+               case 0xB2:
+               case 0xB3:
+               case 0xB4:
+               case 0xB5:
+               case 0xB6:
+               case 0xB7:
+               case 0xB8:
+               case 0xB9:
+               case 0xBA:
+               case 0xBB:
+               case 0xBC:
+               case 0xBD:
+               case 0xBE:
+               case 0xBF: goto yy58;
+               default: goto yy53;
        }
-yy79:
-       YYDEBUG(79, YYPEEK());
+yy61:
+       YYDEBUG(61, YYPEEK());
        YYSKIP();
        yych = YYPEEK();
        switch (yych) {
-       case 0x80:
-       case 0x81:
-       case 0x82:
-       case 0x83:
-       case 0x84:
-       case 0x85:
-       case 0x86:
-       case 0x87:
-       case 0x88:
-       case 0x89:
-       case 0x8A:
-       case 0x8B:
-       case 0x8C:
-       case 0x8D:
-       case 0x8E:
-       case 0x8F:      goto yy76;
-       default:        goto yy71;
+               case 0x80:
+               case 0x81:
+               case 0x82:
+               case 0x83:
+               case 0x84:
+               case 0x85:
+               case 0x86:
+               case 0x87:
+               case 0x88:
+               case 0x89:
+               case 0x8A:
+               case 0x8B:
+               case 0x8C:
+               case 0x8D:
+               case 0x8E:
+               case 0x8F: goto yy58;
+               default: goto yy53;
        }
-yy80:
-       YYDEBUG(80, YYPEEK());
+yy62:
+       YYDEBUG(62, YYPEEK());
        YYSKIP();
-       YYDEBUG(81, YYPEEK());
 #line 271 "../wisitoken_grammar.re2c"
        {*id = 19; skip_to(lexer, ")%"); continue;}
-#line 2016 "../wisitoken_grammar_re2c.c"
-yy82:
-       YYDEBUG(82, YYPEEK());
+#line 1978 "../wisitoken_grammar_re2c.c"
+yy63:
+       YYDEBUG(63, YYPEEK());
        YYSKIP();
-       YYDEBUG(83, YYPEEK());
 #line 270 "../wisitoken_grammar.re2c"
        {*id = 18; skip_to(lexer, "]%"); continue;}
-#line 2023 "../wisitoken_grammar_re2c.c"
-yy84:
-       YYDEBUG(84, YYPEEK());
+#line 1984 "../wisitoken_grammar_re2c.c"
+yy64:
+       YYDEBUG(64, YYPEEK());
        YYSKIP();
-       YYDEBUG(85, YYPEEK());
 #line 269 "../wisitoken_grammar.re2c"
        {*id = 17; skip_to(lexer, "}%"); continue;}
-#line 2030 "../wisitoken_grammar_re2c.c"
-yy86:
-       YYDEBUG(86, YYPEEK());
+#line 1990 "../wisitoken_grammar_re2c.c"
+yy65:
+       YYDEBUG(65, YYPEEK());
        YYSKIP();
        yych = YYPEEK();
-yy87:
-       YYDEBUG(87, YYPEEK());
+yy66:
+       YYDEBUG(66, YYPEEK());
        switch (yych) {
-       case ' ':
-       case '!':
-       case '"':
-       case '#':
-       case '$':
-       case '%':
-       case '&':
-       case '(':
-       case ')':
-       case '*':
-       case '+':
-       case ',':
-       case '-':
-       case '.':
-       case '/':
-       case '0':
-       case '1':
-       case '2':
-       case '3':
-       case '4':
-       case '5':
-       case '6':
-       case '7':
-       case '8':
-       case '9':
-       case ':':
-       case ';':
-       case '<':
-       case '=':
-       case '>':
-       case '?':
-       case '@':
-       case 'A':
-       case 'B':
-       case 'C':
-       case 'D':
-       case 'E':
-       case 'F':
-       case 'G':
-       case 'H':
-       case 'I':
-       case 'J':
-       case 'K':
-       case 'L':
-       case 'M':
-       case 'N':
-       case 'O':
-       case 'P':
-       case 'Q':
-       case 'R':
-       case 'S':
-       case 'T':
-       case 'U':
-       case 'V':
-       case 'W':
-       case 'X':
-       case 'Y':
-       case 'Z':
-       case '[':
-       case '\\':
-       case ']':
-       case '^':
-       case '_':
-       case '`':
-       case 'a':
-       case 'b':
-       case 'c':
-       case 'd':
-       case 'e':
-       case 'f':
-       case 'g':
-       case 'h':
-       case 'i':
-       case 'j':
-       case 'k':
-       case 'l':
-       case 'm':
-       case 'n':
-       case 'o':
-       case 'p':
-       case 'q':
-       case 'r':
-       case 's':
-       case 't':
-       case 'u':
-       case 'v':
-       case 'w':
-       case 'x':
-       case 'y':
-       case 'z':
-       case '{':
-       case '|':
-       case '}':
-       case '~':
-       case 0x7F:      goto yy86;
-       case '\'':      goto yy88;
-       case 0xC2:
-       case 0xC3:
-       case 0xC4:
-       case 0xC5:
-       case 0xC6:
-       case 0xC7:
-       case 0xC8:
-       case 0xC9:
-       case 0xCA:
-       case 0xCB:
-       case 0xCC:
-       case 0xCD:
-       case 0xCE:
-       case 0xCF:
-       case 0xD0:
-       case 0xD1:
-       case 0xD2:
-       case 0xD3:
-       case 0xD4:
-       case 0xD5:
-       case 0xD6:
-       case 0xD7:
-       case 0xD8:
-       case 0xD9:
-       case 0xDA:
-       case 0xDB:
-       case 0xDC:
-       case 0xDD:
-       case 0xDE:
-       case 0xDF:      goto yy90;
-       case 0xE0:      goto yy91;
-       case 0xE1:
-       case 0xE2:
-       case 0xE3:
-       case 0xE4:
-       case 0xE5:
-       case 0xE6:
-       case 0xE7:
-       case 0xE8:
-       case 0xE9:
-       case 0xEA:
-       case 0xEB:
-       case 0xEC:
-       case 0xED:
-       case 0xEE:
-       case 0xEF:      goto yy92;
-       case 0xF0:      goto yy93;
-       case 0xF1:
-       case 0xF2:
-       case 0xF3:      goto yy94;
-       case 0xF4:      goto yy95;
-       default:        goto yy71;
+               case ' ':
+               case '!':
+               case '"':
+               case '#':
+               case '$':
+               case '%':
+               case '&':
+               case '(':
+               case ')':
+               case '*':
+               case '+':
+               case ',':
+               case '-':
+               case '.':
+               case '/':
+               case '0':
+               case '1':
+               case '2':
+               case '3':
+               case '4':
+               case '5':
+               case '6':
+               case '7':
+               case '8':
+               case '9':
+               case ':':
+               case ';':
+               case '<':
+               case '=':
+               case '>':
+               case '?':
+               case '@':
+               case 'A':
+               case 'B':
+               case 'C':
+               case 'D':
+               case 'E':
+               case 'F':
+               case 'G':
+               case 'H':
+               case 'I':
+               case 'J':
+               case 'K':
+               case 'L':
+               case 'M':
+               case 'N':
+               case 'O':
+               case 'P':
+               case 'Q':
+               case 'R':
+               case 'S':
+               case 'T':
+               case 'U':
+               case 'V':
+               case 'W':
+               case 'X':
+               case 'Y':
+               case 'Z':
+               case '[':
+               case '\\':
+               case ']':
+               case '^':
+               case '_':
+               case '`':
+               case 'a':
+               case 'b':
+               case 'c':
+               case 'd':
+               case 'e':
+               case 'f':
+               case 'g':
+               case 'h':
+               case 'i':
+               case 'j':
+               case 'k':
+               case 'l':
+               case 'm':
+               case 'n':
+               case 'o':
+               case 'p':
+               case 'q':
+               case 'r':
+               case 's':
+               case 't':
+               case 'u':
+               case 'v':
+               case 'w':
+               case 'x':
+               case 'y':
+               case 'z':
+               case '{':
+               case '|':
+               case '}':
+               case '~':
+               case 0x7F: goto yy65;
+               case '\'': goto yy67;
+               case 0xC2:
+               case 0xC3:
+               case 0xC4:
+               case 0xC5:
+               case 0xC6:
+               case 0xC7:
+               case 0xC8:
+               case 0xC9:
+               case 0xCA:
+               case 0xCB:
+               case 0xCC:
+               case 0xCD:
+               case 0xCE:
+               case 0xCF:
+               case 0xD0:
+               case 0xD1:
+               case 0xD2:
+               case 0xD3:
+               case 0xD4:
+               case 0xD5:
+               case 0xD6:
+               case 0xD7:
+               case 0xD8:
+               case 0xD9:
+               case 0xDA:
+               case 0xDB:
+               case 0xDC:
+               case 0xDD:
+               case 0xDE:
+               case 0xDF: goto yy69;
+               case 0xE0: goto yy70;
+               case 0xE1:
+               case 0xE2:
+               case 0xE3:
+               case 0xE4:
+               case 0xE5:
+               case 0xE6:
+               case 0xE7:
+               case 0xE8:
+               case 0xE9:
+               case 0xEA:
+               case 0xEB:
+               case 0xEC:
+               case 0xED:
+               case 0xEE:
+               case 0xEF: goto yy71;
+               case 0xF0: goto yy72;
+               case 0xF1:
+               case 0xF2:
+               case 0xF3: goto yy73;
+               case 0xF4: goto yy74;
+               default: goto yy53;
        }
-yy88:
-       YYDEBUG(88, YYPEEK());
+yy67:
+       YYDEBUG(67, YYPEEK());
        yyaccept = 5;
        YYSKIP();
        YYBACKUP();
        yych = YYPEEK();
        switch (yych) {
-       case '\'':      goto yy86;
-       default:        goto yy89;
+               case '\'': goto yy65;
+               default: goto yy68;
        }
-yy89:
-       YYDEBUG(89, YYPEEK());
+yy68:
+       YYDEBUG(68, YYPEEK());
 #line 293 "../wisitoken_grammar.re2c"
        {*id = 41; continue;}
-#line 2201 "../wisitoken_grammar_re2c.c"
-yy90:
-       YYDEBUG(90, YYPEEK());
+#line 2161 "../wisitoken_grammar_re2c.c"
+yy69:
+       YYDEBUG(69, YYPEEK());
        YYSKIP();
        yych = YYPEEK();
        switch (yych) {
-       case 0x80:
-       case 0x81:
-       case 0x82:
-       case 0x83:
-       case 0x84:
-       case 0x85:
-       case 0x86:
-       case 0x87:
-       case 0x88:
-       case 0x89:
-       case 0x8A:
-       case 0x8B:
-       case 0x8C:
-       case 0x8D:
-       case 0x8E:
-       case 0x8F:
-       case 0x90:
-       case 0x91:
-       case 0x92:
-       case 0x93:
-       case 0x94:
-       case 0x95:
-       case 0x96:
-       case 0x97:
-       case 0x98:
-       case 0x99:
-       case 0x9A:
-       case 0x9B:
-       case 0x9C:
-       case 0x9D:
-       case 0x9E:
-       case 0x9F:
-       case 0xA0:
-       case 0xA1:
-       case 0xA2:
-       case 0xA3:
-       case 0xA4:
-       case 0xA5:
-       case 0xA6:
-       case 0xA7:
-       case 0xA8:
-       case 0xA9:
-       case 0xAA:
-       case 0xAB:
-       case 0xAC:
-       case 0xAD:
-       case 0xAE:
-       case 0xAF:
-       case 0xB0:
-       case 0xB1:
-       case 0xB2:
-       case 0xB3:
-       case 0xB4:
-       case 0xB5:
-       case 0xB6:
-       case 0xB7:
-       case 0xB8:
-       case 0xB9:
-       case 0xBA:
-       case 0xBB:
-       case 0xBC:
-       case 0xBD:
-       case 0xBE:
-       case 0xBF:      goto yy86;
-       default:        goto yy71;
+               case 0x80:
+               case 0x81:
+               case 0x82:
+               case 0x83:
+               case 0x84:
+               case 0x85:
+               case 0x86:
+               case 0x87:
+               case 0x88:
+               case 0x89:
+               case 0x8A:
+               case 0x8B:
+               case 0x8C:
+               case 0x8D:
+               case 0x8E:
+               case 0x8F:
+               case 0x90:
+               case 0x91:
+               case 0x92:
+               case 0x93:
+               case 0x94:
+               case 0x95:
+               case 0x96:
+               case 0x97:
+               case 0x98:
+               case 0x99:
+               case 0x9A:
+               case 0x9B:
+               case 0x9C:
+               case 0x9D:
+               case 0x9E:
+               case 0x9F:
+               case 0xA0:
+               case 0xA1:
+               case 0xA2:
+               case 0xA3:
+               case 0xA4:
+               case 0xA5:
+               case 0xA6:
+               case 0xA7:
+               case 0xA8:
+               case 0xA9:
+               case 0xAA:
+               case 0xAB:
+               case 0xAC:
+               case 0xAD:
+               case 0xAE:
+               case 0xAF:
+               case 0xB0:
+               case 0xB1:
+               case 0xB2:
+               case 0xB3:
+               case 0xB4:
+               case 0xB5:
+               case 0xB6:
+               case 0xB7:
+               case 0xB8:
+               case 0xB9:
+               case 0xBA:
+               case 0xBB:
+               case 0xBC:
+               case 0xBD:
+               case 0xBE:
+               case 0xBF: goto yy65;
+               default: goto yy53;
        }
-yy91:
-       YYDEBUG(91, YYPEEK());
+yy70:
+       YYDEBUG(70, YYPEEK());
        YYSKIP();
        yych = YYPEEK();
        switch (yych) {
-       case 0xA0:
-       case 0xA1:
-       case 0xA2:
-       case 0xA3:
-       case 0xA4:
-       case 0xA5:
-       case 0xA6:
-       case 0xA7:
-       case 0xA8:
-       case 0xA9:
-       case 0xAA:
-       case 0xAB:
-       case 0xAC:
-       case 0xAD:
-       case 0xAE:
-       case 0xAF:
-       case 0xB0:
-       case 0xB1:
-       case 0xB2:
-       case 0xB3:
-       case 0xB4:
-       case 0xB5:
-       case 0xB6:
-       case 0xB7:
-       case 0xB8:
-       case 0xB9:
-       case 0xBA:
-       case 0xBB:
-       case 0xBC:
-       case 0xBD:
-       case 0xBE:
-       case 0xBF:      goto yy90;
-       default:        goto yy71;
+               case 0xA0:
+               case 0xA1:
+               case 0xA2:
+               case 0xA3:
+               case 0xA4:
+               case 0xA5:
+               case 0xA6:
+               case 0xA7:
+               case 0xA8:
+               case 0xA9:
+               case 0xAA:
+               case 0xAB:
+               case 0xAC:
+               case 0xAD:
+               case 0xAE:
+               case 0xAF:
+               case 0xB0:
+               case 0xB1:
+               case 0xB2:
+               case 0xB3:
+               case 0xB4:
+               case 0xB5:
+               case 0xB6:
+               case 0xB7:
+               case 0xB8:
+               case 0xB9:
+               case 0xBA:
+               case 0xBB:
+               case 0xBC:
+               case 0xBD:
+               case 0xBE:
+               case 0xBF: goto yy69;
+               default: goto yy53;
        }
-yy92:
-       YYDEBUG(92, YYPEEK());
+yy71:
+       YYDEBUG(71, YYPEEK());
        YYSKIP();
        yych = YYPEEK();
        switch (yych) {
-       case 0x80:
-       case 0x81:
-       case 0x82:
-       case 0x83:
-       case 0x84:
-       case 0x85:
-       case 0x86:
-       case 0x87:
-       case 0x88:
-       case 0x89:
-       case 0x8A:
-       case 0x8B:
-       case 0x8C:
-       case 0x8D:
-       case 0x8E:
-       case 0x8F:
-       case 0x90:
-       case 0x91:
-       case 0x92:
-       case 0x93:
-       case 0x94:
-       case 0x95:
-       case 0x96:
-       case 0x97:
-       case 0x98:
-       case 0x99:
-       case 0x9A:
-       case 0x9B:
-       case 0x9C:
-       case 0x9D:
-       case 0x9E:
-       case 0x9F:
-       case 0xA0:
-       case 0xA1:
-       case 0xA2:
-       case 0xA3:
-       case 0xA4:
-       case 0xA5:
-       case 0xA6:
-       case 0xA7:
-       case 0xA8:
-       case 0xA9:
-       case 0xAA:
-       case 0xAB:
-       case 0xAC:
-       case 0xAD:
-       case 0xAE:
-       case 0xAF:
-       case 0xB0:
-       case 0xB1:
-       case 0xB2:
-       case 0xB3:
-       case 0xB4:
-       case 0xB5:
-       case 0xB6:
-       case 0xB7:
-       case 0xB8:
-       case 0xB9:
-       case 0xBA:
-       case 0xBB:
-       case 0xBC:
-       case 0xBD:
-       case 0xBE:
-       case 0xBF:      goto yy90;
-       default:        goto yy71;
+               case 0x80:
+               case 0x81:
+               case 0x82:
+               case 0x83:
+               case 0x84:
+               case 0x85:
+               case 0x86:
+               case 0x87:
+               case 0x88:
+               case 0x89:
+               case 0x8A:
+               case 0x8B:
+               case 0x8C:
+               case 0x8D:
+               case 0x8E:
+               case 0x8F:
+               case 0x90:
+               case 0x91:
+               case 0x92:
+               case 0x93:
+               case 0x94:
+               case 0x95:
+               case 0x96:
+               case 0x97:
+               case 0x98:
+               case 0x99:
+               case 0x9A:
+               case 0x9B:
+               case 0x9C:
+               case 0x9D:
+               case 0x9E:
+               case 0x9F:
+               case 0xA0:
+               case 0xA1:
+               case 0xA2:
+               case 0xA3:
+               case 0xA4:
+               case 0xA5:
+               case 0xA6:
+               case 0xA7:
+               case 0xA8:
+               case 0xA9:
+               case 0xAA:
+               case 0xAB:
+               case 0xAC:
+               case 0xAD:
+               case 0xAE:
+               case 0xAF:
+               case 0xB0:
+               case 0xB1:
+               case 0xB2:
+               case 0xB3:
+               case 0xB4:
+               case 0xB5:
+               case 0xB6:
+               case 0xB7:
+               case 0xB8:
+               case 0xB9:
+               case 0xBA:
+               case 0xBB:
+               case 0xBC:
+               case 0xBD:
+               case 0xBE:
+               case 0xBF: goto yy69;
+               default: goto yy53;
        }
-yy93:
-       YYDEBUG(93, YYPEEK());
+yy72:
+       YYDEBUG(72, YYPEEK());
        YYSKIP();
        yych = YYPEEK();
        switch (yych) {
-       case 0x90:
-       case 0x91:
-       case 0x92:
-       case 0x93:
-       case 0x94:
-       case 0x95:
-       case 0x96:
-       case 0x97:
-       case 0x98:
-       case 0x99:
-       case 0x9A:
-       case 0x9B:
-       case 0x9C:
-       case 0x9D:
-       case 0x9E:
-       case 0x9F:
-       case 0xA0:
-       case 0xA1:
-       case 0xA2:
-       case 0xA3:
-       case 0xA4:
-       case 0xA5:
-       case 0xA6:
-       case 0xA7:
-       case 0xA8:
-       case 0xA9:
-       case 0xAA:
-       case 0xAB:
-       case 0xAC:
-       case 0xAD:
-       case 0xAE:
-       case 0xAF:
-       case 0xB0:
-       case 0xB1:
-       case 0xB2:
-       case 0xB3:
-       case 0xB4:
-       case 0xB5:
-       case 0xB6:
-       case 0xB7:
-       case 0xB8:
-       case 0xB9:
-       case 0xBA:
-       case 0xBB:
-       case 0xBC:
-       case 0xBD:
-       case 0xBE:
-       case 0xBF:      goto yy92;
-       default:        goto yy71;
+               case 0x90:
+               case 0x91:
+               case 0x92:
+               case 0x93:
+               case 0x94:
+               case 0x95:
+               case 0x96:
+               case 0x97:
+               case 0x98:
+               case 0x99:
+               case 0x9A:
+               case 0x9B:
+               case 0x9C:
+               case 0x9D:
+               case 0x9E:
+               case 0x9F:
+               case 0xA0:
+               case 0xA1:
+               case 0xA2:
+               case 0xA3:
+               case 0xA4:
+               case 0xA5:
+               case 0xA6:
+               case 0xA7:
+               case 0xA8:
+               case 0xA9:
+               case 0xAA:
+               case 0xAB:
+               case 0xAC:
+               case 0xAD:
+               case 0xAE:
+               case 0xAF:
+               case 0xB0:
+               case 0xB1:
+               case 0xB2:
+               case 0xB3:
+               case 0xB4:
+               case 0xB5:
+               case 0xB6:
+               case 0xB7:
+               case 0xB8:
+               case 0xB9:
+               case 0xBA:
+               case 0xBB:
+               case 0xBC:
+               case 0xBD:
+               case 0xBE:
+               case 0xBF: goto yy71;
+               default: goto yy53;
        }
-yy94:
-       YYDEBUG(94, YYPEEK());
+yy73:
+       YYDEBUG(73, YYPEEK());
        YYSKIP();
        yych = YYPEEK();
        switch (yych) {
-       case 0x80:
-       case 0x81:
-       case 0x82:
-       case 0x83:
-       case 0x84:
-       case 0x85:
-       case 0x86:
-       case 0x87:
-       case 0x88:
-       case 0x89:
-       case 0x8A:
-       case 0x8B:
-       case 0x8C:
-       case 0x8D:
-       case 0x8E:
-       case 0x8F:
-       case 0x90:
-       case 0x91:
-       case 0x92:
-       case 0x93:
-       case 0x94:
-       case 0x95:
-       case 0x96:
-       case 0x97:
-       case 0x98:
-       case 0x99:
-       case 0x9A:
-       case 0x9B:
-       case 0x9C:
-       case 0x9D:
-       case 0x9E:
-       case 0x9F:
-       case 0xA0:
-       case 0xA1:
-       case 0xA2:
-       case 0xA3:
-       case 0xA4:
-       case 0xA5:
-       case 0xA6:
-       case 0xA7:
-       case 0xA8:
-       case 0xA9:
-       case 0xAA:
-       case 0xAB:
-       case 0xAC:
-       case 0xAD:
-       case 0xAE:
-       case 0xAF:
-       case 0xB0:
-       case 0xB1:
-       case 0xB2:
-       case 0xB3:
-       case 0xB4:
-       case 0xB5:
-       case 0xB6:
-       case 0xB7:
-       case 0xB8:
-       case 0xB9:
-       case 0xBA:
-       case 0xBB:
-       case 0xBC:
-       case 0xBD:
-       case 0xBE:
-       case 0xBF:      goto yy92;
-       default:        goto yy71;
+               case 0x80:
+               case 0x81:
+               case 0x82:
+               case 0x83:
+               case 0x84:
+               case 0x85:
+               case 0x86:
+               case 0x87:
+               case 0x88:
+               case 0x89:
+               case 0x8A:
+               case 0x8B:
+               case 0x8C:
+               case 0x8D:
+               case 0x8E:
+               case 0x8F:
+               case 0x90:
+               case 0x91:
+               case 0x92:
+               case 0x93:
+               case 0x94:
+               case 0x95:
+               case 0x96:
+               case 0x97:
+               case 0x98:
+               case 0x99:
+               case 0x9A:
+               case 0x9B:
+               case 0x9C:
+               case 0x9D:
+               case 0x9E:
+               case 0x9F:
+               case 0xA0:
+               case 0xA1:
+               case 0xA2:
+               case 0xA3:
+               case 0xA4:
+               case 0xA5:
+               case 0xA6:
+               case 0xA7:
+               case 0xA8:
+               case 0xA9:
+               case 0xAA:
+               case 0xAB:
+               case 0xAC:
+               case 0xAD:
+               case 0xAE:
+               case 0xAF:
+               case 0xB0:
+               case 0xB1:
+               case 0xB2:
+               case 0xB3:
+               case 0xB4:
+               case 0xB5:
+               case 0xB6:
+               case 0xB7:
+               case 0xB8:
+               case 0xB9:
+               case 0xBA:
+               case 0xBB:
+               case 0xBC:
+               case 0xBD:
+               case 0xBE:
+               case 0xBF: goto yy71;
+               default: goto yy53;
        }
-yy95:
-       YYDEBUG(95, YYPEEK());
+yy74:
+       YYDEBUG(74, YYPEEK());
        YYSKIP();
        yych = YYPEEK();
        switch (yych) {
-       case 0x80:
-       case 0x81:
-       case 0x82:
-       case 0x83:
-       case 0x84:
-       case 0x85:
-       case 0x86:
-       case 0x87:
-       case 0x88:
-       case 0x89:
-       case 0x8A:
-       case 0x8B:
-       case 0x8C:
-       case 0x8D:
-       case 0x8E:
-       case 0x8F:      goto yy92;
-       default:        goto yy71;
+               case 0x80:
+               case 0x81:
+               case 0x82:
+               case 0x83:
+               case 0x84:
+               case 0x85:
+               case 0x86:
+               case 0x87:
+               case 0x88:
+               case 0x89:
+               case 0x8A:
+               case 0x8B:
+               case 0x8C:
+               case 0x8D:
+               case 0x8E:
+               case 0x8F: goto yy71;
+               default: goto yy53;
        }
-yy96:
-       YYDEBUG(96, YYPEEK());
+yy75:
+       YYDEBUG(75, YYPEEK());
        YYSKIP();
        yych = YYPEEK();
        switch (yych) {
-       case '=':       goto yy120;
-       default:        goto yy71;
+               case '=': goto yy98;
+               default: goto yy53;
        }
-yy97:
-       YYDEBUG(97, YYPEEK());
+yy76:
+       YYDEBUG(76, YYPEEK());
        YYSKIP();
        yych = YYPEEK();
-       YYDEBUG(98, YYPEEK());
        switch (yych) {
-       case 0x00:
-       case 0x01:
-       case 0x02:
-       case 0x03:
-       case 0x05:
-       case 0x06:
-       case 0x07:
-       case 0x08:
-       case '\t':
-       case '\v':
-       case '\f':
-       case '\r':
-       case 0x0E:
-       case 0x0F:
-       case 0x10:
-       case 0x11:
-       case 0x12:
-       case 0x13:
-       case 0x14:
-       case 0x15:
-       case 0x16:
-       case 0x17:
-       case 0x18:
-       case 0x19:
-       case 0x1A:
-       case 0x1B:
-       case 0x1C:
-       case 0x1D:
-       case 0x1E:
-       case 0x1F:
-       case ' ':
-       case '!':
-       case '"':
-       case '#':
-       case '$':
-       case '%':
-       case '&':
-       case '\'':
-       case '(':
-       case ')':
-       case '*':
-       case '+':
-       case ',':
-       case '-':
-       case '.':
-       case '/':
-       case '0':
-       case '1':
-       case '2':
-       case '3':
-       case '4':
-       case '5':
-       case '6':
-       case '7':
-       case '8':
-       case '9':
-       case ':':
-       case ';':
-       case '<':
-       case '=':
-       case '>':
-       case '?':
-       case '@':
-       case 'A':
-       case 'B':
-       case 'C':
-       case 'D':
-       case 'E':
-       case 'F':
-       case 'G':
-       case 'H':
-       case 'I':
-       case 'J':
-       case 'K':
-       case 'L':
-       case 'M':
-       case 'N':
-       case 'O':
-       case 'P':
-       case 'Q':
-       case 'R':
-       case 'S':
-       case 'T':
-       case 'U':
-       case 'V':
-       case 'W':
-       case 'X':
-       case 'Y':
-       case 'Z':
-       case '[':
-       case '\\':
-       case ']':
-       case '^':
-       case '_':
-       case '`':
-       case 'a':
-       case 'b':
-       case 'c':
-       case 'd':
-       case 'e':
-       case 'f':
-       case 'g':
-       case 'h':
-       case 'i':
-       case 'j':
-       case 'k':
-       case 'l':
-       case 'm':
-       case 'n':
-       case 'o':
-       case 'p':
-       case 'q':
-       case 'r':
-       case 's':
-       case 't':
-       case 'u':
-       case 'v':
-       case 'w':
-       case 'x':
-       case 'y':
-       case 'z':
-       case '{':
-       case '|':
-       case '}':
-       case '~':
-       case 0x7F:      goto yy97;
-       case 0x04:
-       case '\n':      goto yy122;
-       case 0xC2:
-       case 0xC3:
-       case 0xC4:
-       case 0xC5:
-       case 0xC6:
-       case 0xC7:
-       case 0xC8:
-       case 0xC9:
-       case 0xCA:
-       case 0xCB:
-       case 0xCC:
-       case 0xCD:
-       case 0xCE:
-       case 0xCF:
-       case 0xD0:
-       case 0xD1:
-       case 0xD2:
-       case 0xD3:
-       case 0xD4:
-       case 0xD5:
-       case 0xD6:
-       case 0xD7:
-       case 0xD8:
-       case 0xD9:
-       case 0xDA:
-       case 0xDB:
-       case 0xDC:
-       case 0xDD:
-       case 0xDE:
-       case 0xDF:      goto yy124;
-       case 0xE0:      goto yy125;
-       case 0xE1:
-       case 0xE2:
-       case 0xE3:
-       case 0xE4:
-       case 0xE5:
-       case 0xE6:
-       case 0xE7:
-       case 0xE8:
-       case 0xE9:
-       case 0xEA:
-       case 0xEB:
-       case 0xEC:
-       case 0xED:
-       case 0xEE:
-       case 0xEF:      goto yy126;
-       case 0xF0:      goto yy127;
-       case 0xF1:
-       case 0xF2:
-       case 0xF3:      goto yy128;
-       case 0xF4:      goto yy129;
-       default:        goto yy71;
+               case 0x00:
+               case 0x01:
+               case 0x02:
+               case 0x03:
+               case 0x05:
+               case 0x06:
+               case 0x07:
+               case 0x08:
+               case '\t':
+               case '\v':
+               case '\f':
+               case '\r':
+               case 0x0E:
+               case 0x0F:
+               case 0x10:
+               case 0x11:
+               case 0x12:
+               case 0x13:
+               case 0x14:
+               case 0x15:
+               case 0x16:
+               case 0x17:
+               case 0x18:
+               case 0x19:
+               case 0x1A:
+               case 0x1B:
+               case 0x1C:
+               case 0x1D:
+               case 0x1E:
+               case 0x1F:
+               case ' ':
+               case '!':
+               case '"':
+               case '#':
+               case '$':
+               case '%':
+               case '&':
+               case '\'':
+               case '(':
+               case ')':
+               case '*':
+               case '+':
+               case ',':
+               case '-':
+               case '.':
+               case '/':
+               case '0':
+               case '1':
+               case '2':
+               case '3':
+               case '4':
+               case '5':
+               case '6':
+               case '7':
+               case '8':
+               case '9':
+               case ':':
+               case ';':
+               case '<':
+               case '=':
+               case '>':
+               case '?':
+               case '@':
+               case 'A':
+               case 'B':
+               case 'C':
+               case 'D':
+               case 'E':
+               case 'F':
+               case 'G':
+               case 'H':
+               case 'I':
+               case 'J':
+               case 'K':
+               case 'L':
+               case 'M':
+               case 'N':
+               case 'O':
+               case 'P':
+               case 'Q':
+               case 'R':
+               case 'S':
+               case 'T':
+               case 'U':
+               case 'V':
+               case 'W':
+               case 'X':
+               case 'Y':
+               case 'Z':
+               case '[':
+               case '\\':
+               case ']':
+               case '^':
+               case '_':
+               case '`':
+               case 'a':
+               case 'b':
+               case 'c':
+               case 'd':
+               case 'e':
+               case 'f':
+               case 'g':
+               case 'h':
+               case 'i':
+               case 'j':
+               case 'k':
+               case 'l':
+               case 'm':
+               case 'n':
+               case 'o':
+               case 'p':
+               case 'q':
+               case 'r':
+               case 's':
+               case 't':
+               case 'u':
+               case 'v':
+               case 'w':
+               case 'x':
+               case 'y':
+               case 'z':
+               case '{':
+               case '|':
+               case '}':
+               case '~':
+               case 0x7F: goto yy76;
+               case 0x04:
+               case '\n': goto yy99;
+               case 0xC2:
+               case 0xC3:
+               case 0xC4:
+               case 0xC5:
+               case 0xC6:
+               case 0xC7:
+               case 0xC8:
+               case 0xC9:
+               case 0xCA:
+               case 0xCB:
+               case 0xCC:
+               case 0xCD:
+               case 0xCE:
+               case 0xCF:
+               case 0xD0:
+               case 0xD1:
+               case 0xD2:
+               case 0xD3:
+               case 0xD4:
+               case 0xD5:
+               case 0xD6:
+               case 0xD7:
+               case 0xD8:
+               case 0xD9:
+               case 0xDA:
+               case 0xDB:
+               case 0xDC:
+               case 0xDD:
+               case 0xDE:
+               case 0xDF: goto yy100;
+               case 0xE0: goto yy101;
+               case 0xE1:
+               case 0xE2:
+               case 0xE3:
+               case 0xE4:
+               case 0xE5:
+               case 0xE6:
+               case 0xE7:
+               case 0xE8:
+               case 0xE9:
+               case 0xEA:
+               case 0xEB:
+               case 0xEC:
+               case 0xED:
+               case 0xEE:
+               case 0xEF: goto yy102;
+               case 0xF0: goto yy103;
+               case 0xF1:
+               case 0xF2:
+               case 0xF3: goto yy104;
+               case 0xF4: goto yy105;
+               default: goto yy53;
        }
-yy99:
-       YYDEBUG(99, YYPEEK());
+yy77:
+       YYDEBUG(77, YYPEEK());
        yyaccept = 3;
        YYSKIP();
        YYBACKUP();
        yych = YYPEEK();
        switch (yych) {
-       case 'C':
-       case 'c':       goto yy130;
-       default:        goto yy43;
+               case 'C':
+               case 'c': goto yy106;
+               default: goto yy30;
        }
-yy100:
-       YYDEBUG(100, YYPEEK());
+yy78:
+       YYDEBUG(78, YYPEEK());
        YYSKIP();
        yych = YYPEEK();
        switch (yych) {
-       case 0x80:
-       case 0x81:
-       case 0x82:
-       case 0x83:
-       case 0x84:
-       case 0x85:
-       case 0x86:
-       case 0x87:
-       case 0x88:
-       case 0x89:
-       case 0x8A:
-       case 0x8B:
-       case 0x8C:
-       case 0x8D:
-       case 0x8E:
-       case 0x8F:
-       case 0x90:
-       case 0x91:
-       case 0x92:
-       case 0x93:
-       case 0x94:
-       case 0x95:
-       case 0x96:
-       case 0x97:
-       case 0x98:
-       case 0x99:
-       case 0x9A:
-       case 0x9B:
-       case 0x9C:
-       case 0x9D:
-       case 0x9E:
-       case 0x9F:
-       case 0xA0:
-       case 0xA1:
-       case 0xA2:
-       case 0xA3:
-       case 0xA4:
-       case 0xA5:
-       case 0xA6:
-       case 0xA7:
-       case 0xA8:
-       case 0xA9:
-       case 0xAA:
-       case 0xAB:
-       case 0xAC:
-       case 0xAD:
-       case 0xAE:
-       case 0xAF:
-       case 0xB0:
-       case 0xB1:
-       case 0xB2:
-       case 0xB3:
-       case 0xB4:
-       case 0xB5:
-       case 0xB6:
-       case 0xB7:
-       case 0xB8:
-       case 0xB9:
-       case 0xBA:
-       case 0xBB:
-       case 0xBC:
-       case 0xBD:
-       case 0xBE:
-       case 0xBF:      goto yy42;
-       default:        goto yy71;
+               case 0x80:
+               case 0x81:
+               case 0x82:
+               case 0x83:
+               case 0x84:
+               case 0x85:
+               case 0x86:
+               case 0x87:
+               case 0x88:
+               case 0x89:
+               case 0x8A:
+               case 0x8B:
+               case 0x8C:
+               case 0x8D:
+               case 0x8E:
+               case 0x8F:
+               case 0x90:
+               case 0x91:
+               case 0x92:
+               case 0x93:
+               case 0x94:
+               case 0x95:
+               case 0x96:
+               case 0x97:
+               case 0x98:
+               case 0x99:
+               case 0x9A:
+               case 0x9B:
+               case 0x9C:
+               case 0x9D:
+               case 0x9E:
+               case 0x9F:
+               case 0xA0:
+               case 0xA1:
+               case 0xA2:
+               case 0xA3:
+               case 0xA4:
+               case 0xA5:
+               case 0xA6:
+               case 0xA7:
+               case 0xA8:
+               case 0xA9:
+               case 0xAA:
+               case 0xAB:
+               case 0xAC:
+               case 0xAD:
+               case 0xAE:
+               case 0xAF:
+               case 0xB0:
+               case 0xB1:
+               case 0xB2:
+               case 0xB3:
+               case 0xB4:
+               case 0xB5:
+               case 0xB6:
+               case 0xB7:
+               case 0xB8:
+               case 0xB9:
+               case 0xBA:
+               case 0xBB:
+               case 0xBC:
+               case 0xBD:
+               case 0xBE:
+               case 0xBF: goto yy29;
+               default: goto yy53;
        }
-yy101:
-       YYDEBUG(101, YYPEEK());
+yy79:
+       YYDEBUG(79, YYPEEK());
        YYSKIP();
        yych = YYPEEK();
        switch (yych) {
-       case 0xA0:
-       case 0xA1:
-       case 0xA2:
-       case 0xA3:
-       case 0xA4:
-       case 0xA5:
-       case 0xA6:
-       case 0xA7:
-       case 0xA8:
-       case 0xA9:
-       case 0xAA:
-       case 0xAB:
-       case 0xAC:
-       case 0xAD:
-       case 0xAE:
-       case 0xAF:
-       case 0xB0:
-       case 0xB1:
-       case 0xB2:
-       case 0xB3:
-       case 0xB4:
-       case 0xB5:
-       case 0xB6:
-       case 0xB7:
-       case 0xB8:
-       case 0xB9:
-       case 0xBA:
-       case 0xBB:
-       case 0xBC:
-       case 0xBD:
-       case 0xBE:
-       case 0xBF:      goto yy100;
-       default:        goto yy71;
+               case 0xA0:
+               case 0xA1:
+               case 0xA2:
+               case 0xA3:
+               case 0xA4:
+               case 0xA5:
+               case 0xA6:
+               case 0xA7:
+               case 0xA8:
+               case 0xA9:
+               case 0xAA:
+               case 0xAB:
+               case 0xAC:
+               case 0xAD:
+               case 0xAE:
+               case 0xAF:
+               case 0xB0:
+               case 0xB1:
+               case 0xB2:
+               case 0xB3:
+               case 0xB4:
+               case 0xB5:
+               case 0xB6:
+               case 0xB7:
+               case 0xB8:
+               case 0xB9:
+               case 0xBA:
+               case 0xBB:
+               case 0xBC:
+               case 0xBD:
+               case 0xBE:
+               case 0xBF: goto yy78;
+               default: goto yy53;
        }
-yy102:
-       YYDEBUG(102, YYPEEK());
+yy80:
+       YYDEBUG(80, YYPEEK());
        YYSKIP();
        yych = YYPEEK();
        switch (yych) {
-       case 0x80:
-       case 0x81:
-       case 0x82:
-       case 0x83:
-       case 0x84:
-       case 0x85:
-       case 0x86:
-       case 0x87:
-       case 0x88:
-       case 0x89:
-       case 0x8A:
-       case 0x8B:
-       case 0x8C:
-       case 0x8D:
-       case 0x8E:
-       case 0x8F:
-       case 0x90:
-       case 0x91:
-       case 0x92:
-       case 0x93:
-       case 0x94:
-       case 0x95:
-       case 0x96:
-       case 0x97:
-       case 0x98:
-       case 0x99:
-       case 0x9A:
-       case 0x9B:
-       case 0x9C:
-       case 0x9D:
-       case 0x9E:
-       case 0x9F:
-       case 0xA0:
-       case 0xA1:
-       case 0xA2:
-       case 0xA3:
-       case 0xA4:
-       case 0xA5:
-       case 0xA6:
-       case 0xA7:
-       case 0xA8:
-       case 0xA9:
-       case 0xAA:
-       case 0xAB:
-       case 0xAC:
-       case 0xAD:
-       case 0xAE:
-       case 0xAF:
-       case 0xB0:
-       case 0xB1:
-       case 0xB2:
-       case 0xB3:
-       case 0xB4:
-       case 0xB5:
-       case 0xB6:
-       case 0xB7:
-       case 0xB8:
-       case 0xB9:
-       case 0xBA:
-       case 0xBB:
-       case 0xBC:
-       case 0xBD:
-       case 0xBE:
-       case 0xBF:      goto yy100;
-       default:        goto yy71;
+               case 0x80:
+               case 0x81:
+               case 0x82:
+               case 0x83:
+               case 0x84:
+               case 0x85:
+               case 0x86:
+               case 0x87:
+               case 0x88:
+               case 0x89:
+               case 0x8A:
+               case 0x8B:
+               case 0x8C:
+               case 0x8D:
+               case 0x8E:
+               case 0x8F:
+               case 0x90:
+               case 0x91:
+               case 0x92:
+               case 0x93:
+               case 0x94:
+               case 0x95:
+               case 0x96:
+               case 0x97:
+               case 0x98:
+               case 0x99:
+               case 0x9A:
+               case 0x9B:
+               case 0x9C:
+               case 0x9D:
+               case 0x9E:
+               case 0x9F:
+               case 0xA0:
+               case 0xA1:
+               case 0xA2:
+               case 0xA3:
+               case 0xA4:
+               case 0xA5:
+               case 0xA6:
+               case 0xA7:
+               case 0xA8:
+               case 0xA9:
+               case 0xAA:
+               case 0xAB:
+               case 0xAC:
+               case 0xAD:
+               case 0xAE:
+               case 0xAF:
+               case 0xB0:
+               case 0xB1:
+               case 0xB2:
+               case 0xB3:
+               case 0xB4:
+               case 0xB5:
+               case 0xB6:
+               case 0xB7:
+               case 0xB8:
+               case 0xB9:
+               case 0xBA:
+               case 0xBB:
+               case 0xBC:
+               case 0xBD:
+               case 0xBE:
+               case 0xBF: goto yy78;
+               default: goto yy53;
        }
-yy103:
-       YYDEBUG(103, YYPEEK());
+yy81:
+       YYDEBUG(81, YYPEEK());
        YYSKIP();
        yych = YYPEEK();
        switch (yych) {
-       case 0x90:
-       case 0x91:
-       case 0x92:
-       case 0x93:
-       case 0x94:
-       case 0x95:
-       case 0x96:
-       case 0x97:
-       case 0x98:
-       case 0x99:
-       case 0x9A:
-       case 0x9B:
-       case 0x9C:
-       case 0x9D:
-       case 0x9E:
-       case 0x9F:
-       case 0xA0:
-       case 0xA1:
-       case 0xA2:
-       case 0xA3:
-       case 0xA4:
-       case 0xA5:
-       case 0xA6:
-       case 0xA7:
-       case 0xA8:
-       case 0xA9:
-       case 0xAA:
-       case 0xAB:
-       case 0xAC:
-       case 0xAD:
-       case 0xAE:
-       case 0xAF:
-       case 0xB0:
-       case 0xB1:
-       case 0xB2:
-       case 0xB3:
-       case 0xB4:
-       case 0xB5:
-       case 0xB6:
-       case 0xB7:
-       case 0xB8:
-       case 0xB9:
-       case 0xBA:
-       case 0xBB:
-       case 0xBC:
-       case 0xBD:
-       case 0xBE:
-       case 0xBF:      goto yy102;
-       default:        goto yy71;
+               case 0x90:
+               case 0x91:
+               case 0x92:
+               case 0x93:
+               case 0x94:
+               case 0x95:
+               case 0x96:
+               case 0x97:
+               case 0x98:
+               case 0x99:
+               case 0x9A:
+               case 0x9B:
+               case 0x9C:
+               case 0x9D:
+               case 0x9E:
+               case 0x9F:
+               case 0xA0:
+               case 0xA1:
+               case 0xA2:
+               case 0xA3:
+               case 0xA4:
+               case 0xA5:
+               case 0xA6:
+               case 0xA7:
+               case 0xA8:
+               case 0xA9:
+               case 0xAA:
+               case 0xAB:
+               case 0xAC:
+               case 0xAD:
+               case 0xAE:
+               case 0xAF:
+               case 0xB0:
+               case 0xB1:
+               case 0xB2:
+               case 0xB3:
+               case 0xB4:
+               case 0xB5:
+               case 0xB6:
+               case 0xB7:
+               case 0xB8:
+               case 0xB9:
+               case 0xBA:
+               case 0xBB:
+               case 0xBC:
+               case 0xBD:
+               case 0xBE:
+               case 0xBF: goto yy80;
+               default: goto yy53;
        }
-yy104:
-       YYDEBUG(104, YYPEEK());
+yy82:
+       YYDEBUG(82, YYPEEK());
        YYSKIP();
        yych = YYPEEK();
        switch (yych) {
-       case 0x80:
-       case 0x81:
-       case 0x82:
-       case 0x83:
-       case 0x84:
-       case 0x85:
-       case 0x86:
-       case 0x87:
-       case 0x88:
-       case 0x89:
-       case 0x8A:
-       case 0x8B:
-       case 0x8C:
-       case 0x8D:
-       case 0x8E:
-       case 0x8F:
-       case 0x90:
-       case 0x91:
-       case 0x92:
-       case 0x93:
-       case 0x94:
-       case 0x95:
-       case 0x96:
-       case 0x97:
-       case 0x98:
-       case 0x99:
-       case 0x9A:
-       case 0x9B:
-       case 0x9C:
-       case 0x9D:
-       case 0x9E:
-       case 0x9F:
-       case 0xA0:
-       case 0xA1:
-       case 0xA2:
-       case 0xA3:
-       case 0xA4:
-       case 0xA5:
-       case 0xA6:
-       case 0xA7:
-       case 0xA8:
-       case 0xA9:
-       case 0xAA:
-       case 0xAB:
-       case 0xAC:
-       case 0xAD:
-       case 0xAE:
-       case 0xAF:
-       case 0xB0:
-       case 0xB1:
-       case 0xB2:
-       case 0xB3:
-       case 0xB4:
-       case 0xB5:
-       case 0xB6:
-       case 0xB7:
-       case 0xB8:
-       case 0xB9:
-       case 0xBA:
-       case 0xBB:
-       case 0xBC:
-       case 0xBD:
-       case 0xBE:
-       case 0xBF:      goto yy102;
-       default:        goto yy71;
+               case 0x80:
+               case 0x81:
+               case 0x82:
+               case 0x83:
+               case 0x84:
+               case 0x85:
+               case 0x86:
+               case 0x87:
+               case 0x88:
+               case 0x89:
+               case 0x8A:
+               case 0x8B:
+               case 0x8C:
+               case 0x8D:
+               case 0x8E:
+               case 0x8F:
+               case 0x90:
+               case 0x91:
+               case 0x92:
+               case 0x93:
+               case 0x94:
+               case 0x95:
+               case 0x96:
+               case 0x97:
+               case 0x98:
+               case 0x99:
+               case 0x9A:
+               case 0x9B:
+               case 0x9C:
+               case 0x9D:
+               case 0x9E:
+               case 0x9F:
+               case 0xA0:
+               case 0xA1:
+               case 0xA2:
+               case 0xA3:
+               case 0xA4:
+               case 0xA5:
+               case 0xA6:
+               case 0xA7:
+               case 0xA8:
+               case 0xA9:
+               case 0xAA:
+               case 0xAB:
+               case 0xAC:
+               case 0xAD:
+               case 0xAE:
+               case 0xAF:
+               case 0xB0:
+               case 0xB1:
+               case 0xB2:
+               case 0xB3:
+               case 0xB4:
+               case 0xB5:
+               case 0xB6:
+               case 0xB7:
+               case 0xB8:
+               case 0xB9:
+               case 0xBA:
+               case 0xBB:
+               case 0xBC:
+               case 0xBD:
+               case 0xBE:
+               case 0xBF: goto yy80;
+               default: goto yy53;
        }
-yy105:
-       YYDEBUG(105, YYPEEK());
+yy83:
+       YYDEBUG(83, YYPEEK());
        YYSKIP();
        yych = YYPEEK();
        switch (yych) {
-       case 0x80:
-       case 0x81:
-       case 0x82:
-       case 0x83:
-       case 0x84:
-       case 0x85:
-       case 0x86:
-       case 0x87:
-       case 0x88:
-       case 0x89:
-       case 0x8A:
-       case 0x8B:
-       case 0x8C:
-       case 0x8D:
-       case 0x8E:
-       case 0x8F:      goto yy102;
-       default:        goto yy71;
+               case 0x80:
+               case 0x81:
+               case 0x82:
+               case 0x83:
+               case 0x84:
+               case 0x85:
+               case 0x86:
+               case 0x87:
+               case 0x88:
+               case 0x89:
+               case 0x8A:
+               case 0x8B:
+               case 0x8C:
+               case 0x8D:
+               case 0x8E:
+               case 0x8F: goto yy80;
+               default: goto yy53;
        }
-yy106:
-       YYDEBUG(106, YYPEEK());
+yy84:
+       YYDEBUG(84, YYPEEK());
        yyaccept = 3;
        YYSKIP();
        YYBACKUP();
        yych = YYPEEK();
        switch (yych) {
-       case 'D':
-       case 'd':       goto yy131;
-       default:        goto yy43;
+               case 'D':
+               case 'd': goto yy107;
+               default: goto yy30;
        }
-yy107:
-       YYDEBUG(107, YYPEEK());
+yy85:
+       YYDEBUG(85, YYPEEK());
        yyaccept = 3;
        YYSKIP();
        YYBACKUP();
        yych = YYPEEK();
        switch (yych) {
-       case 'I':
-       case 'i':       goto yy132;
-       default:        goto yy43;
+               case 'I':
+               case 'i': goto yy108;
+               default: goto yy30;
        }
-yy108:
-       YYDEBUG(108, YYPEEK());
+yy86:
+       YYDEBUG(86, YYPEEK());
        yyaccept = 3;
        YYSKIP();
        YYBACKUP();
        yych = YYPEEK();
        switch (yych) {
-       case 'd':       goto yy133;
-       case 'n':       goto yy134;
-       default:        goto yy43;
+               case 'd': goto yy109;
+               case 'n': goto yy110;
+               default: goto yy30;
        }
-yy109:
-       YYDEBUG(109, YYPEEK());
+yy87:
+       YYDEBUG(87, YYPEEK());
        yyaccept = 3;
        YYSKIP();
        YYBACKUP();
        yych = YYPEEK();
        switch (yych) {
-       case 's':       goto yy135;
-       default:        goto yy43;
+               case 's': goto yy111;
+               default: goto yy30;
        }
-yy110:
-       YYDEBUG(110, YYPEEK());
+yy88:
+       YYDEBUG(88, YYPEEK());
        yyaccept = 3;
        YYSKIP();
        YYBACKUP();
        yych = YYPEEK();
        switch (yych) {
-       case 'd':       goto yy136;
-       default:        goto yy43;
+               case 'd': goto yy112;
+               default: goto yy30;
        }
-yy111:
-       YYDEBUG(111, YYPEEK());
+yy89:
+       YYDEBUG(89, YYPEEK());
        yyaccept = 6;
        YYSKIP();
        YYBACKUP();
        yych = YYPEEK();
        switch (yych) {
-       case '-':
-       case '0':
-       case '1':
-       case '2':
-       case '3':
-       case '4':
-       case '5':
-       case '6':
-       case '7':
-       case '8':
-       case '9':
-       case 'A':
-       case 'B':
-       case 'C':
-       case 'D':
-       case 'E':
-       case 'F':
-       case 'G':
-       case 'H':
-       case 'I':
-       case 'J':
-       case 'K':
-       case 'L':
-       case 'M':
-       case 'N':
-       case 'O':
-       case 'P':
-       case 'Q':
-       case 'R':
-       case 'S':
-       case 'T':
-       case 'U':
-       case 'V':
-       case 'W':
-       case 'X':
-       case 'Y':
-       case 'Z':
-       case '_':
-       case 'a':
-       case 'b':
-       case 'c':
-       case 'd':
-       case 'e':
-       case 'f':
-       case 'g':
-       case 'h':
-       case 'i':
-       case 'j':
-       case 'k':
-       case 'l':
-       case 'm':
-       case 'n':
-       case 'o':
-       case 'p':
-       case 'q':
-       case 'r':
-       case 's':
-       case 't':
-       case 'u':
-       case 'v':
-       case 'w':
-       case 'x':
-       case 'y':
-       case 'z':
-       case 0xC2:
-       case 0xC3:
-       case 0xC4:
-       case 0xC5:
-       case 0xC6:
-       case 0xC7:
-       case 0xC8:
-       case 0xC9:
-       case 0xCA:
-       case 0xCB:
-       case 0xCC:
-       case 0xCD:
-       case 0xCE:
-       case 0xCF:
-       case 0xD0:
-       case 0xD1:
-       case 0xD2:
-       case 0xD3:
-       case 0xD4:
-       case 0xD5:
-       case 0xD6:
-       case 0xD7:
-       case 0xD8:
-       case 0xD9:
-       case 0xDA:
-       case 0xDB:
-       case 0xDC:
-       case 0xDD:
-       case 0xDE:
-       case 0xDF:
-       case 0xE0:
-       case 0xE1:
-       case 0xE2:
-       case 0xE3:
-       case 0xE4:
-       case 0xE5:
-       case 0xE6:
-       case 0xE7:
-       case 0xE8:
-       case 0xE9:
-       case 0xEA:
-       case 0xEB:
-       case 0xEC:
-       case 0xED:
-       case 0xEE:
-       case 0xEF:
-       case 0xF0:
-       case 0xF1:
-       case 0xF2:
-       case 0xF3:
-       case 0xF4:      goto yy43;
-       default:        goto yy112;
+               case '-':
+               case '0':
+               case '1':
+               case '2':
+               case '3':
+               case '4':
+               case '5':
+               case '6':
+               case '7':
+               case '8':
+               case '9':
+               case 'A':
+               case 'B':
+               case 'C':
+               case 'D':
+               case 'E':
+               case 'F':
+               case 'G':
+               case 'H':
+               case 'I':
+               case 'J':
+               case 'K':
+               case 'L':
+               case 'M':
+               case 'N':
+               case 'O':
+               case 'P':
+               case 'Q':
+               case 'R':
+               case 'S':
+               case 'T':
+               case 'U':
+               case 'V':
+               case 'W':
+               case 'X':
+               case 'Y':
+               case 'Z':
+               case '_':
+               case 'a':
+               case 'b':
+               case 'c':
+               case 'd':
+               case 'e':
+               case 'f':
+               case 'g':
+               case 'h':
+               case 'i':
+               case 'j':
+               case 'k':
+               case 'l':
+               case 'm':
+               case 'n':
+               case 'o':
+               case 'p':
+               case 'q':
+               case 'r':
+               case 's':
+               case 't':
+               case 'u':
+               case 'v':
+               case 'w':
+               case 'x':
+               case 'y':
+               case 'z':
+               case 0xC2:
+               case 0xC3:
+               case 0xC4:
+               case 0xC5:
+               case 0xC6:
+               case 0xC7:
+               case 0xC8:
+               case 0xC9:
+               case 0xCA:
+               case 0xCB:
+               case 0xCC:
+               case 0xCD:
+               case 0xCE:
+               case 0xCF:
+               case 0xD0:
+               case 0xD1:
+               case 0xD2:
+               case 0xD3:
+               case 0xD4:
+               case 0xD5:
+               case 0xD6:
+               case 0xD7:
+               case 0xD8:
+               case 0xD9:
+               case 0xDA:
+               case 0xDB:
+               case 0xDC:
+               case 0xDD:
+               case 0xDE:
+               case 0xDF:
+               case 0xE0:
+               case 0xE1:
+               case 0xE2:
+               case 0xE3:
+               case 0xE4:
+               case 0xE5:
+               case 0xE6:
+               case 0xE7:
+               case 0xE8:
+               case 0xE9:
+               case 0xEA:
+               case 0xEB:
+               case 0xEC:
+               case 0xED:
+               case 0xEE:
+               case 0xEF:
+               case 0xF0:
+               case 0xF1:
+               case 0xF2:
+               case 0xF3:
+               case 0xF4: goto yy30;
+               default: goto yy90;
        }
-yy112:
-       YYDEBUG(112, YYPEEK());
+yy90:
+       YYDEBUG(90, YYPEEK());
 #line 261 "../wisitoken_grammar.re2c"
        {*id = 9; continue;}
-#line 3249 "../wisitoken_grammar_re2c.c"
-yy113:
-       YYDEBUG(113, YYPEEK());
+#line 3208 "../wisitoken_grammar_re2c.c"
+yy91:
+       YYDEBUG(91, YYPEEK());
        yyaccept = 7;
        YYSKIP();
        YYBACKUP();
        yych = YYPEEK();
        switch (yych) {
-       case '-':
-       case '0':
-       case '1':
-       case '2':
-       case '3':
-       case '4':
-       case '5':
-       case '6':
-       case '7':
-       case '8':
-       case '9':
-       case 'A':
-       case 'B':
-       case 'C':
-       case 'D':
-       case 'E':
-       case 'F':
-       case 'G':
-       case 'H':
-       case 'I':
-       case 'J':
-       case 'K':
-       case 'L':
-       case 'M':
-       case 'N':
-       case 'O':
-       case 'P':
-       case 'Q':
-       case 'R':
-       case 'S':
-       case 'T':
-       case 'U':
-       case 'V':
-       case 'W':
-       case 'X':
-       case 'Y':
-       case 'Z':
-       case '_':
-       case 'a':
-       case 'b':
-       case 'c':
-       case 'd':
-       case 'e':
-       case 'f':
-       case 'g':
-       case 'h':
-       case 'i':
-       case 'j':
-       case 'k':
-       case 'l':
-       case 'm':
-       case 'n':
-       case 'o':
-       case 'p':
-       case 'q':
-       case 'r':
-       case 's':
-       case 't':
-       case 'u':
-       case 'v':
-       case 'w':
-       case 'x':
-       case 'y':
-       case 'z':
-       case 0xC2:
-       case 0xC3:
-       case 0xC4:
-       case 0xC5:
-       case 0xC6:
-       case 0xC7:
-       case 0xC8:
-       case 0xC9:
-       case 0xCA:
-       case 0xCB:
-       case 0xCC:
-       case 0xCD:
-       case 0xCE:
-       case 0xCF:
-       case 0xD0:
-       case 0xD1:
-       case 0xD2:
-       case 0xD3:
-       case 0xD4:
-       case 0xD5:
-       case 0xD6:
-       case 0xD7:
-       case 0xD8:
-       case 0xD9:
-       case 0xDA:
-       case 0xDB:
-       case 0xDC:
-       case 0xDD:
-       case 0xDE:
-       case 0xDF:
-       case 0xE0:
-       case 0xE1:
-       case 0xE2:
-       case 0xE3:
-       case 0xE4:
-       case 0xE5:
-       case 0xE6:
-       case 0xE7:
-       case 0xE8:
-       case 0xE9:
-       case 0xEA:
-       case 0xEB:
-       case 0xEC:
-       case 0xED:
-       case 0xEE:
-       case 0xEF:
-       case 0xF0:
-       case 0xF1:
-       case 0xF2:
-       case 0xF3:
-       case 0xF4:      goto yy43;
-       default:        goto yy114;
+               case '-':
+               case '0':
+               case '1':
+               case '2':
+               case '3':
+               case '4':
+               case '5':
+               case '6':
+               case '7':
+               case '8':
+               case '9':
+               case 'A':
+               case 'B':
+               case 'C':
+               case 'D':
+               case 'E':
+               case 'F':
+               case 'G':
+               case 'H':
+               case 'I':
+               case 'J':
+               case 'K':
+               case 'L':
+               case 'M':
+               case 'N':
+               case 'O':
+               case 'P':
+               case 'Q':
+               case 'R':
+               case 'S':
+               case 'T':
+               case 'U':
+               case 'V':
+               case 'W':
+               case 'X':
+               case 'Y':
+               case 'Z':
+               case '_':
+               case 'a':
+               case 'b':
+               case 'c':
+               case 'd':
+               case 'e':
+               case 'f':
+               case 'g':
+               case 'h':
+               case 'i':
+               case 'j':
+               case 'k':
+               case 'l':
+               case 'm':
+               case 'n':
+               case 'o':
+               case 'p':
+               case 'q':
+               case 'r':
+               case 's':
+               case 't':
+               case 'u':
+               case 'v':
+               case 'w':
+               case 'x':
+               case 'y':
+               case 'z':
+               case 0xC2:
+               case 0xC3:
+               case 0xC4:
+               case 0xC5:
+               case 0xC6:
+               case 0xC7:
+               case 0xC8:
+               case 0xC9:
+               case 0xCA:
+               case 0xCB:
+               case 0xCC:
+               case 0xCD:
+               case 0xCE:
+               case 0xCF:
+               case 0xD0:
+               case 0xD1:
+               case 0xD2:
+               case 0xD3:
+               case 0xD4:
+               case 0xD5:
+               case 0xD6:
+               case 0xD7:
+               case 0xD8:
+               case 0xD9:
+               case 0xDA:
+               case 0xDB:
+               case 0xDC:
+               case 0xDD:
+               case 0xDE:
+               case 0xDF:
+               case 0xE0:
+               case 0xE1:
+               case 0xE2:
+               case 0xE3:
+               case 0xE4:
+               case 0xE5:
+               case 0xE6:
+               case 0xE7:
+               case 0xE8:
+               case 0xE9:
+               case 0xEA:
+               case 0xEB:
+               case 0xEC:
+               case 0xED:
+               case 0xEE:
+               case 0xEF:
+               case 0xF0:
+               case 0xF1:
+               case 0xF2:
+               case 0xF3:
+               case 0xF4: goto yy30;
+               default: goto yy92;
        }
-yy114:
-       YYDEBUG(114, YYPEEK());
+yy92:
+       YYDEBUG(92, YYPEEK());
 #line 262 "../wisitoken_grammar.re2c"
        {*id = 10; continue;}
-#line 3378 "../wisitoken_grammar_re2c.c"
-yy115:
-       YYDEBUG(115, YYPEEK());
+#line 3337 "../wisitoken_grammar_re2c.c"
+yy93:
+       YYDEBUG(93, YYPEEK());
        yyaccept = 3;
        YYSKIP();
        YYBACKUP();
        yych = YYPEEK();
        switch (yych) {
-       case 'y':       goto yy138;
-       default:        goto yy43;
+               case 'y': goto yy114;
+               default: goto yy30;
        }
-yy116:
-       YYDEBUG(116, YYPEEK());
+yy94:
+       YYDEBUG(94, YYPEEK());
        yyaccept = 3;
        YYSKIP();
        YYBACKUP();
        yych = YYPEEK();
        switch (yych) {
-       case 'n':       goto yy139;
-       default:        goto yy43;
+               case 'n': goto yy115;
+               default: goto yy30;
        }
-yy117:
-       YYDEBUG(117, YYPEEK());
+yy95:
+       YYDEBUG(95, YYPEEK());
        yyaccept = 8;
        YYSKIP();
        YYBACKUP();
        yych = YYPEEK();
        switch (yych) {
-       case '-':
-       case '0':
-       case '1':
-       case '2':
-       case '3':
-       case '4':
-       case '5':
-       case '6':
-       case '7':
-       case '8':
-       case '9':
-       case 'A':
-       case 'B':
-       case 'C':
-       case 'D':
-       case 'E':
-       case 'F':
-       case 'G':
-       case 'H':
-       case 'I':
-       case 'J':
-       case 'K':
-       case 'L':
-       case 'M':
-       case 'N':
-       case 'O':
-       case 'P':
-       case 'Q':
-       case 'R':
-       case 'S':
-       case 'T':
-       case 'U':
-       case 'V':
-       case 'W':
-       case 'X':
-       case 'Y':
-       case 'Z':
-       case '_':
-       case 'a':
-       case 'b':
-       case 'c':
-       case 'd':
-       case 'e':
-       case 'f':
-       case 'g':
-       case 'h':
-       case 'i':
-       case 'j':
-       case 'k':
-       case 'l':
-       case 'm':
-       case 'n':
-       case 'o':
-       case 'p':
-       case 'q':
-       case 'r':
-       case 's':
-       case 't':
-       case 'u':
-       case 'v':
-       case 'w':
-       case 'x':
-       case 'y':
-       case 'z':
-       case 0xC2:
-       case 0xC3:
-       case 0xC4:
-       case 0xC5:
-       case 0xC6:
-       case 0xC7:
-       case 0xC8:
-       case 0xC9:
-       case 0xCA:
-       case 0xCB:
-       case 0xCC:
-       case 0xCD:
-       case 0xCE:
-       case 0xCF:
-       case 0xD0:
-       case 0xD1:
-       case 0xD2:
-       case 0xD3:
-       case 0xD4:
-       case 0xD5:
-       case 0xD6:
-       case 0xD7:
-       case 0xD8:
-       case 0xD9:
-       case 0xDA:
-       case 0xDB:
-       case 0xDC:
-       case 0xDD:
-       case 0xDE:
-       case 0xDF:
-       case 0xE0:
-       case 0xE1:
-       case 0xE2:
-       case 0xE3:
-       case 0xE4:
-       case 0xE5:
-       case 0xE6:
-       case 0xE7:
-       case 0xE8:
-       case 0xE9:
-       case 0xEA:
-       case 0xEB:
-       case 0xEC:
-       case 0xED:
-       case 0xEE:
-       case 0xEF:
-       case 0xF0:
-       case 0xF1:
-       case 0xF2:
-       case 0xF3:
-       case 0xF4:      goto yy43;
-       default:        goto yy118;
+               case '-':
+               case '0':
+               case '1':
+               case '2':
+               case '3':
+               case '4':
+               case '5':
+               case '6':
+               case '7':
+               case '8':
+               case '9':
+               case 'A':
+               case 'B':
+               case 'C':
+               case 'D':
+               case 'E':
+               case 'F':
+               case 'G':
+               case 'H':
+               case 'I':
+               case 'J':
+               case 'K':
+               case 'L':
+               case 'M':
+               case 'N':
+               case 'O':
+               case 'P':
+               case 'Q':
+               case 'R':
+               case 'S':
+               case 'T':
+               case 'U':
+               case 'V':
+               case 'W':
+               case 'X':
+               case 'Y':
+               case 'Z':
+               case '_':
+               case 'a':
+               case 'b':
+               case 'c':
+               case 'd':
+               case 'e':
+               case 'f':
+               case 'g':
+               case 'h':
+               case 'i':
+               case 'j':
+               case 'k':
+               case 'l':
+               case 'm':
+               case 'n':
+               case 'o':
+               case 'p':
+               case 'q':
+               case 'r':
+               case 's':
+               case 't':
+               case 'u':
+               case 'v':
+               case 'w':
+               case 'x':
+               case 'y':
+               case 'z':
+               case 0xC2:
+               case 0xC3:
+               case 0xC4:
+               case 0xC5:
+               case 0xC6:
+               case 0xC7:
+               case 0xC8:
+               case 0xC9:
+               case 0xCA:
+               case 0xCB:
+               case 0xCC:
+               case 0xCD:
+               case 0xCE:
+               case 0xCF:
+               case 0xD0:
+               case 0xD1:
+               case 0xD2:
+               case 0xD3:
+               case 0xD4:
+               case 0xD5:
+               case 0xD6:
+               case 0xD7:
+               case 0xD8:
+               case 0xD9:
+               case 0xDA:
+               case 0xDB:
+               case 0xDC:
+               case 0xDD:
+               case 0xDE:
+               case 0xDF:
+               case 0xE0:
+               case 0xE1:
+               case 0xE2:
+               case 0xE3:
+               case 0xE4:
+               case 0xE5:
+               case 0xE6:
+               case 0xE7:
+               case 0xE8:
+               case 0xE9:
+               case 0xEA:
+               case 0xEB:
+               case 0xEC:
+               case 0xED:
+               case 0xEE:
+               case 0xEF:
+               case 0xF0:
+               case 0xF1:
+               case 0xF2:
+               case 0xF3:
+               case 0xF4: goto yy30;
+               default: goto yy96;
        }
-yy118:
-       YYDEBUG(118, YYPEEK());
+yy96:
+       YYDEBUG(96, YYPEEK());
 #line 265 "../wisitoken_grammar.re2c"
        {*id = 13; continue;}
-#line 3527 "../wisitoken_grammar_re2c.c"
-yy119:
-       YYDEBUG(119, YYPEEK());
+#line 3486 "../wisitoken_grammar_re2c.c"
+yy97:
+       YYDEBUG(97, YYPEEK());
        yyaccept = 3;
        YYSKIP();
        YYBACKUP();
        yych = YYPEEK();
        switch (yych) {
-       case 'k':       goto yy140;
-       default:        goto yy43;
+               case 'k': goto yy116;
+               default: goto yy30;
        }
-yy120:
-       YYDEBUG(120, YYPEEK());
+yy98:
+       YYDEBUG(98, YYPEEK());
        YYSKIP();
-       YYDEBUG(121, YYPEEK());
 #line 274 "../wisitoken_grammar.re2c"
        {*id = 22; continue;}
-#line 3544 "../wisitoken_grammar_re2c.c"
-yy122:
-       YYDEBUG(122, YYPEEK());
+#line 3502 "../wisitoken_grammar_re2c.c"
+yy99:
+       YYDEBUG(99, YYPEEK());
        YYSKIP();
-       YYDEBUG(123, YYPEEK());
 #line 254 "../wisitoken_grammar.re2c"
        {*id = 2; if (lexer->cursor[-1] == 0x0a || (lexer->cursor[-1] == 0x0d 
&& lexer->cursor[-2] == 0x0a)) lexer->line++; continue;}
-#line 3551 "../wisitoken_grammar_re2c.c"
-yy124:
-       YYDEBUG(124, YYPEEK());
+#line 3508 "../wisitoken_grammar_re2c.c"
+yy100:
+       YYDEBUG(100, YYPEEK());
        YYSKIP();
        yych = YYPEEK();
        switch (yych) {
-       case 0x80:
-       case 0x81:
-       case 0x82:
-       case 0x83:
-       case 0x84:
-       case 0x85:
-       case 0x86:
-       case 0x87:
-       case 0x88:
-       case 0x89:
-       case 0x8A:
-       case 0x8B:
-       case 0x8C:
-       case 0x8D:
-       case 0x8E:
-       case 0x8F:
-       case 0x90:
-       case 0x91:
-       case 0x92:
-       case 0x93:
-       case 0x94:
-       case 0x95:
-       case 0x96:
-       case 0x97:
-       case 0x98:
-       case 0x99:
-       case 0x9A:
-       case 0x9B:
-       case 0x9C:
-       case 0x9D:
-       case 0x9E:
-       case 0x9F:
-       case 0xA0:
-       case 0xA1:
-       case 0xA2:
-       case 0xA3:
-       case 0xA4:
-       case 0xA5:
-       case 0xA6:
-       case 0xA7:
-       case 0xA8:
-       case 0xA9:
-       case 0xAA:
-       case 0xAB:
-       case 0xAC:
-       case 0xAD:
-       case 0xAE:
-       case 0xAF:
-       case 0xB0:
-       case 0xB1:
-       case 0xB2:
-       case 0xB3:
-       case 0xB4:
-       case 0xB5:
-       case 0xB6:
-       case 0xB7:
-       case 0xB8:
-       case 0xB9:
-       case 0xBA:
-       case 0xBB:
-       case 0xBC:
-       case 0xBD:
-       case 0xBE:
-       case 0xBF:      goto yy97;
-       default:        goto yy71;
+               case 0x80:
+               case 0x81:
+               case 0x82:
+               case 0x83:
+               case 0x84:
+               case 0x85:
+               case 0x86:
+               case 0x87:
+               case 0x88:
+               case 0x89:
+               case 0x8A:
+               case 0x8B:
+               case 0x8C:
+               case 0x8D:
+               case 0x8E:
+               case 0x8F:
+               case 0x90:
+               case 0x91:
+               case 0x92:
+               case 0x93:
+               case 0x94:
+               case 0x95:
+               case 0x96:
+               case 0x97:
+               case 0x98:
+               case 0x99:
+               case 0x9A:
+               case 0x9B:
+               case 0x9C:
+               case 0x9D:
+               case 0x9E:
+               case 0x9F:
+               case 0xA0:
+               case 0xA1:
+               case 0xA2:
+               case 0xA3:
+               case 0xA4:
+               case 0xA5:
+               case 0xA6:
+               case 0xA7:
+               case 0xA8:
+               case 0xA9:
+               case 0xAA:
+               case 0xAB:
+               case 0xAC:
+               case 0xAD:
+               case 0xAE:
+               case 0xAF:
+               case 0xB0:
+               case 0xB1:
+               case 0xB2:
+               case 0xB3:
+               case 0xB4:
+               case 0xB5:
+               case 0xB6:
+               case 0xB7:
+               case 0xB8:
+               case 0xB9:
+               case 0xBA:
+               case 0xBB:
+               case 0xBC:
+               case 0xBD:
+               case 0xBE:
+               case 0xBF: goto yy76;
+               default: goto yy53;
        }
-yy125:
-       YYDEBUG(125, YYPEEK());
+yy101:
+       YYDEBUG(101, YYPEEK());
        YYSKIP();
        yych = YYPEEK();
        switch (yych) {
-       case 0xA0:
-       case 0xA1:
-       case 0xA2:
-       case 0xA3:
-       case 0xA4:
-       case 0xA5:
-       case 0xA6:
-       case 0xA7:
-       case 0xA8:
-       case 0xA9:
-       case 0xAA:
-       case 0xAB:
-       case 0xAC:
-       case 0xAD:
-       case 0xAE:
-       case 0xAF:
-       case 0xB0:
-       case 0xB1:
-       case 0xB2:
-       case 0xB3:
-       case 0xB4:
-       case 0xB5:
-       case 0xB6:
-       case 0xB7:
-       case 0xB8:
-       case 0xB9:
-       case 0xBA:
-       case 0xBB:
-       case 0xBC:
-       case 0xBD:
-       case 0xBE:
-       case 0xBF:      goto yy124;
-       default:        goto yy71;
+               case 0xA0:
+               case 0xA1:
+               case 0xA2:
+               case 0xA3:
+               case 0xA4:
+               case 0xA5:
+               case 0xA6:
+               case 0xA7:
+               case 0xA8:
+               case 0xA9:
+               case 0xAA:
+               case 0xAB:
+               case 0xAC:
+               case 0xAD:
+               case 0xAE:
+               case 0xAF:
+               case 0xB0:
+               case 0xB1:
+               case 0xB2:
+               case 0xB3:
+               case 0xB4:
+               case 0xB5:
+               case 0xB6:
+               case 0xB7:
+               case 0xB8:
+               case 0xB9:
+               case 0xBA:
+               case 0xBB:
+               case 0xBC:
+               case 0xBD:
+               case 0xBE:
+               case 0xBF: goto yy100;
+               default: goto yy53;
        }
-yy126:
-       YYDEBUG(126, YYPEEK());
+yy102:
+       YYDEBUG(102, YYPEEK());
        YYSKIP();
        yych = YYPEEK();
        switch (yych) {
-       case 0x80:
-       case 0x81:
-       case 0x82:
-       case 0x83:
-       case 0x84:
-       case 0x85:
-       case 0x86:
-       case 0x87:
-       case 0x88:
-       case 0x89:
-       case 0x8A:
-       case 0x8B:
-       case 0x8C:
-       case 0x8D:
-       case 0x8E:
-       case 0x8F:
-       case 0x90:
-       case 0x91:
-       case 0x92:
-       case 0x93:
-       case 0x94:
-       case 0x95:
-       case 0x96:
-       case 0x97:
-       case 0x98:
-       case 0x99:
-       case 0x9A:
-       case 0x9B:
-       case 0x9C:
-       case 0x9D:
-       case 0x9E:
-       case 0x9F:
-       case 0xA0:
-       case 0xA1:
-       case 0xA2:
-       case 0xA3:
-       case 0xA4:
-       case 0xA5:
-       case 0xA6:
-       case 0xA7:
-       case 0xA8:
-       case 0xA9:
-       case 0xAA:
-       case 0xAB:
-       case 0xAC:
-       case 0xAD:
-       case 0xAE:
-       case 0xAF:
-       case 0xB0:
-       case 0xB1:
-       case 0xB2:
-       case 0xB3:
-       case 0xB4:
-       case 0xB5:
-       case 0xB6:
-       case 0xB7:
-       case 0xB8:
-       case 0xB9:
-       case 0xBA:
-       case 0xBB:
-       case 0xBC:
-       case 0xBD:
-       case 0xBE:
-       case 0xBF:      goto yy124;
-       default:        goto yy71;
+               case 0x80:
+               case 0x81:
+               case 0x82:
+               case 0x83:
+               case 0x84:
+               case 0x85:
+               case 0x86:
+               case 0x87:
+               case 0x88:
+               case 0x89:
+               case 0x8A:
+               case 0x8B:
+               case 0x8C:
+               case 0x8D:
+               case 0x8E:
+               case 0x8F:
+               case 0x90:
+               case 0x91:
+               case 0x92:
+               case 0x93:
+               case 0x94:
+               case 0x95:
+               case 0x96:
+               case 0x97:
+               case 0x98:
+               case 0x99:
+               case 0x9A:
+               case 0x9B:
+               case 0x9C:
+               case 0x9D:
+               case 0x9E:
+               case 0x9F:
+               case 0xA0:
+               case 0xA1:
+               case 0xA2:
+               case 0xA3:
+               case 0xA4:
+               case 0xA5:
+               case 0xA6:
+               case 0xA7:
+               case 0xA8:
+               case 0xA9:
+               case 0xAA:
+               case 0xAB:
+               case 0xAC:
+               case 0xAD:
+               case 0xAE:
+               case 0xAF:
+               case 0xB0:
+               case 0xB1:
+               case 0xB2:
+               case 0xB3:
+               case 0xB4:
+               case 0xB5:
+               case 0xB6:
+               case 0xB7:
+               case 0xB8:
+               case 0xB9:
+               case 0xBA:
+               case 0xBB:
+               case 0xBC:
+               case 0xBD:
+               case 0xBE:
+               case 0xBF: goto yy100;
+               default: goto yy53;
        }
-yy127:
-       YYDEBUG(127, YYPEEK());
+yy103:
+       YYDEBUG(103, YYPEEK());
        YYSKIP();
        yych = YYPEEK();
        switch (yych) {
-       case 0x90:
-       case 0x91:
-       case 0x92:
-       case 0x93:
-       case 0x94:
-       case 0x95:
-       case 0x96:
-       case 0x97:
-       case 0x98:
-       case 0x99:
-       case 0x9A:
-       case 0x9B:
-       case 0x9C:
-       case 0x9D:
-       case 0x9E:
-       case 0x9F:
-       case 0xA0:
-       case 0xA1:
-       case 0xA2:
-       case 0xA3:
-       case 0xA4:
-       case 0xA5:
-       case 0xA6:
-       case 0xA7:
-       case 0xA8:
-       case 0xA9:
-       case 0xAA:
-       case 0xAB:
-       case 0xAC:
-       case 0xAD:
-       case 0xAE:
-       case 0xAF:
-       case 0xB0:
-       case 0xB1:
-       case 0xB2:
-       case 0xB3:
-       case 0xB4:
-       case 0xB5:
-       case 0xB6:
-       case 0xB7:
-       case 0xB8:
-       case 0xB9:
-       case 0xBA:
-       case 0xBB:
-       case 0xBC:
-       case 0xBD:
-       case 0xBE:
-       case 0xBF:      goto yy126;
-       default:        goto yy71;
+               case 0x90:
+               case 0x91:
+               case 0x92:
+               case 0x93:
+               case 0x94:
+               case 0x95:
+               case 0x96:
+               case 0x97:
+               case 0x98:
+               case 0x99:
+               case 0x9A:
+               case 0x9B:
+               case 0x9C:
+               case 0x9D:
+               case 0x9E:
+               case 0x9F:
+               case 0xA0:
+               case 0xA1:
+               case 0xA2:
+               case 0xA3:
+               case 0xA4:
+               case 0xA5:
+               case 0xA6:
+               case 0xA7:
+               case 0xA8:
+               case 0xA9:
+               case 0xAA:
+               case 0xAB:
+               case 0xAC:
+               case 0xAD:
+               case 0xAE:
+               case 0xAF:
+               case 0xB0:
+               case 0xB1:
+               case 0xB2:
+               case 0xB3:
+               case 0xB4:
+               case 0xB5:
+               case 0xB6:
+               case 0xB7:
+               case 0xB8:
+               case 0xB9:
+               case 0xBA:
+               case 0xBB:
+               case 0xBC:
+               case 0xBD:
+               case 0xBE:
+               case 0xBF: goto yy102;
+               default: goto yy53;
        }
-yy128:
-       YYDEBUG(128, YYPEEK());
+yy104:
+       YYDEBUG(104, YYPEEK());
        YYSKIP();
        yych = YYPEEK();
        switch (yych) {
-       case 0x80:
-       case 0x81:
-       case 0x82:
-       case 0x83:
-       case 0x84:
-       case 0x85:
-       case 0x86:
-       case 0x87:
-       case 0x88:
-       case 0x89:
-       case 0x8A:
-       case 0x8B:
-       case 0x8C:
-       case 0x8D:
-       case 0x8E:
-       case 0x8F:
-       case 0x90:
-       case 0x91:
-       case 0x92:
-       case 0x93:
-       case 0x94:
-       case 0x95:
-       case 0x96:
-       case 0x97:
-       case 0x98:
-       case 0x99:
-       case 0x9A:
-       case 0x9B:
-       case 0x9C:
-       case 0x9D:
-       case 0x9E:
-       case 0x9F:
-       case 0xA0:
-       case 0xA1:
-       case 0xA2:
-       case 0xA3:
-       case 0xA4:
-       case 0xA5:
-       case 0xA6:
-       case 0xA7:
-       case 0xA8:
-       case 0xA9:
-       case 0xAA:
-       case 0xAB:
-       case 0xAC:
-       case 0xAD:
-       case 0xAE:
-       case 0xAF:
-       case 0xB0:
-       case 0xB1:
-       case 0xB2:
-       case 0xB3:
-       case 0xB4:
-       case 0xB5:
-       case 0xB6:
-       case 0xB7:
-       case 0xB8:
-       case 0xB9:
-       case 0xBA:
-       case 0xBB:
-       case 0xBC:
-       case 0xBD:
-       case 0xBE:
-       case 0xBF:      goto yy126;
-       default:        goto yy71;
+               case 0x80:
+               case 0x81:
+               case 0x82:
+               case 0x83:
+               case 0x84:
+               case 0x85:
+               case 0x86:
+               case 0x87:
+               case 0x88:
+               case 0x89:
+               case 0x8A:
+               case 0x8B:
+               case 0x8C:
+               case 0x8D:
+               case 0x8E:
+               case 0x8F:
+               case 0x90:
+               case 0x91:
+               case 0x92:
+               case 0x93:
+               case 0x94:
+               case 0x95:
+               case 0x96:
+               case 0x97:
+               case 0x98:
+               case 0x99:
+               case 0x9A:
+               case 0x9B:
+               case 0x9C:
+               case 0x9D:
+               case 0x9E:
+               case 0x9F:
+               case 0xA0:
+               case 0xA1:
+               case 0xA2:
+               case 0xA3:
+               case 0xA4:
+               case 0xA5:
+               case 0xA6:
+               case 0xA7:
+               case 0xA8:
+               case 0xA9:
+               case 0xAA:
+               case 0xAB:
+               case 0xAC:
+               case 0xAD:
+               case 0xAE:
+               case 0xAF:
+               case 0xB0:
+               case 0xB1:
+               case 0xB2:
+               case 0xB3:
+               case 0xB4:
+               case 0xB5:
+               case 0xB6:
+               case 0xB7:
+               case 0xB8:
+               case 0xB9:
+               case 0xBA:
+               case 0xBB:
+               case 0xBC:
+               case 0xBD:
+               case 0xBE:
+               case 0xBF: goto yy102;
+               default: goto yy53;
        }
-yy129:
-       YYDEBUG(129, YYPEEK());
+yy105:
+       YYDEBUG(105, YYPEEK());
        YYSKIP();
        yych = YYPEEK();
        switch (yych) {
-       case 0x80:
-       case 0x81:
-       case 0x82:
-       case 0x83:
-       case 0x84:
-       case 0x85:
-       case 0x86:
-       case 0x87:
-       case 0x88:
-       case 0x89:
-       case 0x8A:
-       case 0x8B:
-       case 0x8C:
-       case 0x8D:
-       case 0x8E:
-       case 0x8F:      goto yy126;
-       default:        goto yy71;
+               case 0x80:
+               case 0x81:
+               case 0x82:
+               case 0x83:
+               case 0x84:
+               case 0x85:
+               case 0x86:
+               case 0x87:
+               case 0x88:
+               case 0x89:
+               case 0x8A:
+               case 0x8B:
+               case 0x8C:
+               case 0x8D:
+               case 0x8E:
+               case 0x8F: goto yy102;
+               default: goto yy53;
        }
-yy130:
-       YYDEBUG(130, YYPEEK());
+yy106:
+       YYDEBUG(106, YYPEEK());
        yyaccept = 3;
        YYSKIP();
        YYBACKUP();
        yych = YYPEEK();
        switch (yych) {
-       case 'E':
-       case 'e':       goto yy141;
-       default:        goto yy43;
+               case 'E':
+               case 'e': goto yy117;
+               default: goto yy30;
        }
-yy131:
-       YYDEBUG(131, YYPEEK());
+yy107:
+       YYDEBUG(107, YYPEEK());
        yyaccept = 3;
        YYSKIP();
        YYBACKUP();
        yych = YYPEEK();
        switch (yych) {
-       case 'U':
-       case 'u':       goto yy142;
-       default:        goto yy43;
+               case 'U':
+               case 'u': goto yy118;
+               default: goto yy30;
        }
-yy132:
-       YYDEBUG(132, YYPEEK());
+yy108:
+       YYDEBUG(108, YYPEEK());
        yyaccept = 3;
        YYSKIP();
        YYBACKUP();
        yych = YYPEEK();
        switch (yych) {
-       case 'F':
-       case 'f':       goto yy143;
-       default:        goto yy43;
+               case 'F':
+               case 'f': goto yy119;
+               default: goto yy30;
        }
-yy133:
-       YYDEBUG(133, YYPEEK());
+yy109:
+       YYDEBUG(109, YYPEEK());
        yyaccept = 3;
        YYSKIP();
        YYBACKUP();
        yych = YYPEEK();
        switch (yych) {
-       case 'e':       goto yy144;
-       default:        goto yy43;
+               case 'e': goto yy120;
+               default: goto yy30;
        }
-yy134:
-       YYDEBUG(134, YYPEEK());
+yy110:
+       YYDEBUG(110, YYPEEK());
        yyaccept = 3;
        YYSKIP();
        YYBACKUP();
        yych = YYPEEK();
        switch (yych) {
-       case 'f':       goto yy146;
-       default:        goto yy43;
+               case 'f': goto yy122;
+               default: goto yy30;
        }
-yy135:
-       YYDEBUG(135, YYPEEK());
+yy111:
+       YYDEBUG(111, YYPEEK());
        yyaccept = 3;
        YYSKIP();
        YYBACKUP();
        yych = YYPEEK();
        switch (yych) {
-       case 'i':       goto yy147;
-       default:        goto yy43;
+               case 'i': goto yy123;
+               default: goto yy30;
        }
-yy136:
-       YYDEBUG(136, YYPEEK());
+yy112:
+       YYDEBUG(112, YYPEEK());
        yyaccept = 9;
        YYSKIP();
        YYBACKUP();
        yych = YYPEEK();
        switch (yych) {
-       case '-':
-       case '0':
-       case '1':
-       case '2':
-       case '3':
-       case '4':
-       case '5':
-       case '6':
-       case '7':
-       case '8':
-       case '9':
-       case 'A':
-       case 'B':
-       case 'C':
-       case 'D':
-       case 'E':
-       case 'F':
-       case 'G':
-       case 'H':
-       case 'I':
-       case 'J':
-       case 'K':
-       case 'L':
-       case 'M':
-       case 'N':
-       case 'O':
-       case 'P':
-       case 'Q':
-       case 'R':
-       case 'S':
-       case 'T':
-       case 'U':
-       case 'V':
-       case 'W':
-       case 'X':
-       case 'Y':
-       case 'Z':
-       case '_':
-       case 'a':
-       case 'b':
-       case 'c':
-       case 'd':
-       case 'e':
-       case 'f':
-       case 'g':
-       case 'h':
-       case 'i':
-       case 'j':
-       case 'k':
-       case 'l':
-       case 'm':
-       case 'n':
-       case 'o':
-       case 'p':
-       case 'q':
-       case 'r':
-       case 's':
-       case 't':
-       case 'u':
-       case 'v':
-       case 'w':
-       case 'x':
-       case 'y':
-       case 'z':
-       case 0xC2:
-       case 0xC3:
-       case 0xC4:
-       case 0xC5:
-       case 0xC6:
-       case 0xC7:
-       case 0xC8:
-       case 0xC9:
-       case 0xCA:
-       case 0xCB:
-       case 0xCC:
-       case 0xCD:
-       case 0xCE:
-       case 0xCF:
-       case 0xD0:
-       case 0xD1:
-       case 0xD2:
-       case 0xD3:
-       case 0xD4:
-       case 0xD5:
-       case 0xD6:
-       case 0xD7:
-       case 0xD8:
-       case 0xD9:
-       case 0xDA:
-       case 0xDB:
-       case 0xDC:
-       case 0xDD:
-       case 0xDE:
-       case 0xDF:
-       case 0xE0:
-       case 0xE1:
-       case 0xE2:
-       case 0xE3:
-       case 0xE4:
-       case 0xE5:
-       case 0xE6:
-       case 0xE7:
-       case 0xE8:
-       case 0xE9:
-       case 0xEA:
-       case 0xEB:
-       case 0xEC:
-       case 0xED:
-       case 0xEE:
-       case 0xEF:
-       case 0xF0:
-       case 0xF1:
-       case 0xF2:
-       case 0xF3:
-       case 0xF4:      goto yy43;
-       default:        goto yy137;
+               case '-':
+               case '0':
+               case '1':
+               case '2':
+               case '3':
+               case '4':
+               case '5':
+               case '6':
+               case '7':
+               case '8':
+               case '9':
+               case 'A':
+               case 'B':
+               case 'C':
+               case 'D':
+               case 'E':
+               case 'F':
+               case 'G':
+               case 'H':
+               case 'I':
+               case 'J':
+               case 'K':
+               case 'L':
+               case 'M':
+               case 'N':
+               case 'O':
+               case 'P':
+               case 'Q':
+               case 'R':
+               case 'S':
+               case 'T':
+               case 'U':
+               case 'V':
+               case 'W':
+               case 'X':
+               case 'Y':
+               case 'Z':
+               case '_':
+               case 'a':
+               case 'b':
+               case 'c':
+               case 'd':
+               case 'e':
+               case 'f':
+               case 'g':
+               case 'h':
+               case 'i':
+               case 'j':
+               case 'k':
+               case 'l':
+               case 'm':
+               case 'n':
+               case 'o':
+               case 'p':
+               case 'q':
+               case 'r':
+               case 's':
+               case 't':
+               case 'u':
+               case 'v':
+               case 'w':
+               case 'x':
+               case 'y':
+               case 'z':
+               case 0xC2:
+               case 0xC3:
+               case 0xC4:
+               case 0xC5:
+               case 0xC6:
+               case 0xC7:
+               case 0xC8:
+               case 0xC9:
+               case 0xCA:
+               case 0xCB:
+               case 0xCC:
+               case 0xCD:
+               case 0xCE:
+               case 0xCF:
+               case 0xD0:
+               case 0xD1:
+               case 0xD2:
+               case 0xD3:
+               case 0xD4:
+               case 0xD5:
+               case 0xD6:
+               case 0xD7:
+               case 0xD8:
+               case 0xD9:
+               case 0xDA:
+               case 0xDB:
+               case 0xDC:
+               case 0xDD:
+               case 0xDE:
+               case 0xDF:
+               case 0xE0:
+               case 0xE1:
+               case 0xE2:
+               case 0xE3:
+               case 0xE4:
+               case 0xE5:
+               case 0xE6:
+               case 0xE7:
+               case 0xE8:
+               case 0xE9:
+               case 0xEA:
+               case 0xEB:
+               case 0xEC:
+               case 0xED:
+               case 0xEE:
+               case 0xEF:
+               case 0xF0:
+               case 0xF1:
+               case 0xF2:
+               case 0xF3:
+               case 0xF4: goto yy30;
+               default: goto yy113;
        }
-yy137:
-       YYDEBUG(137, YYPEEK());
+yy113:
+       YYDEBUG(113, YYPEEK());
 #line 259 "../wisitoken_grammar.re2c"
        {*id = 7; continue;}
-#line 4073 "../wisitoken_grammar_re2c.c"
-yy138:
-       YYDEBUG(138, YYPEEK());
+#line 4030 "../wisitoken_grammar_re2c.c"
+yy114:
+       YYDEBUG(114, YYPEEK());
        yyaccept = 3;
        YYSKIP();
        YYBACKUP();
        yych = YYPEEK();
        switch (yych) {
-       case 'w':       goto yy148;
-       default:        goto yy43;
+               case 'w': goto yy124;
+               default: goto yy30;
        }
-yy139:
-       YYDEBUG(139, YYPEEK());
+yy115:
+       YYDEBUG(115, YYPEEK());
        yyaccept = 3;
        YYSKIP();
        YYBACKUP();
        yych = YYPEEK();
        switch (yych) {
-       case '_':       goto yy149;
-       default:        goto yy43;
+               case '_': goto yy125;
+               default: goto yy30;
        }
-yy140:
-       YYDEBUG(140, YYPEEK());
+yy116:
+       YYDEBUG(116, YYPEEK());
        yyaccept = 3;
        YYSKIP();
        YYBACKUP();
        yych = YYPEEK();
        switch (yych) {
-       case 'e':       goto yy150;
-       default:        goto yy43;
+               case 'e': goto yy126;
+               default: goto yy30;
        }
-yy141:
-       YYDEBUG(141, YYPEEK());
+yy117:
+       YYDEBUG(117, YYPEEK());
        yyaccept = 3;
        YYSKIP();
        YYBACKUP();
        yych = YYPEEK();
        switch (yych) {
-       case 'P':
-       case 'p':       goto yy151;
-       default:        goto yy43;
+               case 'P':
+               case 'p': goto yy127;
+               default: goto yy30;
        }
-yy142:
-       YYDEBUG(142, YYPEEK());
+yy118:
+       YYDEBUG(118, YYPEEK());
        yyaccept = 3;
        YYSKIP();
        YYBACKUP();
        yych = YYPEEK();
        switch (yych) {
-       case 'C':
-       case 'c':       goto yy152;
-       default:        goto yy43;
+               case 'C':
+               case 'c': goto yy128;
+               default: goto yy30;
        }
-yy143:
-       YYDEBUG(143, YYPEEK());
+yy119:
+       YYDEBUG(119, YYPEEK());
        yyaccept = 3;
        YYSKIP();
        YYBACKUP();
        yych = YYPEEK();
        switch (yych) {
-       case 'T':
-       case 't':       goto yy153;
-       default:        goto yy43;
+               case 'T':
+               case 't': goto yy129;
+               default: goto yy30;
        }
-yy144:
-       YYDEBUG(144, YYPEEK());
+yy120:
+       YYDEBUG(120, YYPEEK());
        yyaccept = 10;
        YYSKIP();
        YYBACKUP();
        yych = YYPEEK();
        switch (yych) {
-       case '-':
-       case '0':
-       case '1':
-       case '2':
-       case '3':
-       case '4':
-       case '5':
-       case '6':
-       case '7':
-       case '8':
-       case '9':
-       case 'A':
-       case 'B':
-       case 'C':
-       case 'D':
-       case 'E':
-       case 'F':
-       case 'G':
-       case 'H':
-       case 'I':
-       case 'J':
-       case 'K':
-       case 'L':
-       case 'M':
-       case 'N':
-       case 'O':
-       case 'P':
-       case 'Q':
-       case 'R':
-       case 'S':
-       case 'T':
-       case 'U':
-       case 'V':
-       case 'W':
-       case 'X':
-       case 'Y':
-       case 'Z':
-       case '_':
-       case 'a':
-       case 'b':
-       case 'c':
-       case 'd':
-       case 'e':
-       case 'f':
-       case 'g':
-       case 'h':
-       case 'i':
-       case 'j':
-       case 'k':
-       case 'l':
-       case 'm':
-       case 'n':
-       case 'o':
-       case 'p':
-       case 'q':
-       case 'r':
-       case 's':
-       case 't':
-       case 'u':
-       case 'v':
-       case 'w':
-       case 'x':
-       case 'y':
-       case 'z':
-       case 0xC2:
-       case 0xC3:
-       case 0xC4:
-       case 0xC5:
-       case 0xC6:
-       case 0xC7:
-       case 0xC8:
-       case 0xC9:
-       case 0xCA:
-       case 0xCB:
-       case 0xCC:
-       case 0xCD:
-       case 0xCE:
-       case 0xCF:
-       case 0xD0:
-       case 0xD1:
-       case 0xD2:
-       case 0xD3:
-       case 0xD4:
-       case 0xD5:
-       case 0xD6:
-       case 0xD7:
-       case 0xD8:
-       case 0xD9:
-       case 0xDA:
-       case 0xDB:
-       case 0xDC:
-       case 0xDD:
-       case 0xDE:
-       case 0xDF:
-       case 0xE0:
-       case 0xE1:
-       case 0xE2:
-       case 0xE3:
-       case 0xE4:
-       case 0xE5:
-       case 0xE6:
-       case 0xE7:
-       case 0xE8:
-       case 0xE9:
-       case 0xEA:
-       case 0xEB:
-       case 0xEC:
-       case 0xED:
-       case 0xEE:
-       case 0xEF:
-       case 0xF0:
-       case 0xF1:
-       case 0xF2:
-       case 0xF3:
-       case 0xF4:      goto yy43;
-       default:        goto yy145;
+               case '-':
+               case '0':
+               case '1':
+               case '2':
+               case '3':
+               case '4':
+               case '5':
+               case '6':
+               case '7':
+               case '8':
+               case '9':
+               case 'A':
+               case 'B':
+               case 'C':
+               case 'D':
+               case 'E':
+               case 'F':
+               case 'G':
+               case 'H':
+               case 'I':
+               case 'J':
+               case 'K':
+               case 'L':
+               case 'M':
+               case 'N':
+               case 'O':
+               case 'P':
+               case 'Q':
+               case 'R':
+               case 'S':
+               case 'T':
+               case 'U':
+               case 'V':
+               case 'W':
+               case 'X':
+               case 'Y':
+               case 'Z':
+               case '_':
+               case 'a':
+               case 'b':
+               case 'c':
+               case 'd':
+               case 'e':
+               case 'f':
+               case 'g':
+               case 'h':
+               case 'i':
+               case 'j':
+               case 'k':
+               case 'l':
+               case 'm':
+               case 'n':
+               case 'o':
+               case 'p':
+               case 'q':
+               case 'r':
+               case 's':
+               case 't':
+               case 'u':
+               case 'v':
+               case 'w':
+               case 'x':
+               case 'y':
+               case 'z':
+               case 0xC2:
+               case 0xC3:
+               case 0xC4:
+               case 0xC5:
+               case 0xC6:
+               case 0xC7:
+               case 0xC8:
+               case 0xC9:
+               case 0xCA:
+               case 0xCB:
+               case 0xCC:
+               case 0xCD:
+               case 0xCE:
+               case 0xCF:
+               case 0xD0:
+               case 0xD1:
+               case 0xD2:
+               case 0xD3:
+               case 0xD4:
+               case 0xD5:
+               case 0xD6:
+               case 0xD7:
+               case 0xD8:
+               case 0xD9:
+               case 0xDA:
+               case 0xDB:
+               case 0xDC:
+               case 0xDD:
+               case 0xDE:
+               case 0xDF:
+               case 0xE0:
+               case 0xE1:
+               case 0xE2:
+               case 0xE3:
+               case 0xE4:
+               case 0xE5:
+               case 0xE6:
+               case 0xE7:
+               case 0xE8:
+               case 0xE9:
+               case 0xEA:
+               case 0xEB:
+               case 0xEC:
+               case 0xED:
+               case 0xEE:
+               case 0xEF:
+               case 0xF0:
+               case 0xF1:
+               case 0xF2:
+               case 0xF3:
+               case 0xF4: goto yy30;
+               default: goto yy121;
        }
-yy145:
-       YYDEBUG(145, YYPEEK());
+yy121:
+       YYDEBUG(121, YYPEEK());
 #line 256 "../wisitoken_grammar.re2c"
        {*id = 4; continue;}
-#line 4265 "../wisitoken_grammar_re2c.c"
-yy146:
-       YYDEBUG(146, YYPEEK());
+#line 4222 "../wisitoken_grammar_re2c.c"
+yy122:
+       YYDEBUG(122, YYPEEK());
        yyaccept = 3;
        YYSKIP();
        YYBACKUP();
        yych = YYPEEK();
        switch (yych) {
-       case 'l':       goto yy155;
-       default:        goto yy43;
+               case 'l': goto yy131;
+               default: goto yy30;
        }
-yy147:
-       YYDEBUG(147, YYPEEK());
+yy123:
+       YYDEBUG(123, YYPEEK());
        yyaccept = 3;
        YYSKIP();
        YYBACKUP();
        yych = YYPEEK();
        switch (yych) {
-       case 'f':       goto yy156;
-       default:        goto yy43;
+               case 'f': goto yy132;
+               default: goto yy30;
        }
-yy148:
-       YYDEBUG(148, YYPEEK());
+yy124:
+       YYDEBUG(124, YYPEEK());
        yyaccept = 3;
        YYSKIP();
        YYBACKUP();
        yych = YYPEEK();
        switch (yych) {
-       case 'o':       goto yy158;
-       default:        goto yy43;
+               case 'o': goto yy134;
+               default: goto yy30;
        }
-yy149:
-       YYDEBUG(149, YYPEEK());
+yy125:
+       YYDEBUG(125, YYPEEK());
        yyaccept = 3;
        YYSKIP();
        YYBACKUP();
        yych = YYPEEK();
        switch (yych) {
-       case 'g':       goto yy159;
-       default:        goto yy43;
+               case 'g': goto yy135;
+               default: goto yy30;
        }
-yy150:
-       YYDEBUG(150, YYPEEK());
+yy126:
+       YYDEBUG(126, YYPEEK());
        yyaccept = 3;
        YYSKIP();
        YYBACKUP();
        yych = YYPEEK();
        switch (yych) {
-       case 'n':       goto yy160;
-       default:        goto yy43;
+               case 'n': goto yy136;
+               default: goto yy30;
        }
-yy151:
-       YYDEBUG(151, YYPEEK());
+yy127:
+       YYDEBUG(127, YYPEEK());
        yyaccept = 3;
        YYSKIP();
        YYBACKUP();
        yych = YYPEEK();
        switch (yych) {
-       case 'T':
-       case 't':       goto yy162;
-       default:        goto yy43;
+               case 'T':
+               case 't': goto yy138;
+               default: goto yy30;
        }
-yy152:
-       YYDEBUG(152, YYPEEK());
+yy128:
+       YYDEBUG(128, YYPEEK());
        yyaccept = 3;
        YYSKIP();
        YYBACKUP();
        yych = YYPEEK();
        switch (yych) {
-       case 'E':
-       case 'e':       goto yy163;
-       default:        goto yy43;
+               case 'E':
+               case 'e': goto yy139;
+               default: goto yy30;
        }
-yy153:
-       YYDEBUG(153, YYPEEK());
+yy129:
+       YYDEBUG(129, YYPEEK());
        yyaccept = 11;
        YYSKIP();
        YYBACKUP();
        yych = YYPEEK();
        switch (yych) {
-       case '-':
-       case '0':
-       case '1':
-       case '2':
-       case '3':
-       case '4':
-       case '5':
-       case '6':
-       case '7':
-       case '8':
-       case '9':
-       case 'A':
-       case 'B':
-       case 'C':
-       case 'D':
-       case 'E':
-       case 'F':
-       case 'G':
-       case 'H':
-       case 'I':
-       case 'J':
-       case 'K':
-       case 'L':
-       case 'M':
-       case 'N':
-       case 'O':
-       case 'P':
-       case 'Q':
-       case 'R':
-       case 'S':
-       case 'T':
-       case 'U':
-       case 'V':
-       case 'W':
-       case 'X':
-       case 'Y':
-       case 'Z':
-       case '_':
-       case 'a':
-       case 'b':
-       case 'c':
-       case 'd':
-       case 'e':
-       case 'f':
-       case 'g':
-       case 'h':
-       case 'i':
-       case 'j':
-       case 'k':
-       case 'l':
-       case 'm':
-       case 'n':
-       case 'o':
-       case 'p':
-       case 'q':
-       case 'r':
-       case 's':
-       case 't':
-       case 'u':
-       case 'v':
-       case 'w':
-       case 'x':
-       case 'y':
-       case 'z':
-       case 0xC2:
-       case 0xC3:
-       case 0xC4:
-       case 0xC5:
-       case 0xC6:
-       case 0xC7:
-       case 0xC8:
-       case 0xC9:
-       case 0xCA:
-       case 0xCB:
-       case 0xCC:
-       case 0xCD:
-       case 0xCE:
-       case 0xCF:
-       case 0xD0:
-       case 0xD1:
-       case 0xD2:
-       case 0xD3:
-       case 0xD4:
-       case 0xD5:
-       case 0xD6:
-       case 0xD7:
-       case 0xD8:
-       case 0xD9:
-       case 0xDA:
-       case 0xDB:
-       case 0xDC:
-       case 0xDD:
-       case 0xDE:
-       case 0xDF:
-       case 0xE0:
-       case 0xE1:
-       case 0xE2:
-       case 0xE3:
-       case 0xE4:
-       case 0xE5:
-       case 0xE6:
-       case 0xE7:
-       case 0xE8:
-       case 0xE9:
-       case 0xEA:
-       case 0xEB:
-       case 0xEC:
-       case 0xED:
-       case 0xEE:
-       case 0xEF:
-       case 0xF0:
-       case 0xF1:
-       case 0xF2:
-       case 0xF3:
-       case 0xF4:      goto yy43;
-       default:        goto yy154;
+               case '-':
+               case '0':
+               case '1':
+               case '2':
+               case '3':
+               case '4':
+               case '5':
+               case '6':
+               case '7':
+               case '8':
+               case '9':
+               case 'A':
+               case 'B':
+               case 'C':
+               case 'D':
+               case 'E':
+               case 'F':
+               case 'G':
+               case 'H':
+               case 'I':
+               case 'J':
+               case 'K':
+               case 'L':
+               case 'M':
+               case 'N':
+               case 'O':
+               case 'P':
+               case 'Q':
+               case 'R':
+               case 'S':
+               case 'T':
+               case 'U':
+               case 'V':
+               case 'W':
+               case 'X':
+               case 'Y':
+               case 'Z':
+               case '_':
+               case 'a':
+               case 'b':
+               case 'c':
+               case 'd':
+               case 'e':
+               case 'f':
+               case 'g':
+               case 'h':
+               case 'i':
+               case 'j':
+               case 'k':
+               case 'l':
+               case 'm':
+               case 'n':
+               case 'o':
+               case 'p':
+               case 'q':
+               case 'r':
+               case 's':
+               case 't':
+               case 'u':
+               case 'v':
+               case 'w':
+               case 'x':
+               case 'y':
+               case 'z':
+               case 0xC2:
+               case 0xC3:
+               case 0xC4:
+               case 0xC5:
+               case 0xC6:
+               case 0xC7:
+               case 0xC8:
+               case 0xC9:
+               case 0xCA:
+               case 0xCB:
+               case 0xCC:
+               case 0xCD:
+               case 0xCE:
+               case 0xCF:
+               case 0xD0:
+               case 0xD1:
+               case 0xD2:
+               case 0xD3:
+               case 0xD4:
+               case 0xD5:
+               case 0xD6:
+               case 0xD7:
+               case 0xD8:
+               case 0xD9:
+               case 0xDA:
+               case 0xDB:
+               case 0xDC:
+               case 0xDD:
+               case 0xDE:
+               case 0xDF:
+               case 0xE0:
+               case 0xE1:
+               case 0xE2:
+               case 0xE3:
+               case 0xE4:
+               case 0xE5:
+               case 0xE6:
+               case 0xE7:
+               case 0xE8:
+               case 0xE9:
+               case 0xEA:
+               case 0xEB:
+               case 0xEC:
+               case 0xED:
+               case 0xEE:
+               case 0xEF:
+               case 0xF0:
+               case 0xF1:
+               case 0xF2:
+               case 0xF3:
+               case 0xF4: goto yy30;
+               default: goto yy130;
        }
-yy154:
-       YYDEBUG(154, YYPEEK());
+yy130:
+       YYDEBUG(130, YYPEEK());
 #line 267 "../wisitoken_grammar.re2c"
        {*id = 15; continue;}
-#line 4466 "../wisitoken_grammar_re2c.c"
-yy155:
-       YYDEBUG(155, YYPEEK());
+#line 4423 "../wisitoken_grammar_re2c.c"
+yy131:
+       YYDEBUG(131, YYPEEK());
        yyaccept = 3;
        YYSKIP();
        YYBACKUP();
        yych = YYPEEK();
        switch (yych) {
-       case 'i':       goto yy165;
-       default:        goto yy43;
+               case 'i': goto yy141;
+               default: goto yy30;
        }
-yy156:
-       YYDEBUG(156, YYPEEK());
+yy132:
+       YYDEBUG(132, YYPEEK());
        yyaccept = 12;
        YYSKIP();
        YYBACKUP();
        yych = YYPEEK();
        switch (yych) {
-       case '-':
-       case '0':
-       case '1':
-       case '2':
-       case '3':
-       case '4':
-       case '5':
-       case '6':
-       case '7':
-       case '8':
-       case '9':
-       case 'A':
-       case 'B':
-       case 'C':
-       case 'D':
-       case 'E':
-       case 'F':
-       case 'G':
-       case 'H':
-       case 'I':
-       case 'J':
-       case 'K':
-       case 'L':
-       case 'M':
-       case 'N':
-       case 'O':
-       case 'P':
-       case 'Q':
-       case 'R':
-       case 'S':
-       case 'T':
-       case 'U':
-       case 'V':
-       case 'W':
-       case 'X':
-       case 'Y':
-       case 'Z':
-       case '_':
-       case 'a':
-       case 'b':
-       case 'c':
-       case 'd':
-       case 'e':
-       case 'f':
-       case 'g':
-       case 'h':
-       case 'i':
-       case 'j':
-       case 'k':
-       case 'l':
-       case 'm':
-       case 'n':
-       case 'o':
-       case 'p':
-       case 'q':
-       case 'r':
-       case 's':
-       case 't':
-       case 'u':
-       case 'v':
-       case 'w':
-       case 'x':
-       case 'y':
-       case 'z':
-       case 0xC2:
-       case 0xC3:
-       case 0xC4:
-       case 0xC5:
-       case 0xC6:
-       case 0xC7:
-       case 0xC8:
-       case 0xC9:
-       case 0xCA:
-       case 0xCB:
-       case 0xCC:
-       case 0xCD:
-       case 0xCE:
-       case 0xCF:
-       case 0xD0:
-       case 0xD1:
-       case 0xD2:
-       case 0xD3:
-       case 0xD4:
-       case 0xD5:
-       case 0xD6:
-       case 0xD7:
-       case 0xD8:
-       case 0xD9:
-       case 0xDA:
-       case 0xDB:
-       case 0xDC:
-       case 0xDD:
-       case 0xDE:
-       case 0xDF:
-       case 0xE0:
-       case 0xE1:
-       case 0xE2:
-       case 0xE3:
-       case 0xE4:
-       case 0xE5:
-       case 0xE6:
-       case 0xE7:
-       case 0xE8:
-       case 0xE9:
-       case 0xEA:
-       case 0xEB:
-       case 0xEC:
-       case 0xED:
-       case 0xEE:
-       case 0xEF:
-       case 0xF0:
-       case 0xF1:
-       case 0xF2:
-       case 0xF3:
-       case 0xF4:      goto yy43;
-       default:        goto yy157;
+               case '-':
+               case '0':
+               case '1':
+               case '2':
+               case '3':
+               case '4':
+               case '5':
+               case '6':
+               case '7':
+               case '8':
+               case '9':
+               case 'A':
+               case 'B':
+               case 'C':
+               case 'D':
+               case 'E':
+               case 'F':
+               case 'G':
+               case 'H':
+               case 'I':
+               case 'J':
+               case 'K':
+               case 'L':
+               case 'M':
+               case 'N':
+               case 'O':
+               case 'P':
+               case 'Q':
+               case 'R':
+               case 'S':
+               case 'T':
+               case 'U':
+               case 'V':
+               case 'W':
+               case 'X':
+               case 'Y':
+               case 'Z':
+               case '_':
+               case 'a':
+               case 'b':
+               case 'c':
+               case 'd':
+               case 'e':
+               case 'f':
+               case 'g':
+               case 'h':
+               case 'i':
+               case 'j':
+               case 'k':
+               case 'l':
+               case 'm':
+               case 'n':
+               case 'o':
+               case 'p':
+               case 'q':
+               case 'r':
+               case 's':
+               case 't':
+               case 'u':
+               case 'v':
+               case 'w':
+               case 'x':
+               case 'y':
+               case 'z':
+               case 0xC2:
+               case 0xC3:
+               case 0xC4:
+               case 0xC5:
+               case 0xC6:
+               case 0xC7:
+               case 0xC8:
+               case 0xC9:
+               case 0xCA:
+               case 0xCB:
+               case 0xCC:
+               case 0xCD:
+               case 0xCE:
+               case 0xCF:
+               case 0xD0:
+               case 0xD1:
+               case 0xD2:
+               case 0xD3:
+               case 0xD4:
+               case 0xD5:
+               case 0xD6:
+               case 0xD7:
+               case 0xD8:
+               case 0xD9:
+               case 0xDA:
+               case 0xDB:
+               case 0xDC:
+               case 0xDD:
+               case 0xDE:
+               case 0xDF:
+               case 0xE0:
+               case 0xE1:
+               case 0xE2:
+               case 0xE3:
+               case 0xE4:
+               case 0xE5:
+               case 0xE6:
+               case 0xE7:
+               case 0xE8:
+               case 0xE9:
+               case 0xEA:
+               case 0xEB:
+               case 0xEC:
+               case 0xED:
+               case 0xEE:
+               case 0xEF:
+               case 0xF0:
+               case 0xF1:
+               case 0xF2:
+               case 0xF3:
+               case 0xF4: goto yy30;
+               default: goto yy133;
        }
-yy157:
-       YYDEBUG(157, YYPEEK());
+yy133:
+       YYDEBUG(133, YYPEEK());
 #line 260 "../wisitoken_grammar.re2c"
        {*id = 8; continue;}
-#line 4605 "../wisitoken_grammar_re2c.c"
-yy158:
-       YYDEBUG(158, YYPEEK());
+#line 4562 "../wisitoken_grammar_re2c.c"
+yy134:
+       YYDEBUG(134, YYPEEK());
        yyaccept = 3;
        YYSKIP();
        YYBACKUP();
        yych = YYPEEK();
        switch (yych) {
-       case 'r':       goto yy166;
-       default:        goto yy43;
+               case 'r': goto yy142;
+               default: goto yy30;
        }
-yy159:
-       YYDEBUG(159, YYPEEK());
+yy135:
+       YYDEBUG(135, YYPEEK());
        yyaccept = 3;
        YYSKIP();
        YYBACKUP();
        yych = YYPEEK();
        switch (yych) {
-       case 'r':       goto yy167;
-       default:        goto yy43;
+               case 'r': goto yy143;
+               default: goto yy30;
        }
-yy160:
-       YYDEBUG(160, YYPEEK());
+yy136:
+       YYDEBUG(136, YYPEEK());
        yyaccept = 13;
        YYSKIP();
        YYBACKUP();
        yych = YYPEEK();
        switch (yych) {
-       case '-':
-       case '0':
-       case '1':
-       case '2':
-       case '3':
-       case '4':
-       case '5':
-       case '6':
-       case '7':
-       case '8':
-       case '9':
-       case 'A':
-       case 'B':
-       case 'C':
-       case 'D':
-       case 'E':
-       case 'F':
-       case 'G':
-       case 'H':
-       case 'I':
-       case 'J':
-       case 'K':
-       case 'L':
-       case 'M':
-       case 'N':
-       case 'O':
-       case 'P':
-       case 'Q':
-       case 'R':
-       case 'S':
-       case 'T':
-       case 'U':
-       case 'V':
-       case 'W':
-       case 'X':
-       case 'Y':
-       case 'Z':
-       case '_':
-       case 'a':
-       case 'b':
-       case 'c':
-       case 'd':
-       case 'e':
-       case 'f':
-       case 'g':
-       case 'h':
-       case 'i':
-       case 'j':
-       case 'k':
-       case 'l':
-       case 'm':
-       case 'n':
-       case 'o':
-       case 'p':
-       case 'q':
-       case 'r':
-       case 's':
-       case 't':
-       case 'u':
-       case 'v':
-       case 'w':
-       case 'x':
-       case 'y':
-       case 'z':
-       case 0xC2:
-       case 0xC3:
-       case 0xC4:
-       case 0xC5:
-       case 0xC6:
-       case 0xC7:
-       case 0xC8:
-       case 0xC9:
-       case 0xCA:
-       case 0xCB:
-       case 0xCC:
-       case 0xCD:
-       case 0xCE:
-       case 0xCF:
-       case 0xD0:
-       case 0xD1:
-       case 0xD2:
-       case 0xD3:
-       case 0xD4:
-       case 0xD5:
-       case 0xD6:
-       case 0xD7:
-       case 0xD8:
-       case 0xD9:
-       case 0xDA:
-       case 0xDB:
-       case 0xDC:
-       case 0xDD:
-       case 0xDE:
-       case 0xDF:
-       case 0xE0:
-       case 0xE1:
-       case 0xE2:
-       case 0xE3:
-       case 0xE4:
-       case 0xE5:
-       case 0xE6:
-       case 0xE7:
-       case 0xE8:
-       case 0xE9:
-       case 0xEA:
-       case 0xEB:
-       case 0xEC:
-       case 0xED:
-       case 0xEE:
-       case 0xEF:
-       case 0xF0:
-       case 0xF1:
-       case 0xF2:
-       case 0xF3:
-       case 0xF4:      goto yy43;
-       default:        goto yy161;
+               case '-':
+               case '0':
+               case '1':
+               case '2':
+               case '3':
+               case '4':
+               case '5':
+               case '6':
+               case '7':
+               case '8':
+               case '9':
+               case 'A':
+               case 'B':
+               case 'C':
+               case 'D':
+               case 'E':
+               case 'F':
+               case 'G':
+               case 'H':
+               case 'I':
+               case 'J':
+               case 'K':
+               case 'L':
+               case 'M':
+               case 'N':
+               case 'O':
+               case 'P':
+               case 'Q':
+               case 'R':
+               case 'S':
+               case 'T':
+               case 'U':
+               case 'V':
+               case 'W':
+               case 'X':
+               case 'Y':
+               case 'Z':
+               case '_':
+               case 'a':
+               case 'b':
+               case 'c':
+               case 'd':
+               case 'e':
+               case 'f':
+               case 'g':
+               case 'h':
+               case 'i':
+               case 'j':
+               case 'k':
+               case 'l':
+               case 'm':
+               case 'n':
+               case 'o':
+               case 'p':
+               case 'q':
+               case 'r':
+               case 's':
+               case 't':
+               case 'u':
+               case 'v':
+               case 'w':
+               case 'x':
+               case 'y':
+               case 'z':
+               case 0xC2:
+               case 0xC3:
+               case 0xC4:
+               case 0xC5:
+               case 0xC6:
+               case 0xC7:
+               case 0xC8:
+               case 0xC9:
+               case 0xCA:
+               case 0xCB:
+               case 0xCC:
+               case 0xCD:
+               case 0xCE:
+               case 0xCF:
+               case 0xD0:
+               case 0xD1:
+               case 0xD2:
+               case 0xD3:
+               case 0xD4:
+               case 0xD5:
+               case 0xD6:
+               case 0xD7:
+               case 0xD8:
+               case 0xD9:
+               case 0xDA:
+               case 0xDB:
+               case 0xDC:
+               case 0xDD:
+               case 0xDE:
+               case 0xDF:
+               case 0xE0:
+               case 0xE1:
+               case 0xE2:
+               case 0xE3:
+               case 0xE4:
+               case 0xE5:
+               case 0xE6:
+               case 0xE7:
+               case 0xE8:
+               case 0xE9:
+               case 0xEA:
+               case 0xEB:
+               case 0xEC:
+               case 0xED:
+               case 0xEE:
+               case 0xEF:
+               case 0xF0:
+               case 0xF1:
+               case 0xF2:
+               case 0xF3:
+               case 0xF4: goto yy30;
+               default: goto yy137;
        }
-yy161:
-       YYDEBUG(161, YYPEEK());
+yy137:
+       YYDEBUG(137, YYPEEK());
 #line 268 "../wisitoken_grammar.re2c"
        {*id = 16; continue;}
-#line 4754 "../wisitoken_grammar_re2c.c"
-yy162:
-       YYDEBUG(162, YYPEEK());
+#line 4711 "../wisitoken_grammar_re2c.c"
+yy138:
+       YYDEBUG(138, YYPEEK());
        yyaccept = 3;
        YYSKIP();
        YYBACKUP();
        yych = YYPEEK();
        switch (yych) {
-       case '_':       goto yy168;
-       default:        goto yy43;
+               case '_': goto yy144;
+               default: goto yy30;
        }
-yy163:
-       YYDEBUG(163, YYPEEK());
+yy139:
+       YYDEBUG(139, YYPEEK());
        yyaccept = 14;
        YYSKIP();
        YYBACKUP();
        yych = YYPEEK();
        switch (yych) {
-       case '-':
-       case '0':
-       case '1':
-       case '2':
-       case '3':
-       case '4':
-       case '5':
-       case '6':
-       case '7':
-       case '8':
-       case '9':
-       case 'A':
-       case 'B':
-       case 'C':
-       case 'D':
-       case 'E':
-       case 'F':
-       case 'G':
-       case 'H':
-       case 'I':
-       case 'J':
-       case 'K':
-       case 'L':
-       case 'M':
-       case 'N':
-       case 'O':
-       case 'P':
-       case 'Q':
-       case 'R':
-       case 'S':
-       case 'T':
-       case 'U':
-       case 'V':
-       case 'W':
-       case 'X':
-       case 'Y':
-       case 'Z':
-       case '_':
-       case 'a':
-       case 'b':
-       case 'c':
-       case 'd':
-       case 'e':
-       case 'f':
-       case 'g':
-       case 'h':
-       case 'i':
-       case 'j':
-       case 'k':
-       case 'l':
-       case 'm':
-       case 'n':
-       case 'o':
-       case 'p':
-       case 'q':
-       case 'r':
-       case 's':
-       case 't':
-       case 'u':
-       case 'v':
-       case 'w':
-       case 'x':
-       case 'y':
-       case 'z':
-       case 0xC2:
-       case 0xC3:
-       case 0xC4:
-       case 0xC5:
-       case 0xC6:
-       case 0xC7:
-       case 0xC8:
-       case 0xC9:
-       case 0xCA:
-       case 0xCB:
-       case 0xCC:
-       case 0xCD:
-       case 0xCE:
-       case 0xCF:
-       case 0xD0:
-       case 0xD1:
-       case 0xD2:
-       case 0xD3:
-       case 0xD4:
-       case 0xD5:
-       case 0xD6:
-       case 0xD7:
-       case 0xD8:
-       case 0xD9:
-       case 0xDA:
-       case 0xDB:
-       case 0xDC:
-       case 0xDD:
-       case 0xDE:
-       case 0xDF:
-       case 0xE0:
-       case 0xE1:
-       case 0xE2:
-       case 0xE3:
-       case 0xE4:
-       case 0xE5:
-       case 0xE6:
-       case 0xE7:
-       case 0xE8:
-       case 0xE9:
-       case 0xEA:
-       case 0xEB:
-       case 0xEC:
-       case 0xED:
-       case 0xEE:
-       case 0xEF:
-       case 0xF0:
-       case 0xF1:
-       case 0xF2:
-       case 0xF3:
-       case 0xF4:      goto yy43;
-       default:        goto yy164;
+               case '-':
+               case '0':
+               case '1':
+               case '2':
+               case '3':
+               case '4':
+               case '5':
+               case '6':
+               case '7':
+               case '8':
+               case '9':
+               case 'A':
+               case 'B':
+               case 'C':
+               case 'D':
+               case 'E':
+               case 'F':
+               case 'G':
+               case 'H':
+               case 'I':
+               case 'J':
+               case 'K':
+               case 'L':
+               case 'M':
+               case 'N':
+               case 'O':
+               case 'P':
+               case 'Q':
+               case 'R':
+               case 'S':
+               case 'T':
+               case 'U':
+               case 'V':
+               case 'W':
+               case 'X':
+               case 'Y':
+               case 'Z':
+               case '_':
+               case 'a':
+               case 'b':
+               case 'c':
+               case 'd':
+               case 'e':
+               case 'f':
+               case 'g':
+               case 'h':
+               case 'i':
+               case 'j':
+               case 'k':
+               case 'l':
+               case 'm':
+               case 'n':
+               case 'o':
+               case 'p':
+               case 'q':
+               case 'r':
+               case 's':
+               case 't':
+               case 'u':
+               case 'v':
+               case 'w':
+               case 'x':
+               case 'y':
+               case 'z':
+               case 0xC2:
+               case 0xC3:
+               case 0xC4:
+               case 0xC5:
+               case 0xC6:
+               case 0xC7:
+               case 0xC8:
+               case 0xC9:
+               case 0xCA:
+               case 0xCB:
+               case 0xCC:
+               case 0xCD:
+               case 0xCE:
+               case 0xCF:
+               case 0xD0:
+               case 0xD1:
+               case 0xD2:
+               case 0xD3:
+               case 0xD4:
+               case 0xD5:
+               case 0xD6:
+               case 0xD7:
+               case 0xD8:
+               case 0xD9:
+               case 0xDA:
+               case 0xDB:
+               case 0xDC:
+               case 0xDD:
+               case 0xDE:
+               case 0xDF:
+               case 0xE0:
+               case 0xE1:
+               case 0xE2:
+               case 0xE3:
+               case 0xE4:
+               case 0xE5:
+               case 0xE6:
+               case 0xE7:
+               case 0xE8:
+               case 0xE9:
+               case 0xEA:
+               case 0xEB:
+               case 0xEC:
+               case 0xED:
+               case 0xEE:
+               case 0xEF:
+               case 0xF0:
+               case 0xF1:
+               case 0xF2:
+               case 0xF3:
+               case 0xF4: goto yy30;
+               default: goto yy140;
        }
-yy164:
-       YYDEBUG(164, YYPEEK());
+yy140:
+       YYDEBUG(140, YYPEEK());
 #line 266 "../wisitoken_grammar.re2c"
        {*id = 14; continue;}
-#line 4893 "../wisitoken_grammar_re2c.c"
-yy165:
-       YYDEBUG(165, YYPEEK());
+#line 4850 "../wisitoken_grammar_re2c.c"
+yy141:
+       YYDEBUG(141, YYPEEK());
        yyaccept = 3;
        YYSKIP();
        YYBACKUP();
        yych = YYPEEK();
        switch (yych) {
-       case 'c':       goto yy169;
-       default:        goto yy43;
+               case 'c': goto yy145;
+               default: goto yy30;
        }
-yy166:
-       YYDEBUG(166, YYPEEK());
+yy142:
+       YYDEBUG(142, YYPEEK());
        yyaccept = 3;
        YYSKIP();
        YYBACKUP();
        yych = YYPEEK();
        switch (yych) {
-       case 'd':       goto yy170;
-       default:        goto yy43;
+               case 'd': goto yy146;
+               default: goto yy30;
        }
-yy167:
-       YYDEBUG(167, YYPEEK());
+yy143:
+       YYDEBUG(143, YYPEEK());
        yyaccept = 3;
        YYSKIP();
        YYBACKUP();
        yych = YYPEEK();
        switch (yych) {
-       case 'a':       goto yy172;
-       default:        goto yy43;
+               case 'a': goto yy148;
+               default: goto yy30;
        }
-yy168:
-       YYDEBUG(168, YYPEEK());
+yy144:
+       YYDEBUG(144, YYPEEK());
        yyaccept = 3;
        YYSKIP();
        YYBACKUP();
        yych = YYPEEK();
        switch (yych) {
-       case 'I':
-       case 'i':       goto yy173;
-       default:        goto yy43;
+               case 'I':
+               case 'i': goto yy149;
+               default: goto yy30;
        }
-yy169:
-       YYDEBUG(169, YYPEEK());
+yy145:
+       YYDEBUG(145, YYPEEK());
        yyaccept = 3;
        YYSKIP();
        YYBACKUP();
        yych = YYPEEK();
        switch (yych) {
-       case 't':       goto yy174;
-       default:        goto yy43;
+               case 't': goto yy150;
+               default: goto yy30;
        }
-yy170:
-       YYDEBUG(170, YYPEEK());
+yy146:
+       YYDEBUG(146, YYPEEK());
        yyaccept = 15;
        YYSKIP();
        YYBACKUP();
        yych = YYPEEK();
        switch (yych) {
-       case '-':
-       case '0':
-       case '1':
-       case '2':
-       case '3':
-       case '4':
-       case '5':
-       case '6':
-       case '7':
-       case '8':
-       case '9':
-       case 'A':
-       case 'B':
-       case 'C':
-       case 'D':
-       case 'E':
-       case 'F':
-       case 'G':
-       case 'H':
-       case 'I':
-       case 'J':
-       case 'K':
-       case 'L':
-       case 'M':
-       case 'N':
-       case 'O':
-       case 'P':
-       case 'Q':
-       case 'R':
-       case 'S':
-       case 'T':
-       case 'U':
-       case 'V':
-       case 'W':
-       case 'X':
-       case 'Y':
-       case 'Z':
-       case '_':
-       case 'a':
-       case 'b':
-       case 'c':
-       case 'd':
-       case 'e':
-       case 'f':
-       case 'g':
-       case 'h':
-       case 'i':
-       case 'j':
-       case 'k':
-       case 'l':
-       case 'm':
-       case 'n':
-       case 'o':
-       case 'p':
-       case 'q':
-       case 'r':
-       case 's':
-       case 't':
-       case 'u':
-       case 'v':
-       case 'w':
-       case 'x':
-       case 'y':
-       case 'z':
-       case 0xC2:
-       case 0xC3:
-       case 0xC4:
-       case 0xC5:
-       case 0xC6:
-       case 0xC7:
-       case 0xC8:
-       case 0xC9:
-       case 0xCA:
-       case 0xCB:
-       case 0xCC:
-       case 0xCD:
-       case 0xCE:
-       case 0xCF:
-       case 0xD0:
-       case 0xD1:
-       case 0xD2:
-       case 0xD3:
-       case 0xD4:
-       case 0xD5:
-       case 0xD6:
-       case 0xD7:
-       case 0xD8:
-       case 0xD9:
-       case 0xDA:
-       case 0xDB:
-       case 0xDC:
-       case 0xDD:
-       case 0xDE:
-       case 0xDF:
-       case 0xE0:
-       case 0xE1:
-       case 0xE2:
-       case 0xE3:
-       case 0xE4:
-       case 0xE5:
-       case 0xE6:
-       case 0xE7:
-       case 0xE8:
-       case 0xE9:
-       case 0xEA:
-       case 0xEB:
-       case 0xEC:
-       case 0xED:
-       case 0xEE:
-       case 0xEF:
-       case 0xF0:
-       case 0xF1:
-       case 0xF2:
-       case 0xF3:
-       case 0xF4:      goto yy43;
-       default:        goto yy171;
+               case '-':
+               case '0':
+               case '1':
+               case '2':
+               case '3':
+               case '4':
+               case '5':
+               case '6':
+               case '7':
+               case '8':
+               case '9':
+               case 'A':
+               case 'B':
+               case 'C':
+               case 'D':
+               case 'E':
+               case 'F':
+               case 'G':
+               case 'H':
+               case 'I':
+               case 'J':
+               case 'K':
+               case 'L':
+               case 'M':
+               case 'N':
+               case 'O':
+               case 'P':
+               case 'Q':
+               case 'R':
+               case 'S':
+               case 'T':
+               case 'U':
+               case 'V':
+               case 'W':
+               case 'X':
+               case 'Y':
+               case 'Z':
+               case '_':
+               case 'a':
+               case 'b':
+               case 'c':
+               case 'd':
+               case 'e':
+               case 'f':
+               case 'g':
+               case 'h':
+               case 'i':
+               case 'j':
+               case 'k':
+               case 'l':
+               case 'm':
+               case 'n':
+               case 'o':
+               case 'p':
+               case 'q':
+               case 'r':
+               case 's':
+               case 't':
+               case 'u':
+               case 'v':
+               case 'w':
+               case 'x':
+               case 'y':
+               case 'z':
+               case 0xC2:
+               case 0xC3:
+               case 0xC4:
+               case 0xC5:
+               case 0xC6:
+               case 0xC7:
+               case 0xC8:
+               case 0xC9:
+               case 0xCA:
+               case 0xCB:
+               case 0xCC:
+               case 0xCD:
+               case 0xCE:
+               case 0xCF:
+               case 0xD0:
+               case 0xD1:
+               case 0xD2:
+               case 0xD3:
+               case 0xD4:
+               case 0xD5:
+               case 0xD6:
+               case 0xD7:
+               case 0xD8:
+               case 0xD9:
+               case 0xDA:
+               case 0xDB:
+               case 0xDC:
+               case 0xDD:
+               case 0xDE:
+               case 0xDF:
+               case 0xE0:
+               case 0xE1:
+               case 0xE2:
+               case 0xE3:
+               case 0xE4:
+               case 0xE5:
+               case 0xE6:
+               case 0xE7:
+               case 0xE8:
+               case 0xE9:
+               case 0xEA:
+               case 0xEB:
+               case 0xEC:
+               case 0xED:
+               case 0xEE:
+               case 0xEF:
+               case 0xF0:
+               case 0xF1:
+               case 0xF2:
+               case 0xF3:
+               case 0xF4: goto yy30;
+               default: goto yy147;
        }
-yy171:
-       YYDEBUG(171, YYPEEK());
+yy147:
+       YYDEBUG(147, YYPEEK());
 #line 263 "../wisitoken_grammar.re2c"
        {*id = 11; continue;}
-#line 5073 "../wisitoken_grammar_re2c.c"
-yy172:
-       YYDEBUG(172, YYPEEK());
+#line 5030 "../wisitoken_grammar_re2c.c"
+yy148:
+       YYDEBUG(148, YYPEEK());
        yyaccept = 3;
        YYSKIP();
        YYBACKUP();
        yych = YYPEEK();
        switch (yych) {
-       case 'm':       goto yy176;
-       default:        goto yy43;
+               case 'm': goto yy152;
+               default: goto yy30;
        }
-yy173:
-       YYDEBUG(173, YYPEEK());
+yy149:
+       YYDEBUG(149, YYPEEK());
        yyaccept = 3;
        YYSKIP();
        YYBACKUP();
        yych = YYPEEK();
        switch (yych) {
-       case 'T':
-       case 't':       goto yy177;
-       default:        goto yy43;
+               case 'T':
+               case 't': goto yy153;
+               default: goto yy30;
        }
-yy174:
-       YYDEBUG(174, YYPEEK());
+yy150:
+       YYDEBUG(150, YYPEEK());
        yyaccept = 16;
        YYSKIP();
        YYBACKUP();
        yych = YYPEEK();
        switch (yych) {
-       case '-':
-       case '0':
-       case '1':
-       case '2':
-       case '3':
-       case '4':
-       case '5':
-       case '6':
-       case '7':
-       case '8':
-       case '9':
-       case 'A':
-       case 'B':
-       case 'C':
-       case 'D':
-       case 'E':
-       case 'F':
-       case 'G':
-       case 'H':
-       case 'I':
-       case 'J':
-       case 'K':
-       case 'L':
-       case 'M':
-       case 'N':
-       case 'O':
-       case 'P':
-       case 'Q':
-       case 'R':
-       case 'S':
-       case 'T':
-       case 'U':
-       case 'V':
-       case 'W':
-       case 'X':
-       case 'Y':
-       case 'Z':
-       case 'a':
-       case 'b':
-       case 'c':
-       case 'd':
-       case 'e':
-       case 'f':
-       case 'g':
-       case 'h':
-       case 'i':
-       case 'j':
-       case 'k':
-       case 'l':
-       case 'm':
-       case 'n':
-       case 'o':
-       case 'p':
-       case 'q':
-       case 'r':
-       case 's':
-       case 't':
-       case 'u':
-       case 'v':
-       case 'w':
-       case 'x':
-       case 'y':
-       case 'z':
-       case 0xC2:
-       case 0xC3:
-       case 0xC4:
-       case 0xC5:
-       case 0xC6:
-       case 0xC7:
-       case 0xC8:
-       case 0xC9:
-       case 0xCA:
-       case 0xCB:
-       case 0xCC:
-       case 0xCD:
-       case 0xCE:
-       case 0xCF:
-       case 0xD0:
-       case 0xD1:
-       case 0xD2:
-       case 0xD3:
-       case 0xD4:
-       case 0xD5:
-       case 0xD6:
-       case 0xD7:
-       case 0xD8:
-       case 0xD9:
-       case 0xDA:
-       case 0xDB:
-       case 0xDC:
-       case 0xDD:
-       case 0xDE:
-       case 0xDF:
-       case 0xE0:
-       case 0xE1:
-       case 0xE2:
-       case 0xE3:
-       case 0xE4:
-       case 0xE5:
-       case 0xE6:
-       case 0xE7:
-       case 0xE8:
-       case 0xE9:
-       case 0xEA:
-       case 0xEB:
-       case 0xEC:
-       case 0xED:
-       case 0xEE:
-       case 0xEF:
-       case 0xF0:
-       case 0xF1:
-       case 0xF2:
-       case 0xF3:
-       case 0xF4:      goto yy43;
-       case '_':       goto yy179;
-       default:        goto yy175;
+               case '-':
+               case '0':
+               case '1':
+               case '2':
+               case '3':
+               case '4':
+               case '5':
+               case '6':
+               case '7':
+               case '8':
+               case '9':
+               case 'A':
+               case 'B':
+               case 'C':
+               case 'D':
+               case 'E':
+               case 'F':
+               case 'G':
+               case 'H':
+               case 'I':
+               case 'J':
+               case 'K':
+               case 'L':
+               case 'M':
+               case 'N':
+               case 'O':
+               case 'P':
+               case 'Q':
+               case 'R':
+               case 'S':
+               case 'T':
+               case 'U':
+               case 'V':
+               case 'W':
+               case 'X':
+               case 'Y':
+               case 'Z':
+               case 'a':
+               case 'b':
+               case 'c':
+               case 'd':
+               case 'e':
+               case 'f':
+               case 'g':
+               case 'h':
+               case 'i':
+               case 'j':
+               case 'k':
+               case 'l':
+               case 'm':
+               case 'n':
+               case 'o':
+               case 'p':
+               case 'q':
+               case 'r':
+               case 's':
+               case 't':
+               case 'u':
+               case 'v':
+               case 'w':
+               case 'x':
+               case 'y':
+               case 'z':
+               case 0xC2:
+               case 0xC3:
+               case 0xC4:
+               case 0xC5:
+               case 0xC6:
+               case 0xC7:
+               case 0xC8:
+               case 0xC9:
+               case 0xCA:
+               case 0xCB:
+               case 0xCC:
+               case 0xCD:
+               case 0xCE:
+               case 0xCF:
+               case 0xD0:
+               case 0xD1:
+               case 0xD2:
+               case 0xD3:
+               case 0xD4:
+               case 0xD5:
+               case 0xD6:
+               case 0xD7:
+               case 0xD8:
+               case 0xD9:
+               case 0xDA:
+               case 0xDB:
+               case 0xDC:
+               case 0xDD:
+               case 0xDE:
+               case 0xDF:
+               case 0xE0:
+               case 0xE1:
+               case 0xE2:
+               case 0xE3:
+               case 0xE4:
+               case 0xE5:
+               case 0xE6:
+               case 0xE7:
+               case 0xE8:
+               case 0xE9:
+               case 0xEA:
+               case 0xEB:
+               case 0xEC:
+               case 0xED:
+               case 0xEE:
+               case 0xEF:
+               case 0xF0:
+               case 0xF1:
+               case 0xF2:
+               case 0xF3:
+               case 0xF4: goto yy30;
+               case '_': goto yy155;
+               default: goto yy151;
        }
-yy175:
-       YYDEBUG(175, YYPEEK());
+yy151:
+       YYDEBUG(151, YYPEEK());
 #line 257 "../wisitoken_grammar.re2c"
        {*id = 5; continue;}
-#line 5223 "../wisitoken_grammar_re2c.c"
-yy176:
-       YYDEBUG(176, YYPEEK());
+#line 5180 "../wisitoken_grammar_re2c.c"
+yy152:
+       YYDEBUG(152, YYPEEK());
        yyaccept = 3;
        YYSKIP();
        YYBACKUP();
        yych = YYPEEK();
        switch (yych) {
-       case 'm':       goto yy180;
-       default:        goto yy43;
+               case 'm': goto yy156;
+               default: goto yy30;
        }
-yy177:
-       YYDEBUG(177, YYPEEK());
+yy153:
+       YYDEBUG(153, YYPEEK());
        yyaccept = 17;
        YYSKIP();
        YYBACKUP();
        yych = YYPEEK();
        switch (yych) {
-       case '-':
-       case '0':
-       case '1':
-       case '2':
-       case '3':
-       case '4':
-       case '5':
-       case '6':
-       case '7':
-       case '8':
-       case '9':
-       case 'A':
-       case 'B':
-       case 'C':
-       case 'D':
-       case 'E':
-       case 'F':
-       case 'G':
-       case 'H':
-       case 'I':
-       case 'J':
-       case 'K':
-       case 'L':
-       case 'M':
-       case 'N':
-       case 'O':
-       case 'P':
-       case 'Q':
-       case 'R':
-       case 'S':
-       case 'T':
-       case 'U':
-       case 'V':
-       case 'W':
-       case 'X':
-       case 'Y':
-       case 'Z':
-       case '_':
-       case 'a':
-       case 'b':
-       case 'c':
-       case 'd':
-       case 'e':
-       case 'f':
-       case 'g':
-       case 'h':
-       case 'i':
-       case 'j':
-       case 'k':
-       case 'l':
-       case 'm':
-       case 'n':
-       case 'o':
-       case 'p':
-       case 'q':
-       case 'r':
-       case 's':
-       case 't':
-       case 'u':
-       case 'v':
-       case 'w':
-       case 'x':
-       case 'y':
-       case 'z':
-       case 0xC2:
-       case 0xC3:
-       case 0xC4:
-       case 0xC5:
-       case 0xC6:
-       case 0xC7:
-       case 0xC8:
-       case 0xC9:
-       case 0xCA:
-       case 0xCB:
-       case 0xCC:
-       case 0xCD:
-       case 0xCE:
-       case 0xCF:
-       case 0xD0:
-       case 0xD1:
-       case 0xD2:
-       case 0xD3:
-       case 0xD4:
-       case 0xD5:
-       case 0xD6:
-       case 0xD7:
-       case 0xD8:
-       case 0xD9:
-       case 0xDA:
-       case 0xDB:
-       case 0xDC:
-       case 0xDD:
-       case 0xDE:
-       case 0xDF:
-       case 0xE0:
-       case 0xE1:
-       case 0xE2:
-       case 0xE3:
-       case 0xE4:
-       case 0xE5:
-       case 0xE6:
-       case 0xE7:
-       case 0xE8:
-       case 0xE9:
-       case 0xEA:
-       case 0xEB:
-       case 0xEC:
-       case 0xED:
-       case 0xEE:
-       case 0xEF:
-       case 0xF0:
-       case 0xF1:
-       case 0xF2:
-       case 0xF3:
-       case 0xF4:      goto yy43;
-       default:        goto yy178;
+               case '-':
+               case '0':
+               case '1':
+               case '2':
+               case '3':
+               case '4':
+               case '5':
+               case '6':
+               case '7':
+               case '8':
+               case '9':
+               case 'A':
+               case 'B':
+               case 'C':
+               case 'D':
+               case 'E':
+               case 'F':
+               case 'G':
+               case 'H':
+               case 'I':
+               case 'J':
+               case 'K':
+               case 'L':
+               case 'M':
+               case 'N':
+               case 'O':
+               case 'P':
+               case 'Q':
+               case 'R':
+               case 'S':
+               case 'T':
+               case 'U':
+               case 'V':
+               case 'W':
+               case 'X':
+               case 'Y':
+               case 'Z':
+               case '_':
+               case 'a':
+               case 'b':
+               case 'c':
+               case 'd':
+               case 'e':
+               case 'f':
+               case 'g':
+               case 'h':
+               case 'i':
+               case 'j':
+               case 'k':
+               case 'l':
+               case 'm':
+               case 'n':
+               case 'o':
+               case 'p':
+               case 'q':
+               case 'r':
+               case 's':
+               case 't':
+               case 'u':
+               case 'v':
+               case 'w':
+               case 'x':
+               case 'y':
+               case 'z':
+               case 0xC2:
+               case 0xC3:
+               case 0xC4:
+               case 0xC5:
+               case 0xC6:
+               case 0xC7:
+               case 0xC8:
+               case 0xC9:
+               case 0xCA:
+               case 0xCB:
+               case 0xCC:
+               case 0xCD:
+               case 0xCE:
+               case 0xCF:
+               case 0xD0:
+               case 0xD1:
+               case 0xD2:
+               case 0xD3:
+               case 0xD4:
+               case 0xD5:
+               case 0xD6:
+               case 0xD7:
+               case 0xD8:
+               case 0xD9:
+               case 0xDA:
+               case 0xDB:
+               case 0xDC:
+               case 0xDD:
+               case 0xDE:
+               case 0xDF:
+               case 0xE0:
+               case 0xE1:
+               case 0xE2:
+               case 0xE3:
+               case 0xE4:
+               case 0xE5:
+               case 0xE6:
+               case 0xE7:
+               case 0xE8:
+               case 0xE9:
+               case 0xEA:
+               case 0xEB:
+               case 0xEC:
+               case 0xED:
+               case 0xEE:
+               case 0xEF:
+               case 0xF0:
+               case 0xF1:
+               case 0xF2:
+               case 0xF3:
+               case 0xF4: goto yy30;
+               default: goto yy154;
        }
-yy178:
-       YYDEBUG(178, YYPEEK());
+yy154:
+       YYDEBUG(154, YYPEEK());
 #line 255 "../wisitoken_grammar.re2c"
        {*id = 3; continue;}
-#line 5362 "../wisitoken_grammar_re2c.c"
-yy179:
-       YYDEBUG(179, YYPEEK());
+#line 5319 "../wisitoken_grammar_re2c.c"
+yy155:
+       YYDEBUG(155, YYPEEK());
        yyaccept = 3;
        YYSKIP();
        YYBACKUP();
        yych = YYPEEK();
        switch (yych) {
-       case 'r':       goto yy181;
-       default:        goto yy43;
+               case 'r': goto yy157;
+               default: goto yy30;
        }
-yy180:
-       YYDEBUG(180, YYPEEK());
+yy156:
+       YYDEBUG(156, YYPEEK());
        yyaccept = 3;
        YYSKIP();
        YYBACKUP();
        yych = YYPEEK();
        switch (yych) {
-       case 'a':       goto yy182;
-       default:        goto yy43;
+               case 'a': goto yy158;
+               default: goto yy30;
        }
-yy181:
-       YYDEBUG(181, YYPEEK());
+yy157:
+       YYDEBUG(157, YYPEEK());
        yyaccept = 3;
        YYSKIP();
        YYBACKUP();
        yych = YYPEEK();
        switch (yych) {
-       case 'e':       goto yy183;
-       default:        goto yy43;
+               case 'e': goto yy159;
+               default: goto yy30;
        }
-yy182:
-       YYDEBUG(182, YYPEEK());
+yy158:
+       YYDEBUG(158, YYPEEK());
        yyaccept = 3;
        YYSKIP();
        YYBACKUP();
        yych = YYPEEK();
        switch (yych) {
-       case 'r':       goto yy184;
-       default:        goto yy43;
+               case 'r': goto yy160;
+               default: goto yy30;
        }
-yy183:
-       YYDEBUG(183, YYPEEK());
+yy159:
+       YYDEBUG(159, YYPEEK());
        yyaccept = 3;
        YYSKIP();
        YYBACKUP();
        yych = YYPEEK();
        switch (yych) {
-       case 's':       goto yy186;
-       default:        goto yy43;
+               case 's': goto yy162;
+               default: goto yy30;
        }
-yy184:
-       YYDEBUG(184, YYPEEK());
+yy160:
+       YYDEBUG(160, YYPEEK());
        yyaccept = 18;
        YYSKIP();
        YYBACKUP();
        yych = YYPEEK();
        switch (yych) {
-       case '-':
-       case '0':
-       case '1':
-       case '2':
-       case '3':
-       case '4':
-       case '5':
-       case '6':
-       case '7':
-       case '8':
-       case '9':
-       case 'A':
-       case 'B':
-       case 'C':
-       case 'D':
-       case 'E':
-       case 'F':
-       case 'G':
-       case 'H':
-       case 'I':
-       case 'J':
-       case 'K':
-       case 'L':
-       case 'M':
-       case 'N':
-       case 'O':
-       case 'P':
-       case 'Q':
-       case 'R':
-       case 'S':
-       case 'T':
-       case 'U':
-       case 'V':
-       case 'W':
-       case 'X':
-       case 'Y':
-       case 'Z':
-       case '_':
-       case 'a':
-       case 'b':
-       case 'c':
-       case 'd':
-       case 'e':
-       case 'f':
-       case 'g':
-       case 'h':
-       case 'i':
-       case 'j':
-       case 'k':
-       case 'l':
-       case 'm':
-       case 'n':
-       case 'o':
-       case 'p':
-       case 'q':
-       case 'r':
-       case 's':
-       case 't':
-       case 'u':
-       case 'v':
-       case 'w':
-       case 'x':
-       case 'y':
-       case 'z':
-       case 0xC2:
-       case 0xC3:
-       case 0xC4:
-       case 0xC5:
-       case 0xC6:
-       case 0xC7:
-       case 0xC8:
-       case 0xC9:
-       case 0xCA:
-       case 0xCB:
-       case 0xCC:
-       case 0xCD:
-       case 0xCE:
-       case 0xCF:
-       case 0xD0:
-       case 0xD1:
-       case 0xD2:
-       case 0xD3:
-       case 0xD4:
-       case 0xD5:
-       case 0xD6:
-       case 0xD7:
-       case 0xD8:
-       case 0xD9:
-       case 0xDA:
-       case 0xDB:
-       case 0xDC:
-       case 0xDD:
-       case 0xDE:
-       case 0xDF:
-       case 0xE0:
-       case 0xE1:
-       case 0xE2:
-       case 0xE3:
-       case 0xE4:
-       case 0xE5:
-       case 0xE6:
-       case 0xE7:
-       case 0xE8:
-       case 0xE9:
-       case 0xEA:
-       case 0xEB:
-       case 0xEC:
-       case 0xED:
-       case 0xEE:
-       case 0xEF:
-       case 0xF0:
-       case 0xF1:
-       case 0xF2:
-       case 0xF3:
-       case 0xF4:      goto yy43;
-       default:        goto yy185;
+               case '-':
+               case '0':
+               case '1':
+               case '2':
+               case '3':
+               case '4':
+               case '5':
+               case '6':
+               case '7':
+               case '8':
+               case '9':
+               case 'A':
+               case 'B':
+               case 'C':
+               case 'D':
+               case 'E':
+               case 'F':
+               case 'G':
+               case 'H':
+               case 'I':
+               case 'J':
+               case 'K':
+               case 'L':
+               case 'M':
+               case 'N':
+               case 'O':
+               case 'P':
+               case 'Q':
+               case 'R':
+               case 'S':
+               case 'T':
+               case 'U':
+               case 'V':
+               case 'W':
+               case 'X':
+               case 'Y':
+               case 'Z':
+               case '_':
+               case 'a':
+               case 'b':
+               case 'c':
+               case 'd':
+               case 'e':
+               case 'f':
+               case 'g':
+               case 'h':
+               case 'i':
+               case 'j':
+               case 'k':
+               case 'l':
+               case 'm':
+               case 'n':
+               case 'o':
+               case 'p':
+               case 'q':
+               case 'r':
+               case 's':
+               case 't':
+               case 'u':
+               case 'v':
+               case 'w':
+               case 'x':
+               case 'y':
+               case 'z':
+               case 0xC2:
+               case 0xC3:
+               case 0xC4:
+               case 0xC5:
+               case 0xC6:
+               case 0xC7:
+               case 0xC8:
+               case 0xC9:
+               case 0xCA:
+               case 0xCB:
+               case 0xCC:
+               case 0xCD:
+               case 0xCE:
+               case 0xCF:
+               case 0xD0:
+               case 0xD1:
+               case 0xD2:
+               case 0xD3:
+               case 0xD4:
+               case 0xD5:
+               case 0xD6:
+               case 0xD7:
+               case 0xD8:
+               case 0xD9:
+               case 0xDA:
+               case 0xDB:
+               case 0xDC:
+               case 0xDD:
+               case 0xDE:
+               case 0xDF:
+               case 0xE0:
+               case 0xE1:
+               case 0xE2:
+               case 0xE3:
+               case 0xE4:
+               case 0xE5:
+               case 0xE6:
+               case 0xE7:
+               case 0xE8:
+               case 0xE9:
+               case 0xEA:
+               case 0xEB:
+               case 0xEC:
+               case 0xED:
+               case 0xEE:
+               case 0xEF:
+               case 0xF0:
+               case 0xF1:
+               case 0xF2:
+               case 0xF3:
+               case 0xF4: goto yy30;
+               default: goto yy161;
        }
-yy185:
-       YYDEBUG(185, YYPEEK());
+yy161:
+       YYDEBUG(161, YYPEEK());
 #line 264 "../wisitoken_grammar.re2c"
        {*id = 12; continue;}
-#line 5541 "../wisitoken_grammar_re2c.c"
-yy186:
-       YYDEBUG(186, YYPEEK());
+#line 5498 "../wisitoken_grammar_re2c.c"
+yy162:
+       YYDEBUG(162, YYPEEK());
        yyaccept = 3;
        YYSKIP();
        YYBACKUP();
        yych = YYPEEK();
        switch (yych) {
-       case 'o':       goto yy187;
-       default:        goto yy43;
+               case 'o': goto yy163;
+               default: goto yy30;
        }
-yy187:
-       YYDEBUG(187, YYPEEK());
+yy163:
+       YYDEBUG(163, YYPEEK());
        yyaccept = 3;
        YYSKIP();
        YYBACKUP();
        yych = YYPEEK();
        switch (yych) {
-       case 'l':       goto yy188;
-       default:        goto yy43;
+               case 'l': goto yy164;
+               default: goto yy30;
        }
-yy188:
-       YYDEBUG(188, YYPEEK());
+yy164:
+       YYDEBUG(164, YYPEEK());
        yyaccept = 3;
        YYSKIP();
        YYBACKUP();
        yych = YYPEEK();
        switch (yych) {
-       case 'u':       goto yy189;
-       default:        goto yy43;
+               case 'u': goto yy165;
+               default: goto yy30;
        }
-yy189:
-       YYDEBUG(189, YYPEEK());
+yy165:
+       YYDEBUG(165, YYPEEK());
        yyaccept = 3;
        YYSKIP();
        YYBACKUP();
        yych = YYPEEK();
        switch (yych) {
-       case 't':       goto yy190;
-       default:        goto yy43;
+               case 't': goto yy166;
+               default: goto yy30;
        }
-yy190:
-       YYDEBUG(190, YYPEEK());
+yy166:
+       YYDEBUG(166, YYPEEK());
        yyaccept = 3;
        YYSKIP();
        YYBACKUP();
        yych = YYPEEK();
        switch (yych) {
-       case 'i':       goto yy191;
-       default:        goto yy43;
+               case 'i': goto yy167;
+               default: goto yy30;
        }
-yy191:
-       YYDEBUG(191, YYPEEK());
+yy167:
+       YYDEBUG(167, YYPEEK());
        yyaccept = 3;
        YYSKIP();
        YYBACKUP();
        yych = YYPEEK();
        switch (yych) {
-       case 'o':       goto yy192;
-       default:        goto yy43;
+               case 'o': goto yy168;
+               default: goto yy30;
        }
-yy192:
-       YYDEBUG(192, YYPEEK());
+yy168:
+       YYDEBUG(168, YYPEEK());
        yyaccept = 3;
        YYSKIP();
        YYBACKUP();
        yych = YYPEEK();
        switch (yych) {
-       case 'n':       goto yy193;
-       default:        goto yy43;
+               case 'n': goto yy169;
+               default: goto yy30;
        }
-yy193:
-       YYDEBUG(193, YYPEEK());
+yy169:
+       YYDEBUG(169, YYPEEK());
        yyaccept = 19;
        YYSKIP();
        YYBACKUP();
        yych = YYPEEK();
        switch (yych) {
-       case '-':
-       case '0':
-       case '1':
-       case '2':
-       case '3':
-       case '4':
-       case '5':
-       case '6':
-       case '7':
-       case '8':
-       case '9':
-       case 'A':
-       case 'B':
-       case 'C':
-       case 'D':
-       case 'E':
-       case 'F':
-       case 'G':
-       case 'H':
-       case 'I':
-       case 'J':
-       case 'K':
-       case 'L':
-       case 'M':
-       case 'N':
-       case 'O':
-       case 'P':
-       case 'Q':
-       case 'R':
-       case 'S':
-       case 'T':
-       case 'U':
-       case 'V':
-       case 'W':
-       case 'X':
-       case 'Y':
-       case 'Z':
-       case '_':
-       case 'a':
-       case 'b':
-       case 'c':
-       case 'd':
-       case 'e':
-       case 'f':
-       case 'g':
-       case 'h':
-       case 'i':
-       case 'j':
-       case 'k':
-       case 'l':
-       case 'm':
-       case 'n':
-       case 'o':
-       case 'p':
-       case 'q':
-       case 'r':
-       case 's':
-       case 't':
-       case 'u':
-       case 'v':
-       case 'w':
-       case 'x':
-       case 'y':
-       case 'z':
-       case 0xC2:
-       case 0xC3:
-       case 0xC4:
-       case 0xC5:
-       case 0xC6:
-       case 0xC7:
-       case 0xC8:
-       case 0xC9:
-       case 0xCA:
-       case 0xCB:
-       case 0xCC:
-       case 0xCD:
-       case 0xCE:
-       case 0xCF:
-       case 0xD0:
-       case 0xD1:
-       case 0xD2:
-       case 0xD3:
-       case 0xD4:
-       case 0xD5:
-       case 0xD6:
-       case 0xD7:
-       case 0xD8:
-       case 0xD9:
-       case 0xDA:
-       case 0xDB:
-       case 0xDC:
-       case 0xDD:
-       case 0xDE:
-       case 0xDF:
-       case 0xE0:
-       case 0xE1:
-       case 0xE2:
-       case 0xE3:
-       case 0xE4:
-       case 0xE5:
-       case 0xE6:
-       case 0xE7:
-       case 0xE8:
-       case 0xE9:
-       case 0xEA:
-       case 0xEB:
-       case 0xEC:
-       case 0xED:
-       case 0xEE:
-       case 0xEF:
-       case 0xF0:
-       case 0xF1:
-       case 0xF2:
-       case 0xF3:
-       case 0xF4:      goto yy43;
-       default:        goto yy194;
+               case '-':
+               case '0':
+               case '1':
+               case '2':
+               case '3':
+               case '4':
+               case '5':
+               case '6':
+               case '7':
+               case '8':
+               case '9':
+               case 'A':
+               case 'B':
+               case 'C':
+               case 'D':
+               case 'E':
+               case 'F':
+               case 'G':
+               case 'H':
+               case 'I':
+               case 'J':
+               case 'K':
+               case 'L':
+               case 'M':
+               case 'N':
+               case 'O':
+               case 'P':
+               case 'Q':
+               case 'R':
+               case 'S':
+               case 'T':
+               case 'U':
+               case 'V':
+               case 'W':
+               case 'X':
+               case 'Y':
+               case 'Z':
+               case '_':
+               case 'a':
+               case 'b':
+               case 'c':
+               case 'd':
+               case 'e':
+               case 'f':
+               case 'g':
+               case 'h':
+               case 'i':
+               case 'j':
+               case 'k':
+               case 'l':
+               case 'm':
+               case 'n':
+               case 'o':
+               case 'p':
+               case 'q':
+               case 'r':
+               case 's':
+               case 't':
+               case 'u':
+               case 'v':
+               case 'w':
+               case 'x':
+               case 'y':
+               case 'z':
+               case 0xC2:
+               case 0xC3:
+               case 0xC4:
+               case 0xC5:
+               case 0xC6:
+               case 0xC7:
+               case 0xC8:
+               case 0xC9:
+               case 0xCA:
+               case 0xCB:
+               case 0xCC:
+               case 0xCD:
+               case 0xCE:
+               case 0xCF:
+               case 0xD0:
+               case 0xD1:
+               case 0xD2:
+               case 0xD3:
+               case 0xD4:
+               case 0xD5:
+               case 0xD6:
+               case 0xD7:
+               case 0xD8:
+               case 0xD9:
+               case 0xDA:
+               case 0xDB:
+               case 0xDC:
+               case 0xDD:
+               case 0xDE:
+               case 0xDF:
+               case 0xE0:
+               case 0xE1:
+               case 0xE2:
+               case 0xE3:
+               case 0xE4:
+               case 0xE5:
+               case 0xE6:
+               case 0xE7:
+               case 0xE8:
+               case 0xE9:
+               case 0xEA:
+               case 0xEB:
+               case 0xEC:
+               case 0xED:
+               case 0xEE:
+               case 0xEF:
+               case 0xF0:
+               case 0xF1:
+               case 0xF2:
+               case 0xF3:
+               case 0xF4: goto yy30;
+               default: goto yy170;
        }
-yy194:
-       YYDEBUG(194, YYPEEK());
+yy170:
+       YYDEBUG(170, YYPEEK());
 #line 258 "../wisitoken_grammar.re2c"
        {*id = 6; continue;}
-#line 5740 "../wisitoken_grammar_re2c.c"
+#line 5697 "../wisitoken_grammar_re2c.c"
 }
 #line 297 "../wisitoken_grammar.re2c"
 
diff --git a/wisitoken_grammar_runtime.adb b/wisitoken_grammar_runtime.adb
index 36a68f0a8e..6639f88c1c 100644
--- a/wisitoken_grammar_runtime.adb
+++ b/wisitoken_grammar_runtime.adb
@@ -730,10 +730,6 @@ package body WisiToken_Grammar_Runtime is
                Data.Language_Params.Language_Runtime_Name :=
                  +Get_Text (Data, Tree, Tree.Child (Nonterm, 3), Strip_Quotes 
=> True);
 
-            elsif Kind = "lr1_hash_table_size" then
-               Data.Language_Params.LR1_Hash_Table_Size :=
-                 Positive'Value (Get_Text (Data, Tree, Tree.Child (Nonterm, 
3), Strip_Quotes => True));
-
             elsif Kind = "max_parallel" then
                Data.Max_Parallel := SAL.Base_Peek_Type'Value (Get_Text (Data, 
Tree, Tree.Child (Nonterm, 3)));
 
@@ -813,10 +809,11 @@ package body WisiToken_Grammar_Runtime is
                Data.Language_Params.Use_Language_Runtime := False;
 
             elsif Kind = "no_error_recover" then
-               Data.Language_Params.Error_Recover := False;
+               Data.Language_Params.Error_Recover      := False;
+               Data.Language_Params.Recursion_Strategy := None;
 
             elsif Kind = "partial_recursion" then
-               Data.Language_Params.Partial_Recursion := True;
+               Data.Language_Params.Recursion_Strategy := Partial;
 
             elsif Kind = "start" then
                Data.Language_Params.Start_Token := +Get_Text (Data, Tree, 
Tree.Child (Nonterm, 3));



reply via email to

[Prev in Thread] Current Thread [Next in Thread]