summaryrefslogtreecommitdiffstats
path: root/tcllib/modules/page
diff options
context:
space:
mode:
authorWilliam Joye <wjoye@cfa.harvard.edu>2016-10-27 19:39:39 (GMT)
committerWilliam Joye <wjoye@cfa.harvard.edu>2016-10-27 19:39:39 (GMT)
commitea28451286d3ea4a772fa174483f9a7a66bb1ab3 (patch)
tree6ee9d8a7848333a7ceeee3b13d492e40225f8b86 /tcllib/modules/page
parentb5ca09bae0d6a1edce939eea03594dd56383f2c8 (diff)
parent7c621da28f07e449ad90c387344f07a453927569 (diff)
downloadblt-ea28451286d3ea4a772fa174483f9a7a66bb1ab3.zip
blt-ea28451286d3ea4a772fa174483f9a7a66bb1ab3.tar.gz
blt-ea28451286d3ea4a772fa174483f9a7a66bb1ab3.tar.bz2
Merge commit '7c621da28f07e449ad90c387344f07a453927569' as 'tcllib'
Diffstat (limited to 'tcllib/modules/page')
-rw-r--r--tcllib/modules/page/ChangeLog419
-rw-r--r--tcllib/modules/page/NOTES.txt64
-rw-r--r--tcllib/modules/page/analysis_peg_emodes.tcl458
-rw-r--r--tcllib/modules/page/analysis_peg_minimize.tcl51
-rw-r--r--tcllib/modules/page/analysis_peg_reachable.tcl150
-rw-r--r--tcllib/modules/page/analysis_peg_realizable.tcl257
-rw-r--r--tcllib/modules/page/compiler_peg_mecpu.tcl1642
-rw-r--r--tcllib/modules/page/gen_peg_canon.tcl481
-rw-r--r--tcllib/modules/page/gen_peg_cpkg.tcl171
-rw-r--r--tcllib/modules/page/gen_peg_hb.tcl79
-rw-r--r--tcllib/modules/page/gen_peg_me.tcl888
-rw-r--r--tcllib/modules/page/gen_peg_me.template61
-rw-r--r--tcllib/modules/page/gen_peg_mecpu.tcl289
-rw-r--r--tcllib/modules/page/gen_peg_mecpu.template48
-rw-r--r--tcllib/modules/page/gen_peg_ser.tcl63
-rw-r--r--tcllib/modules/page/gen_tree_text.tcl94
-rw-r--r--tcllib/modules/page/notes/doc_emodes.txt180
-rw-r--r--tcllib/modules/page/notes/doc_emodes_alg.txt171
-rw-r--r--tcllib/modules/page/notes/doc_grammar.txt68
-rw-r--r--tcllib/modules/page/notes/doc_normalize.txt138
-rw-r--r--tcllib/modules/page/notes/doc_reachable.txt71
-rw-r--r--tcllib/modules/page/notes/doc_realizable.txt101
-rw-r--r--tcllib/modules/page/page_intro.man35
-rw-r--r--tcllib/modules/page/page_pluginmgr.man800
-rw-r--r--tcllib/modules/page/page_util_flow.man96
-rw-r--r--tcllib/modules/page/page_util_norm_lemon.man51
-rw-r--r--tcllib/modules/page/page_util_norm_peg.man105
-rw-r--r--tcllib/modules/page/page_util_peg.man108
-rw-r--r--tcllib/modules/page/page_util_quote.man62
-rw-r--r--tcllib/modules/page/parse_lemon.tcl7420
-rw-r--r--tcllib/modules/page/parse_peg.tcl4415
-rw-r--r--tcllib/modules/page/parse_peghb.tcl118
-rw-r--r--tcllib/modules/page/parse_pegser.tcl99
-rw-r--r--tcllib/modules/page/peg_grammar.peg86
-rw-r--r--tcllib/modules/page/peg_grammar.tcl117
-rw-r--r--tcllib/modules/page/pkgIndex.tcl80
-rw-r--r--tcllib/modules/page/pluginmgr.tcl581
-rw-r--r--tcllib/modules/page/plugins/config_peg.tcl14
-rw-r--r--tcllib/modules/page/plugins/pkgIndex.tcl34
-rw-r--r--tcllib/modules/page/plugins/reader_hb.tcl114
-rw-r--r--tcllib/modules/page/plugins/reader_lemon.tcl170
-rw-r--r--tcllib/modules/page/plugins/reader_peg.tcl169
-rw-r--r--tcllib/modules/page/plugins/reader_ser.tcl114
-rw-r--r--tcllib/modules/page/plugins/reader_treeser.tcl116
-rw-r--r--tcllib/modules/page/plugins/transform_mecpu.tcl107
-rw-r--r--tcllib/modules/page/plugins/transform_reachable.tcl107
-rw-r--r--tcllib/modules/page/plugins/transform_realizable.tcl106
-rw-r--r--tcllib/modules/page/plugins/writer_hb.tcl106
-rw-r--r--tcllib/modules/page/plugins/writer_identity.tcl98
-rw-r--r--tcllib/modules/page/plugins/writer_me.tcl115
-rw-r--r--tcllib/modules/page/plugins/writer_mecpu.tcl116
-rw-r--r--tcllib/modules/page/plugins/writer_null.tcl97
-rw-r--r--tcllib/modules/page/plugins/writer_peg.tcl106
-rw-r--r--tcllib/modules/page/plugins/writer_ser.tcl104
-rw-r--r--tcllib/modules/page/plugins/writer_tpc.tcl105
-rw-r--r--tcllib/modules/page/plugins/writer_tree.tcl105
-rw-r--r--tcllib/modules/page/util_flow.tcl90
-rw-r--r--tcllib/modules/page/util_norm_lemon.tcl427
-rw-r--r--tcllib/modules/page/util_norm_peg.tcl415
-rw-r--r--tcllib/modules/page/util_peg.tcl209
-rw-r--r--tcllib/modules/page/util_quote.tcl173
61 files changed, 23434 insertions, 0 deletions
diff --git a/tcllib/modules/page/ChangeLog b/tcllib/modules/page/ChangeLog
new file mode 100644
index 0000000..05b2585
--- /dev/null
+++ b/tcllib/modules/page/ChangeLog
@@ -0,0 +1,419 @@
+2013-02-01 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+ *
+ * Released and tagged Tcllib 1.15 ========================
+ *
+
+2011-12-13 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+ *
+ * Released and tagged Tcllib 1.14 ========================
+ *
+
+2011-11-10 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+ * support/installation/modules.tcl: [Bug 3425271], reported
+ * support/installation/actions.tcl: by Stuart Cassoff. Extended
+ * apps/page: the installer to install the .template files as
+ well. Extended auto_path in the application to find the standard
+ plugins in the installation.
+
+2011-01-24 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+ *
+ * Released and tagged Tcllib 1.13 ========================
+ *
+
+2009-12-07 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+ *
+ * Released and tagged Tcllib 1.12 ========================
+ *
+
+2008-12-12 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+ *
+ * Released and tagged Tcllib 1.11.1 ========================
+ *
+
+2008-10-16 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+ *
+ * Released and tagged Tcllib 1.11 ========================
+ *
+
+2007-09-12 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+ *
+ * Released and tagged Tcllib 1.10 ========================
+ *
+
+2007-08-31 Andreas Kupries <andreask@activestate.com>
+
+ * page_util_norm_peg.man: New files. Two, for the remaining utility
+ * page_util_norm_lemon.man: packages. Lemon docs are partial.
+
+ * page_util_peg.man: New files. Three more manpages, for most of
+ * page_util_quote.man: the utility packages.
+ * page_util_flow.man:
+
+2007-08-30 Andreas Kupries <andreask@activestate.com>
+
+ * page_pluginmgr.man: First documentation for the packages, intro,
+ * page_intro.man: and the plugin management.
+ * pluginmgr.tcl: Fixed a typo in a comment.
+
+2007-06-22 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+ * pluginmgr.tcl: Replaced deprecated {expand} syntax in comments
+ with {*}.
+
+2007-03-28 Andreas Kupries <andreask@activestate.com>
+
+ * apps/page: Added a block of meta data.
+
+2007-03-23 Andreas Kupries <andreask@activestate.com>
+
+ * pkgIndex.tcl: Added MD hints.
+
+2007-03-21 Andreas Kupries <andreask@activestate.com>
+
+ * pkgIndex.tcl: Fixed version mismatches, index vs. package.
+ * plugins/pkgIndex.tcl:
+ * plugins/writer_mecpu.tcl:
+
+2007-03-07 Andreas Kupries <andreask@activestate.com>
+
+ * compiler_peg_mecpu.tcl: Fixed typo in name of required package
+ * pkgIndex.tcl: ('gasm;, was incorrectly 'gas'). Bumped
+ to version 0.1.1.
+
+2006-10-03 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+ *
+ * Released and tagged Tcllib 1.9 ========================
+ *
+
+2006-09-19 Andreas Kupries <andreask@activestate.com>
+
+ * pkgIndex.tcl: Bumped version to 0.2
+ * pluginmgr.tcl:
+
+2006-06-30 Andreas Kupries <akupries@shaw.ca>
+
+ * compiler_peg_mecpu.tcl: New packages generating ME
+ * gen_peg_mecpu.tcl: instructions for the CPU(core).
+ * gen_peg_mecpu.template: And page plugins using them.
+ * plugins/pkgIndex.tcl:
+ * plugins/transform_mecpu.tcl:
+ * plugins/writer_mecpu.tcl:
+ * pkgIndex.tcl:
+
+ * pluginmgr.tcl: Extended the page plugin environment with
+ commands allowing a plugin to write files. Intended for the
+ debugging of plugins, i.e. the dumping of internal state. The
+ destination for such files however are restricted to the current
+ working directory and its sub-directories. Currently only the
+ MEcpu compiler package has code to use this, to write the
+ intermediary graphs and some statistics (Disabled through
+ comments however).
+
+2006-01-11 Andreas Kupries <andreask@activestate.com>
+
+ * util_norm_peg.tcl: Inserted pragmas for the MDgen
+ * util_norm_lemon.tcl: application hinting that the
+ * gen_peg_me.tcl: pseudo-package 'page::plugin'
+ * analysis_peg_emodes.tcl: is not a true dependency.
+ * analysis_peg_minimize.tcl:
+ * analysis_peg_realizable.tcl:
+ * analysis_peg_reachable.tcl:
+
+ * analysis_peg_minimize.tcl: Changed bad reference to 'useful' to
+ the correct string, 'realizable'.
+
+2005-10-06 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+ *
+ * Released and tagged Tcllib 1.8 ========================
+ *
+
+2005-09-28 Andreas Kupries <andreask@activestate.com>
+
+ * NOTES.txt: Renamed from NOTES. This file had the same name as a
+ directory, causing the Windows and OS X filesystem to trip badly
+ as they considered both identical.
+
+2005-09-27 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+ * plugins/config_peg.tcl: Fixed version inconsistency.
+
+ * gen_peg_canon.tcl: Fixed frink warnings.
+ * analysis_peg_emodes.tcl (compute): Fixed inconsistency in return
+ values.
+
+2005-08-02 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+ * ../../apps/page.man: Updated the documentation to list the two
+ new plugins.
+
+ * plugins/writer_identity.tcl: Additional reader and writer plugins.
+ * plugins/reader_treeser.tcl: The writer dumps the incoming data
+ as is, for inspection. The reader takes a tree serialization,
+ validates it as such and then simply passes this one.
+
+ * util_peg.tcl: Bugfixes in the computation of symbol(Node) for
+ tree nodes. Wrong var name, and missing tree reference. Also
+ change of output to stderr to use the regular page logging
+ instead.
+
+ * util_norm_peg.tcl: Extended the code flattening nested x and /
+ operators to transform x and / operators without children into
+ epsilon's.
+
+ * gen_peg_ser.tcl: Fixed output going directly to stderr to go
+ directly through the regular page logging.
+
+2005-07-29 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+ * ../../examples/page: Renamed the directory examples/pg to the
+ proper name now in use.
+
+ * modules/page/plugins/reader_lemon.tcl: Reworked feedback generation
+ * modules/page/plugins/reader_peg.tcl: to properly signal end of
+ * modules/page/plugins/reader_ser.tcl: reading, for good linebreaks
+ * modules/page/plugins/reader_hb.tcl: in the output. Added to the
+ * ../../apps/page: plugins, manager, and application.
+ * pluginmgr.tcl:
+
+ * modules/page/plugins/transform_reach.tcl: Added generic feature
+ * modules/page/plugins/transform_use.tcl: query command to plugin
+ * modules/page/plugins/reader_lemon.tcl: manager and plugins.
+ * modules/page/plugins/writer_null.tcl: Added code to application,
+ * modules/page/plugins/writer_tree.tcl: manager and plugins to ask
+ * modules/page/plugins/writer_peg.tcl: for a feature 'timeable'. The
+ * modules/page/plugins/writer_ser.tcl: application will defer the
+ * modules/page/plugins/writer_tpc.tcl: collection of timing data to
+ * modules/page/plugins/writer_hb.tcl: the plugin if it can do so.
+ * modules/page/plugins/writer_me.tcl: Extended collection of timing
+ * modules/page/plugins/reader_peg.tcl: data from reader to all uses
+ * modules/page/plugins/reader_ser.tcl: of plugins. also a better
+ * modules/page/plugins/reader_hb.tcl: report at the end. All plugins
+ * ../../apps/page: are now timeable. Especially
+ * pluginmgr.tcl: the readers now provide much better data about the
+ number of characters they have read per second.
+
+2005-07-26 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+ * ../../apps/page.man: Completed the documentation of the 'page'
+ application.
+
+ * ../../apps/page: Rewrote option processing to handle the changes
+ in the handling of configuration plugins and files. Also now
+ handling the changes when the default options are used. Better
+ error messages when plugins are not found. Corrected the
+ handling of -a, -p and their long equivalents.
+
+ * pluginmgr.tcl: Rewritten the configuration loader to accept
+ files containing lists of options as well, possibly quoted using
+ double-quotes and quotes.
+
+ * plugins/config_peg.tcl: ** New file **
+ * pkgIndex.tcl: Put the predefined configuration "peg" aka "PEG
+ parser generator" into a plugin.
+
+
+2005-07-19 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+ * A lot of changes. All packages have been renamed, i.e. shuffled
+ to different places in the namespace hierarchy. All have been
+ placed under "::page", and made more consistent. The files have
+ been moved around too, so that their names reflect the namespace
+ hierarchy as well. A customized pluginmgr has been written on
+ top of the general one, and the application has been rewritten
+ to use it. The existing parsers, code generators and
+ transformers have been put into proper plugins.
+
+2005-05-15 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+ * examples/pg/parse.y: Used the new lemon frontend to convert the
+ * examples/pg/sql.log: SQL grammar spec found in sqlite into an
+ * examples/pg/sql.peg: incomplete PEG spec from which we can
+ derive a complete spec (Removal of left
+ recursion, and completion/correction of the
+ lexical definitions).
+
+ * examples/pg/lemon.html: Created a frontend for reading grammar
+ * examples/pg/lemon.peg: specifications written for the LEMON
+ * peg_grammar_lemon.tcl: parser generator by Richard Hipp. The
+ * peg_norm_lemon.tcl: PEG grammar spec is based on the docu-
+ * apps/pg: mentation and the SQL spec found in
+ sqlite3. Integrated the frontend into
+ the PG application.
+
+ * peg_tpcserwriter.tcl: Added code to deal with grammars without
+ * peg_tpcphbwriter.tcl: start expression (as can be generated by
+ * peg_pegwriter.tcl: the usefulness transform).
+ * peg_mewriter.tcl:
+ * peg_writer.tcl:
+ * peg_emodes.tcl:
+ * peg_useful.tcl:
+
+2005-05-11 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+ * peg_emodes.tcl: Fixed problem in gen() phase. A gen() switching
+ to no can force acc() to no as well.
+
+ * apps/pg: Reworked PEG frontend code a bit to allow quick
+ switching between four variants of the PEG fronted (ME parser
+ vs. interpreted grammar, timed vs. untimed).
+
+ * pkgIndex.tcl:
+ * peg_grammar_me.tcl: New implementation of PEG frontend. PEG
+ parser as generated by the ME backend, after the fixes done
+ yesterday (PG dogfooding / bootstrapping).
+
+2005-05-11 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+ * peg_mewriter.tcl: Fixed a number of bugs (special char classes
+ generated bogus code, nonterminals and ! have to import status
+ variable when sub expression is terminal). Added (inactive) code
+ for insertion of logging code into the generated parser.
+
+2005-05-10 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+ * apps/pg: Removed two superfluous commands. Added readable
+ descriptions for the backends. Added 'null' backend which does
+ nothing. Added non-verbose char reader, disabled right now.
+
+ * peg_mewriter.tcl: Completely rewritten, removed all templates
+ save the main one, all code composition via lists, completed
+ option, kleene and pos kleene code generator, added comments
+ containing the parsing expressions matched by a particular
+ command.
+
+ * peg_quote.tcl: More forms of quoting characters.
+
+2005-05-07 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+ * doc_emodes.txt: Recorded some thought about the transformation
+ which make it not worth to implement right now, as we need an
+ LL(1) grammar, otherwise we ran into either cache incoherency or
+ exponential time.
+
+ * peg_emodes.tcl: New transformation. Mode analysis. Computes
+ accept/generate data for all nodes from the given mode hints,
+ finds places where the mode can be made more strict than
+ specified.
+
+ * pg_flow.tcl: Fixed bug in setup of flow when using a start set
+ of nodes.
+
+ * doc_useful.txt: Rewritten to use the new flow management. Stores
+ * peg_useful.tcl: the results differently as well, easier to use
+ by the remove code. Updated the documentation of the transform
+ as well.
+
+2005-05-06 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+ * doc_reachable.tcl:
+ * peg_reachable.tcl: Rewritten to use the new flow
+ management. Stores the results differently as well, easier to
+ use by the remove code. Updated the documentation of the
+ transform as well.
+
+ * pg_flow.tcl: New utility. Generic tree walking, for both topdown
+ and bottomup walks, and anything in between. Maintains the state
+ of nodes to visit, and the code executed per node determines
+ what other nodes to visit.
+
+2005-05-05 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+ * peg_utilities.tcl: Bugfix, have to update user information of
+ symbols when nodes are removed, their definitions may have lost
+ callers.
+
+ * peg_tpcser.tcl: A first, two frontends, reading grammars which
+ * peg_tpcphb.tcl: are either in halfbaked form, or a serialization.
+
+ * peg_tpcphbwriter.tcl: Two new backends, writing the grammar out
+ * peg_tpcserwriter.tcl: as a halfbaked package (See peg_writer,
+ reduced to the Start and Define commands), and as serialization
+ of a PEG container.
+
+ * peg_writer.tcl: Moved a number of generally useful
+ * peg_utilities.tcl: functionality into the utilities.
+
+2005-05-03 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+ * peg_useful.tcl: Tweaked the definition of usefulness, better
+ based on the definition for CFG's.
+
+2005-05-02 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+ * peg_pegwriter.tcl, peg_mewriter.tcl: Updated to changed NPEGT
+ definition (changed attribute names, node classification).
+
+ * peg_useful.tcl: Bugfix, we delete the subtrees of all unuseful
+ nodes. No cutting, deleting.
+
+ * treewriter.tcl: Back unquoted characters. Better readable.
+
+2005-04-29 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+ * peg_useful.tcl: Ditto for the usefulness analysis and
+ * doc_useful.txt: transform. Rewrote algorithm to use more proc
+ local state with quicker access, and easier checks.
+
+ * peg_reachable.tcl: Documented reachable computation and
+ * doc_reachable.txt: transform, updated to the changes in the
+ Normalized PE Grammar Tree.
+
+ * peg_utilities.tcl: New helper package. Common operations on the
+ tree.
+
+2005-04-28 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+ * Reworked documentation of 'Raw PE Grammar AS Tree', as generated
+ by frontend, updated mengine to that.
+
+ * Reworked documentation of normalization step, and updated the
+ transformation code to it. Note: The non-generic backends are
+ broken by this.
+
+ * updated generic treewriter to quote attribute strings, as they
+ now may contain unprintable characters (the attributes carrying
+ lexemes).
+
+2005-04-27 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+ * Added backend writing the input back in the same format, i.e. as
+ PEG. Bug fixes. Added option processing to the application to
+ switch between backends, and to select optimization levels.
+
+ * Character de/encode put into separate package. Started backend
+ writing a recursive descent parser for a grammar, based on
+ mengine.
+
+2005-04-26 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+ * Bug fixes. Added transformations to com;ute reachable and useful
+ parts of the grammar, for minimizing it.
+
+2005-04-23 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+ * Restructured utility packages (renames), and updated the
+ backends.
+
+2005-04-18 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+ * Completed backend for writing the grammar as package providing a
+ PEG container. Bug fixes. First internal docs.
+
+2005-04-16 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+ * Bugfixes, added a transformation normalizing the raw AST.
+
+2005-04-15 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+ * New module: Utility packages for the parser generator
+ application.
diff --git a/tcllib/modules/page/NOTES.txt b/tcllib/modules/page/NOTES.txt
new file mode 100644
index 0000000..030353a
--- /dev/null
+++ b/tcllib/modules/page/NOTES.txt
@@ -0,0 +1,64 @@
+Transforms
+==========
+
+Consider: character sequence to string fusing in PEG writer.
+Consider: expression enumeration, to determine if there are common
+ expressions in the grammar which could be factored into
+ their own match procedures (*).
+
+Consider: Transformations which expand the number of common
+ expressions. Example would be strings, i.e. macthing of
+ character sequences. Instead of matching all in one use a
+ nested sequence of matching ever-growing prefixes. This
+ ensures that common prefixes in terminal strings are
+ factored into one matcher. And if we use nonterminal
+ procedures (See * below) this also enhances the caching,
+ especially if common prefixes occur in different branches of
+ a choice.
+
+(*) This could simple procedures, i.e. _not_ nonterminals. This would
+be without caching. Could also be nonterminal procedures, with mode
+expand (for value, discard would stay), to make its presence invisible
+to the AS tree structure.
+
+
+Removal of nonterminal chains
+
+ A <- B
+ B <- C
+ C <- ...
+
+Static match results !!
+
+mewriter has to be able to work with and
+without static match. Basic expr modes are
+something mewriter should do on its own
+as well.
+
+
+Compile *, + with helper nonterminals which are not shown as such
+(mode: expand).
+
+static match result - sequence - ability to remove checks after an
+always ok call, and abort sequence upon always fail.
+
+static match result - choice - ability to abort choice after ok, or
+skip always fail branches.
+
+
+Main parse routine can be simplified if start expression is a single
+nonterminal, and not a real complex expression.
+
+
+Need encoder for printable tcl char string.
+
+- The basic encoder generates a string acceptable to tcl parser for
+ use in a script, as part of the code.
+
+- The new encoder has to generate a string acceptable to the tcl
+ parser, for use in a script, which then written (puts) generates a
+ human readable representation of the character.
+
+I.e. LF in basic encode is \n, when printed it is an invislble
+character, i.e. a linefeed. In string/human encode it is \\n, which
+prints as \n, making it a readable representation of the character
diff --git a/tcllib/modules/page/analysis_peg_emodes.tcl b/tcllib/modules/page/analysis_peg_emodes.tcl
new file mode 100644
index 0000000..a6b224e
--- /dev/null
+++ b/tcllib/modules/page/analysis_peg_emodes.tcl
@@ -0,0 +1,458 @@
+# -*- tcl -*-
+# ### ### ### ######### ######### #########
+
+# Perform mode analysis (x) on the PE grammar delivered by the
+# frontend. The grammar is in normalized form (*).
+#
+# (x) = See "doc_emodes.txt".
+# and "doc_emodes_alg.txt".
+# (*) = See "doc_normalize.txt".
+
+# This package assumes to be used from within a PAGE plugin. It uses
+# the API commands listed below. These are identical across the major
+# types of PAGE plugins, allowing this package to be used in reader,
+# transform, and writer plugins. It cannot be used in a configuration
+# plugin, and this makes no sense either.
+#
+# To ensure that our assumption is ok we require the relevant pseudo
+# package setup by the PAGE plugin management code.
+#
+# -----------------+--
+# page_info | Reporting to the user.
+# page_warning |
+# page_error |
+# -----------------+--
+# page_log_error | Reporting of internals.
+# page_log_warning |
+# page_log_info |
+# -----------------+--
+
+# ### ### ### ######### ######### #########
+## Requisites
+
+# @mdgen NODEP: page::plugin
+
+package require page::plugin ; # S.a. pseudo-package.
+package require page::util::flow ; # Dataflow walking.
+package require page::util::peg ; # General utilities.
+package require treeql
+
+namespace eval ::page::analysis::peg::emodes {
+ namespace import ::page::util::peg::*
+}
+
+# ### ### ### ######### ######### #########
+## API
+
+proc ::page::analysis::peg::emodes::compute {t} {
+
+ # Ignore call if already done before
+ if {[$t keyexists root page::analysis::peg::emodes]} {return 1}
+
+ # We do not actually compute per node a mode, but rather their
+ # gen'erate and acc'eptance properties, as described in
+ # "doc_emodes.txt".
+
+ # Note: This implementation will not compute acc/gen information
+ # for unreachable nodes.
+
+ # --- --- --- --------- --------- ---------
+
+ array set acc {} ; # Per node X, acc(X), undefined if no element
+ array set call {} ; # Per definition node, number of users
+ array set cala {} ; # Per definition node, number of (non-)accepting users
+
+ foreach {sym def} [$t get root definitions] {
+ set call($def) [llength [$t get $def users]]
+ set cala(0,$def) 0
+ set cala(1,$def) 0
+ }
+
+ set acc(root) 1 ; # Sentinel for root of start expression.
+
+ # --- --- --- --------- --------- ---------
+
+ #puts stderr ~~~~\t~~~\t~~~\t~~~\t~~~
+ #puts stderr Node\tAcc\tNew\tWhat\tOp
+ #puts stderr ~~~~\t~~~\t~~~\t~~~\t~~~
+
+ # A node is visited if its value for acc() is either undefined or
+ # may have changed. Basic flow is top down, from the start
+ # expression and a definition a child of its invokers.
+
+ set gstart [$t get root start]
+ if {$gstart eq ""} {
+ page_error " No start expression, unable to compute accept/generate properties"
+ return 0
+ }
+
+ page::util::flow [list $gstart] flow n {
+ # Determine first or new value.
+
+ #puts -nonewline stderr [string replace $n 1 3]
+
+ if {![info exists acc($n)]} {
+ set a [Accepting $t $n acc call cala]
+ set acc($n) $a
+ set change 0
+
+ #puts -nonewline stderr \t-\t$a\t^
+ } else {
+ set a [Accepting $t $n acc call cala]
+ set old $acc($n)
+ if {$a == $old} {
+ #puts stderr \t$old\t$a\t\ =
+ continue
+ }
+ set change 1
+ set acc($n) $a
+
+ #puts -nonewline stderr \t$old\t$a\t\ \ *
+ }
+
+ # Update counters in definitions, if the node invokes them.
+ # Also, schedule the children for their (re)definition.
+
+ if {[$t keyexists $n symbol]} {
+ #puts -nonewline stderr \t\ DEF\t[$t get $n symbol]\t[$t get $n mode]
+ } else {
+ #puts -nonewline stderr \t[$t get $n op]\t\t
+ }
+
+ if {[$t keyexists $n op] && ([$t get $n op] eq "n")} {
+ #puts -nonewline stderr ->\ [$t get $n sym]
+ set def [$t get $n def]
+ if {$def eq ""} continue
+
+ if {$change} {
+ incr cala($old,$def) -1
+ }
+ incr cala($a,$def)
+ $flow visit $def
+
+ #puts -nonewline stderr @$def\t(0a$cala(0,$def),\ 1a$cala(1,$def),\ #$call($def))\tv($def)
+ #puts stderr ""
+ continue
+ }
+
+ #puts stderr \t\t\t\tv([$t children $n])
+ $flow visitl [$t children $n]
+ }
+
+ # --- --- --- --------- --------- ---------
+
+ array set gen {} ; # Per node X, gen(X), undefined if no element
+ array set nc {} ; # Per node, number of children
+ array set ng {} ; # Per node, number of (non-)generating children
+
+ foreach n [$t nodes] {
+ set nc($n) [$t numchildren $n]
+ set ng(0,$n) 0
+ set ng(1,$n) 0
+ }
+
+ # --- --- --- --------- --------- ---------
+
+ #puts stderr ~~~~\t~~~\t~~~\t~~~\t~~~
+ #puts stderr Node\tGen\tNew\tWhat\tOp
+ #puts stderr ~~~~\t~~~\t~~~\t~~~\t~~~
+
+ # A node is visited if its value for gen() is either undefined or
+ # may have changed. Basic flow is bottom up, from the all
+ # leaves (and lookahead operators). Users of a definition are
+ # considered as its parents.
+
+ set start [$t leaves]
+ set q [treeql q -tree $t]
+ q query tree withatt op ! over n {lappend start $n}
+ q query tree withatt op & over n {lappend start $n}
+ q destroy
+
+ page::util::flow $start flow n {
+ # Ignore root.
+
+ if {$n eq "root"} continue
+
+ #puts -nonewline stderr [string replace $n 1 3]
+
+ # Determine first or new value.
+
+ if {![info exists gen($n)]} {
+ set g [Generating $t $n gen nc ng acc call cala]
+ set gen($n) $g
+
+ #puts -nonewline stderr \t-\t$g\t^
+
+ } else {
+ set g [Generating $t $n gen nc ng acc call cala]
+ set old $gen($n)
+ if {$g eq $old} {
+ #puts stderr \t$old\t$g\t\ =
+ continue
+ }
+ set gen($n) $g
+
+ #puts -nonewline stderr \t$old\t$g\t\ \ *
+ }
+
+ if {($g ne "maybe") && !$g && $acc($n)} {
+ # No generate here implies that none of our children will
+ # generate anything either. So the current acceptance of
+ # these non-existing values can be safely forced to
+ # non-acceptance.
+
+ set acc($n) 0
+ #puts -nonewline stderr "-a"
+ }
+
+ if {0} {
+ if {[$t keyexists $n symbol]} {
+ #puts -nonewline stderr \t\ DEF\t[$t get $n symbol]\t[$t get $n mode]
+ } else {
+ #puts -nonewline stderr \t[$t get $n op]\t\t
+ }
+ }
+
+ #puts -nonewline stderr \t(0g$ng(0,$n),1g$ng(1,$n),\ #$nc($n))
+
+ # Update counters in the (virtual) parents, and schedule them
+ # for a visit.
+
+ if {[$t keyexists $n symbol]} {
+ # Users are virtual parents.
+
+ set users [$t get $n users]
+ $flow visitl $users
+
+ if {$g ne "maybe"} {
+ foreach u $users {incr ng($g,$u)}
+ }
+ #puts stderr \tv($users)
+ continue
+ }
+
+ set p [$t parent $n]
+ $flow visit $p
+ if {$g ne "maybe"} {
+ incr ng($g,$p)
+ }
+
+ #puts stderr \tv($p)
+ }
+
+ # --- --- --- --------- --------- ---------
+
+ # Copy the calculated data over into the tree.
+ # Note: There will be no data for unreachable nodes.
+
+ foreach n [$t nodes] {
+ if {$n eq "root"} continue
+ if {![info exists acc($n)]} continue
+ $t set $n acc $acc($n)
+ $t set $n gen $gen($n)
+ }
+
+ # Recompute the modes based on the current
+ # acc/gen status of the definitions.
+
+ #puts stderr ~~~~\t~~~\t~~~~\t~~~\t~~~\t~~~
+ #puts stderr Node\tSym\tMode\tNew\tGen\tAcc
+ #puts stderr ~~~~\t~~~\t~~~~\t~~~\t~~~\t~~~
+
+ foreach {sym def} [$t get root definitions] {
+ set m {}
+
+ set old [$t get $def mode]
+
+ if {[info exists acc($def)]} {
+ switch -exact -- $gen($def)/$acc($def) {
+ 0/0 {set m discard}
+ 0/1 {error "Bad gen/acc for $sym"}
+ 1/0 {# don't touch (match, leaf)}
+ 1/1 {set m value}
+ maybe/0 {error "Bad gen/acc for $sym"}
+ maybe/1 {set m value}
+ }
+ if {$m ne ""} {
+ # Should check correctness of change, if any (We can drop
+ # to discard, nothing else).
+ $t set $def mode $m
+ }
+ #puts stderr [string replace $def 1 3]\t$sym\t$old\t[$t get $def mode]\t[$t get $def gen]\t[$t get $def acc]
+ } else {
+ #puts stderr [string replace $def 1 3]\t$sym\t$old\t\t\t\tNOT_REACHED
+ }
+ }
+
+ #puts stderr ~~~~\t~~~\t~~~~\t~~~\t~~~\t~~~
+
+ # Wrap up the whole state and save it in the tree. No need to
+ # throw this away, useful for other mode based transforms and
+ # easier to get in this way than walking the tree again.
+
+ $t set root page::analysis::peg::emodes [list \
+ [array get acc] \
+ [array get call] \
+ [array get cala] \
+ [array get gen] \
+ [array get nc] \
+ [array get ng]]
+ return 1
+}
+
+proc ::page::analysis::peg::emodes::reset {t} {
+ # Remove marker, allow recalculation of emodesness after changes.
+
+ $t unset root page::analysis::peg::emodes
+ return
+}
+
+# ### ### ### ######### ######### #########
+## Internal
+
+proc ::page::analysis::peg::emodes::Accepting {t n av cv cav} {
+ upvar 1 $av acc $cv call $cav cala
+
+ # Definitions accept based on how they are called first, and on
+ # their mode if that is not possible.
+
+ if {[$t keyexists $n symbol]} {
+ # Call based acceptance.
+ # !acc if all callers do not accept.
+
+ if {$cala(0,$n) >= $call($n)} {
+ return 0
+ }
+
+ # Falling back to mode specific accptance
+ return [expr {([$t get $n mode] eq "value") ? 1 : 0}]
+ }
+
+ set op [$t get $n op]
+
+ # Lookahead operators will never accept.
+
+ if {($op eq "!") || ($op eq "&")} {
+ return 0
+ }
+
+ # All other operators inherit the acceptance
+ # of their parent.
+
+ return $acc([$t parent $n])
+}
+
+proc ::page::analysis::peg::emodes::Generating {t n gv ncv ngv av cv cav} {
+ upvar 1 $gv gen $ncv nc $ngv ng $av acc $cv call $cav cala
+ # ~~~ ~~ ~~ ~~~ ~~~~ ~~~~
+
+ # Definitions generate based on their mode, their defining
+ # expression, and the acceptance of their callers.
+
+ if {[$t keyexists $n symbol]} {
+
+ # If no caller accepts a value, then this definition will not
+ # generate one, even if its own mode asked it to do so.
+
+ if {$cala(0,$n) >= $call($n)} {
+ return 0
+ }
+
+ # The definition has callers accepting values and callres not
+ # doing so. It will generate as per its own mode and defining
+ # expression.
+
+ # The special modes know if they generate a value or not.
+ # The pass through mode looks at the expression for the
+ # information.
+
+ switch -exact -- [$t get $n mode] {
+ value {return $gen([lindex [$t children $n] 0])}
+ match {return 1}
+ leaf {return 1}
+ discard {return 0}
+ }
+ error PANIC
+ }
+
+ set op [$t get $n op]
+
+ # Inner nodes generate based on operator and children.
+
+ if {$nc($n)} {
+ switch -exact -- $op {
+ ! - & {return 0}
+ ? - * {
+ # No for all children --> no
+ # Otherwise --> maybe
+
+ if {$ng(0,$n) >= $nc($n)} {
+ return 0
+ } else {
+ return maybe
+ }
+ }
+ + - / - | {
+ # Yes for all children --> yes
+ # No for all children --> no
+ # Otherwise --> maybe
+
+ if {$ng(1,$n) >= $nc($n)} {
+ return 1
+ } elseif {$ng(0,$n) >= $nc($n)} {
+ return 0
+ } else {
+ return maybe
+ }
+ }
+ x {
+ # Yes for some children --> yes
+ # No for all children --> no
+ # Otherwise --> maybe
+
+ if {$ng(1,$n) > 0} {
+ return 1
+ } elseif {$ng(0,$n) >= $nc($n)} {
+ return 0
+ } else {
+ return maybe
+ }
+ }
+ }
+ error PANIC
+ }
+
+ # Nonterminal leaves generate based on acceptance from their
+ # parent and the referenced definition.
+
+ # As acc(X) == acc(parent(X)) the test doesn't have to go to the
+ # parent itself.
+
+ if {$op eq "n"} {
+ if {[info exists acc($n)] && !$acc($n)} {return 0}
+
+ set def [$t get $n def]
+
+ # Undefine symbols do not generate anything.
+ if {$def eq ""} {return 0}
+
+ # Inherit directly from the definition, if existing.
+ if {![info exists gen($def)]} {
+ return maybe
+ }
+
+ return $gen($def)
+ }
+
+ # Terminal leaves generate values if and only if such values are
+ # accepted by their parent. As acc(X) == acc(parent(X) the test
+ # doesn't have to go to the parent itself.
+
+
+ return $acc($n)
+}
+
+# ### ### ### ######### ######### #########
+## Ready
+
+package provide page::analysis::peg::emodes 0.1
diff --git a/tcllib/modules/page/analysis_peg_minimize.tcl b/tcllib/modules/page/analysis_peg_minimize.tcl
new file mode 100644
index 0000000..84cf07e
--- /dev/null
+++ b/tcllib/modules/page/analysis_peg_minimize.tcl
@@ -0,0 +1,51 @@
+# -*- tcl -*-
+# Transform - Minimize the grammar, through the removal of the
+# unreachable and not useful nonterminals (and expressions).
+
+# This package assumes to be used from within a PAGE plugin. It uses
+# the API commands listed below. These are identical across the major
+# types of PAGE plugins, allowing this package to be used in reader,
+# transform, and writer plugins. It cannot be used in a configuration
+# plugin, and this makes no sense either.
+#
+# To ensure that our assumption is ok we require the relevant pseudo
+# package setup by the PAGE plugin management code.
+#
+# -----------------+--
+# page_info | Reporting to the user.
+# page_warning |
+# page_error |
+# -----------------+--
+# page_log_error | Reporting of internals.
+# page_log_warning |
+# page_log_info |
+# -----------------+--
+
+# ### ### ### ######### ######### #########
+## Requisites
+
+# @mdgen NODEP: page::plugin
+
+package require page::plugin ; # S.a. pseudo-package.
+package require page::analysis::peg::reachable
+package require page::analysis::peg::realizable
+
+namespace eval ::page::analysis::peg {}
+
+# ### ### ### ######### ######### #########
+## API
+
+proc ::page::analysis::peg::minimize {t} {
+ page_info {[PEG Minimization]}
+ page_log_info ..Reachability ; ::page::analysis::peg::reachable::remove!
+ page_log_info ..Realizability ; ::page::analysis::peg::realizable::remove!
+
+ page_log_info Ok
+ return
+}
+
+# ### ### ### ######### ######### #########
+## Ready
+
+package provide page::analysis::peg::minimize 0.1
+
diff --git a/tcllib/modules/page/analysis_peg_reachable.tcl b/tcllib/modules/page/analysis_peg_reachable.tcl
new file mode 100644
index 0000000..27d12ff
--- /dev/null
+++ b/tcllib/modules/page/analysis_peg_reachable.tcl
@@ -0,0 +1,150 @@
+# -*- tcl -*-
+# ### ### ### ######### ######### #########
+
+# Perform reachability analysis on the PE grammar delivered by the
+# frontend. The grammar is in normalized form (reduced to essentials,
+# graph like node-x-references, expression trees).
+
+# This package assumes to be used from within a PAGE plugin. It uses
+# the API commands listed below. These are identical across the major
+# types of PAGE plugins, allowing this package to be used in reader,
+# transform, and writer plugins. It cannot be used in a configuration
+# plugin, and this makes no sense either.
+#
+# To ensure that our assumption is ok we require the relevant pseudo
+# package setup by the PAGE plugin management code.
+#
+# -----------------+--
+# page_info | Reporting to the user.
+# page_warning |
+# page_error |
+# -----------------+--
+# page_log_error | Reporting of internals.
+# page_log_warning |
+# page_log_info |
+# -----------------+--
+
+# ### ### ### ######### ######### #########
+## Requisites
+
+# @mdgen NODEP: page::plugin
+
+package require page::plugin ; # S.a. pseudo-package.
+package require page::util::flow ; # Dataflow walking.
+package require page::util::peg ; # General utilities.
+
+namespace eval ::page::analysis::peg::reachable {
+ namespace import ::page::util::peg::*
+}
+
+# ### ### ### ######### ######### #########
+## API
+
+proc ::page::analysis::peg::reachable::compute {t} {
+
+ # Ignore call if already done before
+ if {[$t keyexists root page::analysis::peg::reachable]} return
+
+ # We compute the set of all nodes which are reachable from the
+ # root node of the start expression. This is a simple topdown walk
+ # where the children of all reachable nodes are mode reachable as
+ # well, and invokations of nonterminals symbols are treated as
+ # children as well. At the end of the flow all reachable non-
+ # terminal symbols and their expressions are marked, and none
+ # other.
+
+ # Initialize walking state: 2 arrays, all nodes (except root) are
+ # in or the other array, and their location tells if they are
+ # reachable or not. In the beginning no node is reachable. The
+ # goal array (reach) also serves as minder of which nodes have
+ # been seen, to cut multiple visits short.
+
+ array set unreach {} ; foreach n [$t nodes] {set unreach($n) .}
+ unset unreach(root)
+ array set reach {}
+
+ # A node is visited if it has been determined that it is indeed
+ # reachable.
+
+ page::util::flow [list [$t get root start]] flow n {
+ # Ignore nodes already reached.
+ if {[info exists reach($n)]} continue
+
+ # Reclassify node, has been reached now.
+ unset unreach($n)
+ set reach($n) .
+
+ # Schedule children for visit --> topdown flow.
+ $flow visitl [$t children $n]
+
+ # Treat n-Nodes as special, their definition as indirect
+ # child. But ignore invokations of undefined nonterminal
+ # symbols, or those already marked as reachable.
+
+ if {![$t keyexists $n op]} continue
+ if {[$t get $n op] ne "n"} continue
+
+ set def [$t get $n def]
+ if {$def eq ""} continue
+ if {[info exists reach($def)]} continue
+ $flow visit $def
+ }
+
+ # Store results. This also serves as marker.
+
+ $t set root page::analysis::peg::reachable [array names reach]
+ $t set root page::analysis::peg::unreachable [array names unreach]
+ return
+}
+
+proc ::page::analysis::peg::reachable::remove! {t} {
+
+ # Determine which nonterminal symbols are reachable from the root
+ # of the start expression.
+
+ compute $t
+
+ # Remove all nodes which are not reachable.
+
+ set unreach [$t get root page::analysis::peg::unreachable]
+ foreach n [lsort $unreach] {
+ if {[$t exists $n]} {
+ $t delete $n
+ }
+ }
+
+ # Notify the user of the definitions which were among the removed
+ # nodes. Keep only the still-existing definitions.
+
+ set res {}
+ foreach {sym def} [$t get root definitions] {
+ if {![$t exists $def]} {
+ page_warning " $sym: Unreachable nonterminal symbol, deleting"
+ } else {
+ lappend res $sym $def
+ }
+ }
+
+ # Clear computation results.
+
+ $t unset root page::analysis::peg::reachable
+ $t unset root page::analysis::peg::unreachable
+
+ $t set root definitions $res
+ updateUndefinedDueRemoval $t
+ return
+}
+
+proc ::page::analysis::peg::reachable::reset {t} {
+ # Remove marker, allow recalculation of reachability after
+ # changes.
+
+ $t unset root page::analysis::peg::reachable
+ $t unset root page::analysis::peg::unreachable
+ return
+}
+
+# ### ### ### ######### ######### #########
+## Ready
+
+package provide page::analysis::peg::reachable 0.1
diff --git a/tcllib/modules/page/analysis_peg_realizable.tcl b/tcllib/modules/page/analysis_peg_realizable.tcl
new file mode 100644
index 0000000..ef32a68
--- /dev/null
+++ b/tcllib/modules/page/analysis_peg_realizable.tcl
@@ -0,0 +1,257 @@
+# -*- tcl -*-
+# ### ### ### ######### ######### #########
+
+# Perform realizability analysis (x) on the PE grammar delivered by
+# the frontend. The grammar is in normalized form (reduced to
+# essentials, graph like node-x-references, expression trees).
+#
+# (x) = See "doc_realizable.txt".
+
+# This package assumes to be used from within a PAGE plugin. It uses
+# the API commands listed below. These are identical across the major
+# types of PAGE plugins, allowing this package to be used in reader,
+# transform, and writer plugins. It cannot be used in a configuration
+# plugin, and this makes no sense either.
+#
+# To ensure that our assumption is ok we require the relevant pseudo
+# package setup by the PAGE plugin management code.
+#
+# -----------------+--
+# page_info | Reporting to the user.
+# page_warning |
+# page_error |
+# -----------------+--
+# page_log_error | Reporting of internals.
+# page_log_warning |
+# page_log_info |
+# -----------------+--
+
+# ### ### ### ######### ######### #########
+## Requisites
+
+# @mdgen NODEP: page::plugin
+
+package require page::plugin ; # S.a. pseudo-package.
+package require page::util::flow ; # Dataflow walking.
+package require page::util::peg ; # General utilities.
+package require treeql
+
+namespace eval ::page::analysis::peg::realizable {
+ namespace import ::page::util::peg::*
+}
+
+# ### ### ### ######### ######### #########
+## API
+
+proc ::page::analysis::peg::realizable::compute {t} {
+
+ # Ignore call if already done before
+
+ if {[$t keyexists root page::analysis::peg::realizable]} return
+
+ # We compute the set of realizable nonterminal symbols by doing the
+ # computation for all partial PE's in the grammar. We start at the
+ # leaves and then iteratively propagate the property as far as
+ # possible using the rules defining it, see the specification.
+
+ # --- --- --- --------- --------- ---------
+
+ # Initialize all nodes and the local arrays. Everything is not
+ # realizable, except for the terminal leafs of the tree. Their parents
+ # are scheduled to be visited as well.
+
+ array set realizable {} ; # Place where realizable nodes are held
+ array set unrealizable {} ; # Place where unrealizable nodes are held
+ array set nc {} ; # Per node, number of children.
+ array set uc {} ; # Per node, number of realizable children.
+
+ set nodeset [$t leaves]
+
+ set q [treeql q -tree $t]
+ $q query tree withatt op * over n {lappend nodeset $n}
+ $q query tree withatt op ? over n {lappend nodeset $n}
+ q destroy
+
+ foreach n [$t nodes] {
+ set unrealizable($n) .
+ set nc($n) [$t numchildren $n]
+ set uc($n) 0
+ }
+
+ # A node is visited if it _may_ have changed its status (to
+ # realizability).
+
+ page::util::flow $nodeset flow n {
+ # Realizable nodes cannot change, ignore them.
+
+ if {[info exists realizable($n)]} continue
+
+ # Determine new state of realizability, ignore a node if it is
+ # unchanged.
+
+ if {![Realizable $t $n nc uc realizable]} continue
+
+ # Reclassify changed node, it is now realizable.
+ unset unrealizable($n)
+ set realizable($n) .
+
+ # Schedule visits to nodes which may have been affected by
+ # this change. Update the relevant counters as well.
+
+ # @ root - none
+ # @ definition - users of the definition
+ # otherwise - parent of operator.
+
+ if {$n eq "root"} continue
+
+ if {[$t keyexists $n symbol]} {
+ set users [$t get $n users]
+ $flow visitl $users
+ foreach u $users {
+ incr uc($u)
+ }
+ continue
+ }
+
+ set p [$t parent $n]
+ incr uc($p)
+ $flow visit $p
+ }
+
+ # Set marker preventing future calls.
+ $t set root page::analysis::peg::realizable [array names realizable]
+ $t set root page::analysis::peg::unrealizable [array names unrealizable]
+ return
+}
+
+proc ::page::analysis::peg::realizable::remove! {t} {
+ # Determine which parts of the grammar are realizable
+
+ compute $t
+
+ # Remove anything which is not realizable (and all their children),
+ # except for the root itself, should it be unrealizablel.
+
+ set unreal [$t get root page::analysis::peg::unrealizable]
+ foreach n [lsort $unreal] {
+ if {$n eq "root"} continue
+ if {[$t exists $n]} {
+ $t delete $n
+ }
+ }
+
+ # Notify the user of the definitions which were among the removed
+ # nodes. Keep only the still-existing definitions.
+
+ set res {}
+ foreach {sym def} [$t get root definitions] {
+ if {![$t exists $def]} {
+ page_warning " $sym: Nonterminal symbol is not realizable, removed."
+ } else {
+ lappend res $sym $def
+ }
+ }
+ $t set root definitions $res
+
+ if {![$t exists [$t get root start]]} {
+ page_warning " <Start expression>: Is not realizable, removed."
+ $t set root start {}
+ }
+
+ # Find and cut operator chains, very restricted. Cut only chains
+ # of x- and /-operators. The other operators have only one child
+ # by definition and are thus not chains.
+
+ set q [treeql q -tree $t]
+ # q query tree over n
+ foreach n [$t children -all root] {
+ if {[$t keyexists $n symbol]} continue
+ if {[llength [$t children $n]] != 1} continue
+ set op [$t get $n op]
+ if {($op ne "/") && ($op ne "x")} continue
+ $t cut $n
+ }
+
+ flatten $q $t
+ q destroy
+
+ # Clear computation results.
+
+ $t unset root page::analysis::peg::realizable
+ $t unset root page::analysis::peg::unrealizable
+
+ updateUndefinedDueRemoval $t
+ return
+}
+
+proc ::page::analysis::peg::realizable::reset {t} {
+ # Remove marker, allow recalculation of realizability after changes.
+
+ $t unset root page::analysis::peg::realizable
+ return
+}
+
+# ### ### ### ######### ######### #########
+## Internal
+
+proc ::page::analysis::peg::realizable::First {v} {
+ upvar 1 $v visit
+
+ set id [array startsearch visit]
+ set first [array nextelement visit $id]
+ array donesearch visit $id
+
+ unset visit($first)
+ return $first
+}
+
+proc ::page::analysis::peg::realizable::Realizable {t node ncv ucv uv} {
+ upvar 1 $ncv nc $ucv uc $uv realizable
+
+ if {$node eq "root"} {
+ # Root inherits realizability of the start expression.
+
+ return [info exists realizable([$t get root start])]
+ }
+
+ if {[$t keyexists $node symbol]} {
+ # Symbol definitions inherit the realizability of their
+ # expression.
+
+ return [expr {$uc($node) >= $nc($node)}]
+ }
+
+ switch -exact -- [$t get $node op] {
+ t - .. - epsilon - alpha - alnum - dot - * - ? {
+ # The terminal symbols are all realizable.
+ return 1
+ }
+ n {
+ # Symbol invokation inherits realizability of its definition.
+ # Calls to undefined symbols are not realizable.
+
+ set def [$t get $node def]
+ if {$def eq ""} {return 0}
+ return [info exists realizable($def)]
+ }
+ / - | {
+ # Choice, ordered and unordered. Realizable if we have at
+ # least one realizable branch. A quick test based on the count
+ # of realizable children is used.
+
+ return [expr {$uc($node) > 0}]
+ }
+ default {
+ # Sequence, and all other operators, are realizable if and
+ # only if all its children are realizable. A quick test based
+ # on the count of realizable children is used.
+
+ return [expr {$uc($node) >= $nc($node)}]
+ }
+ }
+}
+
+# ### ### ### ######### ######### #########
+## Ready
+
+package provide page::analysis::peg::realizable 0.1
diff --git a/tcllib/modules/page/compiler_peg_mecpu.tcl b/tcllib/modules/page/compiler_peg_mecpu.tcl
new file mode 100644
index 0000000..123c6da
--- /dev/null
+++ b/tcllib/modules/page/compiler_peg_mecpu.tcl
@@ -0,0 +1,1642 @@
+# -*- tcl -*-
+#
+# Copyright (c) 2005 by Andreas Kupries <andreas_kupries@users.sourceforge.net>
+# Parser Generator / Transformation - Compile grammar to ME cpu instructions.
+
+# This package assumes to be used from within a PAGE plugin. It uses
+# the API commands listed below. These are identical across the major
+# types of PAGE plugins, allowing this package to be used in reader,
+# transform, and writer plugins. It cannot be used in a configuration
+# plugin, and this makes no sense either.
+#
+# To ensure that our assumption is ok we require the relevant pseudo
+# package setup by the PAGE plugin management code.
+#
+# -----------------+--
+# page_info | Reporting to the user.
+# page_warning |
+# page_error |
+# -----------------+--
+# page_log_error | Reporting of internals.
+# page_log_warning |
+# page_log_info |
+# -----------------+--
+
+# ### ### ### ######### ######### #########
+## Dumping the input grammar. But not as Tcl or other code. In PEG
+## format again, pretty printing.
+
+# ### ### ### ######### ######### #########
+## Requisites
+
+# @mdgen NODEP: page::plugin
+
+package require page::plugin ; # S.a. pseudo-package.
+
+package require grammar::me::cpu::gasm
+package require textutil
+package require struct::graph
+
+package require page::analysis::peg::emodes
+package require page::util::quote
+package require page::util::peg
+
+namespace eval ::page::compiler::peg::mecpu {
+ # Get the peg char de/encoder commands.
+ # (unquote, quote'tcl)
+
+ namespace import ::page::util::quote::*
+ namespace import ::page::util::peg::*
+
+
+ namespace eval gas {
+ namespace import ::grammar::me::cpu::gas::begin
+ namespace import ::grammar::me::cpu::gas::done
+ namespace import ::grammar::me::cpu::gas::lift
+ namespace import ::grammar::me::cpu::gas::state
+ namespace import ::grammar::me::cpu::gas::state!
+ }
+ namespace import ::grammar::me::cpu::gas::*
+ rename begin {}
+ rename done {}
+ rename lift {}
+ rename state {}
+ rename state! {}
+}
+
+# ### ### ### ######### ######### #########
+## Data structures for the generated code.
+
+## All data is held in node attributes of the tree. Per node:
+##
+## asm - List of instructions implementing the node.
+
+
+
+# ### ### ### ######### ######### #########
+## API
+
+proc ::page::compiler::peg::mecpu {t} {
+ # Resolve the mode hints. Every gen(X) having a value of 'maybe'
+ # (or missing) is for the purposes of this code a 'yes'.
+
+ if {![page::analysis::peg::emodes::compute $t]} {
+ page_error " Unable to generate a ME parser without accept/generate properties"
+ return
+ }
+
+ foreach n [$t nodes] {
+ if {![$t keyexists $n gen] || ([$t get $n gen] eq "maybe")} {
+ $t set $n gen 1
+ }
+ if {![$t keyexists $n acc]} {$t set $n acc 1}
+ }
+
+ # Synthesize a program, then the assembly code.
+
+ mecpu::Synth $t
+ return
+}
+
+# ### ### ### ######### ######### #########
+## Internal. Helpers
+
+proc ::page::compiler::peg::mecpu::Synth {t} {
+ # Phase 2: Bottom-up, synthesized attributes
+
+ # We use a global graph to capture instructions and their
+ # relations. The graph is then converted into a linear list of
+ # instructions, with proper labeling and jump instructions to
+ # handle all non-linear control-flow.
+
+ set g [struct::graph g]
+ $t set root gas::called {}
+
+ page_info "* Synthesize graph code"
+
+ $t walk root -order post -type dfs n {
+ SynthNode $n
+ }
+
+ status $g ; gdump $g synth
+ remove_unconnected $g ; gdump $g nounconnected
+ remove_dead $g ; gdump $g nodead
+ denop $g ; gdump $g nonops
+ parcmerge $g ; gdump $g parcmerge
+ forwmerge $g ; gdump $g fmerge
+ backmerge $g ; gdump $g bmerge
+ status $g
+ pathlengths $g ; gdump $g pathlen
+ jumps $g ; gdump $g jumps
+ status $g
+ symbols $g $t
+
+ set cc [2code $t $g]
+ #write asm/mecode [join $cc \n]
+
+ statistics $cc
+
+ $t set root asm $cc
+ $g destroy
+ return
+}
+
+proc ::page::compiler::peg::mecpu::SynthNode {n} {
+ upvar 1 t t g g
+ if {$n eq "root"} {
+ set code Root
+ } elseif {[$t keyexists $n symbol]} {
+ set code Nonterminal
+ } elseif {[$t keyexists $n op]} {
+ set code [$t get $n op]
+ } else {
+ return -code error "PANIC. Bad node $n, cannot classify"
+ }
+
+ page_log_info " [np $n] := ([linsert [$t children $n] 0 $code])"
+
+ SynthNode/$code $n
+ return
+}
+
+proc ::page::compiler::peg::mecpu::SynthNode/Root {n} {
+ upvar 1 t t g g
+
+ # Root is the grammar itself.
+
+ set gstart [$t get root start]
+ set gname [$t get root name]
+
+ if {$gstart eq ""} {
+ page_error " No start expression."
+ return
+ }
+
+ gas::begin $g $n halt "<Start Expression> '$gname'"
+ $g node set [Who entry] instruction .C
+ $g node set [Who entry] START .
+
+ Inline $t $gstart sexpr
+ /At sexpr/exit/ok ; /Ok ; Jmp exit/return
+ /At sexpr/exit/fail ; /Fail ; Jmp exit/return
+
+ gas::done --> $t
+ return
+}
+
+proc ::page::compiler::peg::mecpu::SynthNode/Nonterminal {n} {
+ upvar 1 t t g g
+
+ # This is the root of a definition.
+ #
+ # The text is a procedure wrapping the match code of its
+ # expression into the required the nonterminal handling (caching
+ # and such), plus the support code for the expression matcher.
+
+ set sym [$t get $n symbol]
+ set label [$t get $n label]
+ set gen [$t get $n gen]
+ set mode [$t get $n mode]
+
+ set pe [lindex [$t children $n] 0]
+ set egen [$t get $pe gen]
+
+ # -> inc_restore -found-> NOP gen: -> ok -> ias_push -> RETURN
+ # /!found \ /
+ # / \-fail --------->/
+ # / !gen: -> RETURN
+ # /
+ # \-> icl_push (-> ias_mark) -> (*) -> SV -> inc_save (-> ias_mrewind) -X
+ #
+ # X -ok----> ias_push -> ier_nonterminal
+ # \ /
+ # \-fail ----------/
+
+ # Poking into the generated instructions, converting the initial
+ # .NOP into a .C'omment.
+
+ set first [gas::begin $g $n !okfail "Nonterminal '$sym'"]
+ $g node set [Who entry] instruction .C
+ $g node set [Who entry] START .
+
+ Cmd inc_restore $label ; /Label restore ; /Ok
+
+ if {$gen} {
+ Bra ; /Label @
+ /Fail ; Nop ; Exit
+ /At @
+ /Ok ; Cmd ias_push ; Exit
+ } else {
+ Nop ; Exit
+ }
+
+ /At restore ; /Fail
+ Cmd icl_push ; # Balanced by inc_save (XX)
+ Cmd icl_push ; # Balanced by pop after ier_terminal
+
+ if {$egen} {
+ # [*] Needed for removal of SV's from stack after handling by
+ # this symbol, only if expression actually generates an SV.
+
+ Cmd ias_mark
+ }
+
+ Inline $t $pe subexpr ; /Ok ; Nop ; /Label unified
+ /At subexpr/exit/fail ; /Fail ; Jmp unified
+ /At unified
+
+ switch -exact -- $mode {
+ value {Cmd isv_nonterminal_reduce $label}
+ match {Cmd isv_nonterminal_range $label}
+ leaf {Cmd isv_nonterminal_leaf $label}
+ discard {Cmd isv_clear}
+ default {return -code error "Bad nonterminal mode \"$mode\""}
+ }
+
+ Cmd inc_save $label ; # Implied icl_pop (XX)
+
+ if {$egen} {
+ # See [*], this is the removal spoken about before.
+ Cmd ias_mrewind
+ }
+
+ /Label hold
+
+ if {$gen} {
+ /Ok
+ Cmd ias_push
+ Nop ; /Label merge
+ /At hold ; /Fail ; Jmp merge
+ /At merge
+ }
+
+ Cmd ier_nonterminal "Expected $label"
+ Cmd icl_pop
+ Exit
+
+ gas::done --> $t
+ return
+}
+
+proc ::page::compiler::peg::mecpu::SynthNode/? {n} {
+ upvar 1 t t g g
+
+ # The expression e? is equivalent to e/epsilon.
+ # And like this it is compiled.
+
+ set pe [lindex [$t children $n] 0]
+
+ gas::begin $g $n okfail ?
+
+ # -> icl_push -> ier_push -> (*) -ok--> ier_merge/ok --> icl_pop -ok----------------> OK
+ # \ /
+ # \-fail-> ier_merge/f ---> icl_rewind -> iok_ok -ok-/
+
+ Cmd icl_push
+ Cmd ier_push
+
+ Inline $t $pe subexpr
+
+ /Ok
+ Cmd ier_merge
+ Cmd icl_pop
+ /Ok ; Exit
+
+ /At subexpr/exit/fail ; /Fail
+ Cmd ier_merge
+ Cmd icl_rewind
+ Cmd iok_ok
+ /Ok ; Exit
+
+ gas::done --> $t
+ return
+}
+
+proc ::page::compiler::peg::mecpu::SynthNode/* {n} {
+ upvar 1 t t g g
+
+ # Kleene star is like a repeated ?
+
+ # Note: Compilation as while loop, as done now
+ # means that the parser has no information about
+ # the intermediate structure of the input in his
+ # cache.
+
+ # Future: Create a helper symbol X and compile
+ # the expression e = e'* as:
+ # e = X; X <- (e' X)?
+ # with match data for X put into the cache. This
+ # is not exactly equivalent, the structure of the
+ # AST is different (right-nested tree instead of
+ # a list). This however can be handled with a
+ # special nonterminal mode to expand the current
+ # SV on the stack.
+
+ # Note 2: This is a transformation which can be
+ # done on the grammar itself, before the actual
+ # backend is let loose. This "strength reduction"
+ # allows us to keep this code here.
+
+ set pe [lindex [$t children $n] 0]
+ set egen [$t get $pe gen]
+
+ # Build instruction graph.
+
+ # /<---------------------------------------------------------------\
+ # \_ \_
+ # ---> icl_push -> ier_push -> (*) -ok--> ier_merge/ok --> icl_pop ->/
+ # \
+ # \-fail-> ier_merge/f ---> icl_rewind -> iok_ok -> OK
+
+ gas::begin $g $n okfail *
+
+ Cmd icl_push ; /Label header
+ Cmd ier_push
+
+ Inline $t $pe loop
+
+ /Ok
+ Cmd ier_merge
+ Cmd icl_pop
+ Jmp header ; /CloseLoop
+
+ /At loop/exit/fail ; /Fail
+ Cmd ier_merge
+ Cmd icl_rewind
+ Cmd iok_ok
+ /Ok ; Exit
+
+ gas::done --> $t
+ return
+}
+
+proc ::page::compiler::peg::mecpu::SynthNode/+ {n} {
+ upvar 1 t t g g
+
+ # Positive Kleene star x+ is equivalent to x x*
+ # This is how it is compiled. See also the notes
+ # at the * above, they apply in essence here as
+ # well, except that the transformat scheme is
+ # slighty different:
+ #
+ # e = e'* ==> e = X; X <- e' X?
+
+ set pe [lindex [$t children $n] 0]
+
+ # Build instruction graph.
+
+ # icl_push -> ier_push -> (*) -fail-> ier_merge/fl -> icl_rewind -> FAIL
+ # \
+ # \--ok---> ier_merge/ok -> icl_pop ->\_
+ # /
+ # /<--------------------------------------------------------/
+ # /
+ # /<---------------------------------------------------------------\
+ # \_ \_
+ # -> icl_push -> ier_push -> (*) -ok--> ier_merge/ok --> icl_pop ->/
+ # \
+ # \-fail-> ier_merge/f ---> icl_rewind -> iok_ok -> OK
+
+ gas::begin $g $n okfail +
+
+ Cmd icl_push
+ Cmd ier_push
+
+ Inline $t $pe first
+ /At first/exit/fail ; /Fail
+ Cmd ier_merge
+ Cmd icl_rewind
+ /Fail ; Exit
+
+ /At first/exit/ok ; /Ok
+ Cmd ier_merge
+ Cmd icl_pop
+
+ # Loop copied from Kleene *, it is *
+
+ Cmd icl_push ; /Label header
+ Cmd ier_push
+
+ # For the loop we create the sub-expression instruction graph a
+ # second time. This is done by walking the subtree a second time
+ # and constructing a completely new node set. The result is
+ # imported under a new name.
+
+ set save [gas::state]
+ $t walk $pe -order post -type dfs n {SynthNode $n}
+ gas::state! $save
+ Inline $t $pe loop
+
+ /Ok
+ Cmd ier_merge
+ Cmd icl_pop
+ Jmp header ; /CloseLoop
+
+ /At loop/exit/fail ; /Fail
+ Cmd ier_merge
+ Cmd icl_rewind
+ Cmd iok_ok
+ /Ok ; Exit
+
+ gas::done --> $t
+ return
+}
+
+proc ::page::compiler::peg::mecpu::SynthNode// {n} {
+ upvar 1 t t g g
+
+ set args [$t children $n]
+
+ if {![llength $args]} {
+ error "PANIC. Empty choice."
+
+ } elseif {[llength $args] == 1} {
+ # A choice over one branch is no real choice. The code
+ # generated for the child applies here as well.
+
+ gas::lift $t $n <-- [lindex $args 0]
+ return
+ }
+
+ # Choice over at least two branches.
+ # Build instruction graph.
+
+ # -> BRA
+ #
+ # BRA -> icl_push (-> ias_mark) -> ier_push -> (*) -ok -> ier_merge -> BRA'OK
+ # \-fail -> ier_merge (-> ias_mrewind) -> icl_rewind -> BRA'FAIL
+ #
+ # BRA'FAIL -> BRA
+ # BRA'FAIL -> FAIL (last branch)
+ #
+ # BRA'OK -> icl_pop -> OK
+
+ gas::begin $g $n okfail /
+
+ /Clear
+ Cmd icl_pop ; /Label BRA'OK ; /Ok ; Exit
+ /At entry
+
+ foreach pe $args {
+ set egen [$t get $pe gen]
+
+ # Note: We do not check for static match results. Doing so is
+ # an optimization we can do earlier, directly on the tree.
+
+ Cmd icl_push
+ if {$egen} {Cmd ias_mark}
+
+ Cmd ier_push
+ Inline $t $pe subexpr
+
+ /Ok
+ Cmd ier_merge
+ Jmp BRA'OK
+
+ /At subexpr/exit/fail ; /Fail
+ Cmd ier_merge
+ if {$egen} {Cmd ias_mrewind}
+ Cmd icl_rewind
+
+ # Branch failed. Go to the next branch. Fail completely at
+ # last branch.
+ }
+
+ /Fail ; Exit
+
+ gas::done --> $t
+ return
+}
+
+proc ::page::compiler::peg::mecpu::SynthNode/x {n} {
+ upvar 1 t t g g
+
+ set args [$t children $n]
+
+ if {![llength $args]} {
+ error "PANIC. Empty sequence."
+
+ } elseif {[llength $args] == 1} {
+ # A sequence of one element is no real sequence. The code
+ # generated for the child applies here as well.
+
+ gas::lift $t $n <-- [lindex $args 0]
+ return
+ }
+
+ # Sequence of at least two elements.
+ # Build instruction graph.
+
+ # -> icl_push -> SEG
+ #
+ # SEG (-> ias_mark) -> ier_push -> (*) -ok -> ier_merge -> SEG'OK
+ # \-fail -> ier_merge -> SEG'FAIL
+ #
+ # SEG'OK -> SEG
+ # SEG'OK -> icl_pop -> OK (last segment)
+ #
+ # SEG'FAIL (-> ias_mrewind) -> icl_rewind -> FAIL
+
+ gas::begin $g $n okfail x
+
+ /Clear
+ Cmd icl_rewind ; /Label SEG'FAIL ; /Fail ; Exit
+
+ /At entry
+ Cmd icl_push
+
+ set gen 0
+ foreach pe $args {
+ set egen [$t get $pe gen]
+ if {$egen && !$gen} {
+ set gen 1
+
+ # From here on out is the sequence able to generate
+ # semantic values which have to be canceled when
+ # backtracking.
+
+ Cmd ias_mark ; /Label @mark
+
+ /Clear
+ Cmd ias_mrewind ; Jmp SEG'FAIL ; /Label SEG'FAIL
+
+ /At @mark
+ }
+
+ Cmd ier_push
+ Inline $t $pe subexpr
+
+ /At subexpr/exit/fail ; /Fail
+ Cmd ier_merge
+ Jmp SEG'FAIL
+
+ /At subexpr/exit/ok ; /Ok
+ Cmd ier_merge
+ }
+
+ Cmd icl_pop
+ /Ok ; Exit
+
+ gas::done --> $t
+ return
+}
+
+proc ::page::compiler::peg::mecpu::SynthNode/& {n} {
+ upvar 1 t t g g
+ SynthLookahead $n no
+ return
+}
+
+proc ::page::compiler::peg::mecpu::SynthNode/! {n} {
+ upvar 1 t t g g
+ SynthLookahead $n yes
+ return
+}
+
+proc ::page::compiler::peg::mecpu::SynthNode/dot {n} {
+ upvar 1 t t g g
+ SynthTerminal $n {} "any character"
+ return
+}
+
+proc ::page::compiler::peg::mecpu::SynthNode/epsilon {n} {
+ upvar 1 t t g g
+
+ gas::begin $g $n okfail epsilon
+
+ Cmd iok_ok ; /Ok ; Exit
+
+ gas::done --> $t
+ return
+}
+
+proc ::page::compiler::peg::mecpu::SynthNode/alnum {n} {
+ upvar 1 t t g g
+ SynthClass $n alnum
+ return
+}
+
+proc ::page::compiler::peg::mecpu::SynthNode/alpha {n} {
+ upvar 1 t t g g
+ SynthClass $n alpha
+ return
+}
+
+proc ::page::compiler::peg::mecpu::SynthNode/digit {n} {
+ upvar 1 t t g g
+ SynthClass $n digit
+ return
+}
+
+proc ::page::compiler::peg::mecpu::SynthNode/xdigit {n} {
+ upvar 1 t t g g
+ SynthClass $n xdigit
+ return
+}
+
+proc ::page::compiler::peg::mecpu::SynthNode/punct {n} {
+ upvar 1 t t g g
+ SynthClass $n punct
+ return
+}
+
+proc ::page::compiler::peg::mecpu::SynthNode/space {n} {
+ upvar 1 t t g g
+ SynthClass $n space
+ return
+}
+
+proc ::page::compiler::peg::mecpu::SynthNode/.. {n} {
+ upvar 1 t t g g
+ # Range is [x-y]
+
+ set b [$t get $n begin]
+ set e [$t get $n end]
+
+ set tb [quote'tcl $b]
+ set te [quote'tcl $e]
+
+ set pb [quote'tclstr $b]
+ set pe [quote'tclstr $e]
+
+ SynthTerminal $n [list ict_match_tokrange $tb $te] "\\\[${pb}..${pe}\\\]"
+ return
+}
+
+proc ::page::compiler::peg::mecpu::SynthNode/t {n} {
+ upvar 1 t t g g
+
+ # Terminal node. Primitive matching.
+ # Code is parameterized by gen(X) of this node X.
+
+ set ch [$t get $n char]
+ set tch [quote'tcl $ch]
+ set pch [quote'tclstr $ch]
+
+ SynthTerminal $n [list ict_match_token $tch] $pch
+ return
+}
+
+proc ::page::compiler::peg::mecpu::SynthNode/n {n} {
+ upvar 1 t t g g
+
+ # Nonterminal node. Primitive matching.
+ # The code is parameterized by acc(X) of this node X, and gen(D)
+ # of the invoked nonterminal D.
+
+ set sym [$t get $n sym]
+ set def [$t get $n def]
+
+ gas::begin $g $n okfail call'$sym'
+
+ if {$def eq ""} {
+ # Invokation of an undefined nonterminal. This will always fail.
+
+ Note "Match for undefined symbol '$sym'"
+ Cmdd iok_fail ; /Fail ; Exit
+ gas::done --> $t
+
+ } else {
+ # Combinations
+ # Acc Gen Action
+ # --- --- ------
+ # 0 0 Plain match
+ # 0 1 Match with canceling of the semantic value.
+ # 1 0 Plain match
+ # 1 1 Plain match
+ # --- --- ------
+
+ if {[$t get $n acc] || ![$t get $def gen]} {
+ Cmd icf_ntcall sym_$sym ; /Label CALL
+ /Ok ; Exit
+ /Fail ; Exit
+
+ } else {
+ Cmd ias_mark
+ Cmd icf_ntcall sym_$sym ; /Label CALL
+ Cmd ias_mrewind
+ /Ok ; Exit
+ /Fail ; Exit
+ }
+
+ set caller [Who CALL]
+ gas::done --> $t
+
+ $t lappend $def gas::callers $caller
+ $t lappend root gas::called $def
+ }
+
+ return
+}
+
+proc ::page::compiler::peg::mecpu::SynthLookahead {n negated} {
+ upvar 1 g g t t
+
+ # Note: Per the rules about expression modes (! is a lookahead
+ # ____| operator) this node has a mode of 'discard', and its child
+ # ____| has so as well.
+
+ # assert t get n mode == discard
+ # assert t get pe mode == discard
+
+ set op [$t get $n op]
+ set pe [lindex [$t children $n] 0]
+ set eop [$t get $pe op]
+
+ # -> icl_push -> (*) -ok--> icl_rewind -> OK
+ # \--fail-> icl_rewind -> FAIL
+
+ # -> icl_push -> (*) -ok--> icl_rewind -> iok_negate -> FAIL
+ # \--fail-> icl_rewind -> iok_negate -> OK
+
+ gas::begin $g $n okfail [expr {$negated ? "!" : "&"}]
+
+ Cmd icl_push
+ Inline $t $pe subexpr
+
+ /Ok
+ Cmd icl_rewind
+ if {$negated} { Cmd iok_negate ; /Fail } else /Ok ; Exit
+
+ /At subexpr/exit/fail ; /Fail
+ Cmd icl_rewind
+ if {$negated} { Cmd iok_negate ; /Ok } else /Fail ; Exit
+
+ gas::done --> $t
+ return
+}
+
+proc ::page::compiler::peg::mecpu::SynthClass {n op} {
+ upvar 1 t t g g
+ SynthTerminal $n [list ict_match_tokclass $op] <$op>
+ return
+}
+
+proc ::page::compiler::peg::mecpu::SynthTerminal {n cmd msg} {
+ upvar 1 t t g g
+
+ # 4 cases (+/- cmd, +/- sv).
+ #
+ # (A) +cmd+sv
+ # entry -> advance -ok-> match -ok-> sv -> OK
+ # \ \
+ # \ \-fail----------> FAIL
+ # \-fail----------------------/
+ #
+ # (B) -cmd+sv
+ # entry -> advance -ok-> sv -> OK
+ # \
+ # \-fail-----------> FAIL
+ #
+ # (C) +cmd-sv
+ # entry -> advance -ok-> match -ok-> OK
+ # \ \
+ # \ \-fail---> FAIL
+ # \-fail---------------/
+ #
+ # (D) -cmd-sv
+ # entry -> advance -ok-> OK
+ # \
+ # \-fail-----> FAIL
+
+ gas::begin $g $n okfail M'[lindex $cmd 0]
+
+ Cmd ict_advance "Expected $msg (got EOF)"
+ /Fail ; Exit
+ /Ok
+
+ if {[llength $cmd]} {
+ lappend cmd "Expected $msg"
+ eval [linsert $cmd 0 Cmd]
+ /Fail ; Exit
+ /Ok
+ }
+
+ if {[$t get $n gen]} {
+ Cmd isv_terminal
+ /Ok
+ }
+
+ Exit
+
+ gas::done --> $t
+ return
+}
+
+# ### ### ### ######### ######### #########
+## Internal. Extending the graph of instructions (expression
+## framework, new instructions, (un)conditional sequencing).
+
+# ### ### ### ######### ######### #########
+## Internal. Working on the graph of instructions.
+
+proc ::page::compiler::peg::mecpu::2code {t g} {
+ page_info "* Generating ME assembler code"
+
+ set insn {}
+ set start [$t get root gas::entry]
+ set cat 0
+ set calls [list $start]
+
+ while {$cat < [llength $calls]} {
+ set now [lindex $calls $cat]
+ incr cat
+
+ set at 0
+ set pending [list $now]
+
+ while {$at < [llength $pending]} {
+ set current [lindex $pending $at]
+ incr at
+
+ while {$current ne ""} {
+ if {[$g node keyexists $current WRITTEN]} break
+
+ insn $g $current insn
+ $g node set $current WRITTEN .
+
+ if {[$g node keyexists $current SAVE]} {
+ lappend pending [$g node get $current SAVE]
+ }
+ if {[$g node keyexists $current CALL]} {
+ lappend calls [$g node get $current CALL]
+ }
+
+ set current [$g node get $current NEXT]
+ if {$current eq ""} break
+ if {[$g node keyexists $current WRITTEN]} {
+ lappend insn [list {} icf_jalways \
+ [$g node get $current LABEL]]
+ break
+ }
+
+ # Process the following instruction,
+ # if there is any.
+ }
+ }
+ }
+
+ return $insn
+}
+
+proc ::page::compiler::peg::mecpu::insn {g current iv} {
+ upvar 1 $iv insn
+
+ set code [$g node get $current instruction]
+ set args [$g node get $current arguments]
+
+ set label {}
+ if {[$g node keyexists $current LABEL]} {
+ set label [$g node get $current LABEL]
+ }
+
+ lappend insn [linsert $args 0 $label $code]
+ return
+}
+
+if 0 {
+ if {[lindex $ins 0] eq "icf_ntcall"} {
+ set tmp {}
+ foreach b $branches {
+ if {[$g node keyexists $b START]} {
+ set sym [$g node get $b symbol]
+ lappend ins sym_$sym
+ } else {
+ lappend tmp $b
+ }
+ }
+ set branches $tmp
+ }
+}
+
+# ### ### ### ######### ######### #########
+## Optimizations.
+#
+## I. Remove all nodes which are not connected to anything.
+## There should be none.
+
+proc ::page::compiler::peg::mecpu::remove_unconnected {g} {
+ page_info "* Remove unconnected instructions"
+
+ foreach n [$g nodes] {
+ if {[$g node degree $n] == 0} {
+ page_error "$n ([printinsn $g $n])"
+ page_error "Found unconnected node. This should not have happened."
+ page_error "Removing the bad node."
+
+ $g node delete $n
+ }
+ }
+}
+
+proc ::page::compiler::peg::mecpu::remove_dead {g} {
+ page_info "* Remove dead instructions"
+
+ set count 0
+ set runs 0
+ set hasdead 1
+ while {$hasdead} {
+ set hasdead 0
+ foreach n [$g nodes] {
+ if {[$g node keyexists $n START]} continue
+ if {[$g node degree -in $n] > 0} continue
+
+ page_log_info " [np $n] removed, dead ([printinsn $g $n])"
+
+ $g node delete $n
+
+ set hasdead 1
+ incr count
+ }
+ incr runs
+ }
+
+ page_info " Removed [plural $count instruction] in [plural $runs run]"
+ return
+}
+
+# ### ### ### ######### ######### #########
+## Optimizations.
+#
+## II. We have lots of .NOP instructions in the control flow, as part
+## of the framework. They made the handling of expressions easier,
+## providing clear and fixed anchor nodes to connect to from
+## inside and outside, but are rather like the epsilon-transitions
+## in a (D,N)FA. Now is the time to get rid of them.
+#
+## We keep the .C'omments, and explicit .BRA'nches.
+## We should not have any .NOP which is a dead-end (without
+## successor), nor should we find .NOPs with more than one
+## successor. The latter should have been .BRA'nches. Both
+## situations are reported on. Dead-ends we
+## remove. Multi-destination NOPs we keep.
+#
+## Without the nops in place to confus the flow we can perform a
+## series peep-hole optimizations to merge/split branches.
+
+proc ::page::compiler::peg::mecpu::denop {g} {
+ # Remove the .NOPs and reroute control flow. We keep the pseudo
+ # instructions for comments (.C) and the explicit branch points
+ # (.BRA).
+
+ page_info "* Removing the helper .NOP instructions."
+
+ set count 0
+ foreach n [$g nodes] {
+ # Skip over nodes already deleted by a previous iteration.
+ if {[$g node get $n instruction] ne ".NOP"} continue
+
+ # We keep branching .NOPs, and warn user. There shouldn't be
+ # any. such should explicit bnrachpoints.
+
+ set destinations [$g arcs -out $n]
+
+ if {[llength $destinations] > 1} {
+ page_error "$n ([printinsn $g $n])"
+ page_error "Found a .NOP with more than one destination."
+ page_error "This should have been a .BRA instruction."
+ page_error "Not removed. Internal error. Fix the transformation."
+ continue
+ }
+
+ # Nops without a destination, dead-end's are not wanted. They
+ # should not exist either too. We will do a general dead-end
+ # and dead-start removal as well.
+
+ if {[llength $destinations] < 1} {
+ page_error "$n ([printinsn $g $n])"
+ page_error "Found a .NOP without any destination, i.e. a dead end."
+ page_error "This should not have happened. Removed the node."
+
+ $g node delete $n
+ continue
+ }
+
+ page_log_info " [np $n] removed, updated cflow ([printinsn $g $n])"
+
+ # As there is exactly one destination we can now reroute all
+ # incoming arcs around the nop to the new destination.
+
+ set target [$g arc target [lindex $destinations 0]]
+ foreach a [$g arcs -in $n] {
+ $g arc move-target $a $target
+ }
+
+ $g node delete $n
+ incr count
+ }
+
+ page_info " Removed [plural $count instruction]"
+ return
+}
+
+
+# ### ### ### ######### ######### #########
+## Optimizations.
+#
+
+# Merge parallel arcs (remove one, make the other unconditional).
+
+proc ::page::compiler::peg::mecpu::parcmerge {g} {
+ page_info "* Search for identical parallel arcs and merge them"
+
+ #puts [join [info loaded] \n] /seg.fault induced with tcllibc! - tree!
+
+ set count 0
+ foreach n [$g nodes] {
+ set arcs [$g arcs -out $n]
+
+ if {[llength $arcs] < 2} continue
+ if {[llength $arcs] > 2} {
+ page_error " $n ([printinsn $g $n])"
+ page_error " Instruction has more than two destinations."
+ page_error " That is not possible. Internal error."
+ continue
+ }
+ # Two way branch. Both targets the same ?
+
+ foreach {a b} $arcs break
+
+ if {[$g arc target $a] ne [$g arc target $b]} continue
+
+ page_log_info " [np $n] outbound arcs merged ([printinsn $g $n])"
+
+ $g arc set $a condition always
+ $g arc delete $b
+
+ incr count 2
+ }
+
+ page_info " Merged [plural $count arc]"
+ return
+}
+
+# Use knowledge of the match status before and after an instruction to
+# label the arcs a bit better (This may guide the forward and backward
+# merging.).
+
+# Forward merging of instructions.
+# An ok/fail decision is done as late as possible.
+#
+# /- ok ---> Y -> U /- ok ---> U
+# X ==> X -> Y
+# \- fail -> Y -> V \- fail -> V
+
+# The Y must not have additional inputs. This more complex case we
+# will look at later.
+
+proc ::page::compiler::peg::mecpu::forwmerge {g} {
+ page_info "* Forward merging of identical instructions"
+ page_info " Delaying decisions"
+ set count 0
+ set runs 0
+
+ set merged 1
+ while {$merged} {
+ set merged 0
+ foreach n [$g nodes] {
+ # Skip nodes already killed in previous rounds.
+ if {![$g node exists $n]} continue
+
+ set outbound [$g arcs -out $n]
+ if {[llength $outbound] != 2} continue
+
+ foreach {aa ab} $outbound break
+ set na [$g arc target $aa]
+ set nb [$g arc target $ab]
+
+ set ia [$g node get $na instruction][$g node get $na arguments]
+ set ib [$g node get $nb instruction][$g node get $nb arguments]
+ if {$ia ne $ib} continue
+
+ # Additional condition: Inbounds in the targets not > 1
+
+ if {([$g node degree -in $na] > 1) ||
+ ([$g node degree -in $nb] > 1)} continue
+
+ page_log_info " /Merge [np $n] : [np $na] <- [np $nb] ([printinsn $g $na])"
+
+ # Label all arcs out of na with the condition of the arc
+ # into it. Ditto for the arcs out of nb. The latter also
+ # get na as their new origin. The arcs out of n relabeled
+ # to always. The nb is deleted. This creates the desired
+ # control structure without having to create a new node
+ # and filling it. We simply use na, discard nb, and
+ # properly rewrite the arcs to have the correct
+ # conditions.
+
+ foreach a [$g arcs -out $na] {
+ $g arc set $a condition [$g arc get $aa condition]
+ }
+ foreach a [$g arcs -out $nb] {
+ $g arc set $a condition [$g arc get $ab condition]
+ $g arc move-source $a $na
+ }
+ $g arc set $aa condition always
+ $g node delete $nb
+ set merged 1
+ incr count
+ }
+ incr runs
+ }
+
+ # NOTE: This may require a parallel arc merge, with identification
+ # of merge-able arcs based on the arc condition, i.e. labeling.
+
+ page_info " Merged [plural $count instruction] in [plural $runs run]"
+ return
+}
+
+# Backward merging of instructions.
+# Common backends are put together.
+#
+# U -> Y ->\ U ->\
+# -> X ==> -> Y -> X
+# V -> Y ->/ V ->/
+
+# Note. It is possible for an instruction to be amenable to both for-
+# and backward merging. No heuristics are known to decide which is
+# better.
+
+proc ::page::compiler::peg::mecpu::backmerge {g} {
+ page_info "* Backward merging of identical instructions"
+ page_info " Unifying paths"
+ set count 0
+ set runs 0
+
+ set merged 1
+ while {$merged} {
+ set merged 0
+ foreach n [$g nodes] {
+ # Skip nodes already killed in previous rounds.
+ if {![$g node exists $n]} continue
+
+ set inbound [$g arcs -in $n]
+ if {[llength $inbound] < 2} continue
+
+ # We have more than 1 inbound arcs on this node. Check all
+ # pairs of pre-decessors for possible unification.
+
+ # Additional condition: Outbounds in the targets not > 1
+ # We check in different levels, to avoid redundant calls.
+
+ while {[llength $inbound] > 2} {
+ set aa [lindex $inbound 0]
+ set tail [lrange $inbound 1 end]
+
+ set na [$g arc source $aa]
+ if {[$g node degree -out $na] > 1} {
+ set inbound $tail
+ continue
+ }
+
+ set inbound {}
+ foreach ab $tail {
+ set nb [$g arc source $ab]
+ if {[$g node degree -out $nb] > 1} continue
+
+ set ia [$g node get $na instruction][$g node get $na arguments]
+ set ib [$g node get $nb instruction][$g node get $nb arguments]
+
+ if {$ia ne $ib} {
+ lappend inbound $ab
+ continue
+ }
+
+ page_log_info " \\Merge [np $n] : [np $na] <- [np $nb] ([printinsn $g $na])"
+
+ # Discard the second node in the pair. Move all
+ # arcs inbound into it so that they reach the
+ # first node instead.
+
+ foreach a [$g arcs -in $nb] {$g arc move-target $a $na}
+ $g node delete $nb
+ set merged 1
+ incr count
+ }
+ }
+ }
+ incr runs
+ }
+
+ page_info " Merged [plural $count instruction] in [plural $runs run]"
+ return
+}
+
+# ### ### ### ######### ######### #########
+
+proc ::page::compiler::peg::mecpu::pathlengths {g} {
+ page_info "* Find maximum length paths"
+
+ set pending [llength [$g nodes]]
+
+ set nodes {}
+ set loops {}
+ foreach n [$g nodes] {
+ $g node set $n WAIT [$g node degree -out $n]
+ set insn [$g node get $n instruction]
+ if {($insn eq "icf_halt") || ($insn eq "icf_ntreturn")} {
+ lappend nodes $n
+ }
+ if {[$g node keyexists $n LOOP]} {
+ lappend loops $n
+ }
+ }
+
+ set level 0
+ while {[llength $nodes]} {
+ incr pending -[llength $nodes]
+ set nodes [closure $g $nodes $level]
+ incr level
+ }
+
+ if {[llength $loops]} {
+ page_info " Loop levels"
+
+ set nodes $loops
+ while {[llength $nodes]} {
+ incr pending -[llength $nodes]
+ set nodes [closure $g $nodes $level]
+ incr level
+ }
+ }
+
+ if {$pending} {
+ page_info " Remainder"
+
+ while {$pending} {
+ set nodes {}
+ foreach n [$g nodes] {
+ if {[$g node keyexists $n LEVEL]} continue
+ if {[$g node get $n WAIT] < [$g node degree -out $n]} {
+ lappend nodes $n
+ }
+ }
+ while {[llength $nodes]} {
+ incr pending -[llength $nodes]
+ set nodes [closure $g $nodes $level]
+ incr level
+ }
+ }
+ }
+ return
+}
+
+proc ::page::compiler::peg::mecpu::closure {g nodes level} {
+ page_log_info " \[[format %6d $level]\] : $nodes"
+
+ foreach n $nodes {$g node set $n LEVEL $level}
+
+ set tmp {}
+ foreach n $nodes {
+ foreach pre [$g nodes -in $n] {
+ # Ignore instructions already given a level.
+ if {[$g node keyexists $pre LEVEL]} continue
+ $g node set $pre WAIT [expr {[$g node get $pre WAIT] - 1}]
+ if {[$g node get $pre WAIT] > 0} continue
+ lappend tmp $pre
+ }
+ }
+ return [lsort -uniq -dict $tmp]
+}
+
+proc ::page::compiler::peg::mecpu::jumps {g} {
+ page_info "* Insert explicit jumps and branches"
+
+ foreach n [$g nodes] {
+ # Inbound > 1, at least one is from a jump, so a label is
+ # needed.
+
+ if {[llength [$g arcs -in $n]] > 1} {
+ set go bra[string range $n 4 end]
+ $g node set $n LABEL $go
+ }
+
+ set darcs [$g arcs -out $n]
+
+ if {[llength $darcs] == 0} {
+ $g node set $n NEXT ""
+ continue
+ }
+
+ if {[llength $darcs] == 1} {
+ set da [lindex $darcs 0]
+ set dn [$g arc target $da]
+
+ if {[$g node get $dn LEVEL] > [$g node get $n LEVEL]} {
+ # Flow is backward, an uncond. jump
+ # is needed here.
+
+ set go bra[string range $dn 4 end]
+ $g node set $dn LABEL $go
+ set j [$g node insert]
+ $g arc move-target $da $j
+ $g node set $j instruction icf_jalways
+ $g node set $j arguments $go
+
+ $g arc insert $j $dn
+
+ $g node set $n NEXT $j
+ $g node set $j NEXT ""
+ } else {
+ $g node set $n NEXT $dn
+ }
+ continue
+ }
+
+ set aok {}
+ set afl {}
+ foreach a $darcs {
+ if {[$g arc get $a condition] eq "ok"} {
+ set aok $a
+ } else {
+ set afl $a
+ }
+ }
+ set nok [$g arc target $aok]
+ set nfl [$g arc target $afl]
+
+ if {[$g node get $n instruction] eq "inc_restore"} {
+ set go bra[string range $nok 4 end]
+ $g node set $nok LABEL $go
+
+ $g node set $n NEXT $nfl
+ $g node set $n SAVE $nok
+
+ $g node set $n arguments [linsert [$g node get $n arguments] 0 $go]
+ continue
+ }
+
+ if {[$g node get $n instruction] ne ".BRA"} {
+ set bra [$g node insert]
+ $g arc move-source $aok $bra
+ $g arc move-source $afl $bra
+ $g arc insert $n $bra
+ $g node set $n NEXT $bra
+ set n $bra
+ }
+
+ if {[$g node get $nok LEVEL] > [$g node get $nfl LEVEL]} {
+ # Ok branch is direct, Fail is jump.
+
+ $g node set $n NEXT $nok
+ $g node set $n SAVE $nfl
+
+ set go bra[string range $nfl 4 end]
+ $g node set $nfl LABEL $go
+ $g node set $n instruction icf_jfail
+ $g node set $n arguments $go
+ } else {
+
+ # Fail branch is direct, Ok is jump.
+
+ $g node set $n NEXT $nfl
+ $g node set $n SAVE $nok
+
+ set go bra[string range $nok 4 end]
+ $g node set $nok LABEL $go
+ $g node set $n instruction icf_jok
+ $g node set $n arguments $go
+ }
+ }
+}
+
+proc ::page::compiler::peg::mecpu::symbols {g t} {
+ page_info "* Label subroutine heads"
+
+ # Label and mark the instructions where subroutines begin.
+ # These markers are used by 2code to locate all actually
+ # used subroutines.
+
+ foreach def [lsort -uniq [$t get root gas::called]] {
+ set gdef [$t get $def gas::entry]
+ foreach caller [$t get $def gas::callers] {
+
+ # Skip callers which are gone because of optimizations.
+ if {![$g node exists $caller]} continue
+
+ $g node set $caller CALL $gdef
+ $g node set $gdef LABEL \
+ [lindex [$g node set $caller arguments] 0]
+ }
+ }
+ return
+}
+
+# ### ### ### ######### ######### #########
+
+proc ::page::compiler::peg::mecpu::statistics {code} {
+ return
+ # disabled
+ page_info "* Statistics"
+ statistics_si $code
+
+ # All higher order statistics are done only on the instructions in
+ # a basic block, i.e. a linear sequence. We are looking for
+ # high-probability blocks in itself, and then also for
+ # high-probability partials.
+
+ set blocks [basicblocks $code]
+
+ # Basic basic block statistics (full blocks)
+
+ Init bl
+ foreach b $blocks {Incr bl($b)}
+ wrstat bl asm/statistics_bb.txt
+ wrstatk bl asm/statistics_bbk.txt
+
+ # Statistics of all partial blocks, i.e. all possible
+ # sub-sequences with length > 1.
+
+ Init ps
+ foreach b $blocks {
+ for {set s 0} {$s < [llength $b]} {incr s} {
+ for {set e [expr {$s + 1}]} {$e < [llength $b]} {incr e} {
+ Incr ps([lrange $b $s $e]) $bl($b)
+ }
+ }
+ }
+
+ wrstat ps asm/statistics_ps.txt
+ wrstatk ps asm/statistics_psk.txt
+ return
+}
+
+proc ::page::compiler::peg::mecpu::statistics_si {code} {
+ page_info " Single instruction probabilities."
+
+ # What are the most used instructions, statically speaking,
+ # without considering context ?
+
+ Init si
+ foreach i $code {
+ foreach {label name} $i break
+ if {$name eq ".C"} continue
+ Incr si($name)
+ }
+
+ wrstat si asm/statistics_si.txt
+ return
+}
+
+proc ::page::compiler::peg::mecpu::Init {v} {
+ upvar 1 $v var total total
+ array set var {}
+ set total 0
+ return
+}
+
+proc ::page::compiler::peg::mecpu::Incr {v {n 1}} {
+ upvar 1 $v var total total
+ if {![info exists var]} {set var $n ; incr total ; return}
+ incr var $n
+ incr total $n
+ return
+}
+
+proc ::page::compiler::peg::mecpu::wrstat {bv file} {
+ upvar 1 $bv buckets total total
+
+ set tmp {}
+ foreach {name count} [array get buckets] {
+ lappend tmp [list $name $count]
+ }
+
+ set lines {}
+ lappend lines "Total: $total"
+
+ set half [expr {$total / 2}]
+ set down $total
+
+ foreach item [lsort -index 1 -decreasing -integer [lsort -index 0 $tmp]] {
+ foreach {key count} $item break
+
+ set percent [format %6.2f [expr {$count*100.0/$total}]]%
+ set fcount [format %8d $count]
+
+ lappend lines " $fcount $percent $key"
+ incr down -$count
+ if {$half && ($down < $half)} {
+ lappend lines **
+ set half 0
+ }
+ }
+
+ write $file [join $lines \n]\n
+ return
+}
+
+proc ::page::compiler::peg::mecpu::wrstatk {bv file} {
+ upvar 1 $bv buckets total total
+
+ set tmp {}
+ foreach {name count} [array get buckets] {
+ lappend tmp [list $name $count]
+ }
+
+ set lines {}
+ lappend lines "Total: $total"
+
+ set half [expr {$total / 2}]
+ set down $total
+
+ foreach item [lsort -index 0 [lsort -index 1 -decreasing -integer $tmp]] {
+ foreach {key count} $item break
+
+ set percent [format %6.2f [expr {$count*100.0/$total}]]%
+ set fcount [format %8d $count]
+
+ lappend lines " $fcount $percent $key"
+ incr down -$count
+ if {$down < $half} {
+ lappend lines **
+ set half -1
+ }
+ }
+
+ write $file [join $lines \n]\n
+ return
+}
+
+proc ::page::compiler::peg::mecpu::basicblocks {code} {
+ set blocks {}
+ set block {}
+
+ foreach i $code {
+ foreach {label name} $i break
+ if {
+ ($name eq ".C") ||
+ ($name eq "icf_jok") ||
+ ($name eq "icf_jfail") ||
+ ($name eq "icf_jalways") ||
+ ($name eq "icf_ntreturn")
+ } {
+ # Jumps stop a block, and are not put into the block
+ # Except if the block is of length 1. Then it is of
+ # interest to see if certain combinations are used
+ # often.
+
+ if {[llength $block]} {
+ if {[llength $block] == 1} {lappend block $name}
+ lappend blocks $block
+ }
+ set block {}
+ continue
+ } elseif {$label ne ""} {
+ # A labeled instruction starts a new block and belongs to
+ # it. Note that the previous block is saved only if it is
+ # of length > 1. A single instruction block is not
+ # something we can optimize.
+
+ if {[llength $block] > 1} {lappend blocks $block}
+ set block [list $name]
+ continue
+ }
+ # Extend current block
+ lappend block $name
+ }
+
+ if {[llength $block]} {lappend blocks $block}
+ return $blocks
+}
+
+# ### ### ### ######### ######### #########
+
+proc ::page::compiler::peg::mecpu::printinsn {g n} {
+ return "[$g node get $n instruction] <[$g node get $n arguments]>"
+}
+
+proc ::page::compiler::peg::mecpu::plural {n prefix} {
+ return "$n ${prefix}[expr {$n == 1 ? "" : "s"}]"
+}
+
+proc ::page::compiler::peg::mecpu::np {n} {
+ format %-*s 8 $n
+}
+
+proc ::page::compiler::peg::mecpu::status {g} {
+ page_info "[plural [llength [$g nodes]] instruction]"
+ return
+}
+
+proc ::page::compiler::peg::mecpu::gdump {g file} {
+ return
+ # disabled
+ variable gnext
+ page_info " %% Saving graph to \"$file\" %%"
+ write asm/[format %02d $gnext]_${file}.sgr [$g serialize]
+ incr gnext
+ return
+}
+
+# ### ### ### ######### ######### #########
+## Internal. Strings.
+
+namespace eval ::page::compiler::peg::mecpu {
+ variable gnext 0
+}
+
+# ### ### ### ######### ######### #########
+## Ready
+
+package provide page::compiler::peg::mecpu 0.1.1
diff --git a/tcllib/modules/page/gen_peg_canon.tcl b/tcllib/modules/page/gen_peg_canon.tcl
new file mode 100644
index 0000000..27d5f4b
--- /dev/null
+++ b/tcllib/modules/page/gen_peg_canon.tcl
@@ -0,0 +1,481 @@
+# -*- tcl -*-
+#
+# Copyright (c) 2005 by Andreas Kupries <andreas_kupries@users.sourceforge.net>
+# Parser Generator / Backend - PEG as ... PEG
+
+# ### ### ### ######### ######### #########
+## Dumping the input grammar. But not as Tcl or other code. In PEG
+## format again, pretty printing.
+
+# ### ### ### ######### ######### #########
+## Requisites
+
+package require textutil
+
+namespace eval ::page::gen::peg::canon {}
+
+# ### ### ### ######### ######### #########
+## API
+
+proc ::page::gen::peg::canon {t chan} {
+
+ # Generate data for inherited attributes
+ # used during synthesis.
+ canon::Setup $t
+
+ # Synthesize all text fragments we need.
+ canon::Synth $t
+
+ # And write the grammar text.
+ puts $chan [$t get root TEXT]
+ return
+}
+
+# ### ### ### ######### ######### #########
+## Internal. Helpers
+
+proc ::page::gen::peg::canon::Setup {t} {
+ # Phase 1: Top-down, inherited attributes:
+ #
+ # - Max length of nonterminal symbols defined by the grammar.
+ #
+ # - Indentation put on all rules to get enough space for
+ # definition attributes.
+
+ set max -1
+ array set modes {}
+
+ foreach {sym def} [$t get root definitions] {
+ set l [string length $sym]
+ if {$l > $max} {set max $l}
+
+ set mode [string index [$t get $def mode] 0]
+ set modes($mode) .
+ }
+ set modeset [join [lsort [array names modes]] ""]
+ set mlen [AttrFieldLength $modeset]
+ set heading [expr {$max + $mlen + 4}]
+ # The constant 4 is for ' <- ', see
+ # SynthNode/Nonterminal
+
+ # Save the computed information for access by the definitions and
+ # other operators.
+
+ $t set root SYM_FIELDLEN $max
+ $t set root ATT_FIELDLEN $mlen
+ $t set root ATT_BASE $modeset
+ $t set root HEADLEN $heading
+ return
+}
+
+proc ::page::gen::peg::canon::Synth {t} {
+ # Phase 2: Bottom-up, synthesized attributes
+ #
+ # - Text block per node, length and height.
+
+ $t walk root -order post -type dfs n {
+ SynthNode $t $n
+ }
+ return
+}
+
+proc ::page::gen::peg::canon::SynthNode {t n} {
+ if {$n eq "root"} {
+ set code Root
+ } elseif {[$t keyexists $n symbol]} {
+ set code Nonterminal
+ } elseif {[$t keyexists $n op]} {
+ set code [$t get $n op]
+ } else {
+ return -code error "PANIC. Bad node $n, cannot classify"
+ }
+
+ #puts stderr "SynthNode/$code $t $n"
+
+ SynthNode/$code $t $n
+
+ #SHOW [$t get $n TEXT] 1 0
+ #catch {puts stderr "\t.[$t get $n W]x[$t get $n H]"}
+ return
+}
+
+proc ::page::gen::peg::canon::SynthNode/Root {t n} {
+ # Root is the grammar itself.
+
+ # Get the data we need from our children, which are start
+ # expression and nonterminal definitions.
+
+ set gname [$t get root name]
+ set gstart [$t get root start]
+ if {$gstart ne ""} {
+ set stext [$t get $gstart TEXT]
+ } else {
+ puts stderr "No start expression."
+ set stext ""
+ }
+ set rules {}
+ foreach {sym def} [$t get root definitions] {
+ lappend rules [list $sym [$t get $def TEXT]]
+ }
+
+ # Combine them into a text for the whole grammar.
+
+ set intro "PEG $gname \("
+ set ispace [::textutil::blank [string length $intro]]
+
+ set out ""
+ append out "# -*- text -*-" \n
+ append out "## Parsing Expression Grammar '$gname'." \n
+ append out "## Layouted by the PG backend 'PEGwriter'." \n
+ append out \n
+ append out $intro[::textutil::indent $stext $ispace 1]\)
+ append out \n
+ append out \n
+
+ foreach e [lsort -dict -index 0 $rules] {
+ foreach {sym text} $e break
+ append out $text \n
+ append out \n
+ }
+
+ append out "END\;" \n
+
+ $t set root TEXT $out
+ return
+}
+
+proc ::page::gen::peg::canon::SynthNode/Nonterminal {t n} {
+ # This is the root of a definition. We now
+ # have to combine the text block for the
+ # expression with nonterminal and attribute
+ # data.
+
+ variable ms
+
+ set abase [$t get root ATT_BASE]
+ set sfl [$t get root SYM_FIELDLEN]
+ set mode [$t get $n mode]
+ set sym [$t get $n symbol]
+ set etext [$t get [lindex [$t children $n] 0] TEXT]
+
+ set out ""
+ append out $ms($abase,$mode)
+ append out $sym
+ append out [::textutil::blank [expr {$sfl - [string length $sym]}]]
+ append out " <- "
+
+ set ispace [::textutil::blank [string length $out]]
+
+ append out [::textutil::indent $etext $ispace 1]
+ append out " ;"
+
+ $t set $n TEXT $out
+ return
+}
+
+proc ::page::gen::peg::canon::SynthNode/t {t n} {
+ # Terminal node. Primitive layout.
+ # Put the char into single or double quotes.
+
+ set ch [$t get $n char]
+ if {$ch eq "'"} {set q "\""} else {set q '}
+
+ set text $q$ch$q
+
+ SetBlock $t $n $text
+ return
+}
+
+proc ::page::gen::peg::canon::SynthNode/n {t n} {
+ # Nonterminal node. Primitive layout. Text is the name of smybol
+ # itself.
+
+ SetBlock $t $n [$t get $n sym]
+ return
+}
+
+proc ::page::gen::peg::canon::SynthNode/.. {t n} {
+ # Range is [x-y]
+ set b [$t get $n begin]
+ set e [$t get $n end]
+ SetBlock $t $n "\[${b}-${e}\]"
+ return
+}
+
+proc ::page::gen::peg::canon::SynthNode/alnum {t n} {SetBlock $t $n <alnum>}
+proc ::page::gen::peg::canon::SynthNode/alpha {t n} {SetBlock $t $n <alpha>}
+proc ::page::gen::peg::canon::SynthNode/dot {t n} {SetBlock $t $n .}
+proc ::page::gen::peg::canon::SynthNode/epsilon {t n} {SetBlock $t $n ""}
+
+proc ::page::gen::peg::canon::SynthNode/? {t n} {SynthSuffix $t $n ?}
+proc ::page::gen::peg::canon::SynthNode/* {t n} {SynthSuffix $t $n *}
+proc ::page::gen::peg::canon::SynthNode/+ {t n} {SynthSuffix $t $n +}
+
+proc ::page::gen::peg::canon::SynthNode/! {t n} {SynthPrefix $t $n !}
+proc ::page::gen::peg::canon::SynthNode/& {t n} {SynthPrefix $t $n &}
+
+proc ::page::gen::peg::canon::SynthSuffix {t n op} {
+
+ set sub [lindex [$t children $n] 0]
+ set sop [$t get $sub op]
+ set etext [$t get $sub TEXT]
+
+ WrapParens $op $sop etext
+ SetBlock $t $n $etext$op
+ return
+}
+
+proc ::page::gen::peg::canon::SynthPrefix {t n op} {
+
+ set sub [lindex [$t children $n] 0]
+ set sop [$t get $sub op]
+ set etext [$t get $sub TEXT]
+
+ WrapParens $op $sop etext
+ SetBlock $t $n $op$etext
+ return
+}
+
+proc ::page::gen::peg::canon::SynthNode/x {t n} {
+ variable llen
+
+ # Space given to us for an expression.
+ set lend [expr {$llen - [$t get root HEADLEN]}]
+
+ set clist [$t children $n]
+ if {[llength $clist] == 1} {
+ # Implicit cutting out of chains.
+
+ CopyBlock $t $n [lindex $clist 0]
+
+ #puts stderr <<implicit>>
+ return
+ }
+
+ set out ""
+
+ # We are not tracking the total width of the block, but only the
+ # width of the current line, as that is where we may have to
+ # wrap. The height however is the total height.
+
+ #puts stderr <<$clist>>
+ #puts stderr \t___________________________________
+
+ set w 0
+ set h 0
+ foreach c $clist {
+ set sop [$t get $c op]
+ set sub [$t get $c TEXT]
+ set sw [$t get $c W]
+ set slw [$t get $c Wlast]
+ set sh [$t get $c H]
+
+ #puts stderr \t<$sop/$sw/$slw/$sh>___________________________________
+ #SHOW $sub $slw $sh
+
+ if {[Paren x $sop]} {
+ set sub "([::textutil::indent $sub " " 1])"
+ incr slw 2
+ incr sw 2
+
+ #puts stderr /paren/
+ #SHOW $sub $slw $sh
+ }
+
+ # Empty buffer ... Put element, and extend dimensions
+
+ #puts stderr \t.=============================
+ #SHOW $out $w $h
+
+ if {$w == 0} {
+ #puts stderr /init
+ append out $sub
+ set w $slw
+ set h $sh
+ } elseif {($w + $sw + 1) > $lend} {
+ #puts stderr /wrap/[expr {($w + $sw + 1)}]/$lend
+ # To large, wrap into next line.
+ append out \n $sub
+ incr h $sh
+ set w $slw
+ } else {
+ # We have still space to put the block in. Either by
+ # simply appending, or by indenting a multiline block
+ # properly so that its parts stay aligned with each other.
+ if {$sh == 1} {
+ #puts stderr /add/line
+ append out " " $sub
+ incr w ; incr w $slw
+ } else {
+ append out " " ; incr w
+ #puts stderr /add/block/$w
+ append out [::textutil::indent $sub [::textutil::blank $w] 1]
+ incr w $slw
+ incr h $sh ; incr h -1
+ }
+ }
+
+ #puts stderr \t.~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ #SHOW $out $w $h
+ }
+
+ SetBlock $t $n $out
+ return
+}
+
+proc ::page::gen::peg::canon::SynthNode// {t n} {
+ # We take all branches and put them together, nicely aligned under
+ # each other.
+
+ set clist [$t children $n]
+ if {[llength $clist] == 1} {
+ # Implicit cutting out of chains.
+
+ CopyBlock $t $n [lindex $clist 0]
+ return
+ }
+
+ set out ""
+ foreach c $clist {
+ set sop [$t get $c op]
+ set sub [$t get $c TEXT]
+ WrapParens / $sop sub
+ append out "/ [::textutil::indent $sub " " 1]" \n
+ }
+
+ SetBlock $t $n " [string range $out 1 end]"
+ return
+}
+
+proc ::page::gen::peg::canon::WrapParens {op sop tvar} {
+ if {[Paren $op $sop]} {
+ upvar 1 $tvar text
+ set text "([::textutil::indent $text " " 1])"
+ }
+}
+
+proc ::page::gen::peg::canon::Paren {op sop} {
+ # sop is nested under op.
+ # Parens are required if sop has a lower priority than op.
+
+ return [expr {[Priority $sop] < [Priority $op]}]
+}
+
+proc ::page::gen::peg::canon::Priority {op} {
+ switch -exact -- $op {
+ t -
+ n -
+ .. -
+ alnum -
+ alpha -
+ dot -
+ epsilon {return 4}
+ ? -
+ * -
+ + {return 3}
+ ! -
+ & {return 2}
+ x {return 1}
+ / {return 0}
+ }
+ return -code error "Internal error, bad operator \"$op\""
+}
+
+proc ::page::gen::peg::canon::CopyBlock {t n src} {
+ $t set $n TEXT [$t get $src TEXT]
+ $t set $n W [$t get $src W]
+ $t set $n Wlast [$t get $src Wlast]
+ $t set $n H [$t get $src H]
+ return
+}
+
+proc ::page::gen::peg::canon::SetBlock {t n text} {
+ set text [string trimright $text]
+ set lines [split $text \n]
+ set height [llength $lines]
+
+ if {$height > 1} {
+ set max -1
+ set ntext {}
+
+ foreach line $lines {
+ set line [string trimright $line]
+ set l [string length $line]
+ if {$l > $max} {set max $l}
+ lappend ntext $line
+ set wlast $l
+ }
+ set text [join $ntext \n]
+ set width $max
+ } else {
+ set width [string length $text]
+ set wlast $width
+ }
+
+ $t set $n TEXT $text
+ $t set $n W $width
+ $t set $n Wlast $wlast
+ $t set $n H $height
+ return
+}
+
+proc ::page::gen::peg::canon::AttrFieldLength {modeset} {
+ variable ms
+ return $ms($modeset,*)
+}
+
+if {0} {
+ proc ::page::gen::peg::canon::SHOW {text w h} {
+ set wl $w ; incr wl -1
+ puts stderr "\t/$h"
+ puts stderr "[textutil::indent $text \t|]"
+ puts stderr "\t\\[string repeat "-" $wl]^ ($w)"
+ return
+ }
+}
+
+# ### ### ### ######### ######### #########
+## Internal. Strings.
+
+namespace eval ::page::gen::peg::canon {
+ variable llen 80
+ variable ms ; array set ms {
+ dlmv,discard {void: }
+ dlmv,leaf {leaf: }
+ dlmv,match {match: }
+ dlmv,value { }
+ dlmv,* 7
+
+ dlm,discard {void: } dlv,discard {void: }
+ dlm,leaf {leaf: } dlv,leaf {leaf: }
+ dlm,match {match: } dlv,value { }
+ dlm,* 7 dlv,* 6
+
+ dmv,discard {void: } lmv,leaf {leaf: }
+ dmv,match {match: } lmv,match {match: }
+ dmv,value { } lmv,value { }
+ dmv,* 7 lmv,* 7
+
+ dl,discard {void: } dm,discard {void: }
+ dl,leaf {leaf: } dm,match {match: }
+ dl,* 6 dm,* 7
+
+ lm,leaf {leaf: } dv,discard {void: }
+ lm,match {match: } dv,value { }
+ lm,* 7 dv,* 6
+
+ lv,leaf {leaf: } mv,match {match: }
+ lv,value { } mv,value { }
+ lv,* 6 mv,* 7
+
+ d,discard {void: } d,* 6
+ l,leaf {leaf: } l,* 6
+ m,match {match: } m,* 7
+ v,value {} v,* 0
+ }
+}
+
+# ### ### ### ######### ######### #########
+## Ready
+
+package provide page::gen::peg::canon 0.1
diff --git a/tcllib/modules/page/gen_peg_cpkg.tcl b/tcllib/modules/page/gen_peg_cpkg.tcl
new file mode 100644
index 0000000..5776f96
--- /dev/null
+++ b/tcllib/modules/page/gen_peg_cpkg.tcl
@@ -0,0 +1,171 @@
+# -*- tcl -*-
+#
+# Copyright (c) 2005 by Andreas Kupries <andreas_kupries@users.sourceforge.net>
+# Parser Generator / Backend - PEG as Tcl script.
+
+# ### ### ### ######### ######### #########
+## Requisites
+
+package require page::util::peg
+
+namespace eval ::page::gen::peg::cpkg {
+ # Get various utilities.
+
+ namespace import ::page::util::peg::*
+}
+
+# ### ### ### ######### ######### #########
+## API
+
+proc ::page::gen::peg::cpkg {t chan} {
+ cpkg::printWarnings [cpkg::getWarnings $t]
+
+ set grname [$t get root name]
+
+ cpkg::Header $chan $grname
+
+ set gstart [$t get root start]
+ if {$gstart ne ""} {
+ set gstart [cpkg::peOf $t $gstart]
+ } else {
+ puts stderr "No start expression."
+ }
+
+ cpkg::Start $chan $gstart
+
+ set temp {}
+ set max -1
+
+ foreach {sym def} [$t get root definitions] {
+ set eroot [lindex [$t children $def] 0]
+ set l [string length [list $sym]]
+ if {$l > $max} {set max $l}
+ lappend temp \
+ [list $sym [$t get $def mode] [cpkg::peOf $t $eroot] $l]
+ }
+
+ foreach e [lsort -dict -index 0 $temp] {
+ foreach {sym mode rule l} $e break
+ cpkg::Rule $chan $sym $mode $rule [expr {$max - $l}]
+ }
+
+ cpkg::Trailer $chan $grname
+ return
+}
+
+# ### ### ### ######### ######### #########
+## Internal. Helpers
+
+proc ::page::gen::peg::cpkg::Header {chan grname} {
+ variable header
+ variable headerb
+
+ set stem [namespace tail $grname]
+ puts $chan [string map \
+ [list \
+ @@ [list $grname] \
+ @stem@ [list $stem] \
+ "\n\t" "\n"
+ ] \
+ $header\n$headerb]
+}
+
+proc ::page::gen::peg::cpkg::Start {chan pe} {
+ puts $chan " Start [printTclExpr $pe]\n"
+ return
+}
+
+proc ::page::gen::peg::cpkg::Rule {chan sym mode pe off} {
+ variable ms
+ set off [string repeat " " $off]
+ puts $chan " Define $ms($mode) $sym$off [printTclExpr $pe]"
+ return
+}
+
+proc ::page::gen::peg::cpkg::Trailer {chan grname} {
+ variable trailer
+ variable trailerb
+ puts $chan [string map \
+ [list \
+ @@ [list $grname] \
+ "\n\t" "\n"
+ ] \
+ $trailer\n$trailerb]
+}
+
+# ### ### ### ######### ######### #########
+## Internal. Strings.
+
+namespace eval ::page::gen::peg::cpkg {
+ variable ms ; array set ms {
+ value {value }
+ discard {discard}
+ match {match }
+ leaf {leaf }
+ }
+ variable header {# -*- tcl -*-
+ ## Parsing Expression Grammar '@@'.
+
+ # ### ### ### ######### ######### #########
+ ## Package description
+
+ ## It provides a single command returning the handle of a
+ ## grammar container in which the grammar '@@'
+ ## is stored. The container is usable by a PEG interpreter
+ ## or other packages taking PE grammars.
+
+ # ### ### ### ######### ######### #########
+ ## Requisites.
+ ## - PEG container type
+
+ package require grammar::peg
+
+ namespace eval ::@@ {}
+
+ # ### ### ### ######### ######### #########
+ ## API
+
+ proc ::@@ {} {
+ return $@stem@::gr
+ }
+
+ # ### ### ### ######### ######### #########
+ # ### ### ### ######### ######### #########
+ ## Data and helpers.
+
+ namespace eval ::@@ {
+ # Grammar container
+ variable gr [::grammar::peg gr]
+ }
+
+ proc ::@@::Start {pe} {
+ variable gr
+ $gr start $pe
+ return
+ }
+
+ proc ::@@::Define {mode sym pe} {
+ variable gr
+ $gr nonterminal add $sym $pe
+ $gr nonterminal mode $sym $mode
+ return
+ }
+
+ # ### ### ### ######### ######### #########
+ ## Initialization = Grammar definition
+ }
+ variable headerb "namespace eval ::@@ \{"
+
+ variable trailer "\}"
+ variable trailerb {
+ # ### ### ### ######### ######### #########
+ ## Package Management - Ready
+
+ package provide @@ 0.1
+ }
+}
+
+# ### ### ### ######### ######### #########
+## Ready
+
+package provide page::gen::peg::cpkg 0.1
diff --git a/tcllib/modules/page/gen_peg_hb.tcl b/tcllib/modules/page/gen_peg_hb.tcl
new file mode 100644
index 0000000..a4cbf6f
--- /dev/null
+++ b/tcllib/modules/page/gen_peg_hb.tcl
@@ -0,0 +1,79 @@
+# -*- tcl -*-
+#
+# Copyright (c) 2005 by Andreas Kupries <andreas_kupries@users.sourceforge.net>
+# Parser Generator / Backend - PEG in half baked form for PEG container.
+
+# ### ### ### ######### ######### #########
+## Requisites
+
+package require page::util::peg
+
+namespace eval ::page::gen::peg::hb {
+ # Get various utilities.
+
+ namespace import ::page::util::peg::*
+}
+
+# ### ### ### ######### ######### #########
+## API
+
+proc ::page::gen::peg::hb {t chan} {
+ hb::printWarnings [hb::getWarnings $t]
+
+ set gstart [$t get root start]
+ if {$gstart ne ""} {
+ set gstart [hb::peOf $t $gstart]
+ } else {
+ puts stderr "No start expression."
+ }
+
+ hb::Start $chan $gstart
+
+ set temp {}
+ set max -1
+ foreach {sym def} [$t get root definitions] {
+ set eroot [lindex [$t children $def] 0]
+ set l [string length [list $sym]]
+ if {$l > $max} {set max $l}
+ lappend temp \
+ [list $sym [$t get $def mode] [hb::peOf $t $eroot] $l]
+ }
+
+ foreach e [lsort -dict -index 0 $temp] {
+ foreach {sym mode rule l} $e break
+ hb::Rule $chan $sym $mode $rule [expr {$max - $l}]
+ }
+ return
+}
+
+# ### ### ### ######### ######### #########
+## Internal. Helpers
+
+proc ::page::gen::peg::hb::Start {chan pe} {
+ puts $chan "Start [printTclExpr $pe]\n"
+ return
+}
+
+proc ::page::gen::peg::hb::Rule {chan sym mode pe off} {
+ variable ms
+ set off [string repeat " " $off]
+ puts $chan "Define $ms($mode) $sym$off [printTclExpr $pe]"
+ return
+}
+
+# ### ### ### ######### ######### #########
+## Internal. Strings.
+
+namespace eval ::page::gen::peg::hb {
+ variable ms ; array set ms {
+ value {value }
+ discard {discard}
+ match {match }
+ leaf {leaf }
+ }
+}
+
+# ### ### ### ######### ######### #########
+## Ready
+
+package provide page::gen::peg::hb 0.1
diff --git a/tcllib/modules/page/gen_peg_me.tcl b/tcllib/modules/page/gen_peg_me.tcl
new file mode 100644
index 0000000..bb98902
--- /dev/null
+++ b/tcllib/modules/page/gen_peg_me.tcl
@@ -0,0 +1,888 @@
+# -*- tcl -*-
+#
+# Copyright (c) 2005 by Andreas Kupries <andreas_kupries@users.sourceforge.net>
+# Parser Generator / Backend - Generate a grammar::mengine based parser.
+
+# This package assumes to be used from within a PAGE plugin. It uses
+# the API commands listed below. These are identical across the major
+# types of PAGE plugins, allowing this package to be used in reader,
+# transform, and writer plugins. It cannot be used in a configuration
+# plugin, and this makes no sense either.
+#
+# To ensure that our assumption is ok we require the relevant pseudo
+# package setup by the PAGE plugin management code.
+#
+# -----------------+--
+# page_info | Reporting to the user.
+# page_warning |
+# page_error |
+# -----------------+--
+# page_log_error | Reporting of internals.
+# page_log_warning |
+# page_log_info |
+# -----------------+--
+
+# ### ### ### ######### ######### #########
+## Dumping the input grammar. But not as Tcl or other code. In PEG
+## format again, pretty printing.
+
+# ### ### ### ######### ######### #########
+## Requisites
+
+# @mdgen NODEP: page::plugin
+
+package require page::plugin ; # S.a. pseudo-package.
+
+package require textutil
+package require page::analysis::peg::emodes
+package require page::util::quote
+package require page::util::peg
+
+namespace eval ::page::gen::peg::me {
+ # Get the peg char de/encoder commands.
+ # (unquote, quote'tcl)
+
+ namespace import ::page::util::quote::*
+ namespace import ::page::util::peg::*
+}
+
+# ### ### ### ######### ######### #########
+## API
+
+proc ::page::gen::peg::me::package {text} {
+ variable package $text
+ return
+}
+
+proc ::page::gen::peg::me::copyright {text} {
+ variable copyright $text
+ return
+}
+
+proc ::page::gen::peg::me {t chan} {
+ variable me::package
+ variable me::copyright
+
+ # Resolve the mode hints. Every gen(X) having a value of 'maybe'
+ # (or missing) is for the purposes of this code a 'yes'.
+
+ if {![page::analysis::peg::emodes::compute $t]} {
+ page_error " Unable to generate a ME parser without accept/generate properties"
+ return
+ }
+
+ foreach n [$t nodes] {
+ if {![$t keyexists $n gen] || ([$t get $n gen] eq "maybe")} {
+ $t set $n gen 1
+ }
+ if {![$t keyexists $n acc]} {$t set $n acc 1}
+ }
+
+ $t set root Pcount 0
+
+ $t set root package $package
+ $t set root copyright $copyright
+
+ # Synthesize all text fragments we need.
+ me::Synth $t
+
+ # And write the grammar text.
+ puts $chan [$t get root TEXT]
+ return
+}
+
+# ### ### ### ######### ######### #########
+## Internal. Helpers
+
+proc ::page::gen::peg::me::Synth {t} {
+ # Phase 2: Bottom-up, synthesized attributes
+ #
+ # - Text blocks per node.
+
+ $t walk root -order post -type dfs n {
+ SynthNode $t $n
+ }
+ return
+}
+
+proc ::page::gen::peg::me::SynthNode {t n} {
+ if {$n eq "root"} {
+ set code Root
+ } elseif {[$t keyexists $n symbol]} {
+ set code Nonterminal
+ } elseif {[$t keyexists $n op]} {
+ set code [$t get $n op]
+ } else {
+ return -code error "PANIC. Bad node $n, cannot classify"
+ }
+
+ #puts stderr "SynthNode/$code $t $n"
+
+ SynthNode/$code $t $n
+
+ #SHOW [$t get $n TEXT] 1 0
+ #catch {puts stderr "\t.[$t get $n W]x[$t get $n H]"}
+ return
+}
+
+proc ::page::gen::peg::me::SynthNode/Root {t n} {
+ variable template
+
+ # Root is the grammar itself.
+
+ # Text blocks we have to combine:
+ # - Code for matching the start expression
+ # - Supporting code for the above.
+ # - Code per Nonterminal definition.
+
+ set gname [$t get root name]
+ set gstart [$t get root start]
+ set gpackage [$t get root package]
+ set gcopy [$t get root copyright]
+
+ if {$gcopy ne ""} {
+ set gcopyright "## (C) $gcopy\n"
+ } else {
+ set gcopyright ""
+ }
+ if {$gpackage eq ""} {
+ set gpackage $gname
+ }
+
+ page_info " Grammar: $gname"
+ page_info " Package: $gpackage"
+ if {$gcopy ne ""} {
+ page_info " Copyright: $gcopy"
+ }
+
+ if {$gstart ne ""} {
+ set match [textutil::indent \
+ [$t get $gstart MATCH] \
+ " "]
+ } else {
+ page_error " No start expression."
+ set match ""
+ }
+
+ set crules {}
+ set rules {}
+ set support [$t get [$t get root start] SUPPORT]
+ if {[string length $support]} {
+ lappend rules $support
+ lappend rules {}
+ }
+
+ lappend crules "# Grammar '$gname'"
+ lappend crules {#}
+
+ array set def [$t get root definitions]
+ foreach sym [lsort -dict [array names def]] {
+ lappend crules [Pfx "# " [$t get $def($sym) EXPR]]
+ lappend crules {#}
+
+ lappend rules [$t get $def($sym) TEXT]
+ lappend rules {}
+ }
+ set rules [join [lrange $rules 0 end-1] \n]
+
+ lappend crules {}
+ lappend crules $rules
+
+ set crules [join $crules \n]
+
+ # @PKG@ and @NAME@ are handled after the other expansions as their
+ # contents may insert additional instances of these placeholders.
+
+ $t set root TEXT \
+ [string map \
+ [list \
+ @NAME@ $gname \
+ @PKG@ $gpackage \
+ @COPY@ $gcopyright] \
+ [string map \
+ [list \
+ @MATCH@ $match \
+ @RULES@ $crules \
+ ] $template]]
+ return
+}
+
+proc ::page::gen::peg::me::SynthNode/Nonterminal {t n} {
+ # This is the root of a definition.
+ #
+ # The text is a procedure wrapping the match code of its
+ # expression into the required the nonterminal handling (caching
+ # and such), plus the support code for the expression matcher.
+
+ set sym [$t get $n symbol]
+ set label [$t get $n label]
+ set gen [$t get $n gen]
+ set mode [$t get $n mode]
+
+ set pe [lindex [$t children $n] 0]
+ set egen [$t get $pe gen]
+ set esupport [$t get $pe SUPPORT]
+ set ematch [$t get $pe MATCH]
+ set eexpr [$t get $pe EXPR]
+
+ # Combine the information.
+
+ set sexpr [Cat "$sym = " $eexpr]
+
+ set match {}
+ #lappend match "puts stderr \"$label << \[icl_get\]\""
+ #lappend match {}
+ lappend match [Pfx "# " $sexpr]
+ lappend match {}
+ if {$gen} {
+ lappend match {variable ok}
+ lappend match "if \{\[inc_restore $label\]\} \{"
+ lappend match " if \{\$ok\} ias_push"
+ #lappend match " puts stderr \">> $label = \$ok (c) \[icl_get\]\""
+ lappend match " return"
+ lappend match "\}"
+ } else {
+ set eop [$t get $pe op]
+ if {
+ ($eop eq "t") || ($eop eq "..") ||
+ ($eop eq "alpha") || ($eop eq "alnum")
+ } {
+ # Required iff !dot
+ # Support for terminal expression
+ lappend match {variable ok}
+ }
+
+ #lappend match "variable ok"
+ lappend match "if \{\[inc_restore $label\]\} return"
+ #lappend match "if \{\[inc_restore $label\]\} \{"
+ #lappend match " puts stderr \">> $label = \$ok (c) \[icl_get\]\""
+ #lappend match " return"
+ #lappend match "\}"
+ }
+ lappend match {}
+ lappend match {set pos [icl_get]}
+ if {$egen} {
+ # [*] Needed for removal of SV's from stack after handling by
+ # this symbol, only if expression actually generates an SV.
+ lappend match {set mrk [ias_mark]}
+ }
+ lappend match {}
+ lappend match $ematch
+ lappend match {}
+
+ switch -exact -- $mode {
+ value {lappend match "isv_nonterminal_reduce $label \$pos \$mrk"}
+ match {lappend match "isv_nonterminal_range $label \$pos"}
+ leaf {lappend match "isv_nonterminal_leaf $label \$pos"}
+ discard {lappend match "isv_clear"}
+ default {return -code error "Bad nonterminal mode \"$mode\""}
+ }
+
+ lappend match "inc_save $label \$pos"
+ if {$egen} {
+ # See [*], this is the removal spoken about before.
+ lappend match {ias_pop2mark $mrk}
+ }
+ if {$gen} {
+ lappend match {if {$ok} ias_push}
+ }
+ lappend match "ier_nonterminal \"Expected $label\" \$pos"
+ #lappend match "puts stderr \">> $label = \$ok \[icl_get\]\""
+ lappend match return
+
+ # Final assembly
+
+ set pname [Call $sym]
+ set match [list [Proc $pname [join $match \n]]]
+
+ if {[string length $esupport]} {
+ lappend match {}
+ lappend match $esupport
+ }
+
+ $t set $n TEXT [join $match \n]
+ $t set $n EXPR $sexpr
+ return
+}
+
+proc ::page::gen::peg::me::SynthNode/? {t n} {
+ # The expression e? is equivalent to e/epsilon.
+ # And like this it is compiled.
+
+ set pe [lindex [$t children $n] 0]
+ set ematch [$t get $pe MATCH]
+ set esupport [$t get $pe SUPPORT]
+ set eexpr [$t get $pe EXPR]
+ set egen [$t get $pe gen]
+ set sexpr "[Cat "(? " $eexpr])"
+
+ set match {}
+ lappend match {}
+ lappend match [Pfx "# " $sexpr]
+ lappend match {}
+ lappend match {variable ok}
+ lappend match {}
+ lappend match {set pos [icl_get]}
+ lappend match {}
+ lappend match {set old [ier_get]}
+ lappend match $ematch
+ lappend match {ier_merge $old}
+ lappend match {}
+ lappend match {if {$ok} return}
+ lappend match {icl_rewind $pos}
+ lappend match {iok_ok}
+ lappend match {return}
+
+ # Final assembly
+
+ set pname [NextProc $t opt]
+ set match [list [Proc $pname [join $match \n]]]
+ if {[string length $esupport]} {
+ lappend match {}
+ lappend match $esupport
+ }
+
+ $t set $n EXPR $sexpr
+ $t set $n MATCH [Cat "$pname ; " [Pfx "# " $sexpr]]
+ $t set $n SUPPORT [join $match \n]
+ return
+}
+
+proc ::page::gen::peg::me::SynthNode/* {t n} {
+ # Kleene star is like a repeated ?
+
+ # Note: Compilation as while loop, as done now
+ # means that the parser has no information about
+ # the intermediate structure of the input in his
+ # cache.
+
+ # Future: Create a helper symbol X and compile
+ # the expression e = e'* as:
+ # e = X; X <- (e' X)?
+ # with match data for X put into the cache. This
+ # is not exactly equivalent, the structure of the
+ # AST is different (right-nested tree instead of
+ # a list). This however can be handled with a
+ # special nonterminal mode to expand the current
+ # SV on the stack.
+
+ # Note 2: This is a transformation which can be
+ # done on the grammar itself, before the actual
+ # backend is let loose. This "strength reduction"
+ # allows us to keep this code here.
+
+ set pe [lindex [$t children $n] 0]
+ set ematch [$t get $pe MATCH]
+ set esupport [$t get $pe SUPPORT]
+ set eexpr [$t get $pe EXPR]
+ set egen [$t get $pe gen]
+ set sexpr "[Cat "(* " $eexpr])"
+
+ set match {}
+ lappend match {}
+ lappend match [Pfx "# " $sexpr]
+ lappend match {}
+ lappend match {variable ok}
+ lappend match {}
+ lappend match "while \{1\} \{"
+ lappend match { set pos [icl_get]}
+ lappend match {}
+ lappend match { set old [ier_get]}
+ lappend match [textutil::indent $ematch " "]
+ lappend match { ier_merge $old}
+ lappend match {}
+ lappend match { if {$ok} continue}
+ lappend match { break}
+ lappend match "\}"
+ lappend match {}
+ lappend match {icl_rewind $pos}
+ lappend match {iok_ok}
+ lappend match {return}
+
+ # Final assembly
+
+ set pname [NextProc $t kleene]
+ set match [list [Proc $pname [join $match \n]]]
+ if {[string length $esupport]} {
+ lappend match {}
+ lappend match $esupport
+ }
+
+ $t set $n MATCH [Cat "$pname ; " [Pfx "# " $sexpr]]
+ $t set $n SUPPORT [join $match \n]
+ $t set $n EXPR $sexpr
+ return
+}
+
+proc ::page::gen::peg::me::SynthNode/+ {t n} {
+ # Positive Kleene star x+ is equivalent to x x*
+ # This is how it is compiled. See also the notes
+ # at the * above, they apply in essence here as
+ # well, except that the transformat scheme is
+ # slighty different:
+ #
+ # e = e'* ==> e = X; X <- e' X?
+
+ set pe [lindex [$t children $n] 0]
+ set ematch [$t get $pe MATCH]
+ set esupport [$t get $pe SUPPORT]
+ set eexpr [$t get $pe EXPR]
+ set egen [$t get $pe gen]
+ set sexpr "[Cat "(+ " $eexpr])"
+
+ set match {}
+ lappend match {}
+ lappend match [Pfx "# " $sexpr]
+ lappend match {}
+ lappend match {variable ok}
+ lappend match {}
+ lappend match {set pos [icl_get]}
+ lappend match {}
+ lappend match {set old [ier_get]}
+ lappend match $ematch
+ lappend match {ier_merge $old}
+ lappend match {}
+ lappend match "if \{!\$ok\} \{"
+ lappend match { icl_rewind $pos}
+ lappend match { return}
+ lappend match "\}"
+ lappend match {}
+ lappend match "while \{1\} \{"
+ lappend match { set pos [icl_get]}
+ lappend match {}
+ lappend match { set old [ier_get]}
+ lappend match [textutil::indent $ematch " "]
+ lappend match { ier_merge $old}
+ lappend match {}
+ lappend match { if {$ok} continue}
+ lappend match { break}
+ lappend match "\}"
+ lappend match {}
+ lappend match {icl_rewind $pos}
+ lappend match {iok_ok}
+ lappend match {return}
+
+ # Final assembly
+
+ set pname [NextProc $t pkleene]
+ set match [list [Proc $pname [join $match \n]]]
+ if {[string length $esupport]} {
+ lappend match {}
+ lappend match $esupport
+ }
+
+ $t set $n MATCH [Cat "$pname ; " [Pfx "# " $sexpr]]
+ $t set $n SUPPORT [join $match \n]
+ $t set $n EXPR $sexpr
+ return
+}
+
+proc ::page::gen::peg::me::SynthNode// {t n} {
+ set args [$t children $n]
+
+ if {![llength $args]} {
+ error "PANIC. Empty choice."
+
+ } elseif {[llength $args] == 1} {
+ # A choice over one branch is no real choice. The code
+ # generated for the child applies here as well.
+
+ set pe [lindex $args 0]
+ $t set $n MATCH [$t get $pe MATCH]
+ $t set $n SUPPORT [$t get $pe SUPPORT]
+ return
+ }
+
+ # Choice over at least two branches.
+
+ set match {}
+ set support {}
+ set sexpr {}
+
+ lappend match {}
+ lappend match {}
+ lappend match {variable ok}
+ lappend match {}
+ lappend match {set pos [icl_get]}
+ foreach pe $args {
+ lappend match {}
+
+ set ematch [$t get $pe MATCH]
+ set esupport [$t get $pe SUPPORT]
+ set eexpr [$t get $pe EXPR]
+ set egen [$t get $pe gen]
+
+ # Note: We do not check for static match results. Doing so is
+ # an optimization we can do earlier, directly on the tree.
+
+ lappend sexpr $eexpr
+
+ if {[string length $esupport]} {
+ lappend support {}
+ lappend support $esupport
+ }
+
+ if {$egen} {
+ lappend match "set mrk \[ias_mark\]"
+ }
+
+ lappend match "set old \[ier_get\]"
+ lappend match $ematch
+ lappend match "ier_merge \$old"
+ lappend match {}
+ lappend match "if \{\$ok\} return"
+
+ if {$egen} {
+ lappend match "ias_pop2mark \$mrk"
+ }
+ lappend match "icl_rewind \$pos"
+ }
+ lappend match {}
+ lappend match return
+
+ # Final assembly
+
+ set sexpr "[Cat "(/ " [join $sexpr \n]])"
+ set match [linsert $match 1 [Pfx "# " $sexpr]]
+
+ set pname [NextProc $t bra]
+ set match [list [Proc $pname [join $match \n]]]
+ if {[llength $support]} {
+ lappend match {}
+ lappend match [join [lrange $support 1 end] \n]
+ }
+
+ $t set $n MATCH [Cat "$pname ; " [Pfx "# " $sexpr]]
+ $t set $n SUPPORT [join $match \n]
+ $t set $n EXPR $sexpr
+ return
+}
+
+proc ::page::gen::peg::me::SynthNode/x {t n} {
+ set args [$t children $n]
+
+ if {![llength $args]} {
+ error "PANIC. Empty sequence."
+
+ } elseif {[llength $args] == 1} {
+ # A sequence of one element is no real sequence. The code
+ # generated for the child applies here as well.
+
+ set pe [lindex $args 0]
+ $t set $n MATCH [$t get $pe MATCH]
+ $t set $n SUPPORT [$t get $pe SUPPORT]
+ $t set $n EXPR [$t get $pe EXPRE]
+ return
+ }
+
+ # Sequence of at least two elements.
+
+ set match {}
+ set support {}
+ set sexpr {}
+ set gen 0
+
+ lappend match {}
+ lappend match {}
+ lappend match {variable ok}
+ lappend match {}
+ lappend match {set pos [icl_get]}
+
+ foreach pe $args {
+ lappend match {}
+
+ set ematch [$t get $pe MATCH]
+ set esupport [$t get $pe SUPPORT]
+ set eexpr [$t get $pe EXPR]
+ set egen [$t get $pe gen]
+
+ lappend sexpr $eexpr
+
+ if {[string length $esupport]} {
+ lappend support {}
+ lappend support $esupport
+ }
+
+ if {$egen && !$gen} {
+ # From here on out is the sequence
+ # able to generate semantic values
+ # which have to be canceled when
+ # backtracking.
+
+ lappend match "set mrk \[ias_mark\]"
+ lappend match {}
+ set gen 1
+ }
+
+ lappend match "set old \[ier_get\]"
+ lappend match $ematch
+ lappend match "ier_merge \$old"
+ lappend match {}
+
+ if {$gen} {
+ lappend match "if \{!\$ok\} \{"
+ lappend match " ias_pop2mark \$mrk"
+ lappend match " icl_rewind \$pos"
+ lappend match " return"
+ lappend match "\}"
+ } else {
+ lappend match "if \{!\$ok\} \{icl_rewind \$pos \; return\}"
+ }
+ }
+ lappend match {}
+ lappend match return
+
+ # Final assembly
+
+ set sexpr "[Cat "(x " [join $sexpr \n]])"
+ set match [linsert $match 1 [Pfx "# " $sexpr]]
+
+ set pname [NextProc $t seq]
+ set match [list [Proc $pname [join $match \n]]]
+ if {[llength $support]} {
+ lappend match {}
+ lappend match [join [lrange $support 1 end] \n]
+ }
+
+ $t set $n MATCH [Cat "$pname ; " [Pfx "# " $sexpr]]
+ $t set $n SUPPORT [join $match \n]
+ $t set $n EXPR $sexpr
+ return
+}
+
+proc ::page::gen::peg::me::SynthNode/& {t n} {
+ SynthLookahead $t $n no
+ return
+}
+
+proc ::page::gen::peg::me::SynthNode/! {t n} {
+ SynthLookahead $t $n yes
+ return
+}
+
+proc ::page::gen::peg::me::SynthNode/dot {t n} {
+ SynthTerminal $t $n \
+ "any character" {}
+ $t set $n EXPR "(dot)"
+ return
+}
+
+proc ::page::gen::peg::me::SynthNode/epsilon {t n} {
+ $t set $n MATCH iok_ok
+ $t set $n SUPPORT {}
+ $t set $n EXPR "(epsilon)"
+ return
+}
+
+proc ::page::gen::peg::me::SynthNode/alnum {t n} {
+ SynthClass $t $n alnum
+ return
+}
+
+proc ::page::gen::peg::me::SynthNode/alpha {t n} {
+ SynthClass $t $n alpha
+ return
+}
+
+proc ::page::gen::peg::me::SynthNode/.. {t n} {
+ # Range is [x-y]
+
+ set b [$t get $n begin]
+ set e [$t get $n end]
+
+ set tb [quote'tcl $b]
+ set te [quote'tcl $e]
+
+ set pb [quote'tclstr $b]
+ set pe [quote'tclstr $e]
+
+ set cb [quote'tclcom $b]
+ set ce [quote'tclcom $e]
+
+ SynthTerminal $t $n \
+ "\\\[${pb}..${pe}\\\]" \
+ "ict_match_tokrange $tb $te"
+ $t set $n EXPR "(.. $cb $ce)"
+ return
+}
+
+proc ::page::gen::peg::me::SynthNode/t {t n} {
+ # Terminal node. Primitive matching.
+ # Code is parameterized by gen(X) of this node X.
+
+ set ch [$t get $n char]
+ set tch [quote'tcl $ch]
+ set pch [quote'tclstr $ch]
+ set cch [quote'tclcom $ch]
+
+ SynthTerminal $t $n \
+ $pch \
+ "ict_match_token $tch"
+ $t set $n EXPR "(t $cch)"
+ return
+}
+
+proc ::page::gen::peg::me::SynthNode/n {t n} {
+ # Nonterminal node. Primitive matching.
+ # The code is parameterized by acc(X) of this node X, and gen(D)
+ # of the invoked nonterminal D.
+
+ set sym [$t get $n sym]
+ set def [$t get $n def]
+
+ if {$def eq ""} {
+ # Invokation of an undefined nonterminal. This will always fail.
+ set match "iok_fail ; # Match for undefined symbol '$sym'."
+ } else {
+ # Combinations
+ # Acc Gen Action
+ # --- --- ------
+ # 0 0 Plain match
+ # 0 1 Match with canceling of the semantic value.
+ # 1 0 Plain match
+ # 1 1 Plain match
+ # --- --- ------
+
+ if {[$t get $n acc] || ![$t get $def gen]} {
+ set match [Call $sym]
+ } else {
+ set match {}
+ lappend match "set p$sym \[ias_mark\]"
+ lappend match [Call $sym]
+ lappend match "ias_pop2mark \$p$sym"
+ set match [join $match \n]
+ }
+ }
+
+ set sexpr "(n $sym)"
+ $t set $n EXPR $sexpr
+ $t set $n MATCH "$match ; # $sexpr"
+ $t set $n SUPPORT {}
+ return
+}
+
+proc ::page::gen::peg::me::SynthLookahead {t n negated} {
+ # Note: Per the rules about expression modes (! is a lookahead
+ # ____| operator) this node has a mode of 'discard', and its child
+ # ____| has so as well.
+
+ # assert t get n mode == discard
+ # assert t get pe mode == discard
+
+ set op [$t get $n op]
+ set pe [lindex [$t children $n] 0]
+ set eop [$t get $pe op]
+ set ematch [$t get $pe MATCH]
+ set esupport [$t get $pe SUPPORT]
+ set eexpr [$t get $pe EXPR]
+ set pname [NextProc $t bang]
+
+ set match {}
+
+ if {
+ ($eop eq "t") || ($eop eq "..") ||
+ ($eop eq "alpha") || ($eop eq "alnum")
+ } {
+ # Required iff !dot
+ # Support for terminal expression
+ lappend match {variable ok}
+ lappend match {}
+ }
+
+ lappend match {set pos [icl_get]}
+ lappend match {}
+ lappend match $ematch
+ lappend match {}
+ lappend match {icl_rewind $pos}
+
+ if {$negated} {
+ lappend match {iok_negate}
+ }
+
+ lappend match return
+
+ set match [list [Proc $pname [join $match \n]]]
+ if {[string length $esupport]} {
+ lappend match {}
+ lappend match $esupport
+ }
+
+ $t set $n MATCH $pname
+ $t set $n SUPPORT [join $match \n]
+ $t set $n EXPR "($op $eexpr)"
+ return
+}
+
+proc ::page::gen::peg::me::SynthClass {t n op} {
+ SynthTerminal $t $n \
+ <$op> \
+ "ict_match_tokclass $op"
+ $t set $n EXPR ($op)
+ return
+}
+
+proc ::page::gen::peg::me::SynthTerminal {t n msg cmd} {
+ set match {}
+ lappend match "ict_advance \"Expected $msg (got EOF)\""
+
+ if {$cmd ne ""} {
+ lappend match "if \{\$ok\} \{$cmd \"Expected $msg\"\}"
+ }
+ if {[$t get $n gen]} {
+ lappend match "if \{\$ok\} isv_terminal"
+ }
+
+ $t set $n MATCH [join $match \n]
+ $t set $n SUPPORT {}
+ return
+}
+
+proc ::page::gen::peg::me::Call {sym} {
+ # Generator for proc names (nonterminal symbols).
+ return matchSymbol_$sym
+}
+
+proc ::page::gen::peg::me::NextProc {t {mark {}}} {
+ set count [$t get root Pcount]
+ incr count
+ $t set root Pcount $count
+ return e$mark$count
+}
+
+proc ::page::gen::peg::me::Proc {name body} {
+ set script {}
+ lappend script "proc ::@PKG@::$name \{\} \{"
+ lappend script [::textutil::indent $body " "]
+ lappend script "\}"
+ return [join $script \n]
+}
+
+proc ::page::gen::peg::me::Cat {prefix suffix} {
+ return "$prefix[textutil::indent $suffix [textutil::blank [string length $prefix]] 1]"
+}
+
+proc ::page::gen::peg::me::Pfx {prefix suffix} {
+ return [textutil::indent $suffix $prefix]
+}
+
+# ### ### ### ######### ######### #########
+## Internal. Strings.
+
+namespace eval ::page::gen::peg::me {
+
+ variable here [file dirname [info script]]
+ variable template_file [file join $here gen_peg_me.template]
+
+ variable ch
+ variable template \
+ [string trimright [read [set ch [open $template_file r]]][close $ch]]
+ unset ch
+
+ variable package ""
+ variable copyright ""
+}
+
+# ### ### ### ######### ######### #########
+## Ready
+
+package provide page::gen::peg::me 0.1
diff --git a/tcllib/modules/page/gen_peg_me.template b/tcllib/modules/page/gen_peg_me.template
new file mode 100644
index 0000000..070e671
--- /dev/null
+++ b/tcllib/modules/page/gen_peg_me.template
@@ -0,0 +1,61 @@
+# -*- tcl -*-
+## Parsing Expression Grammar '@NAME@'.
+## Recursive Descent Packrat parser generated
+## by the PAGE writer plugin 'me'.
+@COPY@
+# ### ### ### ######### ######### #########
+## Package description
+
+# The commands provided here match an input provided through a buffer
+# command to the PE grammar '@NAME@'. The parser is based on the package
+# 'grammar::me::tcl' (recursive-descent, packrat, pulling chars,
+# pushing the generated AST).
+
+# ### ### ### ######### ######### #########
+## Requisites
+
+package require grammar::me::tcl
+
+# ### ### ### ######### ######### #########
+## Implementation
+
+namespace eval ::@PKG@ {
+ # Import the virtual machine for matching.
+
+ namespace import ::grammar::me::tcl::*
+ upvar #0 ::grammar::me::tcl::ok ok
+}
+
+# ### ### ### ######### ######### #########
+## API Implementation.
+
+proc ::@PKG@::parse {nxcmd emvar astvar} {
+ variable ok
+ variable se
+
+ upvar 1 $emvar emsg $astvar ast
+
+ init $nxcmd
+
+@MATCH@
+
+ isv_nonterminal_reduce ALL -1
+ set ast [sv]
+ if {!$ok} {
+ foreach {l m} [ier_get] break
+ lappend l [lc $l]
+ set emsg [list $l $m]
+ }
+
+ return $ok
+}
+
+# ### ### ### ######### ######### #########
+## Internal helper methods
+
+@RULES@
+
+# ### ### ### ######### ######### #########
+## Package Management
+
+package provide @PKG@ 0.1
diff --git a/tcllib/modules/page/gen_peg_mecpu.tcl b/tcllib/modules/page/gen_peg_mecpu.tcl
new file mode 100644
index 0000000..e0b49aa
--- /dev/null
+++ b/tcllib/modules/page/gen_peg_mecpu.tcl
@@ -0,0 +1,289 @@
+# -*- tcl -*-
+#
+# Copyright (c) 2006 by Andreas Kupries <andreas_kupries@users.sourceforge.net>
+# Parser Generator / Backend - Generate a grammar::me::cpu based parser.
+
+# This package assumes to be used from within a PAGE plugin. It uses
+# the API commands listed below. These are identical across the major
+# types of PAGE plugins, allowing this package to be used in reader,
+# transform, and writer plugins. It cannot be used in a configuration
+# plugin, and this makes no sense either.
+#
+# To ensure that our assumption is ok we require the relevant pseudo
+# package setup by the PAGE plugin management code.
+#
+# -----------------+--
+# page_info | Reporting to the user.
+# page_warning |
+# page_error |
+# -----------------+--
+# page_log_error | Reporting of internals.
+# page_log_warning |
+# page_log_info |
+# -----------------+--
+
+# ### ### ### ######### ######### #########
+
+## The input is a grammar, not as tree, but as a list of instructions
+## (symbolic form). This backend converts that into machinecode for
+## grammar::m::cpu::core and inserts the result into a template file.
+
+## The translation from grammar tree to assembler code was done in a
+## preceding transformation.
+
+# ### ### ### ######### ######### #########
+## Requisites
+
+# @mdgen NODEP: page::plugin
+
+package require page::plugin ; # S.a. pseudo-package.
+
+package require grammar::me::cpu::core
+package require textutil
+
+#package require page::analysis::peg::emodes
+#package require page::util::quote
+#package require page::util::peg
+
+namespace eval ::page::gen::peg::mecpu {}
+
+# ### ### ### ######### ######### #########
+## API
+
+proc ::page::gen::peg::mecpu::package {text} {
+ variable package $text
+ return
+}
+
+proc ::page::gen::peg::mecpu::copyright {text} {
+ variable copyright $text
+ return
+}
+
+proc ::page::gen::peg::mecpu::template {path} {
+ variable template $path
+ return
+}
+
+proc ::page::gen::peg::mecpu::cmarker {list} {
+ variable cmarker $list
+ return
+}
+
+proc ::page::gen::peg::mecpu {asmcode chan} {
+
+ # asmcode = list (name code)
+ # code = list (instruction)
+ # instruction = list (label name arg...)
+
+ variable mecpu::package
+ variable mecpu::copyright
+ variable mecpu::cmarker
+ variable mecpu::template
+ variable mecpu::template_file
+
+ # Import the config options, provide fallback to defaults for the
+ # unspecified parts.
+
+ set gname [lindex $asmcode 0]
+ set gcode [lindex $asmcode 1]
+
+ if {$package eq ""} {set package $gname}
+
+ page_info " Grammar: $gname"
+ page_info " Package: $package"
+
+ if {$copyright ne ""} {
+ page_info " Copyright: $copyright"
+ set copyright "\#\# (C) $copyright\n"
+ }
+
+ if {$template eq ""} {
+ set template $template_file
+ }
+
+ page_info " Template: $template"
+
+ # Translate the incoming assembler to machine code.
+
+ set mcode [grammar::me::cpu::core::asm $gcode]
+
+ # We know that the machine code has three parts (instructions,
+ # string pool, token map). We take the data apart to allow separate
+ # insertion if the template so chooses (like for readability).
+
+ foreach {minsn mpool mtmap} $mcode break
+
+ set fminsn {} ; set i 0 ; set j 19
+ while {$i < [llength $minsn]} {
+ append fminsn " [lrange $minsn $i $j]\n"
+ incr i 20 ; incr j 20
+ }
+
+ set fmpool {} ; set i 0 ; set j 4
+ while {$i < [llength $mpool]} {
+ append fmpool " [lrange $mpool $i $j]\n"
+ incr i 5 ; incr j 5
+ }
+
+ # ------------------------------------
+ # We also generate a readable representation of the assembler
+ # instructions for insertion into a comment area.
+
+ set asmp [mecpu::2readable $gcode $minsn]
+
+ # ------------------------------------
+
+ # And write the modified template
+ puts $chan [string map [list \
+ @NAME@ $gname \
+ @PKG@ $package \
+ @COPY@ $copyright \
+ @CODE@ $mcode \
+ @INSN@ $minsn \
+ @FNSN@ $fminsn \
+ @POOL@ $mpool \
+ @FPOL@ $fmpool \
+ @TMAP@ $mtmap \
+ @ASMP@ $asmp \
+ ] [mecpu::Template]]
+ return
+}
+
+proc ::page::gen::peg::mecpu::Template {} {
+ variable template
+ return [string trimright [read [set ch [open $template r]]][close $ch]]
+}
+
+proc ::page::gen::peg::mecpu::2readable {asmcode mecode} {
+ return [2print $asmcode $mecode max [widths $asmcode max]]
+}
+
+proc ::page::gen::peg::mecpu::widths {asmcode mv} {
+ upvar 1 $mv max
+
+ # First iteration, column widths (instructions, and arguments).
+ # Ignore comments, they go across all columns.
+ # Also ignore labels (lrange 1 ..).
+
+ set mc 0
+ foreach insn $asmcode {
+ set i [lindex $insn 1]
+ if {$i eq ".C"} continue
+ set col 0
+
+ foreach x [lrange $insn 1 end] {
+ set xlen [string length $x]
+ if {![info exists max($col)] || ($xlen > $max($col))} {set max($col) $xlen}
+ incr col
+
+ # Shift the strings of various commands into the third
+ # column, if they are not already there.
+
+ if {$i eq "ier_nonterminal"} {incr col ; set i ""}
+ if {$i eq "isv_nonterminal_leaf"} {incr col ; set i ""}
+ if {$i eq "isv_nonterminal_range"} {incr col ; set i ""}
+ if {$i eq "isv_nonterminal_reduce"} {incr col ; set i ""}
+ if {$i eq "inc_save"} {incr col ; set i ""}
+ if {$i eq "ict_advance"} {incr col ; set i ""}
+ }
+ if {$col > $mc} {set mc $col}
+ }
+
+ set max($mc) 0
+ return $mc
+}
+
+proc ::page::gen::peg::mecpu::2print {asmcode mecode mv mc} {
+ variable cmarker
+ upvar 1 $mv max
+
+ set lines {}
+ set pc 0
+
+ foreach insn $asmcode {
+ foreach {label name} $insn break
+ if {$name eq ".C"} {lappend lines "" "-- [join [lrange $insn 2 end] " "]" ""}
+ if {$label ne ""} {lappend lines " ${label}:" }
+ if {$name eq ".C"} continue
+
+ set line " [format %05d $pc] "
+
+ set pcs $pc
+ incr pc [llength $insn] ; incr pc -1
+ set pce $pc ; incr pce -1
+ set imecode [lrange $mecode $pcs $pce]
+
+ if {
+ ($name eq "ier_nonterminal") ||
+ ($name eq "isv_nonterminal_leaf") ||
+ ($name eq "isv_nonterminal_range") ||
+ ($name eq "isv_nonterminal_reduce") ||
+ ($name eq "inc_save") ||
+ ($name eq "ict_advance")
+ } {
+ # Shift first argument into 2nd column, and quote it as well.
+ set insn [lreplace $insn 2 2 "" '[lindex $insn 2]']
+ } elseif {
+ ($name eq "inc_restore") ||
+ ($name eq "ict_match_token") ||
+ ($name eq "ict_match_tokclass")
+ } {
+ # Command with quoted arguments, no shifting.
+ set insn [lreplace $insn 3 3 '[lindex $insn 3]']
+ } elseif {
+ ($name eq "ict_match_tokrange")
+ } {
+ # Command with quoted arguments, no shifting.
+ set insn [lreplace $insn 4 4 '[lindex $insn 4]']
+ }
+
+ while {[llength $insn] <= $mc} {lappend insn ""}
+ lappend insn "-- $imecode"
+
+ set col 0
+ foreach x [lrange $insn 1 end] {
+ set xlen [string length $x]
+ append line " "
+ append line $x
+ append line [string repeat " " [expr {$max($col) - $xlen}]]
+ incr col
+ }
+
+ lappend lines $line
+ }
+
+ # Wrap the lines into a comment.
+
+ if {$cmarker eq ""} {set cmarker "\#"}
+
+ if {[llength $cmarker] > 1} {
+ # Comments are explictly closed as well.
+
+ foreach {cs ce} $cmarker break
+ return "$cs [join $lines " $ce\n$cs "] $ce"
+ } else {
+ # Comments are not explicitly closed. Implicit by end-of-line
+
+ return "$cmarker [join $lines "\n$cmarker "]"
+ }
+}
+
+# ### ### ### ######### ######### #########
+## Internal. Strings.
+
+namespace eval ::page::gen::peg::mecpu {
+
+ variable here [file dirname [info script]]
+ variable template_file [file join $here gen_peg_mecpu.template]
+
+ variable package ""
+ variable copyright ""
+ variable template ""
+ variable cmarker ""
+}
+
+# ### ### ### ######### ######### #########
+## Ready
+
+package provide page::gen::peg::mecpu 0.1
diff --git a/tcllib/modules/page/gen_peg_mecpu.template b/tcllib/modules/page/gen_peg_mecpu.template
new file mode 100644
index 0000000..38cf901
--- /dev/null
+++ b/tcllib/modules/page/gen_peg_mecpu.template
@@ -0,0 +1,48 @@
+# -*- tcl -*-
+## Parsing Expression Grammar '@NAME@'.
+## Recursive Descent Packrat parser generated
+## by the PAGE writer plugin 'mecpu'.
+@COPY@
+# ### ### ### ######### ######### #########
+## Package description
+
+# The commands provided here match an input provided through a buffer
+# command to the PE grammar '@NAME@'. The parser is based on the ME
+# virtual machine (recursive-descent, packrat, pulling chars,
+# pushing the generated AST, suspendable).
+
+# ### ### ### ######### ######### #########
+## Requisites
+
+# Import the virtual machine for matching.
+package require grammar::me::cpu
+
+# ### ### ### ######### ######### #########
+## Implementation
+
+snit::type ::@PKG@ {
+ constructor {} {
+ set cpu [grammar::me::cpu ${selfns}::cpu $mecode]
+ return
+ }
+ variable cpu
+ delegate method * to cpu
+
+ typevariable mecode {
+ {
+@FNSN@ }
+ {
+@FPOL@ }
+ {@TMAP@}
+ }
+}
+
+# ### ### ### ######### ######### #########
+## Documentation. Readable form of 'mecode' above.
+
+@ASMP@
+
+# ### ### ### ######### ######### #########
+## Package Management
+
+package provide @PKG@ 0.1
diff --git a/tcllib/modules/page/gen_peg_ser.tcl b/tcllib/modules/page/gen_peg_ser.tcl
new file mode 100644
index 0000000..7fb8266
--- /dev/null
+++ b/tcllib/modules/page/gen_peg_ser.tcl
@@ -0,0 +1,63 @@
+# -*- tcl -*-
+#
+# Copyright (c) 2005 by Andreas Kupries <andreas_kupries@users.sourceforge.net>
+# Parser Generator / Backend - PEG as serialized PEG container.
+
+# ### ### ### ######### ######### #########
+## Requisites
+
+package require grammar::peg
+package require page::util::quote
+package require page::util::peg
+
+namespace eval ::page::gen::peg::ser {
+ # Get the peg char de/encoder commands.
+ # (unquote, quote'tcl), and other utilities.
+
+ namespace import ::page::util::quote::*
+ namespace import ::page::util::peg::*
+}
+
+# ### ### ### ######### ######### #########
+## API
+
+proc ::page::gen::peg::ser {t chan} {
+ ser::printWarnings [ser::getWarnings $t]
+
+ ::grammar::peg gr
+
+ set gstart [$t get root start]
+ if {$gstart ne ""} {
+ gr start [ser::peOf $t $gstart]
+ } else {
+ page_info "No start expression."
+ }
+
+ foreach {sym def} [$t get root definitions] {
+ set eroot [lindex [$t children $def] 0]
+
+ gr nonterminal add $sym [ser::peOf $t $eroot]
+ gr nonterminal mode $sym [$t get $def mode]
+ }
+
+ puts $chan [gr serialize]
+ gr destroy
+ return
+}
+
+# ### ### ### ######### ######### #########
+## Internal. Helpers
+
+proc ::page::gen::peg::ser::GetRules {t} {
+ return $res
+}
+
+# ### ### ### ######### ######### #########
+## Internal. Strings.
+
+namespace eval ::page::gen::peg::ser {}
+
+# ### ### ### ######### ######### #########
+## Ready
+
+package provide page::gen::peg::ser 0.1
diff --git a/tcllib/modules/page/gen_tree_text.tcl b/tcllib/modules/page/gen_tree_text.tcl
new file mode 100644
index 0000000..44b674f
--- /dev/null
+++ b/tcllib/modules/page/gen_tree_text.tcl
@@ -0,0 +1,94 @@
+# -*- tcl -*-
+#
+# Copyright (c) 2005 by Andreas Kupries <andreas_kupries@users.sourceforge.net>
+# Parser Generator / Backend - Dump (A)ST for inspection.
+
+# ### ### ### ######### ######### #########
+## Requisites
+
+package require page::util::quote
+
+namespace eval ::page::gen::tree::text {
+ # Get the peg char de/encoder commands.
+ # (unquote, quote'tcl)
+
+ namespace import ::page::util::quote::*
+}
+
+# ### ### ### ######### ######### #########
+## API
+
+proc ::page::gen::tree::text {t chan} {
+ set indent ""
+ set bystr " "
+ set bysiz [string length $bystr]
+ set byoff end-$bysiz
+
+ $t walk root -order both -type dfs {a n} {
+ if {$a eq "enter"} {
+ text::WriteNode $indent $chan $t $n
+ append indent $bystr
+ } else {
+ set indent [string range $indent 0 $byoff]
+ }
+ }
+ return
+}
+
+# ### ### ### ######### ######### #########
+## Internal. Helpers
+
+proc ::page::gen::tree::text::WriteNode {indent chan t n} {
+ array set attr [$t getall $n]
+
+ if {[array size attr] == 0} {
+ puts $chan "$indent$n <>"
+ } else {
+ puts -nonewline $chan "$indent$n < "
+
+ set max -1
+ set d {}
+ foreach k [array names attr] {
+ set l [string length $k]
+ if {$l > $max} {set max $l}
+ lappend d [list $k [Quote $attr($k)] $l]
+ }
+
+ if {[llength $d] == 1} {
+ puts $chan "$k = $attr($k) >"
+ return
+ }
+
+ set first 1
+ set space $indent[string repeat " " [string length "$n < "]]
+
+ foreach e [lsort -dict -index 0 $d] {
+ foreach {k v l} $e break
+ set off [string repeat " " [expr {$max-$l}]]
+
+ if {$first} {
+ puts -nonewline $chan "$k$off = $v"
+ set first 0
+ } else {
+ puts -nonewline $chan "\n$space$k$off = $v"
+ }
+ }
+
+ puts $chan " >"
+ }
+}
+
+proc ::page::gen::tree::text::Quote {str} {
+ return $str
+
+ set res ""
+ foreach c [split $str {}] {
+ append res [quote'tcl $c]
+ }
+ return $res
+}
+
+# ### ### ### ######### ######### #########
+## Ready
+
+package provide page::gen::tree::text 0.1
diff --git a/tcllib/modules/page/notes/doc_emodes.txt b/tcllib/modules/page/notes/doc_emodes.txt
new file mode 100644
index 0000000..dd9ea19
--- /dev/null
+++ b/tcllib/modules/page/notes/doc_emodes.txt
@@ -0,0 +1,180 @@
+PE Grammar Tree, after ExprMode Computation
+===========================================
+
+This file documents the augmentations to a Normalized PE Grammar Tree
+as inserted by the transformational package 'pg::peg::emodes'. The
+input to the transformation is assumed to be a 'Normalized PE Grammar
+Tree' as described in 'doc_normalize.txt', possibly with augmentations
+from other transformation, as long as they are not in conflict with
+the augmentations specified here.
+
+Background
+----------
+
+The purpose of the computations and transformations specified here is
+to determine as much static information as we can about the generation
+of semantic values from terminal and non-terminal matchers. Such
+information can then be used to reduce the places in a parser which
+generate and/or handle AST nodes to the bare minimum. I.e we wish to
+avoid the generation of AST nodes by the matcher for which we are sure
+that they will be thrown away by the matcher either immediately, or
+later on.
+
+The fundamental information from which everything else is derived are
+the optional 'mode's which can specified for non-terminal symbols (See
+nonterminal 'Attribute' in the PEG Grammar). They are the hints to the
+matcher on how semantic values are generated and used.
+
+The mode of a nonterminal symbol controls three things at the same
+time: What it does with semantic values generated by its associated
+expression, if it generates its own semantic value, and how. These
+three aspects are interelated to each other, hence using one piece of
+information to set all of them. For this discussion the aspect of
+"how" is not relevant, except where it intersects with the other two.
+
+For the first aspect, the nonterminal has two choices, to either keep
+the semantic value from its expression, or to discard it. I.e this is
+about accepting versus rejection of the value. This aspect is
+'Acceptance'.
+
+For the second aspect the nonterminal has three choices, to either
+generate a value, to not generate a value at all, or to simply pass
+through whatever was done by its expression (a maybe). This aspect is
+'Generation'.
+
+The interelation of these aspects shows up as impossible
+combinations when selecting a value from each set, as made explicit in
+the next table:
+
+ Generation x Acceptance -> Mode
+ ---------- ---------- ----
+ Maybe Yes value
+ Yes Yes value
+ No Yes -- impossible --
+ Maybe No -- impossible --
+ Yes No match, leaf [1]
+ No No discard
+ ---------- ---------- ----
+
+ [1] Here the third aspect, the "how" of the generation comes
+ into play to distinguish these two modes. As said, this
+ distinction is not relevant for the current discussion.
+
+
+What we now wish to achieve is to define the vales for these two
+aspects for all expression and definition modes, which, starting from
+the settings of the modes by the input grammar, is the most definite,
+restrictive and conservative as possible.
+
+- Most definite, try to remove as many Maybe's as possible in favor of
+ Yes or No.
+
+- Most restrictive, prefer a No over Yes when trying to remove a Maybe.
+
+- Most conversative, do not try to remove a Maybe if we are not truly
+ sure about its value.
+
+The two node properties computes are
+
+* gen(X): Node -> {Yes, No, Maybe}
+
+ Yes: The node X definitely generates a semantic
+ value.
+
+ No: The node X definitely does not generate a
+ semantic value.
+
+ Maybe: The node X passes semantic values, should they
+ be generated by a child of X. We do not know
+ if values are generated or not.
+
+ A derivative function is gen', defined as
+
+ gen'(X,G): Node x {Yes, No, Pass} -> Bool
+ gen'(X,G) = (gen(X) == G)
+
+ Conversely we could define gen in terms of gen' as
+
+ gen (X) = G, iff gen'(X,G)
+
+* acc(X): Node -> Bool
+
+ True: The node X will keep semantic values generated
+ by its children.
+
+ False: The node X will throw any semantic values
+ generated by its children away.
+
+General information
+-------------------
+
+* The specification of 'doc_normalize.txt' applies fully.
+
+Structure
+---------
+
+* The structure of the tree is unchanged.
+
+Attributes
+----------
+
+Name Type Details
+---- ---- -------
+pg::peg::emodes
+ none
+ Root node only. The presence of this attribute
+ indicates that the emode computation has been been
+ executed on the grammar and that we have valid
+ results.
+
+ Transformations whose execution invalidates the emode
+ information have to remove this marker.
+==== ==== =======
+gen enum Expression and definition nodes only. Values are in
+ {yes, no, maybe}. Contains the value of gen(X).
+---- ---- -------
+acc bool Expression and definition nodes only. Contains the
+ value of acc(X).
+---- ---- -------
+
+Transformation
+--------------
+
+It is possible to specify a mode transformation based on the mode
+computation. It would resolve discontinuities in the gen/acc stati
+(Use of expressions generating a value where none is accepted) by
+duplicating relevant nonterminal definitions and forcing them into
+specific modes (discard). If expressions to be duplicated contain
+calls to undefined nonterminal symbols then the new definitions will
+do so as well.
+
+This transformation will not be written for now. The reason for that
+is that it essentially defeats packrat parsing.
+
+The definitions which are duplicated are used in both contexts which
+accept and such which do not accept the generated value, otherwise the
+regular analysis would have mode the definition itself non-accepting
+and non-generating.
+
+While it is possible to put the match status of both the original and
+duplicated definition into the packrat cache under the same label
+there is one important distinction which cannot be avoided: The
+duplicated definition does not generate a semantic value. And we
+cannot exclude the possibilities that either a cached semantic value
+is used in a non-accepting context which is not prepared to handle
+this value (by discarding it), or that an accepting context uses
+cached information which is short of one expected semantic value.
+
+So the two definitions have to cache their information under different
+labels to avoid a mixup. But now it becomes possible that the match
+engine has to fully reparse a segment of input during backtracking
+despite actually having information about matchability, just under a
+different label in the cache. And this then costs us the O(n) of the
+packrat parser, pushing it back exponential time-complexity.
+
+Conclusion: The described transformation can be applied if and only if
+we have ensured that the matcher will never backtrack in the input for
+the grammar in question. In other words, other transformation like
+left-factorisation, eliminiation of left-recursion etc. have to be
+applied first. In even other words, the grammar has to be LL(1) (which
+implies that it will not use any lookahead operators either).
diff --git a/tcllib/modules/page/notes/doc_emodes_alg.txt b/tcllib/modules/page/notes/doc_emodes_alg.txt
new file mode 100644
index 0000000..31b9508
--- /dev/null
+++ b/tcllib/modules/page/notes/doc_emodes_alg.txt
@@ -0,0 +1,171 @@
+PE Grammar Tree, after ExprMode Computation
+===========================================
+
+This file is a companion to the file 'doc_emodes.txt'. The former
+describes the node attributes we wish to have, here we formally
+specify the properties of the attributes, and then derive from that an
+algorithm for their computation.
+
+Per node
+--------
+
+First we specify the properties of the attributes on a case by case
+basis, for each possible type of node. This may invole a lot of
+repetition, but this detail is necessary to be able to the patterns in
+the definition which then allow us to simplify things.
+
+Legend
+~~~~~~
+ X Current node.
+ parent(X) Parent node of X.
+ users(X) n-Nodes invoking the definition.
+ def(X) Definition node invoked by X.
+ children(X) Set of all children of X.
+ child(X) Child of X (if X has only a single child)
+ |S| Cardinality of the set S.
+ AllYes(X) gen'(Y,yes), for all Y in children(X).
+ AllNo(X) gen'(Y,no), for all Y in children(X).
+ SomeYes(X) gen'(Y,yes), exists Y in children(X).
+ SomeNo(X) gen'(Y,no), exists Y in children(X).
+ Mode(X) Nonterminal mode provided by the input.
+ Discard(X) Mode(X) == discard
+ Value(X) Mode(X) == value
+ Data(X) Mode(X) in {match, leaf}
+
+
+Node type acc(X) gen(X)
+~~~~~~~~~ ~~~~~~ ~~~~~~
+DEF FALSE, !Value(X) || yes, Data(X) || (Value(X) && AllYes(X))
+ !acc(child(X)) || no, Discard(X) || (Value(X) && AllNo(X))
+ USER || maybe, Value(X) && !AllYes(X) && !AllNo(X)
+ gen(X,no)
+ TRUE, else
+
+ USER = (|Users(X)| == 1) &&
+ !acc(Users(X))
+~~~~~~~~~ ~~~~~~ ~~~~~~
+!, & FALSE no
+~~~~~~~~~ ~~~~~~ ~~~~~~
+?, * acc(parent(X)) no, AllNo(X) [2]
+ maybe, else
+~~~~~~~~~ ~~~~~~ ~~~~~~
++ acc(parent(X)) yes, AllYes(X)
+ no, AllNo(X)
+ maybe, else
+~~~~~~~~~ ~~~~~~ ~~~~~~
+x acc(parent(X)) yes, SomeYes(X) [3]
+ no, AllNo(X)
+ maybe, else
+~~~~~~~~~ ~~~~~~ ~~~~~~
+/ acc(parent(X)) yes, AllYes(X) [3]
+ no, AllNo(X)
+ maybe, else
+~~~~~~~~~ ~~~~~~ ~~~~~~
+t, epsilon, acc(parent(X)) [1] yes, acc(parent(X))
+dot, alnum, no, !acc(parent(X))
+alpha
+~~~~~~~~~ ~~~~~~ ~~~~~~
+n acc(parent(X)) yes, acc(X) && gen'(def(X),yes)
+ no, !acc(X) || gen'(def(X),no)
+ maybe, acc(X) && gen'(def(X),maybe)
+~~~~~~~~~ ~~~~~~ ~~~~~~
+
+From this specification we can draw the following conclusions about
+the properties and their calculation:
+
+- Acceptance data is defined top-down, from root to the leaves.
+
+- Generation data is defined bottom-up, from leaves to the root.
+
+- In the leaves Acceptance data is converted into Generation data.
+ Nonterminal calls additional hook in the Generation data of the
+ called symbols.
+
+- In the definition Generation data can convert into Acceptance data,
+ and Nonterminal uses hook in the Generation data from the calling
+ nodes, and may hook in Acceptance data as well.
+
+The important places are the two sides of boundaries, i.e. the
+definition nodes, and the n-Nodes calling on definitions. Only there
+the property values may need resolution of conflicts. Anywhere else
+the values are derived in simple equations, allowing their computation
+in trivial sweeps.
+
+
+Algorithm
+~~~~~~~~~
+
+1. Initialization.
+
+ acc(X), gen(X) for all DEFs, without consideration for
+ children and users (use maybe for unknown parts).
+
+2. Sweep
+
+ For all definitions
+
+ a. Sweep top-down.
+ acc(X) for all nodes.
+
+ b. Sweep bottom-up
+ gen(X) for all nodes.
+
+3. Resolution.
+
+ Recompute acc(X), gen(X) for all DEFs, using the full
+ equations. Remember which nodes changed.
+
+4. Repeat from 2 using the remembered set of DEFs, if not
+ empty. Stop if the set of changed DEFs is empty.
+
+Algorithm 2
+~~~~~~~~~~~
+
+1. Initialization.
+
+ acc(X), gen(X) for all DEFs, without consideration for
+ children and users (use maybe for unknown parts).
+
+2. Sweep
+
+ For all definitions
+
+ Sweep top-down.
+ acc(X), gen(X) for all nodes
+
+ The gen(X) is possible because an initial value is
+ directly computable from acc(X), without having to
+ look at the children at all.
+
+ !acc(X) => gen(X,No).
+ acc(X) => gen(X,Maybe)
+
+ Even better. If !acc(X) we can count the type of
+ calls for invoked nonterminals, and if that is the
+ number of users we can immediately change their
+ acc(X) and sweep down further (similar to reachable).
+
+ We remember the interesting places where things can change.
+ The leaf nodes, and lookahead operators.
+
+3. Sweep the 2nd, working up from each interesting place (sorted
+ by depth, deepest first) up through the ancestors, and when
+ reaching def-Nodes we can now sweep up further into the users.
+
+ If this changes acc(X) for a definition (only down to discard)
+ we remember, and after completion go back to 2.
+
+_____________________________________________________
+[1] Actually the value is not really relevant as there are no childen
+ to consider. However with the chosen definition the number of
+ special cases to consider is reduced. I.e. the definition of the
+ function is more uniform.
+
+[2] The *- and ?-operators match even if the expression underneath them
+ does not. In which case there will be no SV. So the best we can
+ say even if the expression surely does generates an SV is maybe.
+
+[3] The x- and /-operators can be made more accurate if we have data
+ about static match results, as this information can cut down the
+ set of children to actually consider for matching and generation
+ of values.
diff --git a/tcllib/modules/page/notes/doc_grammar.txt b/tcllib/modules/page/notes/doc_grammar.txt
new file mode 100644
index 0000000..9c02b3b
--- /dev/null
+++ b/tcllib/modules/page/notes/doc_grammar.txt
@@ -0,0 +1,68 @@
+Raw PE Grammar AS Tree
+======================
+
+This file documents the tree generated by the frontend for reading a
+PE grammar in textual form.
+
+General information
+-------------------
+
+* The tree is implemented using 'struct::tree'.
+* It is an abstract syntax tree semantically.
+
+Structure
+---------
+
+* The root node has one child, of type ALL (*), we call this ALL.
+
+* The structure of the tree under the node ALL reflects the structure
+ of the PE grammar used by the frontend to read grammar.
+
+ - Void nonterminals are leafs of the tree.
+
+ - Match nonterminals have one child node carrying the matched
+ terminal string.
+
+ - All other nonterminals have children per the structure of the rule
+ matched and the nonterminals therein.
+
+~~
+(*) <=> ((type == nonterminal) && (text == ALL))
+
+Attributes
+----------
+
+The node root is exceptional, it has no attributes. The "set of all
+nodes" referenced in the descriptions below does not include it.
+
+Name Type Details
+---- ---- -------
+type enum At all nodes. Values in {terminal, nonterminal}. The
+ type of the node, telling us if it is a container for
+ a nonterminal symbol or for a terminal string.
+---- ---- -------
+detail string At all nodes. Meaning of its value is dependent on the
+ value of the attribute 'type'.
+
+ nonterminal : Name of symbol
+
+ terminal : Terminal data.
+
+ This is always the lexeme, as found in
+ the input. For character data from
+ strings this means that the text
+ contains the special forms as well,
+ i.e. quoted with backslashes.
+==== ==== =======
+at int Restricted to nodes of type 'terminal'. Represents the
+atcol int location in the input where the terminal data starts
+atline int (= the location of the first character), as offset,
+ and in line/column notation (*)
+---- ---- -------
+to int As above, but representing the end location.
+tocol int
+toline int
+---- ---- -------
+
+~~
+(*) Lines are counted from 1. Columns are counted from 0.
diff --git a/tcllib/modules/page/notes/doc_normalize.txt b/tcllib/modules/page/notes/doc_normalize.txt
new file mode 100644
index 0000000..b64ad04
--- /dev/null
+++ b/tcllib/modules/page/notes/doc_normalize.txt
@@ -0,0 +1,138 @@
+Normalized PE Grammar Tree
+==========================
+
+This file documents the tree generated by the transformational package
+'pg::peg::normalize'. The input to the transformation is assumed to be
+a 'Raw PE Grammar AS Tree', as generated by the PEG frontend, and
+described in 'doc_grammar.txt'.
+
+General information
+-------------------
+
+* The tree is implemented using 'struct::tree'.
+
+* The tree is used as a higher data structures keeping the various
+ parts of a grammar together, which are: Start parsing expression,
+ definitions, and their parsing expressions. The tree nature of the
+ parsing expressions map especially nicely to this data structure.
+
+Structure
+---------
+
+* The root node represents the overall grammar. It has one child node
+ for the start expression, and one child per definition of a
+ nonterminal symbol in the grammar. No other nodes are possible. The
+ order of the children is not specified and an implementation
+ detail. Attributes in the root provide quick access, and the nodes
+ can also be distinguished by the attributes they have and/or their
+ values.
+
+* A definition node represents a single nonterminal definition from
+ the grammar. Most of the information describing the definition is
+ stored in attributes of the node. Sole exception is the parsing
+ expression associated with the defined nonterminal symbol. This is
+ represented by an expression subtree, the root of which is the
+ single child of the definition node.
+
+* All other nodes represent a parsing expression with the operator
+ stored in the node and its arguments represented by the children of
+ the node. For operators allowing more than one argument the children
+ will be in the same order as specified in the grammar. I.e. the
+ first child represents the first argument to the operator, and so
+ on.
+
+Attributes
+----------
+
+Name Type Details
+---- ---- -------
+name string Root only. The name of the grammar represented by the
+ tree.
+---- ---- -------
+start noderef Root only. Id of the tree node which is the root of
+ the start expression. A child of the root node. Does
+ not intersect with the set of definition nodes. Can be
+ empty, representing a grammar without start expression.
+---- ---- -------
+definitions Root only. Maps the names (strings) of nonterminal
+ dict symbols to the ids of the tree nodes (noderef) which
+ represents the definition of that symbol. The nodes
+ are all immediate children of the root node. None of
+ them can be the root of the start expression
+ however. The dictionary can be empty, representing a
+ grammar which has no nonterminal symbols.
+---- ---- -------
+undefined Root only. Maps the name (string) of a nonterminal
+ dict symbol which has no definition in the grammar to a
+ list containting the ids of the tree nodes (noderef)
+ which use the symbol despite that. I.e. if this value
+ is not empty the grammar is invalid and has 'holes'.
+==== ==== =======
+symbol string Root and definition nodes only. The name of the
+ nonterminal symbol whose definition the node is
+ representing. For root this is '<StartExpression>'.
+ It is defined for root so that some algorithms on
+ expressions can use it as a sentinel.
+---- ---- -------
+label string Definition nodes only. The name of the input grammar
+ level nonterminal symbol represented by the node. This
+ is normally identical to 'symbol', but can differ for
+ helper definitions introduced by transformations. For
+ such 'symbol' will refer to the generated name of the
+ symbol, and 'label' to the name of the symbol in the
+ grammar the helper belongs to.
+---- ---- -------
+mode enum Definition nodes only. Values in {value, discard,
+ leaf, match}. Specifies how the defined nonterminal
+ handles the generation of its semantic value during
+ matching.
+---- ---- -------
+users list Definition nodes only. A list containing the ids of
+ the tree nodes which reference this definition. These
+ nodes are always expression nodes, with operator
+ 'n'. The list can be empty, representing a nonterminal
+ symbol which is defined, but not used anywhere in
+ grammar.
+==== ==== =======
+op enum All expression nodes. Values in {n, t, .., epsilon,
+ alpha, alnum, x, /, ?, *, +, !, &}. Specifies the
+ operator part of the expression represented by the
+ node.
+---- ---- -------
+char char Expression nodes with operator 't' (t-Nodes)
+ only. Value is the single character from the grammar
+ to match, as represented by Tcl. I.e. any quoting from
+ the input has been resolved.
+---- ---- -------
+begin char ..-Nodes only. Values are like 'char' above, the first
+end char and last character in the range to match.
+---- ---- -------
+sym string n-Nodes only. The name of the nonterminal symbol to
+ match.
+---- ---- -------
+def noderef n-Nodes only. The id of the definition node for the
+ nonterminal symbol to match. Can be empty. In that
+ case the node repesents a try to match an undefined
+ nonterminal symbol. The value of 'sym' will be a key
+ in the dictionary of root->undefined, and the id of
+ this node an element in the list associated with that
+ key.
+==== ==== =======
+at*, to* See 'doc_grammar.txt' for the general definition.
+
+ All nodes except root.
+
+ Definition nodes: The span of input covered by the
+ definition.
+
+ Expression nodes: The span of input covered by the
+ expression.
+
+ The nodes for the operators
+
+ dot, alpha, alnum, epsilon
+
+ have no location information right now. Nodes based
+ on them may have only partial or no information as
+ well.
+---- ---- -------
diff --git a/tcllib/modules/page/notes/doc_reachable.txt b/tcllib/modules/page/notes/doc_reachable.txt
new file mode 100644
index 0000000..f6e3b10
--- /dev/null
+++ b/tcllib/modules/page/notes/doc_reachable.txt
@@ -0,0 +1,71 @@
+PE Grammar Tree, after Reachables Computation
+=============================================
+
+This file documents the augmentations to a Normalized PE Grammar Tree
+as inserted by the transformational package 'pg::peg::reachable'. The
+input to the transformation is assumed to be a 'Normalized PE Grammar
+Tree' as described in 'doc_normalize.txt', possibly with augmentations
+from other transformation, as long as they are not in conflict with
+the augmentations specified here.
+
+General information
+-------------------
+
+* The specification of 'doc_normalize.txt' applies fully.
+
+Structure
+---------
+
+* The structure of the tree is unchanged.
+
+Attributes
+----------
+
+Name Type Details
+---- ---- -------
+pg::peg::reachable
+ list
+ Root node only. The presence of this attribute
+ indicates that the reachable computation has been been
+ executed on the grammar and that we have valid
+ results.
+
+ Contains a list of the nodes (definition, and
+ expression) which are reachable from the root node of
+ the start expression.
+---- ---- -------
+pg::peg::unreachable
+ list
+ Root node only. Contains a list of the nodes
+ (definition, and expression) which are __not__
+ reachable from the root node of the start expression.
+---- ---- -------
+
+Reachability is defined on the definition and expression nodes via
+
+- The root node of the start expression is reachable.
+- An expression node is reachable if its parent node (expression or
+ definition) is reachable.
+- A definition node is reachable, if at least one its using expression
+ nodes is reachable.
+- No other node is reachable.
+
+This definition leads to a simple recursive (top-down) algorithm for
+sweeping a grammar and marking all reachable nodes. We do however
+remember only the reachbility of definitions, as that is the only
+information truly relevant.
+
+Transformation
+--------------
+
+The reachable transformation is based on the reachable computation and
+the agumented tree generated by it. The transformation removes all
+definitions which are not reachable. This may leave the grammar
+without definitions.
+
+Note that this change may remove invokations of undefined nonterminal
+symbols. It however cannot produce new invokations of undefined
+nonterminal symbols as the removed definitions have no actual users by
+definition. Those which have invoking nodes (as recorded in 'users')
+are used by an unreachable definition (This can be an unreachable
+circle of definitions).
diff --git a/tcllib/modules/page/notes/doc_realizable.txt b/tcllib/modules/page/notes/doc_realizable.txt
new file mode 100644
index 0000000..6652d90
--- /dev/null
+++ b/tcllib/modules/page/notes/doc_realizable.txt
@@ -0,0 +1,101 @@
+PE Grammar Tree, after Realizability Computation
+================================================
+
+This file documents the augmentations to a Normalized PE Grammar Tree
+as inserted by the transformational package
+'page::analysis::peg::realizable'. The input to the transformation is
+assumed to be a 'Normalized PE Grammar Tree' as described in
+'doc_normalize.txt', possibly with augmentations from other
+transformations, as long as they are not in conflict with the
+augmentations specified here.
+
+Background
+----------
+
+The realizability of a nonterminal is usually defined for Context Free
+Grammars. For PE grammars we define the property by treating them as
+CFG and then following the usual definition, given below:
+
+ A nonterminal symbol N of a CF grammar G is useful, if and
+ only if a terminal sentence can be derived from it in a finite
+ number of steps. A terminal sentence is a sentence which is
+ either empty or contains only terminal symbols.
+
+This intrinsic specification is equivalent to the following explicit
+rules for the computation of realizability of arbitrary parsing
+expressions:
+
+* A char expression (t) is realizable.
+* A range expression (..) is realizable.
+* A special expression (alnum, alpha) is realizable.
+* A dot expression (.) is realizable.
+* An epsilon expression (epsilon) is realizable.
+* A sequence expression (x) is realizable if and only if all of its
+ argument expressions are realizable.
+* A choice-expression (/) is realizable if and only if at least one
+ of its argument expressions is realizable [1].
+* A Kleene closure (*) is realizable.
+* A positive Kleene closure (+) is realizable, if and only if its
+ argument expression is realizable.
+* An optional expression (?) is realizable.
+* A nonterminal expression is realizable if and only if the invoked
+ nonterminal definition is realizable.
+* A nonterminal definition is realizable if and only if its
+ definining expression is realizable.
+* All other expressions are not realizable.
+
+From the rules above it is clear that the property is defined by the
+leaves of the expression trees and then flows upward towards the
+roots, and at the roots it jumps over the gap from nonterminal
+definition to nonterminal use for further propagation.
+
+This leads to an iterative algorithm which starts with the initial set
+of realizable nodes and then works its way to find all of their parents
+which are also realizable.
+
+[1] It is here where we treat the PEG like a CFG. The ordered choice
+is implicitly handled like an unordered choice.
+
+
+General information
+-------------------
+
+* The specification of 'doc_normalize.txt' applies fully.
+
+Structure
+---------
+
+* The structure of the tree is unchanged.
+
+Attributes
+----------
+
+Name Type Details
+---- ---- -------
+pg::peg::realizable Root node only. The presence of this attribute
+ list indicates that the realizability computation has been
+ been executed on the grammar and that we have valid
+ results.
+
+ Contains a list of the nodes which are realizable.
+---- ---- -------
+pg::peg::unrealizable
+ list
+ Root node only. Contains a list of the nodes which are
+ __not__ realizable.
+---- ---- -------
+
+Transformation
+--------------
+
+The realizability transformation is based on the realizability computation
+and the agumented tree generated by it. The transformation removes all
+(partial) expressions and definitions are not realizable. This may leave
+the grammar without definitions, and without a start expression as
+well.
+
+Note that this change may remove invokations of undefined nonterminal
+symbols. It however cannot produce new invokations of undefined
+nonterminal symbols as a unrealizable definition implies a
+unrealizable invokation, i.e. the invokations of unrealizable
+definitions are removed themselves as well.
diff --git a/tcllib/modules/page/page_intro.man b/tcllib/modules/page/page_intro.man
new file mode 100644
index 0000000..66f211a
--- /dev/null
+++ b/tcllib/modules/page/page_intro.man
@@ -0,0 +1,35 @@
+[comment {-*- tcl -*- doctools manpage}]
+[manpage_begin page_intro n 1.0]
+[keywords page]
+[keywords {parser generator}]
+[keywords {text processing}]
+[copyright {2007 Andreas Kupries <andreas_kupries@users.sourceforge.net>}]
+[moddesc {Parser generator tools}]
+[titledesc {page introduction}]
+[category {Page Parser Generator}]
+[description]
+[para]
+
+[term page] (short for [emph {parser generator}]) stands for a set of
+related packages which help in the construction of parser generators,
+and other utilities doing text processing.
+
+[para]
+
+They are mainly geared towards supporting the Tcllib application
+[syscmd page], with the package [package page::pluginmgr] in a central
+role as the plugin management for the application. The other packages
+are performing low-level text processing and utility tasks geared
+towards parser generation and mainly accessed by [syscmd page] through
+plugins.
+
+[para]
+
+The packages implementing the plugins are not documented as regular
+packages, as they cannot be loaded into a general interpreter, like
+tclsh, without extensive preparation of the interpreter. Preparation
+which is done for them by the plugin manager.
+
+[vset CATEGORY page]
+[include ../doctools2base/include/feedback.inc]
+[manpage_end]
diff --git a/tcllib/modules/page/page_pluginmgr.man b/tcllib/modules/page/page_pluginmgr.man
new file mode 100644
index 0000000..c0e67d7
--- /dev/null
+++ b/tcllib/modules/page/page_pluginmgr.man
@@ -0,0 +1,800 @@
+[comment {-*- tcl -*- doctools manpage}]
+[manpage_begin page_pluginmgr n 1.0]
+[keywords page]
+[keywords {parser generator}]
+[keywords {text processing}]
+[copyright {2007 Andreas Kupries <andreas_kupries@users.sourceforge.net>}]
+[moddesc {Parser generator tools}]
+[titledesc {page plugin manager}]
+[category {Page Parser Generator}]
+[require page::pluginmgr [opt 0.2]]
+[require fileutil]
+[description]
+[para]
+
+This package provides the plugin manager central to the [syscmd page]
+application. It manages the various reader, writer, configuration, and
+transformation plugins which actually process the text (read,
+transform, and write).
+
+[para]
+
+All plugins are loaded into slave interpreters specially prepared for
+them. While implemented using packages they need this special
+environment and are not usable in a plain interpreter, like
+tclsh. Because of that they are only described in general terms in
+section [sectref {PREDEFINED PLUGINS}], and not documented as regular
+packages. It is expected that they follow the APIs specified in the
+sections
+
+[list_begin enum]
+[enum] [sectref {CONFIG PLUGIN API}]
+[enum] [sectref {READER PLUGIN API}]
+[enum] [sectref {WRITER PLUGIN API}]
+[enum] [sectref {TRANSFORM PLUGIN API}]
+[list_end]
+
+as per their type.
+
+[section API]
+
+[list_begin definitions]
+
+[call [cmd ::page::pluginmgr::reportvia] [arg cmd]]
+
+This command defines the callback command used by
+
+[cmd ::page::pluginmgr::report] (see below) to report input errors and
+warnings. The default is to write such reports to the standard error
+channel.
+
+[call [cmd ::page::pluginmgr::report] [arg level] [arg text] [opt "[arg from] [opt [arg to]]"]]
+
+This command is used to report input errors and warnings. By default
+such reports are written to the standard error. This can be changed by
+setting a user-specific callback command with
+[cmd ::page::pluginmgr::reportvia] (see above).
+
+[para]
+
+The arguments [arg level] and [arg text] specify both the importance
+of the message, and the message itself. For the former see the package
+[package logger] for the allowed values.
+
+[para]
+
+The optional argument [arg from] and [arg to] can be used by the
+caller to indicate the location (or range) in the input where the
+reported problem occured. Each is a list containing two elements, the
+line and the column in the input, in this order.
+
+[call [cmd ::page::pluginmgr::log] [arg cmd]]
+
+This command defines a log callback command to be used by loaded
+plugins for the reporting of internal errors, warnings, and general
+information. Specifying the empty string as callback disables logging.
+
+[para]
+
+Note: The [arg cmd] has to be created by the [package logger] package,
+or follow the same API as such.
+
+[para]
+
+The command returns the empty string as its result.
+
+[call [cmd ::page::pluginmgr::configuration] [arg name]]
+
+This command loads the named configuration plugin, retrieves the
+options encoded in it, and then immediately unloads it again.
+
+[para]
+
+If the [arg name] is the path to a file, then this files will be tried
+to be loaded as a plugin first, and, if that fails, opened and its
+contents read as a list of options and their arguments, separated by
+spaces, tabs and newlines, possibly quotes with single and double
+quotes.
+
+[para]
+
+See section [sectref {CONFIG PLUGIN API}] for the API expected of
+configuration plugins.
+
+[para]
+
+The result of the command is the list of options retrieved.
+
+[call [cmd ::page::pluginmgr::reader] [arg name]]
+
+This command loads the named reader plugin and initializes it. The
+result of the command is a list of options the plugin understands.
+
+[para]
+
+Only a single reader plugin can be loaded. Loading another reader
+plugin causes the previously loaded reader plugin to be de-initialized
+and unloaded.
+
+[para]
+
+See section [sectref {READER PLUGIN API}] for the API expected of
+reader plugins.
+
+[call [cmd ::page::pluginmgr::rconfigure] [arg dict]]
+
+This commands configures the loaded reader plugin. The options and
+their values are provided as a Tcl dictionary. The result of the
+command is the empty string.
+
+[call [cmd ::page::pluginmgr::rtimeable]]
+
+This commands checks if the loaded reader plugin is able to collect
+timing statistics. The result of the command is a boolean flag. The
+result is [const true] if the plugin can be timed, and [const false]
+otherwise.
+
+[call [cmd ::page::pluginmgr::rtime]]
+
+This command activates the collection of timing statistics in the
+loaded reader plugin.
+
+[call [cmd ::page::pluginmgr::rgettime]]
+
+This command retrieves the collected timing statistics of the loaded
+reader plugin after it was executed.
+
+[call [cmd ::page::pluginmgr::rhelp]]
+
+This command retrieves the help string of the loaded reader
+plugin. This is expected to be in [term doctools] format.
+
+[call [cmd ::page::pluginmgr::rlabel]]
+
+This command retrieves the human-readable name of the loaded reader
+plugin.
+
+[call [cmd ::page::pluginmgr::read] [arg read] [arg eof] [opt [arg complete]]]
+
+This command invokes the loaded reader plugin to process the input,
+and returns the results of the plugin as its own result. The input is
+accessible through the callback commands [arg read], and [arg eof]. The
+optional [arg done] can be used to intrecept when the plugin has
+completed its processing. All arguments are command prefixes.
+
+[para]
+
+The plugin will invoke the various callbacks in the following
+situations:
+
+[list_begin definitions]
+[call [arg read] [arg num]]
+is invoked whenever input to process is needed, with the number of
+characters/bytes it asks for. The result is expected to be the input
+the plugin is in need of.
+
+[call [arg eof]]
+is invoked by the plugin to check if the input has reached the of the
+stream. The result is expected to be a boolean flag, [const true] when
+the input has hit EOF, and [const false] otherwise.
+
+[call [arg done]]
+is invoked when the plugin has completed the processing of the input.
+
+[list_end]
+
+[call [cmd ::page::pluginmgr::writer] [arg name]]
+
+This command loads the named writer plugin and initializes it. The
+result of the command is a list of options the plugin understands.
+
+[para]
+
+Only a single reader plugin can be loaded. Loading another reader
+plugin causes the previously loaded reader plugin to be de-initialized
+and unloaded.
+
+[para]
+
+See section [sectref {WRITER PLUGIN API}] for the API expected of
+writer plugins.
+
+[call [cmd ::page::pluginmgr::wconfigure] [arg dict]]
+
+This commands configures the loaded writer plugin. The options and
+their values are provided as a Tcl dictionary. The result of the
+command is the empty string.
+
+[call [cmd ::page::pluginmgr::wtimeable]]
+
+This commands checks if the loaded writer plugin is able to measure
+execution times. The result of the command is a boolean flag. The
+result is [const true] if the plugin can be timed, and [const false]
+otherwise.
+
+[call [cmd ::page::pluginmgr::wtime]]
+
+This command activates the collection of timing statistics in the
+loaded writer plugin.
+
+[call [cmd ::page::pluginmgr::wgettime]]
+
+This command retrieves the collected timing statistics of the loaded
+writer plugin after it was executed.
+
+[call [cmd ::page::pluginmgr::whelp]]
+
+This command retrieves the help string of the loaded writer
+plugin. This is expected to be in [term doctools] format.
+
+[call [cmd ::page::pluginmgr::wlabel]]
+
+This command retrieves the human-readable name of the loaded writer
+plugin.
+
+[call [cmd ::page::pluginmgr::write] [arg chan] [arg data]]
+
+The loaded writer plugin is invoked to generate the output. It is
+given the [arg data] to generate the outpout from, and the Tcl handle
+[arg chan] of the channel to write the generated output to. The
+command returns th empty string as its result.
+
+[call [cmd ::page::pluginmgr::transform] [arg name]]
+
+This command loads the named transformation plugin and initializes
+it. The result of the command is a 2-element list containing the
+plugin id and a list of options the plugin understands, in this order.
+
+[para]
+
+Multiple transformations plugins can be loaded and are identified by
+handles.
+
+[para]
+
+See section [sectref {TRANSFORM PLUGIN API}] for the API expected of
+transformation plugins.
+
+[call [cmd ::page::pluginmgr::tconfigure] [arg id] [arg dict]]
+
+This commands configures the identified transformation plugin. The
+options and their values are provided as a Tcl dictionary. The result
+of the command is the empty string.
+
+[call [cmd ::page::pluginmgr::ttimeable] [arg id]]
+
+This commands checks if the identified transformation plugin is able
+to collect timing statistics. The result of the command is a boolean
+flag. The result is [const true] if the plugin can be timed, and
+[const false] otherwise.
+
+[call [cmd ::page::pluginmgr::ttime] [arg id]]
+
+This command activates the collection of timing statistics in the
+identified transformation plugin.
+
+[call [cmd ::page::pluginmgr::tgettime] [arg id]]
+
+This command retrieves the collected timing statistics of the
+identified transformation plugin after it was executed.
+
+[call [cmd ::page::pluginmgr::thelp] [arg id]]
+
+This command retrieves the help string of the identified
+transformation plugin. This is expected to be in [term doctools]
+format.
+
+[call [cmd ::page::pluginmgr::tlabel] [arg id]]
+
+This command retrieves the human-readable name of the identified
+transformation plugin.
+
+[call [cmd ::page::pluginmgr::transform_do] [arg id] [arg data]]
+
+The identified transformation plugin is invoked to process the
+specified [arg data]. The result of the plugin is returned as the
+result of the command.
+
+[list_end]
+
+[section {CONFIG PLUGIN API}]
+
+Configuration plugins are expected to provide a single command,
+described below.
+
+[para]
+
+[list_begin definitions]
+[call [cmd page_cdefinition]]
+
+This command of a configuration plugin is called by the plugin manager
+to execute it. Its result has to be a list of options and values to
+process.
+
+[list_end]
+[para]
+
+Configuration plugins do not expect the environment to provide any
+special commands.
+
+[para]
+
+It is expected that a configuration plugin [const FOO] is implemented
+by the package [package page::config::[const FOO]].
+
+[para]
+
+Configuration plugins are loaded, executed, and unloaded in one step,
+they are not kept in memory. The command for doing this is
+[cmd ::page::pluginmgr::configuration].
+
+[section {READER PLUGIN API}]
+
+Reader plugins are expected to provide the following commands,
+described below.
+
+[para]
+
+[list_begin definitions]
+
+[call [cmd page_rfeature] [arg name]]
+
+This command takes a feature [arg name] and returns a boolean flag
+indicating whether the feature is supported by the plugin, or not.
+
+The result has to be [const true] if the feature is supported, and
+[const false] otherwise.
+
+[para]
+
+See section [sectref FEATURES] for the possible features the plugin
+manager will ask for.
+
+[call [cmd page_rtime]]
+
+This command is invoked to activate the collection of timing
+statistics.
+
+[call [cmd page_rgettime]]
+
+This command is invoked to retrieve the collected timing statistics.
+
+[call [cmd page_rlabel]]
+
+This command is invoked to retrieve a human-readable label for the
+plugin.
+
+[call [cmd page_rhelp]]
+
+This command is invoked to retrieve a help text for plugin. The text
+is expected to be in [term doctools] format.
+
+[call [cmd page_roptions]]
+
+This command is invoked to retrieve the options understood by the
+plugin.
+
+[call [cmd page_rconfigure] [arg option] [arg value]]
+
+This command is invoked to reconfigure the plugin, specifically the
+given [arg option] is set to the new [arg value].
+
+[call [cmd page_rrun]]
+
+This command is invoked to process the input stream per the current
+plugin configuration. The result of the command is the result of the
+processing.
+
+[list_end]
+[para]
+
+Reader plugins expect the environment to provide the following special
+commands.
+
+[list_begin definitions]
+
+[call [cmd page_read] [arg num]]
+
+This command is invoked to read [arg num] characters/bytes from the
+input. Its result has to be read characters/bytes.
+
+[call [cmd page_read_done]]
+
+This command is invoked to signal that the plugin has completed the
+processing of the input.
+
+[call [cmd page_eof]]
+
+This command is invoked to check if the input stream has reached its
+end. Its result has to be a boolean flag, [const true] when the input
+has reached the end, [const false] otherwise.
+
+[call [cmd page_info] [arg text] [opt "[arg from] [opt [arg to]]"]]
+
+Invoked to report some information to the user. May indicate a
+location or range in the input. Each piece of location data, if
+provided, is a 2-element list containing line and column numbers.
+
+[call [cmd page_warning] [arg text] [opt "[arg from] [opt [arg to]]"]]
+
+Invoked to report a warning to the user. May indicate a location or
+range in the input. Each piece of location data, if provided, is a
+2-element list containing line and column numbers.
+
+[call [cmd page_error] [arg text] [opt "[arg from] [opt [arg to]]"]]
+
+Invoked to report an error to the user. May indicate a location or
+range in the input. Each piece of location data, if provided, is a
+2-element list containing line and column numbers.
+
+[call [cmd page_log_info] [arg text]]
+
+Invoked to report some internal information.
+
+[call [cmd page_log_warning] [arg text]]
+
+Invoked to report an internal warning.
+
+[call [cmd page_log_error] [arg text]]
+
+Invoked to report an internal error.
+
+[list_end]
+[para]
+
+It is expected that a reader plugin [const FOO] is implemented
+by the package [package page::reader::[const FOO]].
+
+[para]
+
+Reader plugins are loaded by the command
+[cmd ::page::pluginmgr::reader]. At most one reader plugin can be kept
+in memory.
+
+[section {WRITER PLUGIN API}]
+
+Writer plugins are expected to provide the following commands,
+described below.
+
+[para]
+
+[list_begin definitions]
+
+[call [cmd page_wfeature]]
+
+This command takes a feature [arg name] and returns a boolean flag
+indicating whether the feature is supported by the plugin, or not.
+
+The result has to be [const true] if the feature is supported, and
+[const false] otherwise.
+
+[para]
+
+See section [sectref FEATURES] for the possible features the plugin
+manager will ask for.
+
+[call [cmd page_wtime]]
+
+This command is invoked to activate the collection of timing
+statistics.
+
+[call [cmd page_wgettime]]
+
+This command is invoked to retrieve the collected timing statistics.
+
+[call [cmd page_wlabel]]
+
+This command is invoked to retrieve a human-readable label for the
+plugin.
+
+[call [cmd page_whelp]]
+
+This command is invoked to retrieve a help text for plugin. The text
+is expected to be in [term doctools] format.
+
+[call [cmd page_woptions]]
+
+This command is invoked to retrieve the options understood by the
+plugin.
+
+[call [cmd page_wconfigure] [arg option] [arg value]]
+
+This command is invoked to reconfigure the plugin, specifically the
+given [arg option] is set to the new [arg value].
+
+[call [cmd page_wrun] [arg chan] [arg data]]
+
+This command is invoked to process the specified [arg data] and write
+it to the output stream [arg chan]. The latter is a Tcl channel handle
+opened for writing. The result of the command is the empty string.
+
+[list_end]
+[para]
+
+Writer plugins expect the environment to provide the following special
+commands.
+
+[list_begin definitions]
+
+[call [cmd page_info] [arg text] [opt "[arg from] [opt [arg to]]"]]
+
+Invoked to report some information to the user. May indicate a
+location or range in the input. Each piece of location data, if
+provided, is a 2-element list containing line and column numbers.
+
+[call [cmd page_warning] [arg text] [opt "[arg from] [opt [arg to]]"]]
+
+Invoked to report a warning to the user. May indicate a location or
+range in the input. Each piece of location data, if provided, is a
+2-element list containing line and column numbers.
+
+[call [cmd page_error] [arg text] [opt "[arg from] [opt [arg to]]"]]
+
+Invoked to report an error to the user. May indicate a location or
+range in the input. Each piece of location data, if provided, is a
+2-element list containing line and column numbers.
+
+[call [cmd page_log_info] [arg text]]
+
+Invoked to report some internal information.
+
+[call [cmd page_log_warning] [arg text]]
+
+Invoked to report an internal warning.
+
+[call [cmd page_log_error] [arg text]]
+
+Invoked to report an internal error.
+
+[list_end]
+[para]
+
+It is expected that a writer plugin [const FOO] is implemented
+by the package [package page::writer::[const FOO]].
+
+[para]
+
+Writer plugins are loaded by the command
+[cmd ::page::pluginmgr::writer]. At most one writer plugin can be kept
+in memory.
+
+[section {TRANSFORM PLUGIN API}] page::transform::*
+
+Transformation plugins are expected to provide the following commands,
+described below.
+
+[para]
+
+[list_begin definitions]
+
+[call [cmd page_tfeature]]
+
+This command takes a feature [arg name] and returns a boolean flag
+indicating whether the feature is supported by the plugin, or not.
+
+The result has to be [const true] if the feature is supported, and
+[const false] otherwise.
+
+[para]
+
+See section [sectref FEATURES] for the possible features the plugin
+manager will ask for.
+
+[call [cmd page_ttime]]
+
+This command is invoked to activate the collection of timing
+statistics.
+
+[call [cmd page_tgettime]]
+
+This command is invoked to retrieve the collected timing statistics.
+
+[call [cmd page_tlabel]]
+
+This command is invoked to retrieve a human-readable label for the
+plugin.
+
+[call [cmd page_thelp]]
+
+This command is invoked to retrieve a help text for plugin. The text
+is expected to be in [term doctools] format.
+
+[call [cmd page_toptions]]
+
+This command is invoked to retrieve the options understood by the
+plugin.
+
+[call [cmd page_tconfigure] [arg option] [arg value]]
+
+This command is invoked to reconfigure the plugin, specifically the
+given [arg option] is set to the new [arg value].
+
+[call [cmd page_trun] [arg chan] [arg data]]
+
+This command is invoked to process the specified [arg data] and write
+it to the output stream [arg chan]. The latter is a Tcl channel handle
+opened for writing. The result of the command is the empty string.
+
+[list_end]
+[para]
+
+Transformation plugins expect the environment to provide the following
+special commands.
+
+[list_begin definitions]
+
+[call [cmd page_info] [arg text] [opt "[arg from] [opt [arg to]]"]]
+
+Invoked to report some information to the user. May indicate a
+location or range in the input. Each piece of location data, if
+provided, is a 2-element list containing line and column numbers.
+
+[call [cmd page_warning] [arg text] [opt "[arg from] [opt [arg to]]"]]
+
+Invoked to report a warning to the user. May indicate a location or
+range in the input. Each piece of location data, if provided, is a
+2-element list containing line and column numbers.
+
+[call [cmd page_error] [arg text] [opt "[arg from] [opt [arg to]]"]]
+
+Invoked to report an error to the user. May indicate a location or
+range in the input. Each piece of location data, if provided, is a
+2-element list containing line and column numbers.
+
+[call [cmd page_log_info] [arg text]]
+
+Invoked to report some internal information.
+
+[call [cmd page_log_warning] [arg text]]
+
+Invoked to report an internal warning.
+
+[call [cmd page_log_error] [arg text]]
+
+Invoked to report an internal error.
+
+[list_end]
+[para]
+
+It is expected that a transformation plugin [const FOO] is implemented
+by the package [package page::transform::[const FOO]].
+
+[para]
+
+Transformation plugins are loaded by the command
+
+[cmd ::page::pluginmgr::transform]. More than one transformation
+plugin can be kept in memory.
+
+[section {PREDEFINED PLUGINS}]
+
+The following predefined plugins are known, i.e. provided by the page
+module.
+
+[list_begin definitions]
+
+[def Configuration]
+[list_begin definitions]
+[def peg]
+
+Returns a set of options to configure the [syscmd page] application
+for the processing of a PEG grammar and the generation of ME code. See
+the packages [package grammar_peg], [package grammar_me] and relations
+for more details.
+
+[list_end]
+
+[def Reader]
+[list_begin definitions]
+[def hb]
+Expects a so-called [term {half-baked PEG container}] as input and
+returns the equivalent abstract syntax tree. See the writer plugin
+[term hb] for the plugin generating this type of input.
+
+[def lemon]
+Expects a grammar specification as understood by Richar Hipp's LEMON
+parser generator and returns an abstract syntax tree for it.
+
+[def peg]
+Expects a grammar specification in the form of a parsing expression
+grammar (PEG) and returns an abstract syntax tree for it.
+
+[def ser]
+Expect the serialized form of a parsing expression grammar as
+generated by the package [package grammar::peg] as input, converts it
+into an equivalent abstract syntax tree and returns that.
+
+[def treeser]
+Expects the serialized form of a tree as generated by the package
+[package struct::tree] as input and returns it, after validation.
+
+[list_end]
+
+[def Writer]
+[list_begin definitions]
+[def hb]
+Expects an abstract syntax tree for a parsing expression grammar as
+input and writes it out in the form of a so-called
+[term {half-baked PEG container}].
+
+[def identity]
+Takes any input and writes it as is.
+
+[def mecpu]
+Expects symbolic assembler code for the MatchEngine CPU (See the
+package [package grammar::me::cpu] and relatives) and writes it out as
+Tcl code for a parser.
+
+[def me]
+Expects an abstract syntax tree for a parsing expression grammar as
+input and writes it out as Tcl code for the MatchEngine (See the
+package [package grammar::me] and relatives) which parses input in
+that grammar.
+
+[def null]
+Takes any input and writes nothing. The logical equivalent of
+/dev/null.
+
+[def peg]
+Expects an abstract syntax tree for a parsing expression grammar as
+input and writes it out in the form of a canonical PEG which can be
+read by the reader plugin [term peg].
+
+[def ser]
+Expects an abstract syntax tree for a parsing expression grammar as
+input and writes it out as a serialized PEG container which can be
+read by the reader plugin [term ser].
+
+[def tpc]
+Expects an abstract syntax tree for a parsing expression grammar as
+input and writes it out as Tcl code initializing a PEG container as
+provided by the package [package grammar::peg].
+
+[def tree]
+Takes any serialized tree (per package [package struct::tree]) as
+input and writes it out in a generic indented format.
+
+[list_end]
+
+[def Transformation]
+[list_begin definitions]
+
+[def mecpu]
+Takes an abstract syntax tree for a parsing expression grammer as
+input, generates symbolic assembler code for the MatchEngine CPU, and
+returns that as its result (See the package [package grammar::me::cpu]
+and relatives).
+
+[def reachable]
+Takes an abstract syntax tree for a parsing expression grammer as
+input, performs a reachability analysis, and returns the modified and
+annotated tree.
+
+[def realizable]
+Takes an abstract syntax tree for a parsing expression grammer as
+input, performs an analysis of realizability, and returns the modified
+and annotated tree.
+
+[list_end]
+[list_end]
+
+[comment {
+ Make it clear that all data between plugins is shuffled around
+ in serialized form, as objects cannot be transfered/accessed
+ across the interpreter boundaries (safety concerns).
+
+ Describe the commands expected by plugins to be available in
+ the environment.
+
+ Describe the predefined features.
+}]
+
+[section FEATURES]
+
+The plugin manager currently checks the plugins for only one feature,
+[const timeable]. A plugin supporting this feature is assumed to be
+able to collect timing statistics on request.
+
+[vset CATEGORY page]
+[include ../doctools2base/include/feedback.inc]
+[manpage_end]
diff --git a/tcllib/modules/page/page_util_flow.man b/tcllib/modules/page/page_util_flow.man
new file mode 100644
index 0000000..d6535cb
--- /dev/null
+++ b/tcllib/modules/page/page_util_flow.man
@@ -0,0 +1,96 @@
+[comment {-*- tcl -*- doctools manpage}]
+[manpage_begin page_util_flow n 1.0]
+[keywords dataflow]
+[keywords {graph walking}]
+[keywords page]
+[keywords {parser generator}]
+[keywords {text processing}]
+[keywords {tree walking}]
+[copyright {2007 Andreas Kupries <andreas_kupries@users.sourceforge.net>}]
+[moddesc {Parser generator tools}]
+[titledesc {page dataflow/treewalker utility}]
+[category {Page Parser Generator}]
+[require page::util::flow [opt 0.1]]
+[require snit]
+[description]
+[para]
+
+This package provides a single utility command for easy dataflow based
+manipulation of arbitrary data structures, especially abstract syntax
+trees.
+
+[section API]
+
+[list_begin definitions]
+[call [cmd ::page::util::flow] [arg start] [arg flowvar] [arg nodevar] [arg script]]
+
+This command contains the core logic to drive the walking of an
+arbitrary data structure which can partitioned into separate
+parts. Examples of such structures are trees and graphs.
+
+[para]
+
+The command makes no assumptions at all about the API of the structure
+to be walked, except that that its parts, here called [term nodes],
+are identified by strings. These strings are taken as is, from the
+arguments, and the body, and handed back to the body, without
+modification.
+
+[para]
+
+Access to the actual data structure, and all decisions regarding which
+nodes to visit in what order are delegated to the body of the loop,
+i.e. the [arg script].
+
+[para]
+
+The body is invoked first for the nodes in the start-set specified via
+[arg start]), and from then on for the nodes the body has requested to
+be visited. The command stops when the set of nodes to visit becomes
+empty. Note that a node can be visited more than once. The body has
+complete control about this.
+
+[para]
+
+The body is invoked in the context of the caller. The variable named
+by [arg nodevar] will be set to the current node, and the variable
+named by [arg flowvar] will be set to the command of the flow object
+through which the body can request the nodes to visit next. The API
+provided by this object is described in the next section,
+[sectref {FLOW API}].
+
+[para]
+
+Note that the command makes no promises regarding the order in which
+nodes are visited, excpt that the nodes requested to be visited by the
+current iteration will be visited afterward, in some order.
+
+[list_end]
+
+[section {FLOW API}]
+
+This section describes the API provided by the flow object made
+accessible to the body script of [cmd ::page::util::flow].
+
+[list_begin definitions]
+
+[call [arg flow] [method visit] [arg node]]
+
+Invoking this method requests that the node [arg n] is visited after
+the current iteration.
+
+[call [arg flow] [method visitl] [arg nodelist]]
+
+Invoking this method requests that all the nodes found in the list
+[arg nodelist] are visited after the current iteration.
+
+[call [arg flow] [method visita] [arg node]...]
+
+This is the variadic arguments form of the method [method visitl], see
+above.
+
+[list_end]
+
+[vset CATEGORY page]
+[include ../doctools2base/include/feedback.inc]
+[manpage_end]
diff --git a/tcllib/modules/page/page_util_norm_lemon.man b/tcllib/modules/page/page_util_norm_lemon.man
new file mode 100644
index 0000000..5859575
--- /dev/null
+++ b/tcllib/modules/page/page_util_norm_lemon.man
@@ -0,0 +1,51 @@
+[comment {-*- tcl -*- doctools manpage}]
+[manpage_begin page_util_norm_lemon n 1.0]
+[keywords {graph walking}]
+[keywords lemon]
+[keywords normalization]
+[keywords page]
+[keywords {parser generator}]
+[keywords {text processing}]
+[keywords {tree walking}]
+[copyright {2007 Andreas Kupries <andreas_kupries@users.sourceforge.net>}]
+[moddesc {Parser generator tools}]
+[titledesc {page AST normalization, LEMON}]
+[category {Page Parser Generator}]
+[require page::util::norm_lemon [opt 0.1]]
+[require snit]
+[description]
+[para]
+
+This package provides a single utility command which takes an AST for a
+lemon grammar and normalizes it in various ways. The result
+is called a [term {Normalized Lemon Grammar Tree}].
+
+[para]
+
+[emph Note] that this package can only be used from within a plugin
+managed by the package [package page::pluginmgr].
+
+[comment {
+ TODO: Document the structure of a LEMON AST,
+ and then of a Normalized LEMON Tree. Which
+ is not a true AST any longer.
+}]
+
+[section API]
+
+[list_begin definitions]
+[call [cmd ::page::util::norm::lemon] [arg tree]]
+
+This command assumes the [arg tree] object contains for a lemon
+grammar. It normalizes this tree in place. The result is called a
+[term {Normalized Lemon Grammar Tree}].
+
+[para]
+
+The exact operations performed are left undocumented for the moment.
+
+[list_end]
+
+[vset CATEGORY page]
+[include ../doctools2base/include/feedback.inc]
+[manpage_end]
diff --git a/tcllib/modules/page/page_util_norm_peg.man b/tcllib/modules/page/page_util_norm_peg.man
new file mode 100644
index 0000000..d5e98c3
--- /dev/null
+++ b/tcllib/modules/page/page_util_norm_peg.man
@@ -0,0 +1,105 @@
+[comment {-*- tcl -*- doctools manpage}]
+[manpage_begin page_util_norm_peg n 1.0]
+[keywords {graph walking}]
+[keywords normalization]
+[keywords page]
+[keywords {parser generator}]
+[keywords PEG]
+[keywords {text processing}]
+[keywords {tree walking}]
+[copyright {2007 Andreas Kupries <andreas_kupries@users.sourceforge.net>}]
+[moddesc {Parser generator tools}]
+[titledesc {page AST normalization, PEG}]
+[category {Page Parser Generator}]
+[require page::util::norm_peg [opt 0.1]]
+[require snit]
+[description]
+[para]
+
+This package provides a single utility command which takes an AST for a
+parsing expression grammar and normalizes it in various ways. The result
+is called a [term {Normalized PE Grammar Tree}].
+
+[para]
+
+[emph Note] that this package can only be used from within a plugin
+managed by the package [package page::pluginmgr].
+
+[comment {
+ TODO: Document the structure of a PEG AST,
+ and then of a Normalized PEG Tree. Which
+ is not a true AST any longer.
+}]
+
+[section API]
+
+[list_begin definitions]
+[call [cmd ::page::util::norm::peg] [arg tree]]
+
+This command assumes the [arg tree] object contains for a
+parsing expression grammar. It normalizes this tree in place.
+The result is called a [term {Normalized PE Grammar Tree}].
+
+[para]
+
+The following operations are performd
+
+[list_begin enum]
+[enum]
+The data for all terminals is stored in their grandparental
+nodes. The terminal nodes and their parents are removed. Type
+information is dropped.
+
+[enum]
+All nodes which have exactly one child are irrelevant and are
+removed, with the exception of the root node. The immediate
+child of the root is irrelevant as well, and removed as well.
+
+[enum]
+The name of the grammar is moved from the tree node it is stored
+in to an attribute of the root node, and the tree node removed.
+[para]
+The node keeping the start expression separate is removed as
+irrelevant and the root node of the start expression tagged with
+a marker attribute, and its handle saved in an attribute of the
+root node for quick access.
+
+[enum]
+Nonterminal hint information is moved from nodes into attributes,
+and the now irrelevant nodes are deleted.
+[para]
+[emph Note:] This transformation is dependent on the removal of all
+nodes with exactly one child, as it removes the all 'Attribute'
+nodes already. Otherwise this transformation would have to put
+the information into the grandparental node.
+[para]
+The default mode given to the nonterminals is [const value].
+[para]
+Like with the global metadata definition specific information
+is moved out out of nodes into attributes, the now irrelevant
+nodes are deleted, and the root nodes of all definitions are
+tagged with marker attributes. This provides us with a mapping
+from nonterminal names to their defining nodes as well, which
+is saved in an attribute of the root node for quick reference.
+[para]
+At last the range in the input covered by a definition is
+computed. The left extent comes from the terminal for the
+nonterminal symbol it defines. The right extent comes from
+the rightmost child under the definition. While this not an
+expression tree yet the location data is sound already.
+
+[enum]
+The remaining nodes under all definitions are transformed
+into proper expression trees. First character ranges, followed
+by unary operations, characters, and nonterminals. At last the
+tree is flattened by the removal of superfluous inner nodes.
+[para]
+The order matters, to shed as much nodes as possible early, and
+to avoid unnecessary work later.
+
+[list_end]
+[list_end]
+
+[vset CATEGORY page]
+[include ../doctools2base/include/feedback.inc]
+[manpage_end]
diff --git a/tcllib/modules/page/page_util_peg.man b/tcllib/modules/page/page_util_peg.man
new file mode 100644
index 0000000..5e75be5
--- /dev/null
+++ b/tcllib/modules/page/page_util_peg.man
@@ -0,0 +1,108 @@
+[comment {-*- tcl -*- doctools manpage}]
+[manpage_begin page_util_peg n 1.0]
+[keywords page]
+[keywords {parser generator}]
+[keywords {parsing expression grammar}]
+[keywords PEG]
+[keywords {text processing}]
+[keywords transformation]
+[copyright {2007 Andreas Kupries <andreas_kupries@users.sourceforge.net>}]
+[moddesc {Parser generator tools}]
+[titledesc {page PEG transformation utilities}]
+[category {Page Parser Generator}]
+[require page::util::peg [opt 0.1]]
+[require snit]
+[description]
+[para]
+
+This package provides a few common operations to PEG transformations.
+They assume a [term {Normalized PE Grammar Tree}] as input, see the
+package [package page::util::norm::peg], possibly augmented with
+attributes coming from transformations not in conflict with the base
+definition.
+
+[para]
+
+[section API]
+
+[list_begin definitions]
+[call [cmd ::page::util::peg::symbolNodeOf] [arg tree] [arg node]]
+
+Given an arbitrary expression [arg node] in the AST [arg tree] it
+determines the node (itself or an ancestor) containing the name of the
+nonterminal symbol the node belongs to, and returns its id. The result
+is either the root of the tree (for the start expression), or a
+definition node.
+
+[call [cmd ::page::util::peg::symbolOf] [arg tree] [arg node]]
+
+As [cmd ::page::util::peg::symbolNodeOf], but returns the symbol name
+instead of the node.
+
+[call [cmd ::page::util::peg::updateUndefinedDueRemoval] [arg tree]]
+
+The removal of nodes in the AST [arg tree] can cause symbols to lose
+one or more users.
+
+[example {
+ A used by B and C,
+ B is reachable,
+ C is not,
+
+ so A now loses the node in the expression for C calling it,
+ or rather, not calling it anymore.
+}]
+
+This command updates the cross-references and which nonterminals are
+now undefined.
+
+[call [cmd ::page::util::peg::flatten] [arg treequery] [arg tree]]
+
+This commands flattens nested sequence and choice operators in the AST
+[arg tree], re-using the [package treeql] object [arg treequery] to
+run the query determining which nodes to cut.
+
+[call [cmd ::page::util::peg::getWarnings] [arg tree]]
+
+This command looks at the attributes of the AST [arg tree] for
+problems with the grammar and issues warnings. They do not prevent us
+from writing the grammar, but still represent problems with it the
+user should be made aware of.
+
+[para]
+
+The result of the command is a dictionary mapping nonterminal names to
+their associated warnings.
+
+[call [cmd ::page::util::peg::printWarnings] [arg msg]]
+
+The argument of the command is a dictionary mapping nonterminal names
+to their associated warnings, as generated by, for example, the
+command [cmd ::page::util::peg::getWarnings].
+
+[para]
+
+The warnings contained therein are formatted and then printed via the
+log command [cmd page_info]. This means that this command can be used
+only from within a plugin managed by the package
+[package page::pluginmgr].
+
+[call [cmd ::page::util::peg::peOf] [arg tree] [arg eroot]]
+
+This command converts the parsing expression starting at the node
+[arg eroot] in the AST [arg tree] into a nested list. The exact syntax
+of this list specified by the package [package grammar::peg].
+
+[call [cmd ::page::util::peg::printTclExpr] [arg pe]]
+
+This command converts the parsing expression contained in the nested
+list [arg pe] into a Tcl string which can be placed into a Tcl script.
+
+See the package [package grammar::peg] for the exact syntax of
+[arg pe].
+
+[list_end]
+
+[vset CATEGORY page]
+[include ../doctools2base/include/feedback.inc]
+[manpage_end]
diff --git a/tcllib/modules/page/page_util_quote.man b/tcllib/modules/page/page_util_quote.man
new file mode 100644
index 0000000..c1a32f3
--- /dev/null
+++ b/tcllib/modules/page/page_util_quote.man
@@ -0,0 +1,62 @@
+[comment {-*- tcl -*- doctools manpage}]
+[manpage_begin page_util_quote n 1.0]
+[keywords page]
+[keywords {parser generator}]
+[keywords quoting]
+[keywords {text processing}]
+[copyright {2007 Andreas Kupries <andreas_kupries@users.sourceforge.net>}]
+[moddesc {Parser generator tools}]
+[titledesc {page character quoting utilities}]
+[category {Page Parser Generator}]
+[require page::util::quote [opt 0.1]]
+[require snit]
+[description]
+[para]
+
+This package provides a few utility commands to convert characters
+into various forms.
+
+[section API]
+
+[list_begin definitions]
+[call [cmd ::page::util::quote::unquote] [arg char]]
+
+A character, as stored in an abstract syntax tree by a PEG processor
+(See the packages [package grammar::peg::interpreter],
+[package grammar::me], and their relations), i.e. in some quoted form,
+is converted into the equivalent Tcl character. The character is returned
+as the result of the command.
+
+[call [cmd ::page::util::quote::quote'tcl] [arg char]]
+
+This command takes a Tcl character (internal representation) and
+converts it into a string which is accepted by the Tcl parser, will
+regenerate the character in question and is 7bit ASCII. The string is
+returned as the result of this command.
+
+[call [cmd ::page::util::quote::quote'tclstr] [arg char]]
+
+This command takes a Tcl character (internal representation) and
+converts it into a string which is accepted by the Tcl parser and will
+generate a human readable representation of the character in question.
+The string is returned as the result of this command.
+
+[para]
+
+The string does not use any unprintable characters. It may use
+backslash-quoting. High UTF characters are quoted to avoid problems
+with the still prevalent ascii terminals. It is assumed that the
+string will be used in a double-quoted environment.
+
+[call [cmd ::page::util::quote::quote'tclcom] [arg char]]
+
+This command takes a Tcl character (internal representation) and
+converts it into a string which is accepted by the Tcl parser when
+used within a Tcl comment. The string is returned as the result of
+this command.
+
+[list_end]
+
+[vset CATEGORY page]
+[include ../doctools2base/include/feedback.inc]
+[manpage_end]
diff --git a/tcllib/modules/page/parse_lemon.tcl b/tcllib/modules/page/parse_lemon.tcl
new file mode 100644
index 0000000..e3b2447
--- /dev/null
+++ b/tcllib/modules/page/parse_lemon.tcl
@@ -0,0 +1,7420 @@
+# -*- tcl -*-
+## Parsing Expression Grammar 'page::parse::lemon'.
+## RD parser by the PG backend 'MEwriter'.
+
+# ### ### ### ######### ######### #########
+## Package description
+
+# The commands provided here match an input provided through a buffer
+# command to the PE grammar 'page::parse::lemon'. The parser is based on the package
+# 'grammar::mengine' (recursive-descent, packrat, pulling chars,
+# pushing the generated AST).
+
+# ### ### ### ######### ######### #########
+## Requisites
+
+package require grammar::me::tcl
+
+# ### ### ### ######### ######### #########
+## Implementation
+
+namespace eval ::page::parse::lemon {
+ # Import the virtual machine for matching.
+
+ namespace import ::grammar::me::tcl::*
+ upvar #0 ::grammar::me::tcl::ok ok
+}
+
+# ### ### ### ######### ######### #########
+## API Implementation.
+
+proc ::page::parse::lemon::parse {nxcmd emvar astvar} {
+ variable ok
+ variable se
+
+ upvar 1 $emvar emsg $astvar ast
+
+ init $nxcmd
+
+ matchSymbol_LemonGrammar ; # (n LemonGrammar)
+
+ isv_nonterminal_reduce ALL -1
+ set ast [sv]
+ if {!$ok} {
+ foreach {l m} [ier_get] break
+ lappend l [lc $l]
+ set mx {}
+ foreach x $m {lappend mx "Expected $x"}
+ set emsg [list $l $mx]
+ }
+
+ return $ok
+}
+
+# ### ### ### ######### ######### #########
+## Internal helper methods
+
+# Grammar 'page::parse::lemon'
+#
+# ASSIGN = (x (t :)
+# (t :)
+# (t =)
+# (n SPACE))
+#
+# C_COMMENT = (x (n CCOM_OPEN)
+# (* (x (! (n CCOM_CLOSE))
+# (dot)))
+# (n CCOM_CLOSE))
+#
+# CCOM_CLOSE = (x (t *)
+# (t /))
+#
+# CCOM_OPEN = (x (t /)
+# (t *))
+#
+# Code = (x (n DCODE)
+# (n Codeblock))
+#
+# Codeblock = (x (n LBRACE)
+# (* (/ (n Codeblock)
+# (n C_COMMENT)
+# (n Cplusplus_COMMENT)
+# (x (! (n RBRACE))
+# (dot))))
+# (n RBRACE))
+#
+# Cplusplus_COMMENT = (x (t /)
+# (t /)
+# (* (x (! (n EOL))
+# (dot)))
+# (n EOL))
+#
+# DCODE = (x (t c)
+# (t o)
+# (t d)
+# (t e)
+# (n SPACE))
+#
+# DDEFDEST = (x (t d)
+# (t e)
+# (t f)
+# (t a)
+# (t u)
+# (t l)
+# (t t)
+# (t _)
+# (t d)
+# (t e)
+# (t s)
+# (t t)
+# (t r)
+# (t u)
+# (t c)
+# (t t)
+# (t o)
+# (t r)
+# (n SPACE))
+#
+# DDEFTYPE = (x (t d)
+# (t e)
+# (t f)
+# (t a)
+# (t u)
+# (t l)
+# (t t)
+# (t _)
+# (t t)
+# (t y)
+# (t p)
+# (t e)
+# (n SPACE))
+#
+# DDEST = (x (t d)
+# (t e)
+# (t s)
+# (t t)
+# (t r)
+# (t u)
+# (t c)
+# (t t)
+# (t o)
+# (t r)
+# (n SPACE))
+#
+# DefaultDestructor = (x (n DDEFDEST)
+# (n Identifier)
+# (n Codeblock))
+#
+# DefaultType = (x (n DDEFTYPE)
+# (n Codeblock))
+#
+# Definition = (* (x (n Identifier)
+# (? (n Label))))
+#
+# DENDIF = (x (t %)
+# (t e)
+# (t n)
+# (t d)
+# (t i)
+# (t f)
+# (n SPACE))
+#
+# Destructor = (x (n DDEST)
+# (n Identifier)
+# (n Codeblock))
+#
+# DEXTRA = (x (t e)
+# (t x)
+# (t t)
+# (t r)
+# (t a)
+# (t _)
+# (t a)
+# (t r)
+# (t g)
+# (t u)
+# (t m)
+# (t e)
+# (t n)
+# (t t)
+# (n SPACE))
+#
+# DFALLBK = (x (t f)
+# (t a)
+# (t l)
+# (t l)
+# (t b)
+# (t a)
+# (t c)
+# (t k)
+# (n SPACE))
+#
+# DIFDEF = (x (t %)
+# (t i)
+# (t f)
+# (t d)
+# (t e)
+# (t f)
+# (n SPACE))
+#
+# DIFNDEF = (x (t %)
+# (t i)
+# (t f)
+# (t n)
+# (t d)
+# (t e)
+# (t f)
+# (n SPACE))
+#
+# DINCL = (x (t i)
+# (t n)
+# (t c)
+# (t l)
+# (t u)
+# (t d)
+# (t e)
+# (n SPACE))
+#
+# DINTRO = (t %)
+#
+# Directive = (x (n DINTRO)
+# (/ (n Code)
+# (n DefaultDestructor)
+# (n DefaultType)
+# (n Destructor)
+# (n ExtraArgument)
+# (n Include)
+# (n Left)
+# (n Name)
+# (n Nonassoc)
+# (n ParseAccept)
+# (n ParseFailure)
+# (n Right)
+# (n StackOverflow)
+# (n Stacksize)
+# (n StartSymbol)
+# (n SyntaxError)
+# (n TokenDestructor)
+# (n TokenPrefix)
+# (n TokenType)
+# (n Type)
+# (n Fallback)))
+#
+# DLEFT = (x (t l)
+# (t e)
+# (t f)
+# (t t)
+# (n SPACE))
+#
+# DNAME = (x (t n)
+# (t a)
+# (t m)
+# (t e)
+# (n SPACE))
+#
+# DNON = (x (t n)
+# (t o)
+# (t n)
+# (t a)
+# (t s)
+# (t s)
+# (t o)
+# (t c)
+# (n SPACE))
+#
+# DOT = (x (t .)
+# (n SPACE))
+#
+# DPACC = (x (t p)
+# (t a)
+# (t r)
+# (t s)
+# (t e)
+# (t _)
+# (t a)
+# (t c)
+# (t c)
+# (t e)
+# (t p)
+# (t t)
+# (n SPACE))
+#
+# DPFAIL = (x (t p)
+# (t a)
+# (t r)
+# (t s)
+# (t e)
+# (t _)
+# (t f)
+# (t a)
+# (t i)
+# (t l)
+# (t u)
+# (t r)
+# (t e)
+# (n SPACE))
+#
+# DRIGHT = (x (t r)
+# (t i)
+# (t g)
+# (t h)
+# (t t)
+# (n SPACE))
+#
+# DSTART = (x (t s)
+# (t t)
+# (t a)
+# (t r)
+# (t t)
+# (t _)
+# (t s)
+# (t y)
+# (t m)
+# (t b)
+# (t o)
+# (t l)
+# (n SPACE))
+#
+# DSTKOVER = (x (t s)
+# (t t)
+# (t a)
+# (t c)
+# (t k)
+# (t _)
+# (t o)
+# (t v)
+# (t e)
+# (t r)
+# (t f)
+# (t l)
+# (t o)
+# (t w)
+# (n SPACE))
+#
+# DSTKSZ = (x (t s)
+# (t t)
+# (t a)
+# (t c)
+# (t k)
+# (t _)
+# (t s)
+# (t i)
+# (t z)
+# (t e)
+# (n SPACE))
+#
+# DSYNERR = (x (t s)
+# (t y)
+# (t n)
+# (t t)
+# (t a)
+# (t x)
+# (t _)
+# (t e)
+# (t r)
+# (t r)
+# (t o)
+# (t r)
+# (n SPACE))
+#
+# DTOKDEST = (x (t t)
+# (t o)
+# (t k)
+# (t e)
+# (t n)
+# (t _)
+# (t d)
+# (t e)
+# (t s)
+# (t t)
+# (t r)
+# (t u)
+# (t c)
+# (t t)
+# (t o)
+# (t r)
+# (n SPACE))
+#
+# DTOKPFX = (x (t t)
+# (t o)
+# (t k)
+# (t e)
+# (t n)
+# (t _)
+# (t p)
+# (t r)
+# (t e)
+# (t f)
+# (t i)
+# (t x)
+# (n SPACE))
+#
+# DTOKTYPE = (x (t t)
+# (t o)
+# (t k)
+# (t e)
+# (t n)
+# (t _)
+# (t t)
+# (t y)
+# (t p)
+# (t e)
+# (n SPACE))
+#
+# DTYPE = (x (t t)
+# (t y)
+# (t p)
+# (t e)
+# (n SPACE))
+#
+# Endif = (n DENDIF)
+#
+# EOF = (! (dot))
+#
+# EOL = (/ (x (t \r)
+# (t \n))
+# (t \r)
+# (t \n))
+#
+# ExtraArgument = (x (n DEXTRA)
+# (n Codeblock))
+#
+# Fallback = (x (n DFALLBK)
+# (+ (n Identifier))
+# (n DOT))
+#
+# Ident = (x (/ (alpha)
+# (t _))
+# (* (/ (alnum)
+# (t _))))
+#
+# Identifier = (x (n Ident)
+# (n SPACE))
+#
+# Ifdef = (x (n DIFDEF)
+# (n Identifier))
+#
+# Ifndef = (x (n DIFNDEF)
+# (n Identifier))
+#
+# Include = (x (n DINCL)
+# (n Codeblock))
+#
+# Label = (x (n LPAREN)
+# (n Identifier)
+# (n RPAREN))
+#
+# LBRACE = (t \{)
+#
+# LBRACKET = (x (t [)
+# (n SPACE))
+#
+# Left = (x (n DLEFT)
+# (+ (n Identifier))
+# (n DOT))
+#
+# LemonGrammar = (x (n SPACE)
+# (+ (n Statement))
+# (n EOF))
+#
+# LPAREN = (x (t \()
+# (n SPACE))
+#
+# Name = (x (n DNAME)
+# (n Identifier))
+#
+# NatNum = (+ (.. 0 9))
+#
+# NaturalNumber = (x (n NatNum)
+# (n SPACE))
+#
+# Nonassoc = (x (n DNON)
+# (+ (n Identifier))
+# (n DOT))
+#
+# ParseAccept = (x (n DPACC)
+# (n Codeblock))
+#
+# ParseFailure = (x (n DPFAIL)
+# (n Codeblock))
+#
+# Precedence = (x (n LBRACKET)
+# (n Identifier)
+# (n RBRACKET))
+#
+# RBRACE = (t \})
+#
+# RBRACKET = (x (t ])
+# (n SPACE))
+#
+# Right = (x (n DRIGHT)
+# (+ (n Identifier))
+# (n DOT))
+#
+# RPAREN = (x (t \))
+# (n SPACE))
+#
+# Rule = (x (n Identifier)
+# (? (n Label))
+# (n ASSIGN)
+# (n Definition)
+# (n DOT)
+# (? (n Precedence))
+# (? (n Codeblock)))
+#
+# SPACE = (* (/ (t <blank>)
+# (t \t)
+# (t \n)
+# (t \r)
+# (n C_COMMENT)
+# (n Cplusplus_COMMENT)
+# (n Ifndef)
+# (n Ifdef)
+# (n Endif)))
+#
+# StackOverflow = (x (n DSTKOVER)
+# (n Codeblock))
+#
+# Stacksize = (x (n DSTKSZ)
+# (n NaturalNumber))
+#
+# StartSymbol = (x (n DSTART)
+# (n Identifier))
+#
+# Statement = (x (/ (n Directive)
+# (n Rule))
+# (n SPACE))
+#
+# SyntaxError = (x (n DSYNERR)
+# (n Codeblock))
+#
+# TokenDestructor = (x (n DTOKDEST)
+# (n Identifier)
+# (n Codeblock))
+#
+# TokenPrefix = (x (n DTOKPFX)
+# (n Identifier))
+#
+# TokenType = (x (n DTOKTYPE)
+# (n Codeblock))
+#
+# Type = (x (n DTYPE)
+# (n Identifier)
+# (n Codeblock))
+#
+
+proc ::page::parse::lemon::matchSymbol_ASSIGN {} {
+ # ASSIGN = (x (t :)
+ # (t :)
+ # (t =)
+ # (n SPACE))
+
+ if {[inc_restore ASSIGN]} return
+
+ set pos [icl_get]
+
+ eseq53 ; # (x (t :)
+ # (t :)
+ # (t =)
+ # (n SPACE))
+
+ isv_clear
+ inc_save ASSIGN $pos
+ ier_nonterminal ASSIGN $pos
+ return
+}
+
+proc ::page::parse::lemon::eseq53 {} {
+
+ # (x (t :)
+ # (t :)
+ # (t =)
+ # (n SPACE))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set old [ier_get]
+ ict_advance :
+ if {$ok} {ict_match_token :}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance :
+ if {$ok} {ict_match_token :}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance =
+ if {$ok} {ict_match_token =}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ matchSymbol_SPACE ; # (n SPACE)
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ return
+}
+
+proc ::page::parse::lemon::matchSymbol_C_COMMENT {} {
+ # C_COMMENT = (x (n CCOM_OPEN)
+ # (* (x (! (n CCOM_CLOSE))
+ # (dot)))
+ # (n CCOM_CLOSE))
+
+ if {[inc_restore C_COMMENT]} return
+
+ set pos [icl_get]
+
+ eseq90 ; # (x (n CCOM_OPEN)
+ # (* (x (! (n CCOM_CLOSE))
+ # (dot)))
+ # (n CCOM_CLOSE))
+
+ isv_clear
+ inc_save C_COMMENT $pos
+ ier_nonterminal C_COMMENT $pos
+ return
+}
+
+proc ::page::parse::lemon::eseq90 {} {
+
+ # (x (n CCOM_OPEN)
+ # (* (x (! (n CCOM_CLOSE))
+ # (dot)))
+ # (n CCOM_CLOSE))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set old [ier_get]
+ matchSymbol_CCOM_OPEN ; # (n CCOM_OPEN)
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ekleene89 ; # (* (x (! (n CCOM_CLOSE))
+ # (dot)))
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ matchSymbol_CCOM_CLOSE ; # (n CCOM_CLOSE)
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ return
+}
+
+proc ::page::parse::lemon::ekleene89 {} {
+
+ # (* (x (! (n CCOM_CLOSE))
+ # (dot)))
+
+ variable ok
+
+ while {1} {
+ set pos [icl_get]
+
+ set old [ier_get]
+ eseq88 ; # (x (! (n CCOM_CLOSE))
+ # (dot))
+ ier_merge $old
+
+ if {$ok} continue
+ break
+ }
+
+ icl_rewind $pos
+ iok_ok
+ return
+}
+
+proc ::page::parse::lemon::eseq88 {} {
+
+ # (x (! (n CCOM_CLOSE))
+ # (dot))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set old [ier_get]
+ ebang87
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance "any character"
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ return
+}
+
+proc ::page::parse::lemon::ebang87 {} {
+ set pos [icl_get]
+
+ matchSymbol_CCOM_CLOSE ; # (n CCOM_CLOSE)
+
+ icl_rewind $pos
+ iok_negate
+ return
+}
+
+proc ::page::parse::lemon::matchSymbol_CCOM_CLOSE {} {
+ # CCOM_CLOSE = (x (t *)
+ # (t /))
+
+ if {[inc_restore CCOM_CLOSE]} return
+
+ set pos [icl_get]
+
+ eseq92 ; # (x (t *)
+ # (t /))
+
+ isv_clear
+ inc_save CCOM_CLOSE $pos
+ ier_nonterminal CCOM_CLOSE $pos
+ return
+}
+
+proc ::page::parse::lemon::eseq92 {} {
+
+ # (x (t *)
+ # (t /))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set old [ier_get]
+ ict_advance *
+ if {$ok} {ict_match_token *}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance /
+ if {$ok} {ict_match_token /}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ return
+}
+
+proc ::page::parse::lemon::matchSymbol_CCOM_OPEN {} {
+ # CCOM_OPEN = (x (t /)
+ # (t *))
+
+ if {[inc_restore CCOM_OPEN]} return
+
+ set pos [icl_get]
+
+ eseq91 ; # (x (t /)
+ # (t *))
+
+ isv_clear
+ inc_save CCOM_OPEN $pos
+ ier_nonterminal CCOM_OPEN $pos
+ return
+}
+
+proc ::page::parse::lemon::eseq91 {} {
+
+ # (x (t /)
+ # (t *))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set old [ier_get]
+ ict_advance /
+ if {$ok} {ict_match_token /}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance *
+ if {$ok} {ict_match_token *}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ return
+}
+
+proc ::page::parse::lemon::matchSymbol_Code {} {
+ # Code = (x (n DCODE)
+ # (n Codeblock))
+
+ variable ok
+ if {[inc_restore Code]} {
+ if {$ok} ias_push
+ return
+ }
+
+ set pos [icl_get]
+ set mrk [ias_mark]
+
+ eseq16 ; # (x (n DCODE)
+ # (n Codeblock))
+
+ isv_nonterminal_reduce Code $pos $mrk
+ inc_save Code $pos
+ ias_pop2mark $mrk
+ if {$ok} ias_push
+ ier_nonterminal Code $pos
+ return
+}
+
+proc ::page::parse::lemon::eseq16 {} {
+
+ # (x (n DCODE)
+ # (n Codeblock))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set old [ier_get]
+ matchSymbol_DCODE ; # (n DCODE)
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set mrk [ias_mark]
+
+ set old [ier_get]
+ matchSymbol_Codeblock ; # (n Codeblock)
+ ier_merge $old
+
+ if {!$ok} {
+ ias_pop2mark $mrk
+ icl_rewind $pos
+ return
+ }
+
+ return
+}
+
+proc ::page::parse::lemon::matchSymbol_Codeblock {} {
+ # Codeblock = (x (n LBRACE)
+ # (* (/ (n Codeblock)
+ # (n C_COMMENT)
+ # (n Cplusplus_COMMENT)
+ # (x (! (n RBRACE))
+ # (dot))))
+ # (n RBRACE))
+
+ variable ok
+ if {[inc_restore Codeblock]} {
+ if {$ok} ias_push
+ return
+ }
+
+ set pos [icl_get]
+
+ eseq45 ; # (x (n LBRACE)
+ # (* (/ (n Codeblock)
+ # (n C_COMMENT)
+ # (n Cplusplus_COMMENT)
+ # (x (! (n RBRACE))
+ # (dot))))
+ # (n RBRACE))
+
+ isv_nonterminal_range Codeblock $pos
+ inc_save Codeblock $pos
+ if {$ok} ias_push
+ ier_nonterminal Codeblock $pos
+ return
+}
+
+proc ::page::parse::lemon::eseq45 {} {
+
+ # (x (n LBRACE)
+ # (* (/ (n Codeblock)
+ # (n C_COMMENT)
+ # (n Cplusplus_COMMENT)
+ # (x (! (n RBRACE))
+ # (dot))))
+ # (n RBRACE))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set old [ier_get]
+ matchSymbol_LBRACE ; # (n LBRACE)
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ekleene44 ; # (* (/ (n Codeblock)
+ # (n C_COMMENT)
+ # (n Cplusplus_COMMENT)
+ # (x (! (n RBRACE))
+ # (dot))))
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ matchSymbol_RBRACE ; # (n RBRACE)
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ return
+}
+
+proc ::page::parse::lemon::ekleene44 {} {
+
+ # (* (/ (n Codeblock)
+ # (n C_COMMENT)
+ # (n Cplusplus_COMMENT)
+ # (x (! (n RBRACE))
+ # (dot))))
+
+ variable ok
+
+ while {1} {
+ set pos [icl_get]
+
+ set old [ier_get]
+ ebra43 ; # (/ (n Codeblock)
+ # (n C_COMMENT)
+ # (n Cplusplus_COMMENT)
+ # (x (! (n RBRACE))
+ # (dot)))
+ ier_merge $old
+
+ if {$ok} continue
+ break
+ }
+
+ icl_rewind $pos
+ iok_ok
+ return
+}
+
+proc ::page::parse::lemon::ebra43 {} {
+
+ # (/ (n Codeblock)
+ # (n C_COMMENT)
+ # (n Cplusplus_COMMENT)
+ # (x (! (n RBRACE))
+ # (dot)))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set old [ier_get]
+ set pCodeblock [ias_mark]
+ matchSymbol_Codeblock
+ ias_pop2mark $pCodeblock ; # (n Codeblock)
+ ier_merge $old
+
+ if {$ok} return
+ icl_rewind $pos
+
+ set old [ier_get]
+ matchSymbol_C_COMMENT ; # (n C_COMMENT)
+ ier_merge $old
+
+ if {$ok} return
+ icl_rewind $pos
+
+ set old [ier_get]
+ matchSymbol_Cplusplus_COMMENT ; # (n Cplusplus_COMMENT)
+ ier_merge $old
+
+ if {$ok} return
+ icl_rewind $pos
+
+ set old [ier_get]
+ eseq42 ; # (x (! (n RBRACE))
+ # (dot))
+ ier_merge $old
+
+ if {$ok} return
+ icl_rewind $pos
+
+ return
+}
+
+proc ::page::parse::lemon::eseq42 {} {
+
+ # (x (! (n RBRACE))
+ # (dot))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set old [ier_get]
+ ebang41
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance "any character"
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ return
+}
+
+proc ::page::parse::lemon::ebang41 {} {
+ set pos [icl_get]
+
+ matchSymbol_RBRACE ; # (n RBRACE)
+
+ icl_rewind $pos
+ iok_negate
+ return
+}
+
+proc ::page::parse::lemon::matchSymbol_Cplusplus_COMMENT {} {
+ # Cplusplus_COMMENT = (x (t /)
+ # (t /)
+ # (* (x (! (n EOL))
+ # (dot)))
+ # (n EOL))
+
+ if {[inc_restore Cplusplus_COMMENT]} return
+
+ set pos [icl_get]
+
+ eseq96 ; # (x (t /)
+ # (t /)
+ # (* (x (! (n EOL))
+ # (dot)))
+ # (n EOL))
+
+ isv_clear
+ inc_save Cplusplus_COMMENT $pos
+ ier_nonterminal Cplusplus_COMMENT $pos
+ return
+}
+
+proc ::page::parse::lemon::eseq96 {} {
+
+ # (x (t /)
+ # (t /)
+ # (* (x (! (n EOL))
+ # (dot)))
+ # (n EOL))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set old [ier_get]
+ ict_advance /
+ if {$ok} {ict_match_token /}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance /
+ if {$ok} {ict_match_token /}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ekleene95 ; # (* (x (! (n EOL))
+ # (dot)))
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ matchSymbol_EOL ; # (n EOL)
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ return
+}
+
+proc ::page::parse::lemon::ekleene95 {} {
+
+ # (* (x (! (n EOL))
+ # (dot)))
+
+ variable ok
+
+ while {1} {
+ set pos [icl_get]
+
+ set old [ier_get]
+ eseq94 ; # (x (! (n EOL))
+ # (dot))
+ ier_merge $old
+
+ if {$ok} continue
+ break
+ }
+
+ icl_rewind $pos
+ iok_ok
+ return
+}
+
+proc ::page::parse::lemon::eseq94 {} {
+
+ # (x (! (n EOL))
+ # (dot))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set old [ier_get]
+ ebang93
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance "any character"
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ return
+}
+
+proc ::page::parse::lemon::ebang93 {} {
+ set pos [icl_get]
+
+ matchSymbol_EOL ; # (n EOL)
+
+ icl_rewind $pos
+ iok_negate
+ return
+}
+
+proc ::page::parse::lemon::matchSymbol_DCODE {} {
+ # DCODE = (x (t c)
+ # (t o)
+ # (t d)
+ # (t e)
+ # (n SPACE))
+
+ if {[inc_restore DCODE]} return
+
+ set pos [icl_get]
+
+ eseq59 ; # (x (t c)
+ # (t o)
+ # (t d)
+ # (t e)
+ # (n SPACE))
+
+ isv_clear
+ inc_save DCODE $pos
+ ier_nonterminal DCODE $pos
+ return
+}
+
+proc ::page::parse::lemon::eseq59 {} {
+
+ # (x (t c)
+ # (t o)
+ # (t d)
+ # (t e)
+ # (n SPACE))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set old [ier_get]
+ ict_advance c
+ if {$ok} {ict_match_token c}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance o
+ if {$ok} {ict_match_token o}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance d
+ if {$ok} {ict_match_token d}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance e
+ if {$ok} {ict_match_token e}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ matchSymbol_SPACE ; # (n SPACE)
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ return
+}
+
+proc ::page::parse::lemon::matchSymbol_DDEFDEST {} {
+ # DDEFDEST = (x (t d)
+ # (t e)
+ # (t f)
+ # (t a)
+ # (t u)
+ # (t l)
+ # (t t)
+ # (t _)
+ # (t d)
+ # (t e)
+ # (t s)
+ # (t t)
+ # (t r)
+ # (t u)
+ # (t c)
+ # (t t)
+ # (t o)
+ # (t r)
+ # (n SPACE))
+
+ if {[inc_restore DDEFDEST]} return
+
+ set pos [icl_get]
+
+ eseq60 ; # (x (t d)
+ # (t e)
+ # (t f)
+ # (t a)
+ # (t u)
+ # (t l)
+ # (t t)
+ # (t _)
+ # (t d)
+ # (t e)
+ # (t s)
+ # (t t)
+ # (t r)
+ # (t u)
+ # (t c)
+ # (t t)
+ # (t o)
+ # (t r)
+ # (n SPACE))
+
+ isv_clear
+ inc_save DDEFDEST $pos
+ ier_nonterminal DDEFDEST $pos
+ return
+}
+
+proc ::page::parse::lemon::eseq60 {} {
+
+ # (x (t d)
+ # (t e)
+ # (t f)
+ # (t a)
+ # (t u)
+ # (t l)
+ # (t t)
+ # (t _)
+ # (t d)
+ # (t e)
+ # (t s)
+ # (t t)
+ # (t r)
+ # (t u)
+ # (t c)
+ # (t t)
+ # (t o)
+ # (t r)
+ # (n SPACE))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set old [ier_get]
+ ict_advance d
+ if {$ok} {ict_match_token d}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance e
+ if {$ok} {ict_match_token e}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance f
+ if {$ok} {ict_match_token f}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance a
+ if {$ok} {ict_match_token a}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance u
+ if {$ok} {ict_match_token u}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance l
+ if {$ok} {ict_match_token l}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance t
+ if {$ok} {ict_match_token t}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance _
+ if {$ok} {ict_match_token _}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance d
+ if {$ok} {ict_match_token d}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance e
+ if {$ok} {ict_match_token e}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance s
+ if {$ok} {ict_match_token s}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance t
+ if {$ok} {ict_match_token t}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance r
+ if {$ok} {ict_match_token r}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance u
+ if {$ok} {ict_match_token u}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance c
+ if {$ok} {ict_match_token c}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance t
+ if {$ok} {ict_match_token t}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance o
+ if {$ok} {ict_match_token o}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance r
+ if {$ok} {ict_match_token r}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ matchSymbol_SPACE ; # (n SPACE)
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ return
+}
+
+proc ::page::parse::lemon::matchSymbol_DDEFTYPE {} {
+ # DDEFTYPE = (x (t d)
+ # (t e)
+ # (t f)
+ # (t a)
+ # (t u)
+ # (t l)
+ # (t t)
+ # (t _)
+ # (t t)
+ # (t y)
+ # (t p)
+ # (t e)
+ # (n SPACE))
+
+ if {[inc_restore DDEFTYPE]} return
+
+ set pos [icl_get]
+
+ eseq61 ; # (x (t d)
+ # (t e)
+ # (t f)
+ # (t a)
+ # (t u)
+ # (t l)
+ # (t t)
+ # (t _)
+ # (t t)
+ # (t y)
+ # (t p)
+ # (t e)
+ # (n SPACE))
+
+ isv_clear
+ inc_save DDEFTYPE $pos
+ ier_nonterminal DDEFTYPE $pos
+ return
+}
+
+proc ::page::parse::lemon::eseq61 {} {
+
+ # (x (t d)
+ # (t e)
+ # (t f)
+ # (t a)
+ # (t u)
+ # (t l)
+ # (t t)
+ # (t _)
+ # (t t)
+ # (t y)
+ # (t p)
+ # (t e)
+ # (n SPACE))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set old [ier_get]
+ ict_advance d
+ if {$ok} {ict_match_token d}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance e
+ if {$ok} {ict_match_token e}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance f
+ if {$ok} {ict_match_token f}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance a
+ if {$ok} {ict_match_token a}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance u
+ if {$ok} {ict_match_token u}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance l
+ if {$ok} {ict_match_token l}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance t
+ if {$ok} {ict_match_token t}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance _
+ if {$ok} {ict_match_token _}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance t
+ if {$ok} {ict_match_token t}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance y
+ if {$ok} {ict_match_token y}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance p
+ if {$ok} {ict_match_token p}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance e
+ if {$ok} {ict_match_token e}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ matchSymbol_SPACE ; # (n SPACE)
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ return
+}
+
+proc ::page::parse::lemon::matchSymbol_DDEST {} {
+ # DDEST = (x (t d)
+ # (t e)
+ # (t s)
+ # (t t)
+ # (t r)
+ # (t u)
+ # (t c)
+ # (t t)
+ # (t o)
+ # (t r)
+ # (n SPACE))
+
+ if {[inc_restore DDEST]} return
+
+ set pos [icl_get]
+
+ eseq62 ; # (x (t d)
+ # (t e)
+ # (t s)
+ # (t t)
+ # (t r)
+ # (t u)
+ # (t c)
+ # (t t)
+ # (t o)
+ # (t r)
+ # (n SPACE))
+
+ isv_clear
+ inc_save DDEST $pos
+ ier_nonterminal DDEST $pos
+ return
+}
+
+proc ::page::parse::lemon::eseq62 {} {
+
+ # (x (t d)
+ # (t e)
+ # (t s)
+ # (t t)
+ # (t r)
+ # (t u)
+ # (t c)
+ # (t t)
+ # (t o)
+ # (t r)
+ # (n SPACE))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set old [ier_get]
+ ict_advance d
+ if {$ok} {ict_match_token d}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance e
+ if {$ok} {ict_match_token e}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance s
+ if {$ok} {ict_match_token s}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance t
+ if {$ok} {ict_match_token t}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance r
+ if {$ok} {ict_match_token r}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance u
+ if {$ok} {ict_match_token u}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance c
+ if {$ok} {ict_match_token c}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance t
+ if {$ok} {ict_match_token t}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance o
+ if {$ok} {ict_match_token o}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance r
+ if {$ok} {ict_match_token r}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ matchSymbol_SPACE ; # (n SPACE)
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ return
+}
+
+proc ::page::parse::lemon::matchSymbol_DefaultDestructor {} {
+ # DefaultDestructor = (x (n DDEFDEST)
+ # (n Identifier)
+ # (n Codeblock))
+
+ variable ok
+ if {[inc_restore DefaultDestructor]} {
+ if {$ok} ias_push
+ return
+ }
+
+ set pos [icl_get]
+ set mrk [ias_mark]
+
+ eseq17 ; # (x (n DDEFDEST)
+ # (n Identifier)
+ # (n Codeblock))
+
+ isv_nonterminal_reduce DefaultDestructor $pos $mrk
+ inc_save DefaultDestructor $pos
+ ias_pop2mark $mrk
+ if {$ok} ias_push
+ ier_nonterminal DefaultDestructor $pos
+ return
+}
+
+proc ::page::parse::lemon::eseq17 {} {
+
+ # (x (n DDEFDEST)
+ # (n Identifier)
+ # (n Codeblock))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set old [ier_get]
+ matchSymbol_DDEFDEST ; # (n DDEFDEST)
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set mrk [ias_mark]
+
+ set old [ier_get]
+ matchSymbol_Identifier ; # (n Identifier)
+ ier_merge $old
+
+ if {!$ok} {
+ ias_pop2mark $mrk
+ icl_rewind $pos
+ return
+ }
+
+ set old [ier_get]
+ matchSymbol_Codeblock ; # (n Codeblock)
+ ier_merge $old
+
+ if {!$ok} {
+ ias_pop2mark $mrk
+ icl_rewind $pos
+ return
+ }
+
+ return
+}
+
+proc ::page::parse::lemon::matchSymbol_DefaultType {} {
+ # DefaultType = (x (n DDEFTYPE)
+ # (n Codeblock))
+
+ variable ok
+ if {[inc_restore DefaultType]} {
+ if {$ok} ias_push
+ return
+ }
+
+ set pos [icl_get]
+ set mrk [ias_mark]
+
+ eseq18 ; # (x (n DDEFTYPE)
+ # (n Codeblock))
+
+ isv_nonterminal_reduce DefaultType $pos $mrk
+ inc_save DefaultType $pos
+ ias_pop2mark $mrk
+ if {$ok} ias_push
+ ier_nonterminal DefaultType $pos
+ return
+}
+
+proc ::page::parse::lemon::eseq18 {} {
+
+ # (x (n DDEFTYPE)
+ # (n Codeblock))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set old [ier_get]
+ matchSymbol_DDEFTYPE ; # (n DDEFTYPE)
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set mrk [ias_mark]
+
+ set old [ier_get]
+ matchSymbol_Codeblock ; # (n Codeblock)
+ ier_merge $old
+
+ if {!$ok} {
+ ias_pop2mark $mrk
+ icl_rewind $pos
+ return
+ }
+
+ return
+}
+
+proc ::page::parse::lemon::matchSymbol_Definition {} {
+ # Definition = (* (x (n Identifier)
+ # (? (n Label))))
+
+ variable ok
+ if {[inc_restore Definition]} {
+ if {$ok} ias_push
+ return
+ }
+
+ set pos [icl_get]
+ set mrk [ias_mark]
+
+ ekleene11 ; # (* (x (n Identifier)
+ # (? (n Label))))
+
+ isv_nonterminal_reduce Definition $pos $mrk
+ inc_save Definition $pos
+ ias_pop2mark $mrk
+ if {$ok} ias_push
+ ier_nonterminal Definition $pos
+ return
+}
+
+proc ::page::parse::lemon::ekleene11 {} {
+
+ # (* (x (n Identifier)
+ # (? (n Label))))
+
+ variable ok
+
+ while {1} {
+ set pos [icl_get]
+
+ set old [ier_get]
+ eseq10 ; # (x (n Identifier)
+ # (? (n Label)))
+ ier_merge $old
+
+ if {$ok} continue
+ break
+ }
+
+ icl_rewind $pos
+ iok_ok
+ return
+}
+
+proc ::page::parse::lemon::eseq10 {} {
+
+ # (x (n Identifier)
+ # (? (n Label)))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set mrk [ias_mark]
+
+ set old [ier_get]
+ matchSymbol_Identifier ; # (n Identifier)
+ ier_merge $old
+
+ if {!$ok} {
+ ias_pop2mark $mrk
+ icl_rewind $pos
+ return
+ }
+
+ set old [ier_get]
+ eopt9 ; # (? (n Label))
+ ier_merge $old
+
+ if {!$ok} {
+ ias_pop2mark $mrk
+ icl_rewind $pos
+ return
+ }
+
+ return
+}
+
+proc ::page::parse::lemon::eopt9 {} {
+
+ # (? (n Label))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set old [ier_get]
+ matchSymbol_Label ; # (n Label)
+ ier_merge $old
+
+ if {$ok} return
+ icl_rewind $pos
+ iok_ok
+ return
+}
+
+proc ::page::parse::lemon::matchSymbol_DENDIF {} {
+ # DENDIF = (x (t %)
+ # (t e)
+ # (t n)
+ # (t d)
+ # (t i)
+ # (t f)
+ # (n SPACE))
+
+ if {[inc_restore DENDIF]} return
+
+ set pos [icl_get]
+
+ eseq82 ; # (x (t %)
+ # (t e)
+ # (t n)
+ # (t d)
+ # (t i)
+ # (t f)
+ # (n SPACE))
+
+ isv_clear
+ inc_save DENDIF $pos
+ ier_nonterminal DENDIF $pos
+ return
+}
+
+proc ::page::parse::lemon::eseq82 {} {
+
+ # (x (t %)
+ # (t e)
+ # (t n)
+ # (t d)
+ # (t i)
+ # (t f)
+ # (n SPACE))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set old [ier_get]
+ ict_advance %
+ if {$ok} {ict_match_token %}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance e
+ if {$ok} {ict_match_token e}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance n
+ if {$ok} {ict_match_token n}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance d
+ if {$ok} {ict_match_token d}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance i
+ if {$ok} {ict_match_token i}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance f
+ if {$ok} {ict_match_token f}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ matchSymbol_SPACE ; # (n SPACE)
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ return
+}
+
+proc ::page::parse::lemon::matchSymbol_Destructor {} {
+ # Destructor = (x (n DDEST)
+ # (n Identifier)
+ # (n Codeblock))
+
+ variable ok
+ if {[inc_restore Destructor]} {
+ if {$ok} ias_push
+ return
+ }
+
+ set pos [icl_get]
+ set mrk [ias_mark]
+
+ eseq19 ; # (x (n DDEST)
+ # (n Identifier)
+ # (n Codeblock))
+
+ isv_nonterminal_reduce Destructor $pos $mrk
+ inc_save Destructor $pos
+ ias_pop2mark $mrk
+ if {$ok} ias_push
+ ier_nonterminal Destructor $pos
+ return
+}
+
+proc ::page::parse::lemon::eseq19 {} {
+
+ # (x (n DDEST)
+ # (n Identifier)
+ # (n Codeblock))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set old [ier_get]
+ matchSymbol_DDEST ; # (n DDEST)
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set mrk [ias_mark]
+
+ set old [ier_get]
+ matchSymbol_Identifier ; # (n Identifier)
+ ier_merge $old
+
+ if {!$ok} {
+ ias_pop2mark $mrk
+ icl_rewind $pos
+ return
+ }
+
+ set old [ier_get]
+ matchSymbol_Codeblock ; # (n Codeblock)
+ ier_merge $old
+
+ if {!$ok} {
+ ias_pop2mark $mrk
+ icl_rewind $pos
+ return
+ }
+
+ return
+}
+
+proc ::page::parse::lemon::matchSymbol_DEXTRA {} {
+ # DEXTRA = (x (t e)
+ # (t x)
+ # (t t)
+ # (t r)
+ # (t a)
+ # (t _)
+ # (t a)
+ # (t r)
+ # (t g)
+ # (t u)
+ # (t m)
+ # (t e)
+ # (t n)
+ # (t t)
+ # (n SPACE))
+
+ if {[inc_restore DEXTRA]} return
+
+ set pos [icl_get]
+
+ eseq63 ; # (x (t e)
+ # (t x)
+ # (t t)
+ # (t r)
+ # (t a)
+ # (t _)
+ # (t a)
+ # (t r)
+ # (t g)
+ # (t u)
+ # (t m)
+ # (t e)
+ # (t n)
+ # (t t)
+ # (n SPACE))
+
+ isv_clear
+ inc_save DEXTRA $pos
+ ier_nonterminal DEXTRA $pos
+ return
+}
+
+proc ::page::parse::lemon::eseq63 {} {
+
+ # (x (t e)
+ # (t x)
+ # (t t)
+ # (t r)
+ # (t a)
+ # (t _)
+ # (t a)
+ # (t r)
+ # (t g)
+ # (t u)
+ # (t m)
+ # (t e)
+ # (t n)
+ # (t t)
+ # (n SPACE))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set old [ier_get]
+ ict_advance e
+ if {$ok} {ict_match_token e}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance x
+ if {$ok} {ict_match_token x}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance t
+ if {$ok} {ict_match_token t}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance r
+ if {$ok} {ict_match_token r}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance a
+ if {$ok} {ict_match_token a}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance _
+ if {$ok} {ict_match_token _}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance a
+ if {$ok} {ict_match_token a}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance r
+ if {$ok} {ict_match_token r}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance g
+ if {$ok} {ict_match_token g}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance u
+ if {$ok} {ict_match_token u}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance m
+ if {$ok} {ict_match_token m}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance e
+ if {$ok} {ict_match_token e}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance n
+ if {$ok} {ict_match_token n}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance t
+ if {$ok} {ict_match_token t}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ matchSymbol_SPACE ; # (n SPACE)
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ return
+}
+
+proc ::page::parse::lemon::matchSymbol_DFALLBK {} {
+ # DFALLBK = (x (t f)
+ # (t a)
+ # (t l)
+ # (t l)
+ # (t b)
+ # (t a)
+ # (t c)
+ # (t k)
+ # (n SPACE))
+
+ if {[inc_restore DFALLBK]} return
+
+ set pos [icl_get]
+
+ eseq79 ; # (x (t f)
+ # (t a)
+ # (t l)
+ # (t l)
+ # (t b)
+ # (t a)
+ # (t c)
+ # (t k)
+ # (n SPACE))
+
+ isv_clear
+ inc_save DFALLBK $pos
+ ier_nonterminal DFALLBK $pos
+ return
+}
+
+proc ::page::parse::lemon::eseq79 {} {
+
+ # (x (t f)
+ # (t a)
+ # (t l)
+ # (t l)
+ # (t b)
+ # (t a)
+ # (t c)
+ # (t k)
+ # (n SPACE))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set old [ier_get]
+ ict_advance f
+ if {$ok} {ict_match_token f}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance a
+ if {$ok} {ict_match_token a}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance l
+ if {$ok} {ict_match_token l}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance l
+ if {$ok} {ict_match_token l}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance b
+ if {$ok} {ict_match_token b}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance a
+ if {$ok} {ict_match_token a}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance c
+ if {$ok} {ict_match_token c}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance k
+ if {$ok} {ict_match_token k}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ matchSymbol_SPACE ; # (n SPACE)
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ return
+}
+
+proc ::page::parse::lemon::matchSymbol_DIFDEF {} {
+ # DIFDEF = (x (t %)
+ # (t i)
+ # (t f)
+ # (t d)
+ # (t e)
+ # (t f)
+ # (n SPACE))
+
+ if {[inc_restore DIFDEF]} return
+
+ set pos [icl_get]
+
+ eseq80 ; # (x (t %)
+ # (t i)
+ # (t f)
+ # (t d)
+ # (t e)
+ # (t f)
+ # (n SPACE))
+
+ isv_clear
+ inc_save DIFDEF $pos
+ ier_nonterminal DIFDEF $pos
+ return
+}
+
+proc ::page::parse::lemon::eseq80 {} {
+
+ # (x (t %)
+ # (t i)
+ # (t f)
+ # (t d)
+ # (t e)
+ # (t f)
+ # (n SPACE))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set old [ier_get]
+ ict_advance %
+ if {$ok} {ict_match_token %}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance i
+ if {$ok} {ict_match_token i}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance f
+ if {$ok} {ict_match_token f}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance d
+ if {$ok} {ict_match_token d}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance e
+ if {$ok} {ict_match_token e}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance f
+ if {$ok} {ict_match_token f}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ matchSymbol_SPACE ; # (n SPACE)
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ return
+}
+
+proc ::page::parse::lemon::matchSymbol_DIFNDEF {} {
+ # DIFNDEF = (x (t %)
+ # (t i)
+ # (t f)
+ # (t n)
+ # (t d)
+ # (t e)
+ # (t f)
+ # (n SPACE))
+
+ if {[inc_restore DIFNDEF]} return
+
+ set pos [icl_get]
+
+ eseq81 ; # (x (t %)
+ # (t i)
+ # (t f)
+ # (t n)
+ # (t d)
+ # (t e)
+ # (t f)
+ # (n SPACE))
+
+ isv_clear
+ inc_save DIFNDEF $pos
+ ier_nonterminal DIFNDEF $pos
+ return
+}
+
+proc ::page::parse::lemon::eseq81 {} {
+
+ # (x (t %)
+ # (t i)
+ # (t f)
+ # (t n)
+ # (t d)
+ # (t e)
+ # (t f)
+ # (n SPACE))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set old [ier_get]
+ ict_advance %
+ if {$ok} {ict_match_token %}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance i
+ if {$ok} {ict_match_token i}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance f
+ if {$ok} {ict_match_token f}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance n
+ if {$ok} {ict_match_token n}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance d
+ if {$ok} {ict_match_token d}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance e
+ if {$ok} {ict_match_token e}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance f
+ if {$ok} {ict_match_token f}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ matchSymbol_SPACE ; # (n SPACE)
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ return
+}
+
+proc ::page::parse::lemon::matchSymbol_DINCL {} {
+ # DINCL = (x (t i)
+ # (t n)
+ # (t c)
+ # (t l)
+ # (t u)
+ # (t d)
+ # (t e)
+ # (n SPACE))
+
+ if {[inc_restore DINCL]} return
+
+ set pos [icl_get]
+
+ eseq64 ; # (x (t i)
+ # (t n)
+ # (t c)
+ # (t l)
+ # (t u)
+ # (t d)
+ # (t e)
+ # (n SPACE))
+
+ isv_clear
+ inc_save DINCL $pos
+ ier_nonterminal DINCL $pos
+ return
+}
+
+proc ::page::parse::lemon::eseq64 {} {
+
+ # (x (t i)
+ # (t n)
+ # (t c)
+ # (t l)
+ # (t u)
+ # (t d)
+ # (t e)
+ # (n SPACE))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set old [ier_get]
+ ict_advance i
+ if {$ok} {ict_match_token i}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance n
+ if {$ok} {ict_match_token n}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance c
+ if {$ok} {ict_match_token c}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance l
+ if {$ok} {ict_match_token l}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance u
+ if {$ok} {ict_match_token u}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance d
+ if {$ok} {ict_match_token d}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance e
+ if {$ok} {ict_match_token e}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ matchSymbol_SPACE ; # (n SPACE)
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ return
+}
+
+proc ::page::parse::lemon::matchSymbol_DINTRO {} {
+ # DINTRO = (t %)
+
+ variable ok
+ if {[inc_restore DINTRO]} return
+
+ set pos [icl_get]
+
+ ict_advance %
+ if {$ok} {ict_match_token %}
+
+ isv_clear
+ inc_save DINTRO $pos
+ ier_nonterminal DINTRO $pos
+ return
+}
+
+proc ::page::parse::lemon::matchSymbol_Directive {} {
+ # Directive = (x (n DINTRO)
+ # (/ (n Code)
+ # (n DefaultDestructor)
+ # (n DefaultType)
+ # (n Destructor)
+ # (n ExtraArgument)
+ # (n Include)
+ # (n Left)
+ # (n Name)
+ # (n Nonassoc)
+ # (n ParseAccept)
+ # (n ParseFailure)
+ # (n Right)
+ # (n StackOverflow)
+ # (n Stacksize)
+ # (n StartSymbol)
+ # (n SyntaxError)
+ # (n TokenDestructor)
+ # (n TokenPrefix)
+ # (n TokenType)
+ # (n Type)
+ # (n Fallback)))
+
+ variable ok
+ if {[inc_restore Directive]} {
+ if {$ok} ias_push
+ return
+ }
+
+ set pos [icl_get]
+ set mrk [ias_mark]
+
+ eseq15 ; # (x (n DINTRO)
+ # (/ (n Code)
+ # (n DefaultDestructor)
+ # (n DefaultType)
+ # (n Destructor)
+ # (n ExtraArgument)
+ # (n Include)
+ # (n Left)
+ # (n Name)
+ # (n Nonassoc)
+ # (n ParseAccept)
+ # (n ParseFailure)
+ # (n Right)
+ # (n StackOverflow)
+ # (n Stacksize)
+ # (n StartSymbol)
+ # (n SyntaxError)
+ # (n TokenDestructor)
+ # (n TokenPrefix)
+ # (n TokenType)
+ # (n Type)
+ # (n Fallback)))
+
+ isv_nonterminal_reduce Directive $pos $mrk
+ inc_save Directive $pos
+ ias_pop2mark $mrk
+ if {$ok} ias_push
+ ier_nonterminal Directive $pos
+ return
+}
+
+proc ::page::parse::lemon::eseq15 {} {
+
+ # (x (n DINTRO)
+ # (/ (n Code)
+ # (n DefaultDestructor)
+ # (n DefaultType)
+ # (n Destructor)
+ # (n ExtraArgument)
+ # (n Include)
+ # (n Left)
+ # (n Name)
+ # (n Nonassoc)
+ # (n ParseAccept)
+ # (n ParseFailure)
+ # (n Right)
+ # (n StackOverflow)
+ # (n Stacksize)
+ # (n StartSymbol)
+ # (n SyntaxError)
+ # (n TokenDestructor)
+ # (n TokenPrefix)
+ # (n TokenType)
+ # (n Type)
+ # (n Fallback)))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set old [ier_get]
+ matchSymbol_DINTRO ; # (n DINTRO)
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set mrk [ias_mark]
+
+ set old [ier_get]
+ ebra14 ; # (/ (n Code)
+ # (n DefaultDestructor)
+ # (n DefaultType)
+ # (n Destructor)
+ # (n ExtraArgument)
+ # (n Include)
+ # (n Left)
+ # (n Name)
+ # (n Nonassoc)
+ # (n ParseAccept)
+ # (n ParseFailure)
+ # (n Right)
+ # (n StackOverflow)
+ # (n Stacksize)
+ # (n StartSymbol)
+ # (n SyntaxError)
+ # (n TokenDestructor)
+ # (n TokenPrefix)
+ # (n TokenType)
+ # (n Type)
+ # (n Fallback))
+ ier_merge $old
+
+ if {!$ok} {
+ ias_pop2mark $mrk
+ icl_rewind $pos
+ return
+ }
+
+ return
+}
+
+proc ::page::parse::lemon::ebra14 {} {
+
+ # (/ (n Code)
+ # (n DefaultDestructor)
+ # (n DefaultType)
+ # (n Destructor)
+ # (n ExtraArgument)
+ # (n Include)
+ # (n Left)
+ # (n Name)
+ # (n Nonassoc)
+ # (n ParseAccept)
+ # (n ParseFailure)
+ # (n Right)
+ # (n StackOverflow)
+ # (n Stacksize)
+ # (n StartSymbol)
+ # (n SyntaxError)
+ # (n TokenDestructor)
+ # (n TokenPrefix)
+ # (n TokenType)
+ # (n Type)
+ # (n Fallback))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set mrk [ias_mark]
+ set old [ier_get]
+ matchSymbol_Code ; # (n Code)
+ ier_merge $old
+
+ if {$ok} return
+ ias_pop2mark $mrk
+ icl_rewind $pos
+
+ set mrk [ias_mark]
+ set old [ier_get]
+ matchSymbol_DefaultDestructor ; # (n DefaultDestructor)
+ ier_merge $old
+
+ if {$ok} return
+ ias_pop2mark $mrk
+ icl_rewind $pos
+
+ set mrk [ias_mark]
+ set old [ier_get]
+ matchSymbol_DefaultType ; # (n DefaultType)
+ ier_merge $old
+
+ if {$ok} return
+ ias_pop2mark $mrk
+ icl_rewind $pos
+
+ set mrk [ias_mark]
+ set old [ier_get]
+ matchSymbol_Destructor ; # (n Destructor)
+ ier_merge $old
+
+ if {$ok} return
+ ias_pop2mark $mrk
+ icl_rewind $pos
+
+ set mrk [ias_mark]
+ set old [ier_get]
+ matchSymbol_ExtraArgument ; # (n ExtraArgument)
+ ier_merge $old
+
+ if {$ok} return
+ ias_pop2mark $mrk
+ icl_rewind $pos
+
+ set mrk [ias_mark]
+ set old [ier_get]
+ matchSymbol_Include ; # (n Include)
+ ier_merge $old
+
+ if {$ok} return
+ ias_pop2mark $mrk
+ icl_rewind $pos
+
+ set mrk [ias_mark]
+ set old [ier_get]
+ matchSymbol_Left ; # (n Left)
+ ier_merge $old
+
+ if {$ok} return
+ ias_pop2mark $mrk
+ icl_rewind $pos
+
+ set mrk [ias_mark]
+ set old [ier_get]
+ matchSymbol_Name ; # (n Name)
+ ier_merge $old
+
+ if {$ok} return
+ ias_pop2mark $mrk
+ icl_rewind $pos
+
+ set mrk [ias_mark]
+ set old [ier_get]
+ matchSymbol_Nonassoc ; # (n Nonassoc)
+ ier_merge $old
+
+ if {$ok} return
+ ias_pop2mark $mrk
+ icl_rewind $pos
+
+ set mrk [ias_mark]
+ set old [ier_get]
+ matchSymbol_ParseAccept ; # (n ParseAccept)
+ ier_merge $old
+
+ if {$ok} return
+ ias_pop2mark $mrk
+ icl_rewind $pos
+
+ set mrk [ias_mark]
+ set old [ier_get]
+ matchSymbol_ParseFailure ; # (n ParseFailure)
+ ier_merge $old
+
+ if {$ok} return
+ ias_pop2mark $mrk
+ icl_rewind $pos
+
+ set mrk [ias_mark]
+ set old [ier_get]
+ matchSymbol_Right ; # (n Right)
+ ier_merge $old
+
+ if {$ok} return
+ ias_pop2mark $mrk
+ icl_rewind $pos
+
+ set mrk [ias_mark]
+ set old [ier_get]
+ matchSymbol_StackOverflow ; # (n StackOverflow)
+ ier_merge $old
+
+ if {$ok} return
+ ias_pop2mark $mrk
+ icl_rewind $pos
+
+ set mrk [ias_mark]
+ set old [ier_get]
+ matchSymbol_Stacksize ; # (n Stacksize)
+ ier_merge $old
+
+ if {$ok} return
+ ias_pop2mark $mrk
+ icl_rewind $pos
+
+ set mrk [ias_mark]
+ set old [ier_get]
+ matchSymbol_StartSymbol ; # (n StartSymbol)
+ ier_merge $old
+
+ if {$ok} return
+ ias_pop2mark $mrk
+ icl_rewind $pos
+
+ set mrk [ias_mark]
+ set old [ier_get]
+ matchSymbol_SyntaxError ; # (n SyntaxError)
+ ier_merge $old
+
+ if {$ok} return
+ ias_pop2mark $mrk
+ icl_rewind $pos
+
+ set mrk [ias_mark]
+ set old [ier_get]
+ matchSymbol_TokenDestructor ; # (n TokenDestructor)
+ ier_merge $old
+
+ if {$ok} return
+ ias_pop2mark $mrk
+ icl_rewind $pos
+
+ set mrk [ias_mark]
+ set old [ier_get]
+ matchSymbol_TokenPrefix ; # (n TokenPrefix)
+ ier_merge $old
+
+ if {$ok} return
+ ias_pop2mark $mrk
+ icl_rewind $pos
+
+ set mrk [ias_mark]
+ set old [ier_get]
+ matchSymbol_TokenType ; # (n TokenType)
+ ier_merge $old
+
+ if {$ok} return
+ ias_pop2mark $mrk
+ icl_rewind $pos
+
+ set mrk [ias_mark]
+ set old [ier_get]
+ matchSymbol_Type ; # (n Type)
+ ier_merge $old
+
+ if {$ok} return
+ ias_pop2mark $mrk
+ icl_rewind $pos
+
+ set mrk [ias_mark]
+ set old [ier_get]
+ matchSymbol_Fallback ; # (n Fallback)
+ ier_merge $old
+
+ if {$ok} return
+ ias_pop2mark $mrk
+ icl_rewind $pos
+
+ return
+}
+
+proc ::page::parse::lemon::matchSymbol_DLEFT {} {
+ # DLEFT = (x (t l)
+ # (t e)
+ # (t f)
+ # (t t)
+ # (n SPACE))
+
+ if {[inc_restore DLEFT]} return
+
+ set pos [icl_get]
+
+ eseq65 ; # (x (t l)
+ # (t e)
+ # (t f)
+ # (t t)
+ # (n SPACE))
+
+ isv_clear
+ inc_save DLEFT $pos
+ ier_nonterminal DLEFT $pos
+ return
+}
+
+proc ::page::parse::lemon::eseq65 {} {
+
+ # (x (t l)
+ # (t e)
+ # (t f)
+ # (t t)
+ # (n SPACE))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set old [ier_get]
+ ict_advance l
+ if {$ok} {ict_match_token l}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance e
+ if {$ok} {ict_match_token e}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance f
+ if {$ok} {ict_match_token f}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance t
+ if {$ok} {ict_match_token t}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ matchSymbol_SPACE ; # (n SPACE)
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ return
+}
+
+proc ::page::parse::lemon::matchSymbol_DNAME {} {
+ # DNAME = (x (t n)
+ # (t a)
+ # (t m)
+ # (t e)
+ # (n SPACE))
+
+ if {[inc_restore DNAME]} return
+
+ set pos [icl_get]
+
+ eseq66 ; # (x (t n)
+ # (t a)
+ # (t m)
+ # (t e)
+ # (n SPACE))
+
+ isv_clear
+ inc_save DNAME $pos
+ ier_nonterminal DNAME $pos
+ return
+}
+
+proc ::page::parse::lemon::eseq66 {} {
+
+ # (x (t n)
+ # (t a)
+ # (t m)
+ # (t e)
+ # (n SPACE))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set old [ier_get]
+ ict_advance n
+ if {$ok} {ict_match_token n}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance a
+ if {$ok} {ict_match_token a}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance m
+ if {$ok} {ict_match_token m}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance e
+ if {$ok} {ict_match_token e}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ matchSymbol_SPACE ; # (n SPACE)
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ return
+}
+
+proc ::page::parse::lemon::matchSymbol_DNON {} {
+ # DNON = (x (t n)
+ # (t o)
+ # (t n)
+ # (t a)
+ # (t s)
+ # (t s)
+ # (t o)
+ # (t c)
+ # (n SPACE))
+
+ if {[inc_restore DNON]} return
+
+ set pos [icl_get]
+
+ eseq67 ; # (x (t n)
+ # (t o)
+ # (t n)
+ # (t a)
+ # (t s)
+ # (t s)
+ # (t o)
+ # (t c)
+ # (n SPACE))
+
+ isv_clear
+ inc_save DNON $pos
+ ier_nonterminal DNON $pos
+ return
+}
+
+proc ::page::parse::lemon::eseq67 {} {
+
+ # (x (t n)
+ # (t o)
+ # (t n)
+ # (t a)
+ # (t s)
+ # (t s)
+ # (t o)
+ # (t c)
+ # (n SPACE))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set old [ier_get]
+ ict_advance n
+ if {$ok} {ict_match_token n}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance o
+ if {$ok} {ict_match_token o}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance n
+ if {$ok} {ict_match_token n}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance a
+ if {$ok} {ict_match_token a}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance s
+ if {$ok} {ict_match_token s}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance s
+ if {$ok} {ict_match_token s}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance o
+ if {$ok} {ict_match_token o}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance c
+ if {$ok} {ict_match_token c}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ matchSymbol_SPACE ; # (n SPACE)
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ return
+}
+
+proc ::page::parse::lemon::matchSymbol_DOT {} {
+ # DOT = (x (t .)
+ # (n SPACE))
+
+ if {[inc_restore DOT]} return
+
+ set pos [icl_get]
+
+ eseq54 ; # (x (t .)
+ # (n SPACE))
+
+ isv_clear
+ inc_save DOT $pos
+ ier_nonterminal DOT $pos
+ return
+}
+
+proc ::page::parse::lemon::eseq54 {} {
+
+ # (x (t .)
+ # (n SPACE))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set old [ier_get]
+ ict_advance .
+ if {$ok} {ict_match_token .}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ matchSymbol_SPACE ; # (n SPACE)
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ return
+}
+
+proc ::page::parse::lemon::matchSymbol_DPACC {} {
+ # DPACC = (x (t p)
+ # (t a)
+ # (t r)
+ # (t s)
+ # (t e)
+ # (t _)
+ # (t a)
+ # (t c)
+ # (t c)
+ # (t e)
+ # (t p)
+ # (t t)
+ # (n SPACE))
+
+ if {[inc_restore DPACC]} return
+
+ set pos [icl_get]
+
+ eseq68 ; # (x (t p)
+ # (t a)
+ # (t r)
+ # (t s)
+ # (t e)
+ # (t _)
+ # (t a)
+ # (t c)
+ # (t c)
+ # (t e)
+ # (t p)
+ # (t t)
+ # (n SPACE))
+
+ isv_clear
+ inc_save DPACC $pos
+ ier_nonterminal DPACC $pos
+ return
+}
+
+proc ::page::parse::lemon::eseq68 {} {
+
+ # (x (t p)
+ # (t a)
+ # (t r)
+ # (t s)
+ # (t e)
+ # (t _)
+ # (t a)
+ # (t c)
+ # (t c)
+ # (t e)
+ # (t p)
+ # (t t)
+ # (n SPACE))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set old [ier_get]
+ ict_advance p
+ if {$ok} {ict_match_token p}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance a
+ if {$ok} {ict_match_token a}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance r
+ if {$ok} {ict_match_token r}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance s
+ if {$ok} {ict_match_token s}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance e
+ if {$ok} {ict_match_token e}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance _
+ if {$ok} {ict_match_token _}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance a
+ if {$ok} {ict_match_token a}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance c
+ if {$ok} {ict_match_token c}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance c
+ if {$ok} {ict_match_token c}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance e
+ if {$ok} {ict_match_token e}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance p
+ if {$ok} {ict_match_token p}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance t
+ if {$ok} {ict_match_token t}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ matchSymbol_SPACE ; # (n SPACE)
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ return
+}
+
+proc ::page::parse::lemon::matchSymbol_DPFAIL {} {
+ # DPFAIL = (x (t p)
+ # (t a)
+ # (t r)
+ # (t s)
+ # (t e)
+ # (t _)
+ # (t f)
+ # (t a)
+ # (t i)
+ # (t l)
+ # (t u)
+ # (t r)
+ # (t e)
+ # (n SPACE))
+
+ if {[inc_restore DPFAIL]} return
+
+ set pos [icl_get]
+
+ eseq69 ; # (x (t p)
+ # (t a)
+ # (t r)
+ # (t s)
+ # (t e)
+ # (t _)
+ # (t f)
+ # (t a)
+ # (t i)
+ # (t l)
+ # (t u)
+ # (t r)
+ # (t e)
+ # (n SPACE))
+
+ isv_clear
+ inc_save DPFAIL $pos
+ ier_nonterminal DPFAIL $pos
+ return
+}
+
+proc ::page::parse::lemon::eseq69 {} {
+
+ # (x (t p)
+ # (t a)
+ # (t r)
+ # (t s)
+ # (t e)
+ # (t _)
+ # (t f)
+ # (t a)
+ # (t i)
+ # (t l)
+ # (t u)
+ # (t r)
+ # (t e)
+ # (n SPACE))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set old [ier_get]
+ ict_advance p
+ if {$ok} {ict_match_token p}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance a
+ if {$ok} {ict_match_token a}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance r
+ if {$ok} {ict_match_token r}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance s
+ if {$ok} {ict_match_token s}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance e
+ if {$ok} {ict_match_token e}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance _
+ if {$ok} {ict_match_token _}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance f
+ if {$ok} {ict_match_token f}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance a
+ if {$ok} {ict_match_token a}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance i
+ if {$ok} {ict_match_token i}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance l
+ if {$ok} {ict_match_token l}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance u
+ if {$ok} {ict_match_token u}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance r
+ if {$ok} {ict_match_token r}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance e
+ if {$ok} {ict_match_token e}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ matchSymbol_SPACE ; # (n SPACE)
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ return
+}
+
+proc ::page::parse::lemon::matchSymbol_DRIGHT {} {
+ # DRIGHT = (x (t r)
+ # (t i)
+ # (t g)
+ # (t h)
+ # (t t)
+ # (n SPACE))
+
+ if {[inc_restore DRIGHT]} return
+
+ set pos [icl_get]
+
+ eseq70 ; # (x (t r)
+ # (t i)
+ # (t g)
+ # (t h)
+ # (t t)
+ # (n SPACE))
+
+ isv_clear
+ inc_save DRIGHT $pos
+ ier_nonterminal DRIGHT $pos
+ return
+}
+
+proc ::page::parse::lemon::eseq70 {} {
+
+ # (x (t r)
+ # (t i)
+ # (t g)
+ # (t h)
+ # (t t)
+ # (n SPACE))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set old [ier_get]
+ ict_advance r
+ if {$ok} {ict_match_token r}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance i
+ if {$ok} {ict_match_token i}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance g
+ if {$ok} {ict_match_token g}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance h
+ if {$ok} {ict_match_token h}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance t
+ if {$ok} {ict_match_token t}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ matchSymbol_SPACE ; # (n SPACE)
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ return
+}
+
+proc ::page::parse::lemon::matchSymbol_DSTART {} {
+ # DSTART = (x (t s)
+ # (t t)
+ # (t a)
+ # (t r)
+ # (t t)
+ # (t _)
+ # (t s)
+ # (t y)
+ # (t m)
+ # (t b)
+ # (t o)
+ # (t l)
+ # (n SPACE))
+
+ if {[inc_restore DSTART]} return
+
+ set pos [icl_get]
+
+ eseq73 ; # (x (t s)
+ # (t t)
+ # (t a)
+ # (t r)
+ # (t t)
+ # (t _)
+ # (t s)
+ # (t y)
+ # (t m)
+ # (t b)
+ # (t o)
+ # (t l)
+ # (n SPACE))
+
+ isv_clear
+ inc_save DSTART $pos
+ ier_nonterminal DSTART $pos
+ return
+}
+
+proc ::page::parse::lemon::eseq73 {} {
+
+ # (x (t s)
+ # (t t)
+ # (t a)
+ # (t r)
+ # (t t)
+ # (t _)
+ # (t s)
+ # (t y)
+ # (t m)
+ # (t b)
+ # (t o)
+ # (t l)
+ # (n SPACE))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set old [ier_get]
+ ict_advance s
+ if {$ok} {ict_match_token s}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance t
+ if {$ok} {ict_match_token t}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance a
+ if {$ok} {ict_match_token a}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance r
+ if {$ok} {ict_match_token r}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance t
+ if {$ok} {ict_match_token t}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance _
+ if {$ok} {ict_match_token _}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance s
+ if {$ok} {ict_match_token s}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance y
+ if {$ok} {ict_match_token y}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance m
+ if {$ok} {ict_match_token m}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance b
+ if {$ok} {ict_match_token b}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance o
+ if {$ok} {ict_match_token o}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance l
+ if {$ok} {ict_match_token l}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ matchSymbol_SPACE ; # (n SPACE)
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ return
+}
+
+proc ::page::parse::lemon::matchSymbol_DSTKOVER {} {
+ # DSTKOVER = (x (t s)
+ # (t t)
+ # (t a)
+ # (t c)
+ # (t k)
+ # (t _)
+ # (t o)
+ # (t v)
+ # (t e)
+ # (t r)
+ # (t f)
+ # (t l)
+ # (t o)
+ # (t w)
+ # (n SPACE))
+
+ if {[inc_restore DSTKOVER]} return
+
+ set pos [icl_get]
+
+ eseq71 ; # (x (t s)
+ # (t t)
+ # (t a)
+ # (t c)
+ # (t k)
+ # (t _)
+ # (t o)
+ # (t v)
+ # (t e)
+ # (t r)
+ # (t f)
+ # (t l)
+ # (t o)
+ # (t w)
+ # (n SPACE))
+
+ isv_clear
+ inc_save DSTKOVER $pos
+ ier_nonterminal DSTKOVER $pos
+ return
+}
+
+proc ::page::parse::lemon::eseq71 {} {
+
+ # (x (t s)
+ # (t t)
+ # (t a)
+ # (t c)
+ # (t k)
+ # (t _)
+ # (t o)
+ # (t v)
+ # (t e)
+ # (t r)
+ # (t f)
+ # (t l)
+ # (t o)
+ # (t w)
+ # (n SPACE))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set old [ier_get]
+ ict_advance s
+ if {$ok} {ict_match_token s}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance t
+ if {$ok} {ict_match_token t}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance a
+ if {$ok} {ict_match_token a}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance c
+ if {$ok} {ict_match_token c}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance k
+ if {$ok} {ict_match_token k}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance _
+ if {$ok} {ict_match_token _}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance o
+ if {$ok} {ict_match_token o}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance v
+ if {$ok} {ict_match_token v}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance e
+ if {$ok} {ict_match_token e}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance r
+ if {$ok} {ict_match_token r}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance f
+ if {$ok} {ict_match_token f}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance l
+ if {$ok} {ict_match_token l}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance o
+ if {$ok} {ict_match_token o}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance w
+ if {$ok} {ict_match_token w}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ matchSymbol_SPACE ; # (n SPACE)
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ return
+}
+
+proc ::page::parse::lemon::matchSymbol_DSTKSZ {} {
+ # DSTKSZ = (x (t s)
+ # (t t)
+ # (t a)
+ # (t c)
+ # (t k)
+ # (t _)
+ # (t s)
+ # (t i)
+ # (t z)
+ # (t e)
+ # (n SPACE))
+
+ if {[inc_restore DSTKSZ]} return
+
+ set pos [icl_get]
+
+ eseq72 ; # (x (t s)
+ # (t t)
+ # (t a)
+ # (t c)
+ # (t k)
+ # (t _)
+ # (t s)
+ # (t i)
+ # (t z)
+ # (t e)
+ # (n SPACE))
+
+ isv_clear
+ inc_save DSTKSZ $pos
+ ier_nonterminal DSTKSZ $pos
+ return
+}
+
+proc ::page::parse::lemon::eseq72 {} {
+
+ # (x (t s)
+ # (t t)
+ # (t a)
+ # (t c)
+ # (t k)
+ # (t _)
+ # (t s)
+ # (t i)
+ # (t z)
+ # (t e)
+ # (n SPACE))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set old [ier_get]
+ ict_advance s
+ if {$ok} {ict_match_token s}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance t
+ if {$ok} {ict_match_token t}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance a
+ if {$ok} {ict_match_token a}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance c
+ if {$ok} {ict_match_token c}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance k
+ if {$ok} {ict_match_token k}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance _
+ if {$ok} {ict_match_token _}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance s
+ if {$ok} {ict_match_token s}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance i
+ if {$ok} {ict_match_token i}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance z
+ if {$ok} {ict_match_token z}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance e
+ if {$ok} {ict_match_token e}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ matchSymbol_SPACE ; # (n SPACE)
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ return
+}
+
+proc ::page::parse::lemon::matchSymbol_DSYNERR {} {
+ # DSYNERR = (x (t s)
+ # (t y)
+ # (t n)
+ # (t t)
+ # (t a)
+ # (t x)
+ # (t _)
+ # (t e)
+ # (t r)
+ # (t r)
+ # (t o)
+ # (t r)
+ # (n SPACE))
+
+ if {[inc_restore DSYNERR]} return
+
+ set pos [icl_get]
+
+ eseq74 ; # (x (t s)
+ # (t y)
+ # (t n)
+ # (t t)
+ # (t a)
+ # (t x)
+ # (t _)
+ # (t e)
+ # (t r)
+ # (t r)
+ # (t o)
+ # (t r)
+ # (n SPACE))
+
+ isv_clear
+ inc_save DSYNERR $pos
+ ier_nonterminal DSYNERR $pos
+ return
+}
+
+proc ::page::parse::lemon::eseq74 {} {
+
+ # (x (t s)
+ # (t y)
+ # (t n)
+ # (t t)
+ # (t a)
+ # (t x)
+ # (t _)
+ # (t e)
+ # (t r)
+ # (t r)
+ # (t o)
+ # (t r)
+ # (n SPACE))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set old [ier_get]
+ ict_advance s
+ if {$ok} {ict_match_token s}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance y
+ if {$ok} {ict_match_token y}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance n
+ if {$ok} {ict_match_token n}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance t
+ if {$ok} {ict_match_token t}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance a
+ if {$ok} {ict_match_token a}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance x
+ if {$ok} {ict_match_token x}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance _
+ if {$ok} {ict_match_token _}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance e
+ if {$ok} {ict_match_token e}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance r
+ if {$ok} {ict_match_token r}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance r
+ if {$ok} {ict_match_token r}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance o
+ if {$ok} {ict_match_token o}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance r
+ if {$ok} {ict_match_token r}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ matchSymbol_SPACE ; # (n SPACE)
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ return
+}
+
+proc ::page::parse::lemon::matchSymbol_DTOKDEST {} {
+ # DTOKDEST = (x (t t)
+ # (t o)
+ # (t k)
+ # (t e)
+ # (t n)
+ # (t _)
+ # (t d)
+ # (t e)
+ # (t s)
+ # (t t)
+ # (t r)
+ # (t u)
+ # (t c)
+ # (t t)
+ # (t o)
+ # (t r)
+ # (n SPACE))
+
+ if {[inc_restore DTOKDEST]} return
+
+ set pos [icl_get]
+
+ eseq75 ; # (x (t t)
+ # (t o)
+ # (t k)
+ # (t e)
+ # (t n)
+ # (t _)
+ # (t d)
+ # (t e)
+ # (t s)
+ # (t t)
+ # (t r)
+ # (t u)
+ # (t c)
+ # (t t)
+ # (t o)
+ # (t r)
+ # (n SPACE))
+
+ isv_clear
+ inc_save DTOKDEST $pos
+ ier_nonterminal DTOKDEST $pos
+ return
+}
+
+proc ::page::parse::lemon::eseq75 {} {
+
+ # (x (t t)
+ # (t o)
+ # (t k)
+ # (t e)
+ # (t n)
+ # (t _)
+ # (t d)
+ # (t e)
+ # (t s)
+ # (t t)
+ # (t r)
+ # (t u)
+ # (t c)
+ # (t t)
+ # (t o)
+ # (t r)
+ # (n SPACE))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set old [ier_get]
+ ict_advance t
+ if {$ok} {ict_match_token t}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance o
+ if {$ok} {ict_match_token o}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance k
+ if {$ok} {ict_match_token k}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance e
+ if {$ok} {ict_match_token e}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance n
+ if {$ok} {ict_match_token n}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance _
+ if {$ok} {ict_match_token _}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance d
+ if {$ok} {ict_match_token d}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance e
+ if {$ok} {ict_match_token e}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance s
+ if {$ok} {ict_match_token s}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance t
+ if {$ok} {ict_match_token t}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance r
+ if {$ok} {ict_match_token r}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance u
+ if {$ok} {ict_match_token u}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance c
+ if {$ok} {ict_match_token c}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance t
+ if {$ok} {ict_match_token t}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance o
+ if {$ok} {ict_match_token o}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance r
+ if {$ok} {ict_match_token r}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ matchSymbol_SPACE ; # (n SPACE)
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ return
+}
+
+proc ::page::parse::lemon::matchSymbol_DTOKPFX {} {
+ # DTOKPFX = (x (t t)
+ # (t o)
+ # (t k)
+ # (t e)
+ # (t n)
+ # (t _)
+ # (t p)
+ # (t r)
+ # (t e)
+ # (t f)
+ # (t i)
+ # (t x)
+ # (n SPACE))
+
+ if {[inc_restore DTOKPFX]} return
+
+ set pos [icl_get]
+
+ eseq76 ; # (x (t t)
+ # (t o)
+ # (t k)
+ # (t e)
+ # (t n)
+ # (t _)
+ # (t p)
+ # (t r)
+ # (t e)
+ # (t f)
+ # (t i)
+ # (t x)
+ # (n SPACE))
+
+ isv_clear
+ inc_save DTOKPFX $pos
+ ier_nonterminal DTOKPFX $pos
+ return
+}
+
+proc ::page::parse::lemon::eseq76 {} {
+
+ # (x (t t)
+ # (t o)
+ # (t k)
+ # (t e)
+ # (t n)
+ # (t _)
+ # (t p)
+ # (t r)
+ # (t e)
+ # (t f)
+ # (t i)
+ # (t x)
+ # (n SPACE))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set old [ier_get]
+ ict_advance t
+ if {$ok} {ict_match_token t}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance o
+ if {$ok} {ict_match_token o}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance k
+ if {$ok} {ict_match_token k}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance e
+ if {$ok} {ict_match_token e}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance n
+ if {$ok} {ict_match_token n}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance _
+ if {$ok} {ict_match_token _}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance p
+ if {$ok} {ict_match_token p}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance r
+ if {$ok} {ict_match_token r}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance e
+ if {$ok} {ict_match_token e}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance f
+ if {$ok} {ict_match_token f}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance i
+ if {$ok} {ict_match_token i}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance x
+ if {$ok} {ict_match_token x}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ matchSymbol_SPACE ; # (n SPACE)
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ return
+}
+
+proc ::page::parse::lemon::matchSymbol_DTOKTYPE {} {
+ # DTOKTYPE = (x (t t)
+ # (t o)
+ # (t k)
+ # (t e)
+ # (t n)
+ # (t _)
+ # (t t)
+ # (t y)
+ # (t p)
+ # (t e)
+ # (n SPACE))
+
+ if {[inc_restore DTOKTYPE]} return
+
+ set pos [icl_get]
+
+ eseq77 ; # (x (t t)
+ # (t o)
+ # (t k)
+ # (t e)
+ # (t n)
+ # (t _)
+ # (t t)
+ # (t y)
+ # (t p)
+ # (t e)
+ # (n SPACE))
+
+ isv_clear
+ inc_save DTOKTYPE $pos
+ ier_nonterminal DTOKTYPE $pos
+ return
+}
+
+proc ::page::parse::lemon::eseq77 {} {
+
+ # (x (t t)
+ # (t o)
+ # (t k)
+ # (t e)
+ # (t n)
+ # (t _)
+ # (t t)
+ # (t y)
+ # (t p)
+ # (t e)
+ # (n SPACE))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set old [ier_get]
+ ict_advance t
+ if {$ok} {ict_match_token t}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance o
+ if {$ok} {ict_match_token o}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance k
+ if {$ok} {ict_match_token k}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance e
+ if {$ok} {ict_match_token e}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance n
+ if {$ok} {ict_match_token n}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance _
+ if {$ok} {ict_match_token _}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance t
+ if {$ok} {ict_match_token t}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance y
+ if {$ok} {ict_match_token y}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance p
+ if {$ok} {ict_match_token p}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance e
+ if {$ok} {ict_match_token e}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ matchSymbol_SPACE ; # (n SPACE)
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ return
+}
+
+proc ::page::parse::lemon::matchSymbol_DTYPE {} {
+ # DTYPE = (x (t t)
+ # (t y)
+ # (t p)
+ # (t e)
+ # (n SPACE))
+
+ if {[inc_restore DTYPE]} return
+
+ set pos [icl_get]
+
+ eseq78 ; # (x (t t)
+ # (t y)
+ # (t p)
+ # (t e)
+ # (n SPACE))
+
+ isv_clear
+ inc_save DTYPE $pos
+ ier_nonterminal DTYPE $pos
+ return
+}
+
+proc ::page::parse::lemon::eseq78 {} {
+
+ # (x (t t)
+ # (t y)
+ # (t p)
+ # (t e)
+ # (n SPACE))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set old [ier_get]
+ ict_advance t
+ if {$ok} {ict_match_token t}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance y
+ if {$ok} {ict_match_token y}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance p
+ if {$ok} {ict_match_token p}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance e
+ if {$ok} {ict_match_token e}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ matchSymbol_SPACE ; # (n SPACE)
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ return
+}
+
+proc ::page::parse::lemon::matchSymbol_Endif {} {
+ # Endif = (n DENDIF)
+
+ if {[inc_restore Endif]} return
+
+ set pos [icl_get]
+
+ matchSymbol_DENDIF ; # (n DENDIF)
+
+ isv_clear
+ inc_save Endif $pos
+ ier_nonterminal Endif $pos
+ return
+}
+
+proc ::page::parse::lemon::matchSymbol_EOF {} {
+ # EOF = (! (dot))
+
+ if {[inc_restore EOF]} return
+
+ set pos [icl_get]
+
+ ebang99
+
+ isv_clear
+ inc_save EOF $pos
+ ier_nonterminal EOF $pos
+ return
+}
+
+proc ::page::parse::lemon::ebang99 {} {
+ set pos [icl_get]
+
+ ict_advance "any character"
+
+ icl_rewind $pos
+ iok_negate
+ return
+}
+
+proc ::page::parse::lemon::matchSymbol_EOL {} {
+ # EOL = (/ (x (t \r)
+ # (t \n))
+ # (t \r)
+ # (t \n))
+
+ if {[inc_restore EOL]} return
+
+ set pos [icl_get]
+
+ ebra98 ; # (/ (x (t \r)
+ # (t \n))
+ # (t \r)
+ # (t \n))
+
+ isv_clear
+ inc_save EOL $pos
+ ier_nonterminal EOL $pos
+ return
+}
+
+proc ::page::parse::lemon::ebra98 {} {
+
+ # (/ (x (t \r)
+ # (t \n))
+ # (t \r)
+ # (t \n))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set old [ier_get]
+ eseq97 ; # (x (t \r)
+ # (t \n))
+ ier_merge $old
+
+ if {$ok} return
+ icl_rewind $pos
+
+ set old [ier_get]
+ ict_advance \\r
+ if {$ok} {ict_match_token \r}
+ ier_merge $old
+
+ if {$ok} return
+ icl_rewind $pos
+
+ set old [ier_get]
+ ict_advance \\n
+ if {$ok} {ict_match_token \n}
+ ier_merge $old
+
+ if {$ok} return
+ icl_rewind $pos
+
+ return
+}
+
+proc ::page::parse::lemon::eseq97 {} {
+
+ # (x (t \r)
+ # (t \n))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set old [ier_get]
+ ict_advance \\r
+ if {$ok} {ict_match_token \r}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance \\n
+ if {$ok} {ict_match_token \n}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ return
+}
+
+proc ::page::parse::lemon::matchSymbol_ExtraArgument {} {
+ # ExtraArgument = (x (n DEXTRA)
+ # (n Codeblock))
+
+ variable ok
+ if {[inc_restore ExtraArgument]} {
+ if {$ok} ias_push
+ return
+ }
+
+ set pos [icl_get]
+ set mrk [ias_mark]
+
+ eseq20 ; # (x (n DEXTRA)
+ # (n Codeblock))
+
+ isv_nonterminal_reduce ExtraArgument $pos $mrk
+ inc_save ExtraArgument $pos
+ ias_pop2mark $mrk
+ if {$ok} ias_push
+ ier_nonterminal ExtraArgument $pos
+ return
+}
+
+proc ::page::parse::lemon::eseq20 {} {
+
+ # (x (n DEXTRA)
+ # (n Codeblock))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set old [ier_get]
+ matchSymbol_DEXTRA ; # (n DEXTRA)
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set mrk [ias_mark]
+
+ set old [ier_get]
+ matchSymbol_Codeblock ; # (n Codeblock)
+ ier_merge $old
+
+ if {!$ok} {
+ ias_pop2mark $mrk
+ icl_rewind $pos
+ return
+ }
+
+ return
+}
+
+proc ::page::parse::lemon::matchSymbol_Fallback {} {
+ # Fallback = (x (n DFALLBK)
+ # (+ (n Identifier))
+ # (n DOT))
+
+ variable ok
+ if {[inc_restore Fallback]} {
+ if {$ok} ias_push
+ return
+ }
+
+ set pos [icl_get]
+ set mrk [ias_mark]
+
+ eseq40 ; # (x (n DFALLBK)
+ # (+ (n Identifier))
+ # (n DOT))
+
+ isv_nonterminal_reduce Fallback $pos $mrk
+ inc_save Fallback $pos
+ ias_pop2mark $mrk
+ if {$ok} ias_push
+ ier_nonterminal Fallback $pos
+ return
+}
+
+proc ::page::parse::lemon::eseq40 {} {
+
+ # (x (n DFALLBK)
+ # (+ (n Identifier))
+ # (n DOT))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set old [ier_get]
+ matchSymbol_DFALLBK ; # (n DFALLBK)
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set mrk [ias_mark]
+
+ set old [ier_get]
+ epkleene39 ; # (+ (n Identifier))
+ ier_merge $old
+
+ if {!$ok} {
+ ias_pop2mark $mrk
+ icl_rewind $pos
+ return
+ }
+
+ set old [ier_get]
+ matchSymbol_DOT ; # (n DOT)
+ ier_merge $old
+
+ if {!$ok} {
+ ias_pop2mark $mrk
+ icl_rewind $pos
+ return
+ }
+
+ return
+}
+
+proc ::page::parse::lemon::epkleene39 {} {
+
+ # (+ (n Identifier))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set old [ier_get]
+ matchSymbol_Identifier ; # (n Identifier)
+ ier_merge $old
+
+ if {!$ok} {
+ icl_rewind $pos
+ return
+ }
+
+ while {1} {
+ set pos [icl_get]
+
+ set old [ier_get]
+ matchSymbol_Identifier ; # (n Identifier)
+ ier_merge $old
+
+ if {$ok} continue
+ break
+ }
+
+ icl_rewind $pos
+ iok_ok
+ return
+}
+
+proc ::page::parse::lemon::matchSymbol_Ident {} {
+ # Ident = (x (/ (alpha)
+ # (t _))
+ # (* (/ (alnum)
+ # (t _))))
+
+ variable ok
+ if {[inc_restore Ident]} {
+ if {$ok} ias_push
+ return
+ }
+
+ set pos [icl_get]
+
+ eseq50 ; # (x (/ (alpha)
+ # (t _))
+ # (* (/ (alnum)
+ # (t _))))
+
+ isv_nonterminal_range Ident $pos
+ inc_save Ident $pos
+ if {$ok} ias_push
+ ier_nonterminal Ident $pos
+ return
+}
+
+proc ::page::parse::lemon::eseq50 {} {
+
+ # (x (/ (alpha)
+ # (t _))
+ # (* (/ (alnum)
+ # (t _))))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set old [ier_get]
+ ebra47 ; # (/ (alpha)
+ # (t _))
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ekleene49 ; # (* (/ (alnum)
+ # (t _)))
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ return
+}
+
+proc ::page::parse::lemon::ebra47 {} {
+
+ # (/ (alpha)
+ # (t _))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set old [ier_get]
+ ict_advance alpha
+ if {$ok} {ict_match_tokclass alpha}
+ ier_merge $old
+
+ if {$ok} return
+ icl_rewind $pos
+
+ set old [ier_get]
+ ict_advance _
+ if {$ok} {ict_match_token _}
+ ier_merge $old
+
+ if {$ok} return
+ icl_rewind $pos
+
+ return
+}
+
+proc ::page::parse::lemon::ekleene49 {} {
+
+ # (* (/ (alnum)
+ # (t _)))
+
+ variable ok
+
+ while {1} {
+ set pos [icl_get]
+
+ set old [ier_get]
+ ebra48 ; # (/ (alnum)
+ # (t _))
+ ier_merge $old
+
+ if {$ok} continue
+ break
+ }
+
+ icl_rewind $pos
+ iok_ok
+ return
+}
+
+proc ::page::parse::lemon::ebra48 {} {
+
+ # (/ (alnum)
+ # (t _))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set old [ier_get]
+ ict_advance alnum
+ if {$ok} {ict_match_tokclass alnum}
+ ier_merge $old
+
+ if {$ok} return
+ icl_rewind $pos
+
+ set old [ier_get]
+ ict_advance _
+ if {$ok} {ict_match_token _}
+ ier_merge $old
+
+ if {$ok} return
+ icl_rewind $pos
+
+ return
+}
+
+proc ::page::parse::lemon::matchSymbol_Identifier {} {
+ # Identifier = (x (n Ident)
+ # (n SPACE))
+
+ variable ok
+ if {[inc_restore Identifier]} {
+ if {$ok} ias_push
+ return
+ }
+
+ set pos [icl_get]
+ set mrk [ias_mark]
+
+ eseq46 ; # (x (n Ident)
+ # (n SPACE))
+
+ isv_nonterminal_reduce Identifier $pos $mrk
+ inc_save Identifier $pos
+ ias_pop2mark $mrk
+ if {$ok} ias_push
+ ier_nonterminal Identifier $pos
+ return
+}
+
+proc ::page::parse::lemon::eseq46 {} {
+
+ # (x (n Ident)
+ # (n SPACE))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set mrk [ias_mark]
+
+ set old [ier_get]
+ matchSymbol_Ident ; # (n Ident)
+ ier_merge $old
+
+ if {!$ok} {
+ ias_pop2mark $mrk
+ icl_rewind $pos
+ return
+ }
+
+ set old [ier_get]
+ matchSymbol_SPACE ; # (n SPACE)
+ ier_merge $old
+
+ if {!$ok} {
+ ias_pop2mark $mrk
+ icl_rewind $pos
+ return
+ }
+
+ return
+}
+
+proc ::page::parse::lemon::matchSymbol_Ifdef {} {
+ # Ifdef = (x (n DIFDEF)
+ # (n Identifier))
+
+ if {[inc_restore Ifdef]} return
+
+ set pos [icl_get]
+
+ eseq83 ; # (x (n DIFDEF)
+ # (n Identifier))
+
+ isv_clear
+ inc_save Ifdef $pos
+ ier_nonterminal Ifdef $pos
+ return
+}
+
+proc ::page::parse::lemon::eseq83 {} {
+
+ # (x (n DIFDEF)
+ # (n Identifier))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set old [ier_get]
+ matchSymbol_DIFDEF ; # (n DIFDEF)
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ set pIdentifier [ias_mark]
+ matchSymbol_Identifier
+ ias_pop2mark $pIdentifier ; # (n Identifier)
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ return
+}
+
+proc ::page::parse::lemon::matchSymbol_Ifndef {} {
+ # Ifndef = (x (n DIFNDEF)
+ # (n Identifier))
+
+ if {[inc_restore Ifndef]} return
+
+ set pos [icl_get]
+
+ eseq84 ; # (x (n DIFNDEF)
+ # (n Identifier))
+
+ isv_clear
+ inc_save Ifndef $pos
+ ier_nonterminal Ifndef $pos
+ return
+}
+
+proc ::page::parse::lemon::eseq84 {} {
+
+ # (x (n DIFNDEF)
+ # (n Identifier))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set old [ier_get]
+ matchSymbol_DIFNDEF ; # (n DIFNDEF)
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ set pIdentifier [ias_mark]
+ matchSymbol_Identifier
+ ias_pop2mark $pIdentifier ; # (n Identifier)
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ return
+}
+
+proc ::page::parse::lemon::matchSymbol_Include {} {
+ # Include = (x (n DINCL)
+ # (n Codeblock))
+
+ variable ok
+ if {[inc_restore Include]} {
+ if {$ok} ias_push
+ return
+ }
+
+ set pos [icl_get]
+ set mrk [ias_mark]
+
+ eseq21 ; # (x (n DINCL)
+ # (n Codeblock))
+
+ isv_nonterminal_reduce Include $pos $mrk
+ inc_save Include $pos
+ ias_pop2mark $mrk
+ if {$ok} ias_push
+ ier_nonterminal Include $pos
+ return
+}
+
+proc ::page::parse::lemon::eseq21 {} {
+
+ # (x (n DINCL)
+ # (n Codeblock))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set old [ier_get]
+ matchSymbol_DINCL ; # (n DINCL)
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set mrk [ias_mark]
+
+ set old [ier_get]
+ matchSymbol_Codeblock ; # (n Codeblock)
+ ier_merge $old
+
+ if {!$ok} {
+ ias_pop2mark $mrk
+ icl_rewind $pos
+ return
+ }
+
+ return
+}
+
+proc ::page::parse::lemon::matchSymbol_Label {} {
+ # Label = (x (n LPAREN)
+ # (n Identifier)
+ # (n RPAREN))
+
+ variable ok
+ if {[inc_restore Label]} {
+ if {$ok} ias_push
+ return
+ }
+
+ set pos [icl_get]
+ set mrk [ias_mark]
+
+ eseq12 ; # (x (n LPAREN)
+ # (n Identifier)
+ # (n RPAREN))
+
+ isv_nonterminal_reduce Label $pos $mrk
+ inc_save Label $pos
+ ias_pop2mark $mrk
+ if {$ok} ias_push
+ ier_nonterminal Label $pos
+ return
+}
+
+proc ::page::parse::lemon::eseq12 {} {
+
+ # (x (n LPAREN)
+ # (n Identifier)
+ # (n RPAREN))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set old [ier_get]
+ matchSymbol_LPAREN ; # (n LPAREN)
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set mrk [ias_mark]
+
+ set old [ier_get]
+ matchSymbol_Identifier ; # (n Identifier)
+ ier_merge $old
+
+ if {!$ok} {
+ ias_pop2mark $mrk
+ icl_rewind $pos
+ return
+ }
+
+ set old [ier_get]
+ matchSymbol_RPAREN ; # (n RPAREN)
+ ier_merge $old
+
+ if {!$ok} {
+ ias_pop2mark $mrk
+ icl_rewind $pos
+ return
+ }
+
+ return
+}
+
+proc ::page::parse::lemon::matchSymbol_LBRACE {} {
+ # LBRACE = (t \{)
+
+ variable ok
+ if {[inc_restore LBRACE]} return
+
+ set pos [icl_get]
+
+ ict_advance \{
+ if {$ok} {ict_match_token \173}
+
+ isv_clear
+ inc_save LBRACE $pos
+ ier_nonterminal LBRACE $pos
+ return
+}
+
+proc ::page::parse::lemon::matchSymbol_LBRACKET {} {
+ # LBRACKET = (x (t [)
+ # (n SPACE))
+
+ if {[inc_restore LBRACKET]} return
+
+ set pos [icl_get]
+
+ eseq57 ; # (x (t [)
+ # (n SPACE))
+
+ isv_clear
+ inc_save LBRACKET $pos
+ ier_nonterminal LBRACKET $pos
+ return
+}
+
+proc ::page::parse::lemon::eseq57 {} {
+
+ # (x (t [)
+ # (n SPACE))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set old [ier_get]
+ ict_advance \[
+ if {$ok} {ict_match_token \133}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ matchSymbol_SPACE ; # (n SPACE)
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ return
+}
+
+proc ::page::parse::lemon::matchSymbol_Left {} {
+ # Left = (x (n DLEFT)
+ # (+ (n Identifier))
+ # (n DOT))
+
+ variable ok
+ if {[inc_restore Left]} {
+ if {$ok} ias_push
+ return
+ }
+
+ set pos [icl_get]
+ set mrk [ias_mark]
+
+ eseq23 ; # (x (n DLEFT)
+ # (+ (n Identifier))
+ # (n DOT))
+
+ isv_nonterminal_reduce Left $pos $mrk
+ inc_save Left $pos
+ ias_pop2mark $mrk
+ if {$ok} ias_push
+ ier_nonterminal Left $pos
+ return
+}
+
+proc ::page::parse::lemon::eseq23 {} {
+
+ # (x (n DLEFT)
+ # (+ (n Identifier))
+ # (n DOT))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set old [ier_get]
+ matchSymbol_DLEFT ; # (n DLEFT)
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set mrk [ias_mark]
+
+ set old [ier_get]
+ epkleene22 ; # (+ (n Identifier))
+ ier_merge $old
+
+ if {!$ok} {
+ ias_pop2mark $mrk
+ icl_rewind $pos
+ return
+ }
+
+ set old [ier_get]
+ matchSymbol_DOT ; # (n DOT)
+ ier_merge $old
+
+ if {!$ok} {
+ ias_pop2mark $mrk
+ icl_rewind $pos
+ return
+ }
+
+ return
+}
+
+proc ::page::parse::lemon::epkleene22 {} {
+
+ # (+ (n Identifier))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set old [ier_get]
+ matchSymbol_Identifier ; # (n Identifier)
+ ier_merge $old
+
+ if {!$ok} {
+ icl_rewind $pos
+ return
+ }
+
+ while {1} {
+ set pos [icl_get]
+
+ set old [ier_get]
+ matchSymbol_Identifier ; # (n Identifier)
+ ier_merge $old
+
+ if {$ok} continue
+ break
+ }
+
+ icl_rewind $pos
+ iok_ok
+ return
+}
+
+proc ::page::parse::lemon::matchSymbol_LemonGrammar {} {
+ # LemonGrammar = (x (n SPACE)
+ # (+ (n Statement))
+ # (n EOF))
+
+ variable ok
+ if {[inc_restore LemonGrammar]} {
+ if {$ok} ias_push
+ return
+ }
+
+ set pos [icl_get]
+ set mrk [ias_mark]
+
+ eseq2 ; # (x (n SPACE)
+ # (+ (n Statement))
+ # (n EOF))
+
+ isv_nonterminal_reduce LemonGrammar $pos $mrk
+ inc_save LemonGrammar $pos
+ ias_pop2mark $mrk
+ if {$ok} ias_push
+ ier_nonterminal LemonGrammar $pos
+ return
+}
+
+proc ::page::parse::lemon::eseq2 {} {
+
+ # (x (n SPACE)
+ # (+ (n Statement))
+ # (n EOF))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set old [ier_get]
+ matchSymbol_SPACE ; # (n SPACE)
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set mrk [ias_mark]
+
+ set old [ier_get]
+ epkleene1 ; # (+ (n Statement))
+ ier_merge $old
+
+ if {!$ok} {
+ ias_pop2mark $mrk
+ icl_rewind $pos
+ return
+ }
+
+ set old [ier_get]
+ matchSymbol_EOF ; # (n EOF)
+ ier_merge $old
+
+ if {!$ok} {
+ ias_pop2mark $mrk
+ icl_rewind $pos
+ return
+ }
+
+ return
+}
+
+proc ::page::parse::lemon::epkleene1 {} {
+
+ # (+ (n Statement))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set old [ier_get]
+ matchSymbol_Statement ; # (n Statement)
+ ier_merge $old
+
+ if {!$ok} {
+ icl_rewind $pos
+ return
+ }
+
+ while {1} {
+ set pos [icl_get]
+
+ set old [ier_get]
+ matchSymbol_Statement ; # (n Statement)
+ ier_merge $old
+
+ if {$ok} continue
+ break
+ }
+
+ icl_rewind $pos
+ iok_ok
+ return
+}
+
+proc ::page::parse::lemon::matchSymbol_LPAREN {} {
+ # LPAREN = (x (t \()
+ # (n SPACE))
+
+ if {[inc_restore LPAREN]} return
+
+ set pos [icl_get]
+
+ eseq55 ; # (x (t \()
+ # (n SPACE))
+
+ isv_clear
+ inc_save LPAREN $pos
+ ier_nonterminal LPAREN $pos
+ return
+}
+
+proc ::page::parse::lemon::eseq55 {} {
+
+ # (x (t \()
+ # (n SPACE))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set old [ier_get]
+ ict_advance \(
+ if {$ok} {ict_match_token \50}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ matchSymbol_SPACE ; # (n SPACE)
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ return
+}
+
+proc ::page::parse::lemon::matchSymbol_Name {} {
+ # Name = (x (n DNAME)
+ # (n Identifier))
+
+ variable ok
+ if {[inc_restore Name]} {
+ if {$ok} ias_push
+ return
+ }
+
+ set pos [icl_get]
+ set mrk [ias_mark]
+
+ eseq24 ; # (x (n DNAME)
+ # (n Identifier))
+
+ isv_nonterminal_reduce Name $pos $mrk
+ inc_save Name $pos
+ ias_pop2mark $mrk
+ if {$ok} ias_push
+ ier_nonterminal Name $pos
+ return
+}
+
+proc ::page::parse::lemon::eseq24 {} {
+
+ # (x (n DNAME)
+ # (n Identifier))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set old [ier_get]
+ matchSymbol_DNAME ; # (n DNAME)
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set mrk [ias_mark]
+
+ set old [ier_get]
+ matchSymbol_Identifier ; # (n Identifier)
+ ier_merge $old
+
+ if {!$ok} {
+ ias_pop2mark $mrk
+ icl_rewind $pos
+ return
+ }
+
+ return
+}
+
+proc ::page::parse::lemon::matchSymbol_NatNum {} {
+ # NatNum = (+ (.. 0 9))
+
+ variable ok
+ if {[inc_restore NatNum]} {
+ if {$ok} ias_push
+ return
+ }
+
+ set pos [icl_get]
+
+ epkleene52 ; # (+ (.. 0 9))
+
+ isv_nonterminal_range NatNum $pos
+ inc_save NatNum $pos
+ if {$ok} ias_push
+ ier_nonterminal NatNum $pos
+ return
+}
+
+proc ::page::parse::lemon::epkleene52 {} {
+
+ # (+ (.. 0 9))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set old [ier_get]
+ ict_advance "any in 0..9"
+ if {$ok} {ict_match_tokrange 0 9}
+ ier_merge $old
+
+ if {!$ok} {
+ icl_rewind $pos
+ return
+ }
+
+ while {1} {
+ set pos [icl_get]
+
+ set old [ier_get]
+ ict_advance "any in 0..9"
+ if {$ok} {ict_match_tokrange 0 9}
+ ier_merge $old
+
+ if {$ok} continue
+ break
+ }
+
+ icl_rewind $pos
+ iok_ok
+ return
+}
+
+proc ::page::parse::lemon::matchSymbol_NaturalNumber {} {
+ # NaturalNumber = (x (n NatNum)
+ # (n SPACE))
+
+ variable ok
+ if {[inc_restore NaturalNumber]} {
+ if {$ok} ias_push
+ return
+ }
+
+ set pos [icl_get]
+ set mrk [ias_mark]
+
+ eseq51 ; # (x (n NatNum)
+ # (n SPACE))
+
+ isv_nonterminal_reduce NaturalNumber $pos $mrk
+ inc_save NaturalNumber $pos
+ ias_pop2mark $mrk
+ if {$ok} ias_push
+ ier_nonterminal NaturalNumber $pos
+ return
+}
+
+proc ::page::parse::lemon::eseq51 {} {
+
+ # (x (n NatNum)
+ # (n SPACE))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set mrk [ias_mark]
+
+ set old [ier_get]
+ matchSymbol_NatNum ; # (n NatNum)
+ ier_merge $old
+
+ if {!$ok} {
+ ias_pop2mark $mrk
+ icl_rewind $pos
+ return
+ }
+
+ set old [ier_get]
+ matchSymbol_SPACE ; # (n SPACE)
+ ier_merge $old
+
+ if {!$ok} {
+ ias_pop2mark $mrk
+ icl_rewind $pos
+ return
+ }
+
+ return
+}
+
+proc ::page::parse::lemon::matchSymbol_Nonassoc {} {
+ # Nonassoc = (x (n DNON)
+ # (+ (n Identifier))
+ # (n DOT))
+
+ variable ok
+ if {[inc_restore Nonassoc]} {
+ if {$ok} ias_push
+ return
+ }
+
+ set pos [icl_get]
+ set mrk [ias_mark]
+
+ eseq26 ; # (x (n DNON)
+ # (+ (n Identifier))
+ # (n DOT))
+
+ isv_nonterminal_reduce Nonassoc $pos $mrk
+ inc_save Nonassoc $pos
+ ias_pop2mark $mrk
+ if {$ok} ias_push
+ ier_nonterminal Nonassoc $pos
+ return
+}
+
+proc ::page::parse::lemon::eseq26 {} {
+
+ # (x (n DNON)
+ # (+ (n Identifier))
+ # (n DOT))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set old [ier_get]
+ matchSymbol_DNON ; # (n DNON)
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set mrk [ias_mark]
+
+ set old [ier_get]
+ epkleene25 ; # (+ (n Identifier))
+ ier_merge $old
+
+ if {!$ok} {
+ ias_pop2mark $mrk
+ icl_rewind $pos
+ return
+ }
+
+ set old [ier_get]
+ matchSymbol_DOT ; # (n DOT)
+ ier_merge $old
+
+ if {!$ok} {
+ ias_pop2mark $mrk
+ icl_rewind $pos
+ return
+ }
+
+ return
+}
+
+proc ::page::parse::lemon::epkleene25 {} {
+
+ # (+ (n Identifier))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set old [ier_get]
+ matchSymbol_Identifier ; # (n Identifier)
+ ier_merge $old
+
+ if {!$ok} {
+ icl_rewind $pos
+ return
+ }
+
+ while {1} {
+ set pos [icl_get]
+
+ set old [ier_get]
+ matchSymbol_Identifier ; # (n Identifier)
+ ier_merge $old
+
+ if {$ok} continue
+ break
+ }
+
+ icl_rewind $pos
+ iok_ok
+ return
+}
+
+proc ::page::parse::lemon::matchSymbol_ParseAccept {} {
+ # ParseAccept = (x (n DPACC)
+ # (n Codeblock))
+
+ variable ok
+ if {[inc_restore ParseAccept]} {
+ if {$ok} ias_push
+ return
+ }
+
+ set pos [icl_get]
+ set mrk [ias_mark]
+
+ eseq27 ; # (x (n DPACC)
+ # (n Codeblock))
+
+ isv_nonterminal_reduce ParseAccept $pos $mrk
+ inc_save ParseAccept $pos
+ ias_pop2mark $mrk
+ if {$ok} ias_push
+ ier_nonterminal ParseAccept $pos
+ return
+}
+
+proc ::page::parse::lemon::eseq27 {} {
+
+ # (x (n DPACC)
+ # (n Codeblock))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set old [ier_get]
+ matchSymbol_DPACC ; # (n DPACC)
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set mrk [ias_mark]
+
+ set old [ier_get]
+ matchSymbol_Codeblock ; # (n Codeblock)
+ ier_merge $old
+
+ if {!$ok} {
+ ias_pop2mark $mrk
+ icl_rewind $pos
+ return
+ }
+
+ return
+}
+
+proc ::page::parse::lemon::matchSymbol_ParseFailure {} {
+ # ParseFailure = (x (n DPFAIL)
+ # (n Codeblock))
+
+ variable ok
+ if {[inc_restore ParseFailure]} {
+ if {$ok} ias_push
+ return
+ }
+
+ set pos [icl_get]
+ set mrk [ias_mark]
+
+ eseq28 ; # (x (n DPFAIL)
+ # (n Codeblock))
+
+ isv_nonterminal_reduce ParseFailure $pos $mrk
+ inc_save ParseFailure $pos
+ ias_pop2mark $mrk
+ if {$ok} ias_push
+ ier_nonterminal ParseFailure $pos
+ return
+}
+
+proc ::page::parse::lemon::eseq28 {} {
+
+ # (x (n DPFAIL)
+ # (n Codeblock))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set old [ier_get]
+ matchSymbol_DPFAIL ; # (n DPFAIL)
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set mrk [ias_mark]
+
+ set old [ier_get]
+ matchSymbol_Codeblock ; # (n Codeblock)
+ ier_merge $old
+
+ if {!$ok} {
+ ias_pop2mark $mrk
+ icl_rewind $pos
+ return
+ }
+
+ return
+}
+
+proc ::page::parse::lemon::matchSymbol_Precedence {} {
+ # Precedence = (x (n LBRACKET)
+ # (n Identifier)
+ # (n RBRACKET))
+
+ variable ok
+ if {[inc_restore Precedence]} {
+ if {$ok} ias_push
+ return
+ }
+
+ set pos [icl_get]
+ set mrk [ias_mark]
+
+ eseq13 ; # (x (n LBRACKET)
+ # (n Identifier)
+ # (n RBRACKET))
+
+ isv_nonterminal_reduce Precedence $pos $mrk
+ inc_save Precedence $pos
+ ias_pop2mark $mrk
+ if {$ok} ias_push
+ ier_nonterminal Precedence $pos
+ return
+}
+
+proc ::page::parse::lemon::eseq13 {} {
+
+ # (x (n LBRACKET)
+ # (n Identifier)
+ # (n RBRACKET))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set old [ier_get]
+ matchSymbol_LBRACKET ; # (n LBRACKET)
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set mrk [ias_mark]
+
+ set old [ier_get]
+ matchSymbol_Identifier ; # (n Identifier)
+ ier_merge $old
+
+ if {!$ok} {
+ ias_pop2mark $mrk
+ icl_rewind $pos
+ return
+ }
+
+ set old [ier_get]
+ matchSymbol_RBRACKET ; # (n RBRACKET)
+ ier_merge $old
+
+ if {!$ok} {
+ ias_pop2mark $mrk
+ icl_rewind $pos
+ return
+ }
+
+ return
+}
+
+proc ::page::parse::lemon::matchSymbol_RBRACE {} {
+ # RBRACE = (t \})
+
+ variable ok
+ if {[inc_restore RBRACE]} return
+
+ set pos [icl_get]
+
+ ict_advance \}
+ if {$ok} {ict_match_token \175}
+
+ isv_clear
+ inc_save RBRACE $pos
+ ier_nonterminal RBRACE $pos
+ return
+}
+
+proc ::page::parse::lemon::matchSymbol_RBRACKET {} {
+ # RBRACKET = (x (t ])
+ # (n SPACE))
+
+ if {[inc_restore RBRACKET]} return
+
+ set pos [icl_get]
+
+ eseq58 ; # (x (t ])
+ # (n SPACE))
+
+ isv_clear
+ inc_save RBRACKET $pos
+ ier_nonterminal RBRACKET $pos
+ return
+}
+
+proc ::page::parse::lemon::eseq58 {} {
+
+ # (x (t ])
+ # (n SPACE))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set old [ier_get]
+ ict_advance \]
+ if {$ok} {ict_match_token \135}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ matchSymbol_SPACE ; # (n SPACE)
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ return
+}
+
+proc ::page::parse::lemon::matchSymbol_Right {} {
+ # Right = (x (n DRIGHT)
+ # (+ (n Identifier))
+ # (n DOT))
+
+ variable ok
+ if {[inc_restore Right]} {
+ if {$ok} ias_push
+ return
+ }
+
+ set pos [icl_get]
+ set mrk [ias_mark]
+
+ eseq30 ; # (x (n DRIGHT)
+ # (+ (n Identifier))
+ # (n DOT))
+
+ isv_nonterminal_reduce Right $pos $mrk
+ inc_save Right $pos
+ ias_pop2mark $mrk
+ if {$ok} ias_push
+ ier_nonterminal Right $pos
+ return
+}
+
+proc ::page::parse::lemon::eseq30 {} {
+
+ # (x (n DRIGHT)
+ # (+ (n Identifier))
+ # (n DOT))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set old [ier_get]
+ matchSymbol_DRIGHT ; # (n DRIGHT)
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set mrk [ias_mark]
+
+ set old [ier_get]
+ epkleene29 ; # (+ (n Identifier))
+ ier_merge $old
+
+ if {!$ok} {
+ ias_pop2mark $mrk
+ icl_rewind $pos
+ return
+ }
+
+ set old [ier_get]
+ matchSymbol_DOT ; # (n DOT)
+ ier_merge $old
+
+ if {!$ok} {
+ ias_pop2mark $mrk
+ icl_rewind $pos
+ return
+ }
+
+ return
+}
+
+proc ::page::parse::lemon::epkleene29 {} {
+
+ # (+ (n Identifier))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set old [ier_get]
+ matchSymbol_Identifier ; # (n Identifier)
+ ier_merge $old
+
+ if {!$ok} {
+ icl_rewind $pos
+ return
+ }
+
+ while {1} {
+ set pos [icl_get]
+
+ set old [ier_get]
+ matchSymbol_Identifier ; # (n Identifier)
+ ier_merge $old
+
+ if {$ok} continue
+ break
+ }
+
+ icl_rewind $pos
+ iok_ok
+ return
+}
+
+proc ::page::parse::lemon::matchSymbol_RPAREN {} {
+ # RPAREN = (x (t \))
+ # (n SPACE))
+
+ if {[inc_restore RPAREN]} return
+
+ set pos [icl_get]
+
+ eseq56 ; # (x (t \))
+ # (n SPACE))
+
+ isv_clear
+ inc_save RPAREN $pos
+ ier_nonterminal RPAREN $pos
+ return
+}
+
+proc ::page::parse::lemon::eseq56 {} {
+
+ # (x (t \))
+ # (n SPACE))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set old [ier_get]
+ ict_advance \)
+ if {$ok} {ict_match_token \51}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ matchSymbol_SPACE ; # (n SPACE)
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ return
+}
+
+proc ::page::parse::lemon::matchSymbol_Rule {} {
+ # Rule = (x (n Identifier)
+ # (? (n Label))
+ # (n ASSIGN)
+ # (n Definition)
+ # (n DOT)
+ # (? (n Precedence))
+ # (? (n Codeblock)))
+
+ variable ok
+ if {[inc_restore Rule]} {
+ if {$ok} ias_push
+ return
+ }
+
+ set pos [icl_get]
+ set mrk [ias_mark]
+
+ eseq8 ; # (x (n Identifier)
+ # (? (n Label))
+ # (n ASSIGN)
+ # (n Definition)
+ # (n DOT)
+ # (? (n Precedence))
+ # (? (n Codeblock)))
+
+ isv_nonterminal_reduce Rule $pos $mrk
+ inc_save Rule $pos
+ ias_pop2mark $mrk
+ if {$ok} ias_push
+ ier_nonterminal Rule $pos
+ return
+}
+
+proc ::page::parse::lemon::eseq8 {} {
+
+ # (x (n Identifier)
+ # (? (n Label))
+ # (n ASSIGN)
+ # (n Definition)
+ # (n DOT)
+ # (? (n Precedence))
+ # (? (n Codeblock)))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set mrk [ias_mark]
+
+ set old [ier_get]
+ matchSymbol_Identifier ; # (n Identifier)
+ ier_merge $old
+
+ if {!$ok} {
+ ias_pop2mark $mrk
+ icl_rewind $pos
+ return
+ }
+
+ set old [ier_get]
+ eopt5 ; # (? (n Label))
+ ier_merge $old
+
+ if {!$ok} {
+ ias_pop2mark $mrk
+ icl_rewind $pos
+ return
+ }
+
+ set old [ier_get]
+ matchSymbol_ASSIGN ; # (n ASSIGN)
+ ier_merge $old
+
+ if {!$ok} {
+ ias_pop2mark $mrk
+ icl_rewind $pos
+ return
+ }
+
+ set old [ier_get]
+ matchSymbol_Definition ; # (n Definition)
+ ier_merge $old
+
+ if {!$ok} {
+ ias_pop2mark $mrk
+ icl_rewind $pos
+ return
+ }
+
+ set old [ier_get]
+ matchSymbol_DOT ; # (n DOT)
+ ier_merge $old
+
+ if {!$ok} {
+ ias_pop2mark $mrk
+ icl_rewind $pos
+ return
+ }
+
+ set old [ier_get]
+ eopt6 ; # (? (n Precedence))
+ ier_merge $old
+
+ if {!$ok} {
+ ias_pop2mark $mrk
+ icl_rewind $pos
+ return
+ }
+
+ set old [ier_get]
+ eopt7 ; # (? (n Codeblock))
+ ier_merge $old
+
+ if {!$ok} {
+ ias_pop2mark $mrk
+ icl_rewind $pos
+ return
+ }
+
+ return
+}
+
+proc ::page::parse::lemon::eopt5 {} {
+
+ # (? (n Label))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set old [ier_get]
+ matchSymbol_Label ; # (n Label)
+ ier_merge $old
+
+ if {$ok} return
+ icl_rewind $pos
+ iok_ok
+ return
+}
+
+proc ::page::parse::lemon::eopt6 {} {
+
+ # (? (n Precedence))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set old [ier_get]
+ matchSymbol_Precedence ; # (n Precedence)
+ ier_merge $old
+
+ if {$ok} return
+ icl_rewind $pos
+ iok_ok
+ return
+}
+
+proc ::page::parse::lemon::eopt7 {} {
+
+ # (? (n Codeblock))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set old [ier_get]
+ matchSymbol_Codeblock ; # (n Codeblock)
+ ier_merge $old
+
+ if {$ok} return
+ icl_rewind $pos
+ iok_ok
+ return
+}
+
+proc ::page::parse::lemon::matchSymbol_SPACE {} {
+ # SPACE = (* (/ (t <blank>)
+ # (t \t)
+ # (t \n)
+ # (t \r)
+ # (n C_COMMENT)
+ # (n Cplusplus_COMMENT)
+ # (n Ifndef)
+ # (n Ifdef)
+ # (n Endif)))
+
+ if {[inc_restore SPACE]} return
+
+ set pos [icl_get]
+
+ ekleene86 ; # (* (/ (t <blank>)
+ # (t \t)
+ # (t \n)
+ # (t \r)
+ # (n C_COMMENT)
+ # (n Cplusplus_COMMENT)
+ # (n Ifndef)
+ # (n Ifdef)
+ # (n Endif)))
+
+ isv_clear
+ inc_save SPACE $pos
+ ier_nonterminal SPACE $pos
+ return
+}
+
+proc ::page::parse::lemon::ekleene86 {} {
+
+ # (* (/ (t <blank>)
+ # (t \t)
+ # (t \n)
+ # (t \r)
+ # (n C_COMMENT)
+ # (n Cplusplus_COMMENT)
+ # (n Ifndef)
+ # (n Ifdef)
+ # (n Endif)))
+
+ variable ok
+
+ while {1} {
+ set pos [icl_get]
+
+ set old [ier_get]
+ ebra85 ; # (/ (t <blank>)
+ # (t \t)
+ # (t \n)
+ # (t \r)
+ # (n C_COMMENT)
+ # (n Cplusplus_COMMENT)
+ # (n Ifndef)
+ # (n Ifdef)
+ # (n Endif))
+ ier_merge $old
+
+ if {$ok} continue
+ break
+ }
+
+ icl_rewind $pos
+ iok_ok
+ return
+}
+
+proc ::page::parse::lemon::ebra85 {} {
+
+ # (/ (t <blank>)
+ # (t \t)
+ # (t \n)
+ # (t \r)
+ # (n C_COMMENT)
+ # (n Cplusplus_COMMENT)
+ # (n Ifndef)
+ # (n Ifdef)
+ # (n Endif))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set old [ier_get]
+ ict_advance <blank>
+ if {$ok} {ict_match_token \40}
+ ier_merge $old
+
+ if {$ok} return
+ icl_rewind $pos
+
+ set old [ier_get]
+ ict_advance \\t
+ if {$ok} {ict_match_token \t}
+ ier_merge $old
+
+ if {$ok} return
+ icl_rewind $pos
+
+ set old [ier_get]
+ ict_advance \\n
+ if {$ok} {ict_match_token \n}
+ ier_merge $old
+
+ if {$ok} return
+ icl_rewind $pos
+
+ set old [ier_get]
+ ict_advance \\r
+ if {$ok} {ict_match_token \r}
+ ier_merge $old
+
+ if {$ok} return
+ icl_rewind $pos
+
+ set old [ier_get]
+ matchSymbol_C_COMMENT ; # (n C_COMMENT)
+ ier_merge $old
+
+ if {$ok} return
+ icl_rewind $pos
+
+ set old [ier_get]
+ matchSymbol_Cplusplus_COMMENT ; # (n Cplusplus_COMMENT)
+ ier_merge $old
+
+ if {$ok} return
+ icl_rewind $pos
+
+ set old [ier_get]
+ matchSymbol_Ifndef ; # (n Ifndef)
+ ier_merge $old
+
+ if {$ok} return
+ icl_rewind $pos
+
+ set old [ier_get]
+ matchSymbol_Ifdef ; # (n Ifdef)
+ ier_merge $old
+
+ if {$ok} return
+ icl_rewind $pos
+
+ set old [ier_get]
+ matchSymbol_Endif ; # (n Endif)
+ ier_merge $old
+
+ if {$ok} return
+ icl_rewind $pos
+
+ return
+}
+
+proc ::page::parse::lemon::matchSymbol_StackOverflow {} {
+ # StackOverflow = (x (n DSTKOVER)
+ # (n Codeblock))
+
+ variable ok
+ if {[inc_restore StackOverflow]} {
+ if {$ok} ias_push
+ return
+ }
+
+ set pos [icl_get]
+ set mrk [ias_mark]
+
+ eseq31 ; # (x (n DSTKOVER)
+ # (n Codeblock))
+
+ isv_nonterminal_reduce StackOverflow $pos $mrk
+ inc_save StackOverflow $pos
+ ias_pop2mark $mrk
+ if {$ok} ias_push
+ ier_nonterminal StackOverflow $pos
+ return
+}
+
+proc ::page::parse::lemon::eseq31 {} {
+
+ # (x (n DSTKOVER)
+ # (n Codeblock))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set old [ier_get]
+ matchSymbol_DSTKOVER ; # (n DSTKOVER)
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set mrk [ias_mark]
+
+ set old [ier_get]
+ matchSymbol_Codeblock ; # (n Codeblock)
+ ier_merge $old
+
+ if {!$ok} {
+ ias_pop2mark $mrk
+ icl_rewind $pos
+ return
+ }
+
+ return
+}
+
+proc ::page::parse::lemon::matchSymbol_Stacksize {} {
+ # Stacksize = (x (n DSTKSZ)
+ # (n NaturalNumber))
+
+ variable ok
+ if {[inc_restore Stacksize]} {
+ if {$ok} ias_push
+ return
+ }
+
+ set pos [icl_get]
+ set mrk [ias_mark]
+
+ eseq32 ; # (x (n DSTKSZ)
+ # (n NaturalNumber))
+
+ isv_nonterminal_reduce Stacksize $pos $mrk
+ inc_save Stacksize $pos
+ ias_pop2mark $mrk
+ if {$ok} ias_push
+ ier_nonterminal Stacksize $pos
+ return
+}
+
+proc ::page::parse::lemon::eseq32 {} {
+
+ # (x (n DSTKSZ)
+ # (n NaturalNumber))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set old [ier_get]
+ matchSymbol_DSTKSZ ; # (n DSTKSZ)
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set mrk [ias_mark]
+
+ set old [ier_get]
+ matchSymbol_NaturalNumber ; # (n NaturalNumber)
+ ier_merge $old
+
+ if {!$ok} {
+ ias_pop2mark $mrk
+ icl_rewind $pos
+ return
+ }
+
+ return
+}
+
+proc ::page::parse::lemon::matchSymbol_StartSymbol {} {
+ # StartSymbol = (x (n DSTART)
+ # (n Identifier))
+
+ variable ok
+ if {[inc_restore StartSymbol]} {
+ if {$ok} ias_push
+ return
+ }
+
+ set pos [icl_get]
+ set mrk [ias_mark]
+
+ eseq33 ; # (x (n DSTART)
+ # (n Identifier))
+
+ isv_nonterminal_reduce StartSymbol $pos $mrk
+ inc_save StartSymbol $pos
+ ias_pop2mark $mrk
+ if {$ok} ias_push
+ ier_nonterminal StartSymbol $pos
+ return
+}
+
+proc ::page::parse::lemon::eseq33 {} {
+
+ # (x (n DSTART)
+ # (n Identifier))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set old [ier_get]
+ matchSymbol_DSTART ; # (n DSTART)
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set mrk [ias_mark]
+
+ set old [ier_get]
+ matchSymbol_Identifier ; # (n Identifier)
+ ier_merge $old
+
+ if {!$ok} {
+ ias_pop2mark $mrk
+ icl_rewind $pos
+ return
+ }
+
+ return
+}
+
+proc ::page::parse::lemon::matchSymbol_Statement {} {
+ # Statement = (x (/ (n Directive)
+ # (n Rule))
+ # (n SPACE))
+
+ variable ok
+ if {[inc_restore Statement]} {
+ if {$ok} ias_push
+ return
+ }
+
+ set pos [icl_get]
+ set mrk [ias_mark]
+
+ eseq4 ; # (x (/ (n Directive)
+ # (n Rule))
+ # (n SPACE))
+
+ isv_nonterminal_reduce Statement $pos $mrk
+ inc_save Statement $pos
+ ias_pop2mark $mrk
+ if {$ok} ias_push
+ ier_nonterminal Statement $pos
+ return
+}
+
+proc ::page::parse::lemon::eseq4 {} {
+
+ # (x (/ (n Directive)
+ # (n Rule))
+ # (n SPACE))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set mrk [ias_mark]
+
+ set old [ier_get]
+ ebra3 ; # (/ (n Directive)
+ # (n Rule))
+ ier_merge $old
+
+ if {!$ok} {
+ ias_pop2mark $mrk
+ icl_rewind $pos
+ return
+ }
+
+ set old [ier_get]
+ matchSymbol_SPACE ; # (n SPACE)
+ ier_merge $old
+
+ if {!$ok} {
+ ias_pop2mark $mrk
+ icl_rewind $pos
+ return
+ }
+
+ return
+}
+
+proc ::page::parse::lemon::ebra3 {} {
+
+ # (/ (n Directive)
+ # (n Rule))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set mrk [ias_mark]
+ set old [ier_get]
+ matchSymbol_Directive ; # (n Directive)
+ ier_merge $old
+
+ if {$ok} return
+ ias_pop2mark $mrk
+ icl_rewind $pos
+
+ set mrk [ias_mark]
+ set old [ier_get]
+ matchSymbol_Rule ; # (n Rule)
+ ier_merge $old
+
+ if {$ok} return
+ ias_pop2mark $mrk
+ icl_rewind $pos
+
+ return
+}
+
+proc ::page::parse::lemon::matchSymbol_SyntaxError {} {
+ # SyntaxError = (x (n DSYNERR)
+ # (n Codeblock))
+
+ variable ok
+ if {[inc_restore SyntaxError]} {
+ if {$ok} ias_push
+ return
+ }
+
+ set pos [icl_get]
+ set mrk [ias_mark]
+
+ eseq34 ; # (x (n DSYNERR)
+ # (n Codeblock))
+
+ isv_nonterminal_reduce SyntaxError $pos $mrk
+ inc_save SyntaxError $pos
+ ias_pop2mark $mrk
+ if {$ok} ias_push
+ ier_nonterminal SyntaxError $pos
+ return
+}
+
+proc ::page::parse::lemon::eseq34 {} {
+
+ # (x (n DSYNERR)
+ # (n Codeblock))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set old [ier_get]
+ matchSymbol_DSYNERR ; # (n DSYNERR)
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set mrk [ias_mark]
+
+ set old [ier_get]
+ matchSymbol_Codeblock ; # (n Codeblock)
+ ier_merge $old
+
+ if {!$ok} {
+ ias_pop2mark $mrk
+ icl_rewind $pos
+ return
+ }
+
+ return
+}
+
+proc ::page::parse::lemon::matchSymbol_TokenDestructor {} {
+ # TokenDestructor = (x (n DTOKDEST)
+ # (n Identifier)
+ # (n Codeblock))
+
+ variable ok
+ if {[inc_restore TokenDestructor]} {
+ if {$ok} ias_push
+ return
+ }
+
+ set pos [icl_get]
+ set mrk [ias_mark]
+
+ eseq35 ; # (x (n DTOKDEST)
+ # (n Identifier)
+ # (n Codeblock))
+
+ isv_nonterminal_reduce TokenDestructor $pos $mrk
+ inc_save TokenDestructor $pos
+ ias_pop2mark $mrk
+ if {$ok} ias_push
+ ier_nonterminal TokenDestructor $pos
+ return
+}
+
+proc ::page::parse::lemon::eseq35 {} {
+
+ # (x (n DTOKDEST)
+ # (n Identifier)
+ # (n Codeblock))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set old [ier_get]
+ matchSymbol_DTOKDEST ; # (n DTOKDEST)
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set mrk [ias_mark]
+
+ set old [ier_get]
+ matchSymbol_Identifier ; # (n Identifier)
+ ier_merge $old
+
+ if {!$ok} {
+ ias_pop2mark $mrk
+ icl_rewind $pos
+ return
+ }
+
+ set old [ier_get]
+ matchSymbol_Codeblock ; # (n Codeblock)
+ ier_merge $old
+
+ if {!$ok} {
+ ias_pop2mark $mrk
+ icl_rewind $pos
+ return
+ }
+
+ return
+}
+
+proc ::page::parse::lemon::matchSymbol_TokenPrefix {} {
+ # TokenPrefix = (x (n DTOKPFX)
+ # (n Identifier))
+
+ variable ok
+ if {[inc_restore TokenPrefix]} {
+ if {$ok} ias_push
+ return
+ }
+
+ set pos [icl_get]
+ set mrk [ias_mark]
+
+ eseq36 ; # (x (n DTOKPFX)
+ # (n Identifier))
+
+ isv_nonterminal_reduce TokenPrefix $pos $mrk
+ inc_save TokenPrefix $pos
+ ias_pop2mark $mrk
+ if {$ok} ias_push
+ ier_nonterminal TokenPrefix $pos
+ return
+}
+
+proc ::page::parse::lemon::eseq36 {} {
+
+ # (x (n DTOKPFX)
+ # (n Identifier))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set old [ier_get]
+ matchSymbol_DTOKPFX ; # (n DTOKPFX)
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set mrk [ias_mark]
+
+ set old [ier_get]
+ matchSymbol_Identifier ; # (n Identifier)
+ ier_merge $old
+
+ if {!$ok} {
+ ias_pop2mark $mrk
+ icl_rewind $pos
+ return
+ }
+
+ return
+}
+
+proc ::page::parse::lemon::matchSymbol_TokenType {} {
+ # TokenType = (x (n DTOKTYPE)
+ # (n Codeblock))
+
+ variable ok
+ if {[inc_restore TokenType]} {
+ if {$ok} ias_push
+ return
+ }
+
+ set pos [icl_get]
+ set mrk [ias_mark]
+
+ eseq37 ; # (x (n DTOKTYPE)
+ # (n Codeblock))
+
+ isv_nonterminal_reduce TokenType $pos $mrk
+ inc_save TokenType $pos
+ ias_pop2mark $mrk
+ if {$ok} ias_push
+ ier_nonterminal TokenType $pos
+ return
+}
+
+proc ::page::parse::lemon::eseq37 {} {
+
+ # (x (n DTOKTYPE)
+ # (n Codeblock))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set old [ier_get]
+ matchSymbol_DTOKTYPE ; # (n DTOKTYPE)
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set mrk [ias_mark]
+
+ set old [ier_get]
+ matchSymbol_Codeblock ; # (n Codeblock)
+ ier_merge $old
+
+ if {!$ok} {
+ ias_pop2mark $mrk
+ icl_rewind $pos
+ return
+ }
+
+ return
+}
+
+proc ::page::parse::lemon::matchSymbol_Type {} {
+ # Type = (x (n DTYPE)
+ # (n Identifier)
+ # (n Codeblock))
+
+ variable ok
+ if {[inc_restore Type]} {
+ if {$ok} ias_push
+ return
+ }
+
+ set pos [icl_get]
+ set mrk [ias_mark]
+
+ eseq38 ; # (x (n DTYPE)
+ # (n Identifier)
+ # (n Codeblock))
+
+ isv_nonterminal_reduce Type $pos $mrk
+ inc_save Type $pos
+ ias_pop2mark $mrk
+ if {$ok} ias_push
+ ier_nonterminal Type $pos
+ return
+}
+
+proc ::page::parse::lemon::eseq38 {} {
+
+ # (x (n DTYPE)
+ # (n Identifier)
+ # (n Codeblock))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set old [ier_get]
+ matchSymbol_DTYPE ; # (n DTYPE)
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set mrk [ias_mark]
+
+ set old [ier_get]
+ matchSymbol_Identifier ; # (n Identifier)
+ ier_merge $old
+
+ if {!$ok} {
+ ias_pop2mark $mrk
+ icl_rewind $pos
+ return
+ }
+
+ set old [ier_get]
+ matchSymbol_Codeblock ; # (n Codeblock)
+ ier_merge $old
+
+ if {!$ok} {
+ ias_pop2mark $mrk
+ icl_rewind $pos
+ return
+ }
+
+ return
+}
+
+# ### ### ### ######### ######### #########
+## Package Management
+
+package provide page::parse::lemon 0.1
diff --git a/tcllib/modules/page/parse_peg.tcl b/tcllib/modules/page/parse_peg.tcl
new file mode 100644
index 0000000..13f7265
--- /dev/null
+++ b/tcllib/modules/page/parse_peg.tcl
@@ -0,0 +1,4415 @@
+# -*- tcl -*-
+## Parsing Expression Grammar 'pg::peg::grammar'.
+## Recursive Descent Packrat parser generated
+## by the PAGE writer plugin 'me'.
+## (C) 2005 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+# ### ### ### ######### ######### #########
+## Package description
+
+# The commands provided here match an input provided through a buffer
+# command to the PE grammar 'pg::peg::grammar'. The parser is based on the package
+# 'grammar::me::tcl' (recursive-descent, packrat, pulling chars,
+# pushing the generated AST).
+
+# ### ### ### ######### ######### #########
+## Requisites
+
+package require grammar::me::tcl
+
+# ### ### ### ######### ######### #########
+## Implementation
+
+namespace eval ::page::parse::peg {
+ # Import the virtual machine for matching.
+
+ namespace import ::grammar::me::tcl::*
+ upvar #0 ::grammar::me::tcl::ok ok
+}
+
+# ### ### ### ######### ######### #########
+## API Implementation.
+
+proc ::page::parse::peg::parse {nxcmd emvar astvar} {
+ variable ok
+ variable se
+
+ upvar 1 $emvar emsg $astvar ast
+
+ init $nxcmd
+
+ matchSymbol_Grammar ; # (n Grammar)
+
+ isv_nonterminal_reduce ALL -1
+ set ast [sv]
+ if {!$ok} {
+ foreach {l m} [ier_get] break
+ lappend l [lc $l]
+ set emsg [list $l $m]
+ }
+
+ return $ok
+}
+
+# ### ### ### ######### ######### #########
+## Internal helper methods
+
+# Grammar 'pg::peg::grammar'
+#
+# ALNUM = (x (t <)
+# (t a)
+# (t l)
+# (t n)
+# (t u)
+# (t m)
+# (t >)
+# (n SPACE))
+#
+# ALPHA = (x (t <)
+# (t a)
+# (t l)
+# (t p)
+# (t h)
+# (t a)
+# (t >)
+# (n SPACE))
+#
+# AND = (x (t &)
+# (n SPACE))
+#
+# APOSTROPH = (t ')
+#
+# Attribute = (x (/ (n VOID)
+# (n LEAF)
+# (n MATCH))
+# (n COLON))
+#
+# Char = (/ (n CharSpecial)
+# (n CharOctalFull)
+# (n CharOctalPart)
+# (n CharUnicode)
+# (n CharUnescaped))
+#
+# CharOctalFull = (x (t \)
+# (.. 0 2)
+# (.. 0 7)
+# (.. 0 7))
+#
+# CharOctalPart = (x (t \)
+# (.. 0 7)
+# (? (.. 0 7)))
+#
+# CharSpecial = (x (t \)
+# (/ (t n)
+# (t r)
+# (t t)
+# (t ')
+# (t \")
+# (t [)
+# (t ])
+# (t \)))
+#
+# CharUnescaped = (x (! (t \))
+# (dot))
+#
+# CharUnicode = (x (t \)
+# (t u)
+# (n HexDigit)
+# (? (x (n HexDigit)
+# (? (x (n HexDigit)
+# (? (n HexDigit)))))))
+#
+# Class = (x (n OPENB)
+# (* (x (! (n CLOSEB))
+# (n Range)))
+# (n CLOSEB)
+# (n SPACE))
+#
+# CLOSE = (x (t \))
+# (n SPACE))
+#
+# CLOSEB = (t ])
+#
+# COLON = (x (t :)
+# (n SPACE))
+#
+# COMMENT = (x (t #)
+# (* (x (! (n EOL))
+# (dot)))
+# (n EOL))
+#
+# DAPOSTROPH = (t \")
+#
+# Definition = (x (? (n Attribute))
+# (n Identifier)
+# (n IS)
+# (n Expression)
+# (n SEMICOLON))
+#
+# DOT = (x (t .)
+# (n SPACE))
+#
+# END = (x (t E)
+# (t N)
+# (t D)
+# (n SPACE))
+#
+# EOF = (! (dot))
+#
+# EOL = (/ (x (t \n)
+# (t \r))
+# (t \n)
+# (t \r))
+#
+# Expression = (x (n Sequence)
+# (* (x (n SLASH)
+# (n Sequence))))
+#
+# Final = (x (n END)
+# (n SEMICOLON)
+# (n SPACE))
+#
+# Grammar = (x (n SPACE)
+# (n Header)
+# (+ (n Definition))
+# (n Final)
+# (n EOF))
+#
+# Header = (x (n PEG)
+# (n Identifier)
+# (n StartExpr))
+#
+# HexDigit = (/ (.. 0 9)
+# (.. a f)
+# (.. A F))
+#
+# Ident = (x (/ (t _)
+# (t :)
+# (alpha))
+# (* (/ (t _)
+# (t :)
+# (alnum))))
+#
+# Identifier = (x (n Ident)
+# (n SPACE))
+#
+# IS = (x (t <)
+# (t -)
+# (n SPACE))
+#
+# LEAF = (x (t l)
+# (t e)
+# (t a)
+# (t f)
+# (n SPACE))
+#
+# Literal = (/ (x (n APOSTROPH)
+# (* (x (! (n APOSTROPH))
+# (n Char)))
+# (n APOSTROPH)
+# (n SPACE))
+# (x (n DAPOSTROPH)
+# (* (x (! (n DAPOSTROPH))
+# (n Char)))
+# (n DAPOSTROPH)
+# (n SPACE)))
+#
+# MATCH = (x (t m)
+# (t a)
+# (t t)
+# (t c)
+# (t h)
+# (n SPACE))
+#
+# NOT = (x (t !)
+# (n SPACE))
+#
+# OPEN = (x (t \()
+# (n SPACE))
+#
+# OPENB = (t [)
+#
+# PEG = (x (t P)
+# (t E)
+# (t G)
+# (n SPACE))
+#
+# PLUS = (x (t +)
+# (n SPACE))
+#
+# Prefix = (x (? (/ (n AND)
+# (n NOT)))
+# (n Suffix))
+#
+# Primary = (/ (n ALNUM)
+# (n ALPHA)
+# (n Identifier)
+# (x (n OPEN)
+# (n Expression)
+# (n CLOSE))
+# (n Literal)
+# (n Class)
+# (n DOT))
+#
+# QUESTION = (x (t ?)
+# (n SPACE))
+#
+# Range = (/ (x (n Char)
+# (n TO)
+# (n Char))
+# (n Char))
+#
+# SEMICOLON = (x (t ;)
+# (n SPACE))
+#
+# Sequence = (+ (n Prefix))
+#
+# SLASH = (x (t /)
+# (n SPACE))
+#
+# SPACE = (* (/ (t <blank>)
+# (t \t)
+# (n EOL)
+# (n COMMENT)))
+#
+# STAR = (x (t *)
+# (n SPACE))
+#
+# StartExpr = (x (n OPEN)
+# (n Expression)
+# (n CLOSE))
+#
+# Suffix = (x (n Primary)
+# (? (/ (n QUESTION)
+# (n STAR)
+# (n PLUS))))
+#
+# TO = (t -)
+#
+# VOID = (x (t v)
+# (t o)
+# (t i)
+# (t d)
+# (n SPACE))
+#
+
+proc ::page::parse::peg::matchSymbol_ALNUM {} {
+ # ALNUM = (x (t <)
+ # (t a)
+ # (t l)
+ # (t n)
+ # (t u)
+ # (t m)
+ # (t >)
+ # (n SPACE))
+
+ variable ok
+ if {[inc_restore ALNUM]} {
+ if {$ok} ias_push
+ return
+ }
+
+ set pos [icl_get]
+
+ eseq75 ; # (x (t <)
+ # (t a)
+ # (t l)
+ # (t n)
+ # (t u)
+ # (t m)
+ # (t >)
+ # (n SPACE))
+
+ isv_nonterminal_leaf ALNUM $pos
+ inc_save ALNUM $pos
+ if {$ok} ias_push
+ ier_nonterminal "Expected ALNUM" $pos
+ return
+}
+
+proc ::page::parse::peg::eseq75 {} {
+
+ # (x (t <)
+ # (t a)
+ # (t l)
+ # (t n)
+ # (t u)
+ # (t m)
+ # (t >)
+ # (n SPACE))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set old [ier_get]
+ ict_advance "Expected < (got EOF)"
+ if {$ok} {ict_match_token < "Expected <"}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance "Expected a (got EOF)"
+ if {$ok} {ict_match_token a "Expected a"}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance "Expected l (got EOF)"
+ if {$ok} {ict_match_token l "Expected l"}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance "Expected n (got EOF)"
+ if {$ok} {ict_match_token n "Expected n"}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance "Expected u (got EOF)"
+ if {$ok} {ict_match_token u "Expected u"}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance "Expected m (got EOF)"
+ if {$ok} {ict_match_token m "Expected m"}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance "Expected > (got EOF)"
+ if {$ok} {ict_match_token > "Expected >"}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ matchSymbol_SPACE ; # (n SPACE)
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ return
+}
+
+proc ::page::parse::peg::matchSymbol_ALPHA {} {
+ # ALPHA = (x (t <)
+ # (t a)
+ # (t l)
+ # (t p)
+ # (t h)
+ # (t a)
+ # (t >)
+ # (n SPACE))
+
+ variable ok
+ if {[inc_restore ALPHA]} {
+ if {$ok} ias_push
+ return
+ }
+
+ set pos [icl_get]
+
+ eseq74 ; # (x (t <)
+ # (t a)
+ # (t l)
+ # (t p)
+ # (t h)
+ # (t a)
+ # (t >)
+ # (n SPACE))
+
+ isv_nonterminal_leaf ALPHA $pos
+ inc_save ALPHA $pos
+ if {$ok} ias_push
+ ier_nonterminal "Expected ALPHA" $pos
+ return
+}
+
+proc ::page::parse::peg::eseq74 {} {
+
+ # (x (t <)
+ # (t a)
+ # (t l)
+ # (t p)
+ # (t h)
+ # (t a)
+ # (t >)
+ # (n SPACE))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set old [ier_get]
+ ict_advance "Expected < (got EOF)"
+ if {$ok} {ict_match_token < "Expected <"}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance "Expected a (got EOF)"
+ if {$ok} {ict_match_token a "Expected a"}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance "Expected l (got EOF)"
+ if {$ok} {ict_match_token l "Expected l"}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance "Expected p (got EOF)"
+ if {$ok} {ict_match_token p "Expected p"}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance "Expected h (got EOF)"
+ if {$ok} {ict_match_token h "Expected h"}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance "Expected a (got EOF)"
+ if {$ok} {ict_match_token a "Expected a"}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance "Expected > (got EOF)"
+ if {$ok} {ict_match_token > "Expected >"}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ matchSymbol_SPACE ; # (n SPACE)
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ return
+}
+
+proc ::page::parse::peg::matchSymbol_AND {} {
+ # AND = (x (t &)
+ # (n SPACE))
+
+ variable ok
+ if {[inc_restore AND]} {
+ if {$ok} ias_push
+ return
+ }
+
+ set pos [icl_get]
+
+ eseq66 ; # (x (t &)
+ # (n SPACE))
+
+ isv_nonterminal_leaf AND $pos
+ inc_save AND $pos
+ if {$ok} ias_push
+ ier_nonterminal "Expected AND" $pos
+ return
+}
+
+proc ::page::parse::peg::eseq66 {} {
+
+ # (x (t &)
+ # (n SPACE))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set old [ier_get]
+ ict_advance "Expected & (got EOF)"
+ if {$ok} {ict_match_token & "Expected &"}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ matchSymbol_SPACE ; # (n SPACE)
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ return
+}
+
+proc ::page::parse::peg::matchSymbol_APOSTROPH {} {
+ # APOSTROPH = (t ')
+
+ variable ok
+ if {[inc_restore APOSTROPH]} return
+
+ set pos [icl_get]
+
+ ict_advance "Expected ' (got EOF)"
+ if {$ok} {ict_match_token ' "Expected '"}
+
+ isv_clear
+ inc_save APOSTROPH $pos
+ ier_nonterminal "Expected APOSTROPH" $pos
+ return
+}
+
+proc ::page::parse::peg::matchSymbol_Attribute {} {
+ # Attribute = (x (/ (n VOID)
+ # (n LEAF)
+ # (n MATCH))
+ # (n COLON))
+
+ variable ok
+ if {[inc_restore Attribute]} {
+ if {$ok} ias_push
+ return
+ }
+
+ set pos [icl_get]
+ set mrk [ias_mark]
+
+ eseq7 ; # (x (/ (n VOID)
+ # (n LEAF)
+ # (n MATCH))
+ # (n COLON))
+
+ isv_nonterminal_reduce Attribute $pos $mrk
+ inc_save Attribute $pos
+ ias_pop2mark $mrk
+ if {$ok} ias_push
+ ier_nonterminal "Expected Attribute" $pos
+ return
+}
+
+proc ::page::parse::peg::eseq7 {} {
+
+ # (x (/ (n VOID)
+ # (n LEAF)
+ # (n MATCH))
+ # (n COLON))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set mrk [ias_mark]
+
+ set old [ier_get]
+ ebra6 ; # (/ (n VOID)
+ # (n LEAF)
+ # (n MATCH))
+ ier_merge $old
+
+ if {!$ok} {
+ ias_pop2mark $mrk
+ icl_rewind $pos
+ return
+ }
+
+ set old [ier_get]
+ matchSymbol_COLON ; # (n COLON)
+ ier_merge $old
+
+ if {!$ok} {
+ ias_pop2mark $mrk
+ icl_rewind $pos
+ return
+ }
+
+ return
+}
+
+proc ::page::parse::peg::ebra6 {} {
+
+ # (/ (n VOID)
+ # (n LEAF)
+ # (n MATCH))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set mrk [ias_mark]
+ set old [ier_get]
+ matchSymbol_VOID ; # (n VOID)
+ ier_merge $old
+
+ if {$ok} return
+ ias_pop2mark $mrk
+ icl_rewind $pos
+
+ set mrk [ias_mark]
+ set old [ier_get]
+ matchSymbol_LEAF ; # (n LEAF)
+ ier_merge $old
+
+ if {$ok} return
+ ias_pop2mark $mrk
+ icl_rewind $pos
+
+ set mrk [ias_mark]
+ set old [ier_get]
+ matchSymbol_MATCH ; # (n MATCH)
+ ier_merge $old
+
+ if {$ok} return
+ ias_pop2mark $mrk
+ icl_rewind $pos
+
+ return
+}
+
+proc ::page::parse::peg::matchSymbol_Char {} {
+ # Char = (/ (n CharSpecial)
+ # (n CharOctalFull)
+ # (n CharOctalPart)
+ # (n CharUnicode)
+ # (n CharUnescaped))
+
+ variable ok
+ if {[inc_restore Char]} {
+ if {$ok} ias_push
+ return
+ }
+
+ set pos [icl_get]
+ set mrk [ias_mark]
+
+ ebra42 ; # (/ (n CharSpecial)
+ # (n CharOctalFull)
+ # (n CharOctalPart)
+ # (n CharUnicode)
+ # (n CharUnescaped))
+
+ isv_nonterminal_reduce Char $pos $mrk
+ inc_save Char $pos
+ ias_pop2mark $mrk
+ if {$ok} ias_push
+ ier_nonterminal "Expected Char" $pos
+ return
+}
+
+proc ::page::parse::peg::ebra42 {} {
+
+ # (/ (n CharSpecial)
+ # (n CharOctalFull)
+ # (n CharOctalPart)
+ # (n CharUnicode)
+ # (n CharUnescaped))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set mrk [ias_mark]
+ set old [ier_get]
+ matchSymbol_CharSpecial ; # (n CharSpecial)
+ ier_merge $old
+
+ if {$ok} return
+ ias_pop2mark $mrk
+ icl_rewind $pos
+
+ set mrk [ias_mark]
+ set old [ier_get]
+ matchSymbol_CharOctalFull ; # (n CharOctalFull)
+ ier_merge $old
+
+ if {$ok} return
+ ias_pop2mark $mrk
+ icl_rewind $pos
+
+ set mrk [ias_mark]
+ set old [ier_get]
+ matchSymbol_CharOctalPart ; # (n CharOctalPart)
+ ier_merge $old
+
+ if {$ok} return
+ ias_pop2mark $mrk
+ icl_rewind $pos
+
+ set mrk [ias_mark]
+ set old [ier_get]
+ matchSymbol_CharUnicode ; # (n CharUnicode)
+ ier_merge $old
+
+ if {$ok} return
+ ias_pop2mark $mrk
+ icl_rewind $pos
+
+ set mrk [ias_mark]
+ set old [ier_get]
+ matchSymbol_CharUnescaped ; # (n CharUnescaped)
+ ier_merge $old
+
+ if {$ok} return
+ ias_pop2mark $mrk
+ icl_rewind $pos
+
+ return
+}
+
+proc ::page::parse::peg::matchSymbol_CharOctalFull {} {
+ # CharOctalFull = (x (t \)
+ # (.. 0 2)
+ # (.. 0 7)
+ # (.. 0 7))
+
+ variable ok
+ if {[inc_restore CharOctalFull]} {
+ if {$ok} ias_push
+ return
+ }
+
+ set pos [icl_get]
+
+ eseq45 ; # (x (t \)
+ # (.. 0 2)
+ # (.. 0 7)
+ # (.. 0 7))
+
+ isv_nonterminal_range CharOctalFull $pos
+ inc_save CharOctalFull $pos
+ if {$ok} ias_push
+ ier_nonterminal "Expected CharOctalFull" $pos
+ return
+}
+
+proc ::page::parse::peg::eseq45 {} {
+
+ # (x (t \)
+ # (.. 0 2)
+ # (.. 0 7)
+ # (.. 0 7))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set old [ier_get]
+ ict_advance "Expected \\ (got EOF)"
+ if {$ok} {ict_match_token \134 "Expected \\"}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance "Expected \[0..2\] (got EOF)"
+ if {$ok} {ict_match_tokrange 0 2 "Expected \[0..2\]"}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance "Expected \[0..7\] (got EOF)"
+ if {$ok} {ict_match_tokrange 0 7 "Expected \[0..7\]"}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance "Expected \[0..7\] (got EOF)"
+ if {$ok} {ict_match_tokrange 0 7 "Expected \[0..7\]"}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ return
+}
+
+proc ::page::parse::peg::matchSymbol_CharOctalPart {} {
+ # CharOctalPart = (x (t \)
+ # (.. 0 7)
+ # (? (.. 0 7)))
+
+ variable ok
+ if {[inc_restore CharOctalPart]} {
+ if {$ok} ias_push
+ return
+ }
+
+ set pos [icl_get]
+
+ eseq47 ; # (x (t \)
+ # (.. 0 7)
+ # (? (.. 0 7)))
+
+ isv_nonterminal_range CharOctalPart $pos
+ inc_save CharOctalPart $pos
+ if {$ok} ias_push
+ ier_nonterminal "Expected CharOctalPart" $pos
+ return
+}
+
+proc ::page::parse::peg::eseq47 {} {
+
+ # (x (t \)
+ # (.. 0 7)
+ # (? (.. 0 7)))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set old [ier_get]
+ ict_advance "Expected \\ (got EOF)"
+ if {$ok} {ict_match_token \134 "Expected \\"}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance "Expected \[0..7\] (got EOF)"
+ if {$ok} {ict_match_tokrange 0 7 "Expected \[0..7\]"}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ eopt46 ; # (? (.. 0 7))
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ return
+}
+
+proc ::page::parse::peg::eopt46 {} {
+
+ # (? (.. 0 7))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set old [ier_get]
+ ict_advance "Expected \[0..7\] (got EOF)"
+ if {$ok} {ict_match_tokrange 0 7 "Expected \[0..7\]"}
+ ier_merge $old
+
+ if {$ok} return
+ icl_rewind $pos
+ iok_ok
+ return
+}
+
+proc ::page::parse::peg::matchSymbol_CharSpecial {} {
+ # CharSpecial = (x (t \)
+ # (/ (t n)
+ # (t r)
+ # (t t)
+ # (t ')
+ # (t \")
+ # (t [)
+ # (t ])
+ # (t \)))
+
+ variable ok
+ if {[inc_restore CharSpecial]} {
+ if {$ok} ias_push
+ return
+ }
+
+ set pos [icl_get]
+
+ eseq44 ; # (x (t \)
+ # (/ (t n)
+ # (t r)
+ # (t t)
+ # (t ')
+ # (t \")
+ # (t [)
+ # (t ])
+ # (t \)))
+
+ isv_nonterminal_range CharSpecial $pos
+ inc_save CharSpecial $pos
+ if {$ok} ias_push
+ ier_nonterminal "Expected CharSpecial" $pos
+ return
+}
+
+proc ::page::parse::peg::eseq44 {} {
+
+ # (x (t \)
+ # (/ (t n)
+ # (t r)
+ # (t t)
+ # (t ')
+ # (t \")
+ # (t [)
+ # (t ])
+ # (t \)))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set old [ier_get]
+ ict_advance "Expected \\ (got EOF)"
+ if {$ok} {ict_match_token \134 "Expected \\"}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ebra43 ; # (/ (t n)
+ # (t r)
+ # (t t)
+ # (t ')
+ # (t \")
+ # (t [)
+ # (t ])
+ # (t \))
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ return
+}
+
+proc ::page::parse::peg::ebra43 {} {
+
+ # (/ (t n)
+ # (t r)
+ # (t t)
+ # (t ')
+ # (t \")
+ # (t [)
+ # (t ])
+ # (t \))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set old [ier_get]
+ ict_advance "Expected n (got EOF)"
+ if {$ok} {ict_match_token n "Expected n"}
+ ier_merge $old
+
+ if {$ok} return
+ icl_rewind $pos
+
+ set old [ier_get]
+ ict_advance "Expected r (got EOF)"
+ if {$ok} {ict_match_token r "Expected r"}
+ ier_merge $old
+
+ if {$ok} return
+ icl_rewind $pos
+
+ set old [ier_get]
+ ict_advance "Expected t (got EOF)"
+ if {$ok} {ict_match_token t "Expected t"}
+ ier_merge $old
+
+ if {$ok} return
+ icl_rewind $pos
+
+ set old [ier_get]
+ ict_advance "Expected ' (got EOF)"
+ if {$ok} {ict_match_token ' "Expected '"}
+ ier_merge $old
+
+ if {$ok} return
+ icl_rewind $pos
+
+ set old [ier_get]
+ ict_advance "Expected \" (got EOF)"
+ if {$ok} {ict_match_token \42 "Expected \""}
+ ier_merge $old
+
+ if {$ok} return
+ icl_rewind $pos
+
+ set old [ier_get]
+ ict_advance "Expected \[ (got EOF)"
+ if {$ok} {ict_match_token \133 "Expected \["}
+ ier_merge $old
+
+ if {$ok} return
+ icl_rewind $pos
+
+ set old [ier_get]
+ ict_advance "Expected \] (got EOF)"
+ if {$ok} {ict_match_token \135 "Expected \]"}
+ ier_merge $old
+
+ if {$ok} return
+ icl_rewind $pos
+
+ set old [ier_get]
+ ict_advance "Expected \\ (got EOF)"
+ if {$ok} {ict_match_token \134 "Expected \\"}
+ ier_merge $old
+
+ if {$ok} return
+ icl_rewind $pos
+
+ return
+}
+
+proc ::page::parse::peg::matchSymbol_CharUnescaped {} {
+ # CharUnescaped = (x (! (t \))
+ # (dot))
+
+ variable ok
+ if {[inc_restore CharUnescaped]} {
+ if {$ok} ias_push
+ return
+ }
+
+ set pos [icl_get]
+
+ eseq55 ; # (x (! (t \))
+ # (dot))
+
+ isv_nonterminal_range CharUnescaped $pos
+ inc_save CharUnescaped $pos
+ if {$ok} ias_push
+ ier_nonterminal "Expected CharUnescaped" $pos
+ return
+}
+
+proc ::page::parse::peg::eseq55 {} {
+
+ # (x (! (t \))
+ # (dot))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set old [ier_get]
+ ebang54
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance "Expected any character (got EOF)"
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ return
+}
+
+proc ::page::parse::peg::ebang54 {} {
+ variable ok
+
+ set pos [icl_get]
+
+ ict_advance "Expected \\ (got EOF)"
+ if {$ok} {ict_match_token \134 "Expected \\"}
+
+ icl_rewind $pos
+ iok_negate
+ return
+}
+
+proc ::page::parse::peg::matchSymbol_CharUnicode {} {
+ # CharUnicode = (x (t \)
+ # (t u)
+ # (n HexDigit)
+ # (? (x (n HexDigit)
+ # (? (x (n HexDigit)
+ # (? (n HexDigit)))))))
+
+ variable ok
+ if {[inc_restore CharUnicode]} {
+ if {$ok} ias_push
+ return
+ }
+
+ set pos [icl_get]
+
+ eseq53 ; # (x (t \)
+ # (t u)
+ # (n HexDigit)
+ # (? (x (n HexDigit)
+ # (? (x (n HexDigit)
+ # (? (n HexDigit)))))))
+
+ isv_nonterminal_range CharUnicode $pos
+ inc_save CharUnicode $pos
+ if {$ok} ias_push
+ ier_nonterminal "Expected CharUnicode" $pos
+ return
+}
+
+proc ::page::parse::peg::eseq53 {} {
+
+ # (x (t \)
+ # (t u)
+ # (n HexDigit)
+ # (? (x (n HexDigit)
+ # (? (x (n HexDigit)
+ # (? (n HexDigit)))))))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set old [ier_get]
+ ict_advance "Expected \\ (got EOF)"
+ if {$ok} {ict_match_token \134 "Expected \\"}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance "Expected u (got EOF)"
+ if {$ok} {ict_match_token u "Expected u"}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ matchSymbol_HexDigit ; # (n HexDigit)
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ eopt52 ; # (? (x (n HexDigit)
+ # (? (x (n HexDigit)
+ # (? (n HexDigit))))))
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ return
+}
+
+proc ::page::parse::peg::eopt52 {} {
+
+ # (? (x (n HexDigit)
+ # (? (x (n HexDigit)
+ # (? (n HexDigit))))))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set old [ier_get]
+ eseq51 ; # (x (n HexDigit)
+ # (? (x (n HexDigit)
+ # (? (n HexDigit)))))
+ ier_merge $old
+
+ if {$ok} return
+ icl_rewind $pos
+ iok_ok
+ return
+}
+
+proc ::page::parse::peg::eseq51 {} {
+
+ # (x (n HexDigit)
+ # (? (x (n HexDigit)
+ # (? (n HexDigit)))))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set old [ier_get]
+ matchSymbol_HexDigit ; # (n HexDigit)
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ eopt50 ; # (? (x (n HexDigit)
+ # (? (n HexDigit))))
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ return
+}
+
+proc ::page::parse::peg::eopt50 {} {
+
+ # (? (x (n HexDigit)
+ # (? (n HexDigit))))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set old [ier_get]
+ eseq49 ; # (x (n HexDigit)
+ # (? (n HexDigit)))
+ ier_merge $old
+
+ if {$ok} return
+ icl_rewind $pos
+ iok_ok
+ return
+}
+
+proc ::page::parse::peg::eseq49 {} {
+
+ # (x (n HexDigit)
+ # (? (n HexDigit)))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set old [ier_get]
+ matchSymbol_HexDigit ; # (n HexDigit)
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ eopt48 ; # (? (n HexDigit))
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ return
+}
+
+proc ::page::parse::peg::eopt48 {} {
+
+ # (? (n HexDigit))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set old [ier_get]
+ matchSymbol_HexDigit ; # (n HexDigit)
+ ier_merge $old
+
+ if {$ok} return
+ icl_rewind $pos
+ iok_ok
+ return
+}
+
+proc ::page::parse::peg::matchSymbol_Class {} {
+ # Class = (x (n OPENB)
+ # (* (x (! (n CLOSEB))
+ # (n Range)))
+ # (n CLOSEB)
+ # (n SPACE))
+
+ variable ok
+ if {[inc_restore Class]} {
+ if {$ok} ias_push
+ return
+ }
+
+ set pos [icl_get]
+ set mrk [ias_mark]
+
+ eseq32 ; # (x (n OPENB)
+ # (* (x (! (n CLOSEB))
+ # (n Range)))
+ # (n CLOSEB)
+ # (n SPACE))
+
+ isv_nonterminal_reduce Class $pos $mrk
+ inc_save Class $pos
+ ias_pop2mark $mrk
+ if {$ok} ias_push
+ ier_nonterminal "Expected Class" $pos
+ return
+}
+
+proc ::page::parse::peg::eseq32 {} {
+
+ # (x (n OPENB)
+ # (* (x (! (n CLOSEB))
+ # (n Range)))
+ # (n CLOSEB)
+ # (n SPACE))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set old [ier_get]
+ matchSymbol_OPENB ; # (n OPENB)
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set mrk [ias_mark]
+
+ set old [ier_get]
+ ekleene31 ; # (* (x (! (n CLOSEB))
+ # (n Range)))
+ ier_merge $old
+
+ if {!$ok} {
+ ias_pop2mark $mrk
+ icl_rewind $pos
+ return
+ }
+
+ set old [ier_get]
+ matchSymbol_CLOSEB ; # (n CLOSEB)
+ ier_merge $old
+
+ if {!$ok} {
+ ias_pop2mark $mrk
+ icl_rewind $pos
+ return
+ }
+
+ set old [ier_get]
+ matchSymbol_SPACE ; # (n SPACE)
+ ier_merge $old
+
+ if {!$ok} {
+ ias_pop2mark $mrk
+ icl_rewind $pos
+ return
+ }
+
+ return
+}
+
+proc ::page::parse::peg::ekleene31 {} {
+
+ # (* (x (! (n CLOSEB))
+ # (n Range)))
+
+ variable ok
+
+ while {1} {
+ set pos [icl_get]
+
+ set old [ier_get]
+ eseq30 ; # (x (! (n CLOSEB))
+ # (n Range))
+ ier_merge $old
+
+ if {$ok} continue
+ break
+ }
+
+ icl_rewind $pos
+ iok_ok
+ return
+}
+
+proc ::page::parse::peg::eseq30 {} {
+
+ # (x (! (n CLOSEB))
+ # (n Range))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set old [ier_get]
+ ebang29
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set mrk [ias_mark]
+
+ set old [ier_get]
+ matchSymbol_Range ; # (n Range)
+ ier_merge $old
+
+ if {!$ok} {
+ ias_pop2mark $mrk
+ icl_rewind $pos
+ return
+ }
+
+ return
+}
+
+proc ::page::parse::peg::ebang29 {} {
+ set pos [icl_get]
+
+ matchSymbol_CLOSEB ; # (n CLOSEB)
+
+ icl_rewind $pos
+ iok_negate
+ return
+}
+
+proc ::page::parse::peg::matchSymbol_CLOSE {} {
+ # CLOSE = (x (t \))
+ # (n SPACE))
+
+ if {[inc_restore CLOSE]} return
+
+ set pos [icl_get]
+
+ eseq72 ; # (x (t \))
+ # (n SPACE))
+
+ isv_clear
+ inc_save CLOSE $pos
+ ier_nonterminal "Expected CLOSE" $pos
+ return
+}
+
+proc ::page::parse::peg::eseq72 {} {
+
+ # (x (t \))
+ # (n SPACE))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set old [ier_get]
+ ict_advance "Expected \) (got EOF)"
+ if {$ok} {ict_match_token \51 "Expected \)"}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ matchSymbol_SPACE ; # (n SPACE)
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ return
+}
+
+proc ::page::parse::peg::matchSymbol_CLOSEB {} {
+ # CLOSEB = (t ])
+
+ variable ok
+ if {[inc_restore CLOSEB]} return
+
+ set pos [icl_get]
+
+ ict_advance "Expected \] (got EOF)"
+ if {$ok} {ict_match_token \135 "Expected \]"}
+
+ isv_clear
+ inc_save CLOSEB $pos
+ ier_nonterminal "Expected CLOSEB" $pos
+ return
+}
+
+proc ::page::parse::peg::matchSymbol_COLON {} {
+ # COLON = (x (t :)
+ # (n SPACE))
+
+ if {[inc_restore COLON]} return
+
+ set pos [icl_get]
+
+ eseq64 ; # (x (t :)
+ # (n SPACE))
+
+ isv_clear
+ inc_save COLON $pos
+ ier_nonterminal "Expected COLON" $pos
+ return
+}
+
+proc ::page::parse::peg::eseq64 {} {
+
+ # (x (t :)
+ # (n SPACE))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set old [ier_get]
+ ict_advance "Expected : (got EOF)"
+ if {$ok} {ict_match_token : "Expected :"}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ matchSymbol_SPACE ; # (n SPACE)
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ return
+}
+
+proc ::page::parse::peg::matchSymbol_COMMENT {} {
+ # COMMENT = (x (t #)
+ # (* (x (! (n EOL))
+ # (dot)))
+ # (n EOL))
+
+ if {[inc_restore COMMENT]} return
+
+ set pos [icl_get]
+
+ eseq81 ; # (x (t #)
+ # (* (x (! (n EOL))
+ # (dot)))
+ # (n EOL))
+
+ isv_clear
+ inc_save COMMENT $pos
+ ier_nonterminal "Expected COMMENT" $pos
+ return
+}
+
+proc ::page::parse::peg::eseq81 {} {
+
+ # (x (t #)
+ # (* (x (! (n EOL))
+ # (dot)))
+ # (n EOL))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set old [ier_get]
+ ict_advance "Expected # (got EOF)"
+ if {$ok} {ict_match_token # "Expected #"}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ekleene80 ; # (* (x (! (n EOL))
+ # (dot)))
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ matchSymbol_EOL ; # (n EOL)
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ return
+}
+
+proc ::page::parse::peg::ekleene80 {} {
+
+ # (* (x (! (n EOL))
+ # (dot)))
+
+ variable ok
+
+ while {1} {
+ set pos [icl_get]
+
+ set old [ier_get]
+ eseq79 ; # (x (! (n EOL))
+ # (dot))
+ ier_merge $old
+
+ if {$ok} continue
+ break
+ }
+
+ icl_rewind $pos
+ iok_ok
+ return
+}
+
+proc ::page::parse::peg::eseq79 {} {
+
+ # (x (! (n EOL))
+ # (dot))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set old [ier_get]
+ ebang78
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance "Expected any character (got EOF)"
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ return
+}
+
+proc ::page::parse::peg::ebang78 {} {
+ set pos [icl_get]
+
+ matchSymbol_EOL ; # (n EOL)
+
+ icl_rewind $pos
+ iok_negate
+ return
+}
+
+proc ::page::parse::peg::matchSymbol_DAPOSTROPH {} {
+ # DAPOSTROPH = (t \")
+
+ variable ok
+ if {[inc_restore DAPOSTROPH]} return
+
+ set pos [icl_get]
+
+ ict_advance "Expected \" (got EOF)"
+ if {$ok} {ict_match_token \42 "Expected \""}
+
+ isv_clear
+ inc_save DAPOSTROPH $pos
+ ier_nonterminal "Expected DAPOSTROPH" $pos
+ return
+}
+
+proc ::page::parse::peg::matchSymbol_Definition {} {
+ # Definition = (x (? (n Attribute))
+ # (n Identifier)
+ # (n IS)
+ # (n Expression)
+ # (n SEMICOLON))
+
+ variable ok
+ if {[inc_restore Definition]} {
+ if {$ok} ias_push
+ return
+ }
+
+ set pos [icl_get]
+ set mrk [ias_mark]
+
+ eseq5 ; # (x (? (n Attribute))
+ # (n Identifier)
+ # (n IS)
+ # (n Expression)
+ # (n SEMICOLON))
+
+ isv_nonterminal_reduce Definition $pos $mrk
+ inc_save Definition $pos
+ ias_pop2mark $mrk
+ if {$ok} ias_push
+ ier_nonterminal "Expected Definition" $pos
+ return
+}
+
+proc ::page::parse::peg::eseq5 {} {
+
+ # (x (? (n Attribute))
+ # (n Identifier)
+ # (n IS)
+ # (n Expression)
+ # (n SEMICOLON))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set mrk [ias_mark]
+
+ set old [ier_get]
+ eopt4 ; # (? (n Attribute))
+ ier_merge $old
+
+ if {!$ok} {
+ ias_pop2mark $mrk
+ icl_rewind $pos
+ return
+ }
+
+ set old [ier_get]
+ matchSymbol_Identifier ; # (n Identifier)
+ ier_merge $old
+
+ if {!$ok} {
+ ias_pop2mark $mrk
+ icl_rewind $pos
+ return
+ }
+
+ set old [ier_get]
+ matchSymbol_IS ; # (n IS)
+ ier_merge $old
+
+ if {!$ok} {
+ ias_pop2mark $mrk
+ icl_rewind $pos
+ return
+ }
+
+ set old [ier_get]
+ matchSymbol_Expression ; # (n Expression)
+ ier_merge $old
+
+ if {!$ok} {
+ ias_pop2mark $mrk
+ icl_rewind $pos
+ return
+ }
+
+ set old [ier_get]
+ matchSymbol_SEMICOLON ; # (n SEMICOLON)
+ ier_merge $old
+
+ if {!$ok} {
+ ias_pop2mark $mrk
+ icl_rewind $pos
+ return
+ }
+
+ return
+}
+
+proc ::page::parse::peg::eopt4 {} {
+
+ # (? (n Attribute))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set old [ier_get]
+ matchSymbol_Attribute ; # (n Attribute)
+ ier_merge $old
+
+ if {$ok} return
+ icl_rewind $pos
+ iok_ok
+ return
+}
+
+proc ::page::parse::peg::matchSymbol_DOT {} {
+ # DOT = (x (t .)
+ # (n SPACE))
+
+ variable ok
+ if {[inc_restore DOT]} {
+ if {$ok} ias_push
+ return
+ }
+
+ set pos [icl_get]
+
+ eseq73 ; # (x (t .)
+ # (n SPACE))
+
+ isv_nonterminal_leaf DOT $pos
+ inc_save DOT $pos
+ if {$ok} ias_push
+ ier_nonterminal "Expected DOT" $pos
+ return
+}
+
+proc ::page::parse::peg::eseq73 {} {
+
+ # (x (t .)
+ # (n SPACE))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set old [ier_get]
+ ict_advance "Expected . (got EOF)"
+ if {$ok} {ict_match_token . "Expected ."}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ matchSymbol_SPACE ; # (n SPACE)
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ return
+}
+
+proc ::page::parse::peg::matchSymbol_END {} {
+ # END = (x (t E)
+ # (t N)
+ # (t D)
+ # (n SPACE))
+
+ if {[inc_restore END]} return
+
+ set pos [icl_get]
+
+ eseq62 ; # (x (t E)
+ # (t N)
+ # (t D)
+ # (n SPACE))
+
+ isv_clear
+ inc_save END $pos
+ ier_nonterminal "Expected END" $pos
+ return
+}
+
+proc ::page::parse::peg::eseq62 {} {
+
+ # (x (t E)
+ # (t N)
+ # (t D)
+ # (n SPACE))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set old [ier_get]
+ ict_advance "Expected E (got EOF)"
+ if {$ok} {ict_match_token E "Expected E"}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance "Expected N (got EOF)"
+ if {$ok} {ict_match_token N "Expected N"}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance "Expected D (got EOF)"
+ if {$ok} {ict_match_token D "Expected D"}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ matchSymbol_SPACE ; # (n SPACE)
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ return
+}
+
+proc ::page::parse::peg::matchSymbol_EOF {} {
+ # EOF = (! (dot))
+
+ if {[inc_restore EOF]} return
+
+ set pos [icl_get]
+
+ ebang84
+
+ isv_clear
+ inc_save EOF $pos
+ ier_nonterminal "Expected EOF" $pos
+ return
+}
+
+proc ::page::parse::peg::ebang84 {} {
+ set pos [icl_get]
+
+ ict_advance "Expected any character (got EOF)"
+
+ icl_rewind $pos
+ iok_negate
+ return
+}
+
+proc ::page::parse::peg::matchSymbol_EOL {} {
+ # EOL = (/ (x (t \n)
+ # (t \r))
+ # (t \n)
+ # (t \r))
+
+ if {[inc_restore EOL]} return
+
+ set pos [icl_get]
+
+ ebra83 ; # (/ (x (t \n)
+ # (t \r))
+ # (t \n)
+ # (t \r))
+
+ isv_clear
+ inc_save EOL $pos
+ ier_nonterminal "Expected EOL" $pos
+ return
+}
+
+proc ::page::parse::peg::ebra83 {} {
+
+ # (/ (x (t \n)
+ # (t \r))
+ # (t \n)
+ # (t \r))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set old [ier_get]
+ eseq82 ; # (x (t \n)
+ # (t \r))
+ ier_merge $old
+
+ if {$ok} return
+ icl_rewind $pos
+
+ set old [ier_get]
+ ict_advance "Expected \\n (got EOF)"
+ if {$ok} {ict_match_token \n "Expected \\n"}
+ ier_merge $old
+
+ if {$ok} return
+ icl_rewind $pos
+
+ set old [ier_get]
+ ict_advance "Expected \\r (got EOF)"
+ if {$ok} {ict_match_token \r "Expected \\r"}
+ ier_merge $old
+
+ if {$ok} return
+ icl_rewind $pos
+
+ return
+}
+
+proc ::page::parse::peg::eseq82 {} {
+
+ # (x (t \n)
+ # (t \r))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set old [ier_get]
+ ict_advance "Expected \\n (got EOF)"
+ if {$ok} {ict_match_token \n "Expected \\n"}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance "Expected \\r (got EOF)"
+ if {$ok} {ict_match_token \r "Expected \\r"}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ return
+}
+
+proc ::page::parse::peg::matchSymbol_Expression {} {
+ # Expression = (x (n Sequence)
+ # (* (x (n SLASH)
+ # (n Sequence))))
+
+ variable ok
+ if {[inc_restore Expression]} {
+ if {$ok} ias_push
+ return
+ }
+
+ set pos [icl_get]
+ set mrk [ias_mark]
+
+ eseq10 ; # (x (n Sequence)
+ # (* (x (n SLASH)
+ # (n Sequence))))
+
+ isv_nonterminal_reduce Expression $pos $mrk
+ inc_save Expression $pos
+ ias_pop2mark $mrk
+ if {$ok} ias_push
+ ier_nonterminal "Expected Expression" $pos
+ return
+}
+
+proc ::page::parse::peg::eseq10 {} {
+
+ # (x (n Sequence)
+ # (* (x (n SLASH)
+ # (n Sequence))))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set mrk [ias_mark]
+
+ set old [ier_get]
+ matchSymbol_Sequence ; # (n Sequence)
+ ier_merge $old
+
+ if {!$ok} {
+ ias_pop2mark $mrk
+ icl_rewind $pos
+ return
+ }
+
+ set old [ier_get]
+ ekleene9 ; # (* (x (n SLASH)
+ # (n Sequence)))
+ ier_merge $old
+
+ if {!$ok} {
+ ias_pop2mark $mrk
+ icl_rewind $pos
+ return
+ }
+
+ return
+}
+
+proc ::page::parse::peg::ekleene9 {} {
+
+ # (* (x (n SLASH)
+ # (n Sequence)))
+
+ variable ok
+
+ while {1} {
+ set pos [icl_get]
+
+ set old [ier_get]
+ eseq8 ; # (x (n SLASH)
+ # (n Sequence))
+ ier_merge $old
+
+ if {$ok} continue
+ break
+ }
+
+ icl_rewind $pos
+ iok_ok
+ return
+}
+
+proc ::page::parse::peg::eseq8 {} {
+
+ # (x (n SLASH)
+ # (n Sequence))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set old [ier_get]
+ matchSymbol_SLASH ; # (n SLASH)
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set mrk [ias_mark]
+
+ set old [ier_get]
+ matchSymbol_Sequence ; # (n Sequence)
+ ier_merge $old
+
+ if {!$ok} {
+ ias_pop2mark $mrk
+ icl_rewind $pos
+ return
+ }
+
+ return
+}
+
+proc ::page::parse::peg::matchSymbol_Final {} {
+ # Final = (x (n END)
+ # (n SEMICOLON)
+ # (n SPACE))
+
+ if {[inc_restore Final]} return
+
+ set pos [icl_get]
+
+ eseq36 ; # (x (n END)
+ # (n SEMICOLON)
+ # (n SPACE))
+
+ isv_clear
+ inc_save Final $pos
+ ier_nonterminal "Expected Final" $pos
+ return
+}
+
+proc ::page::parse::peg::eseq36 {} {
+
+ # (x (n END)
+ # (n SEMICOLON)
+ # (n SPACE))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set old [ier_get]
+ matchSymbol_END ; # (n END)
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ matchSymbol_SEMICOLON ; # (n SEMICOLON)
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ matchSymbol_SPACE ; # (n SPACE)
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ return
+}
+
+proc ::page::parse::peg::matchSymbol_Grammar {} {
+ # Grammar = (x (n SPACE)
+ # (n Header)
+ # (+ (n Definition))
+ # (n Final)
+ # (n EOF))
+
+ variable ok
+ if {[inc_restore Grammar]} {
+ if {$ok} ias_push
+ return
+ }
+
+ set pos [icl_get]
+ set mrk [ias_mark]
+
+ eseq2 ; # (x (n SPACE)
+ # (n Header)
+ # (+ (n Definition))
+ # (n Final)
+ # (n EOF))
+
+ isv_nonterminal_reduce Grammar $pos $mrk
+ inc_save Grammar $pos
+ ias_pop2mark $mrk
+ if {$ok} ias_push
+ ier_nonterminal "Expected Grammar" $pos
+ return
+}
+
+proc ::page::parse::peg::eseq2 {} {
+
+ # (x (n SPACE)
+ # (n Header)
+ # (+ (n Definition))
+ # (n Final)
+ # (n EOF))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set old [ier_get]
+ matchSymbol_SPACE ; # (n SPACE)
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set mrk [ias_mark]
+
+ set old [ier_get]
+ matchSymbol_Header ; # (n Header)
+ ier_merge $old
+
+ if {!$ok} {
+ ias_pop2mark $mrk
+ icl_rewind $pos
+ return
+ }
+
+ set old [ier_get]
+ epkleene1 ; # (+ (n Definition))
+ ier_merge $old
+
+ if {!$ok} {
+ ias_pop2mark $mrk
+ icl_rewind $pos
+ return
+ }
+
+ set old [ier_get]
+ matchSymbol_Final ; # (n Final)
+ ier_merge $old
+
+ if {!$ok} {
+ ias_pop2mark $mrk
+ icl_rewind $pos
+ return
+ }
+
+ set old [ier_get]
+ matchSymbol_EOF ; # (n EOF)
+ ier_merge $old
+
+ if {!$ok} {
+ ias_pop2mark $mrk
+ icl_rewind $pos
+ return
+ }
+
+ return
+}
+
+proc ::page::parse::peg::epkleene1 {} {
+
+ # (+ (n Definition))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set old [ier_get]
+ matchSymbol_Definition ; # (n Definition)
+ ier_merge $old
+
+ if {!$ok} {
+ icl_rewind $pos
+ return
+ }
+
+ while {1} {
+ set pos [icl_get]
+
+ set old [ier_get]
+ matchSymbol_Definition ; # (n Definition)
+ ier_merge $old
+
+ if {$ok} continue
+ break
+ }
+
+ icl_rewind $pos
+ iok_ok
+ return
+}
+
+proc ::page::parse::peg::matchSymbol_Header {} {
+ # Header = (x (n PEG)
+ # (n Identifier)
+ # (n StartExpr))
+
+ variable ok
+ if {[inc_restore Header]} {
+ if {$ok} ias_push
+ return
+ }
+
+ set pos [icl_get]
+ set mrk [ias_mark]
+
+ eseq3 ; # (x (n PEG)
+ # (n Identifier)
+ # (n StartExpr))
+
+ isv_nonterminal_reduce Header $pos $mrk
+ inc_save Header $pos
+ ias_pop2mark $mrk
+ if {$ok} ias_push
+ ier_nonterminal "Expected Header" $pos
+ return
+}
+
+proc ::page::parse::peg::eseq3 {} {
+
+ # (x (n PEG)
+ # (n Identifier)
+ # (n StartExpr))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set old [ier_get]
+ matchSymbol_PEG ; # (n PEG)
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set mrk [ias_mark]
+
+ set old [ier_get]
+ matchSymbol_Identifier ; # (n Identifier)
+ ier_merge $old
+
+ if {!$ok} {
+ ias_pop2mark $mrk
+ icl_rewind $pos
+ return
+ }
+
+ set old [ier_get]
+ matchSymbol_StartExpr ; # (n StartExpr)
+ ier_merge $old
+
+ if {!$ok} {
+ ias_pop2mark $mrk
+ icl_rewind $pos
+ return
+ }
+
+ return
+}
+
+proc ::page::parse::peg::matchSymbol_HexDigit {} {
+ # HexDigit = (/ (.. 0 9)
+ # (.. a f)
+ # (.. A F))
+
+ if {[inc_restore HexDigit]} return
+
+ set pos [icl_get]
+
+ ebra56 ; # (/ (.. 0 9)
+ # (.. a f)
+ # (.. A F))
+
+ isv_clear
+ inc_save HexDigit $pos
+ ier_nonterminal "Expected HexDigit" $pos
+ return
+}
+
+proc ::page::parse::peg::ebra56 {} {
+
+ # (/ (.. 0 9)
+ # (.. a f)
+ # (.. A F))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set old [ier_get]
+ ict_advance "Expected \[0..9\] (got EOF)"
+ if {$ok} {ict_match_tokrange 0 9 "Expected \[0..9\]"}
+ ier_merge $old
+
+ if {$ok} return
+ icl_rewind $pos
+
+ set old [ier_get]
+ ict_advance "Expected \[a..f\] (got EOF)"
+ if {$ok} {ict_match_tokrange a f "Expected \[a..f\]"}
+ ier_merge $old
+
+ if {$ok} return
+ icl_rewind $pos
+
+ set old [ier_get]
+ ict_advance "Expected \[A..F\] (got EOF)"
+ if {$ok} {ict_match_tokrange A F "Expected \[A..F\]"}
+ ier_merge $old
+
+ if {$ok} return
+ icl_rewind $pos
+
+ return
+}
+
+proc ::page::parse::peg::matchSymbol_Ident {} {
+ # Ident = (x (/ (t _)
+ # (t :)
+ # (alpha))
+ # (* (/ (t _)
+ # (t :)
+ # (alnum))))
+
+ variable ok
+ if {[inc_restore Ident]} {
+ if {$ok} ias_push
+ return
+ }
+
+ set pos [icl_get]
+
+ eseq41 ; # (x (/ (t _)
+ # (t :)
+ # (alpha))
+ # (* (/ (t _)
+ # (t :)
+ # (alnum))))
+
+ isv_nonterminal_range Ident $pos
+ inc_save Ident $pos
+ if {$ok} ias_push
+ ier_nonterminal "Expected Ident" $pos
+ return
+}
+
+proc ::page::parse::peg::eseq41 {} {
+
+ # (x (/ (t _)
+ # (t :)
+ # (alpha))
+ # (* (/ (t _)
+ # (t :)
+ # (alnum))))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set old [ier_get]
+ ebra38 ; # (/ (t _)
+ # (t :)
+ # (alpha))
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ekleene40 ; # (* (/ (t _)
+ # (t :)
+ # (alnum)))
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ return
+}
+
+proc ::page::parse::peg::ebra38 {} {
+
+ # (/ (t _)
+ # (t :)
+ # (alpha))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set old [ier_get]
+ ict_advance "Expected _ (got EOF)"
+ if {$ok} {ict_match_token _ "Expected _"}
+ ier_merge $old
+
+ if {$ok} return
+ icl_rewind $pos
+
+ set old [ier_get]
+ ict_advance "Expected : (got EOF)"
+ if {$ok} {ict_match_token : "Expected :"}
+ ier_merge $old
+
+ if {$ok} return
+ icl_rewind $pos
+
+ set old [ier_get]
+ ict_advance "Expected <alpha> (got EOF)"
+ if {$ok} {ict_match_tokclass alpha "Expected <alpha>"}
+ ier_merge $old
+
+ if {$ok} return
+ icl_rewind $pos
+
+ return
+}
+
+proc ::page::parse::peg::ekleene40 {} {
+
+ # (* (/ (t _)
+ # (t :)
+ # (alnum)))
+
+ variable ok
+
+ while {1} {
+ set pos [icl_get]
+
+ set old [ier_get]
+ ebra39 ; # (/ (t _)
+ # (t :)
+ # (alnum))
+ ier_merge $old
+
+ if {$ok} continue
+ break
+ }
+
+ icl_rewind $pos
+ iok_ok
+ return
+}
+
+proc ::page::parse::peg::ebra39 {} {
+
+ # (/ (t _)
+ # (t :)
+ # (alnum))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set old [ier_get]
+ ict_advance "Expected _ (got EOF)"
+ if {$ok} {ict_match_token _ "Expected _"}
+ ier_merge $old
+
+ if {$ok} return
+ icl_rewind $pos
+
+ set old [ier_get]
+ ict_advance "Expected : (got EOF)"
+ if {$ok} {ict_match_token : "Expected :"}
+ ier_merge $old
+
+ if {$ok} return
+ icl_rewind $pos
+
+ set old [ier_get]
+ ict_advance "Expected <alnum> (got EOF)"
+ if {$ok} {ict_match_tokclass alnum "Expected <alnum>"}
+ ier_merge $old
+
+ if {$ok} return
+ icl_rewind $pos
+
+ return
+}
+
+proc ::page::parse::peg::matchSymbol_Identifier {} {
+ # Identifier = (x (n Ident)
+ # (n SPACE))
+
+ variable ok
+ if {[inc_restore Identifier]} {
+ if {$ok} ias_push
+ return
+ }
+
+ set pos [icl_get]
+ set mrk [ias_mark]
+
+ eseq37 ; # (x (n Ident)
+ # (n SPACE))
+
+ isv_nonterminal_reduce Identifier $pos $mrk
+ inc_save Identifier $pos
+ ias_pop2mark $mrk
+ if {$ok} ias_push
+ ier_nonterminal "Expected Identifier" $pos
+ return
+}
+
+proc ::page::parse::peg::eseq37 {} {
+
+ # (x (n Ident)
+ # (n SPACE))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set mrk [ias_mark]
+
+ set old [ier_get]
+ matchSymbol_Ident ; # (n Ident)
+ ier_merge $old
+
+ if {!$ok} {
+ ias_pop2mark $mrk
+ icl_rewind $pos
+ return
+ }
+
+ set old [ier_get]
+ matchSymbol_SPACE ; # (n SPACE)
+ ier_merge $old
+
+ if {!$ok} {
+ ias_pop2mark $mrk
+ icl_rewind $pos
+ return
+ }
+
+ return
+}
+
+proc ::page::parse::peg::matchSymbol_IS {} {
+ # IS = (x (t <)
+ # (t -)
+ # (n SPACE))
+
+ if {[inc_restore IS]} return
+
+ set pos [icl_get]
+
+ eseq58 ; # (x (t <)
+ # (t -)
+ # (n SPACE))
+
+ isv_clear
+ inc_save IS $pos
+ ier_nonterminal "Expected IS" $pos
+ return
+}
+
+proc ::page::parse::peg::eseq58 {} {
+
+ # (x (t <)
+ # (t -)
+ # (n SPACE))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set old [ier_get]
+ ict_advance "Expected < (got EOF)"
+ if {$ok} {ict_match_token < "Expected <"}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance "Expected - (got EOF)"
+ if {$ok} {ict_match_token - "Expected -"}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ matchSymbol_SPACE ; # (n SPACE)
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ return
+}
+
+proc ::page::parse::peg::matchSymbol_LEAF {} {
+ # LEAF = (x (t l)
+ # (t e)
+ # (t a)
+ # (t f)
+ # (n SPACE))
+
+ variable ok
+ if {[inc_restore LEAF]} {
+ if {$ok} ias_push
+ return
+ }
+
+ set pos [icl_get]
+
+ eseq60 ; # (x (t l)
+ # (t e)
+ # (t a)
+ # (t f)
+ # (n SPACE))
+
+ isv_nonterminal_leaf LEAF $pos
+ inc_save LEAF $pos
+ if {$ok} ias_push
+ ier_nonterminal "Expected LEAF" $pos
+ return
+}
+
+proc ::page::parse::peg::eseq60 {} {
+
+ # (x (t l)
+ # (t e)
+ # (t a)
+ # (t f)
+ # (n SPACE))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set old [ier_get]
+ ict_advance "Expected l (got EOF)"
+ if {$ok} {ict_match_token l "Expected l"}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance "Expected e (got EOF)"
+ if {$ok} {ict_match_token e "Expected e"}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance "Expected a (got EOF)"
+ if {$ok} {ict_match_token a "Expected a"}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance "Expected f (got EOF)"
+ if {$ok} {ict_match_token f "Expected f"}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ matchSymbol_SPACE ; # (n SPACE)
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ return
+}
+
+proc ::page::parse::peg::matchSymbol_Literal {} {
+ # Literal = (/ (x (n APOSTROPH)
+ # (* (x (! (n APOSTROPH))
+ # (n Char)))
+ # (n APOSTROPH)
+ # (n SPACE))
+ # (x (n DAPOSTROPH)
+ # (* (x (! (n DAPOSTROPH))
+ # (n Char)))
+ # (n DAPOSTROPH)
+ # (n SPACE)))
+
+ variable ok
+ if {[inc_restore Literal]} {
+ if {$ok} ias_push
+ return
+ }
+
+ set pos [icl_get]
+ set mrk [ias_mark]
+
+ ebra28 ; # (/ (x (n APOSTROPH)
+ # (* (x (! (n APOSTROPH))
+ # (n Char)))
+ # (n APOSTROPH)
+ # (n SPACE))
+ # (x (n DAPOSTROPH)
+ # (* (x (! (n DAPOSTROPH))
+ # (n Char)))
+ # (n DAPOSTROPH)
+ # (n SPACE)))
+
+ isv_nonterminal_reduce Literal $pos $mrk
+ inc_save Literal $pos
+ ias_pop2mark $mrk
+ if {$ok} ias_push
+ ier_nonterminal "Expected Literal" $pos
+ return
+}
+
+proc ::page::parse::peg::ebra28 {} {
+
+ # (/ (x (n APOSTROPH)
+ # (* (x (! (n APOSTROPH))
+ # (n Char)))
+ # (n APOSTROPH)
+ # (n SPACE))
+ # (x (n DAPOSTROPH)
+ # (* (x (! (n DAPOSTROPH))
+ # (n Char)))
+ # (n DAPOSTROPH)
+ # (n SPACE)))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set mrk [ias_mark]
+ set old [ier_get]
+ eseq23 ; # (x (n APOSTROPH)
+ # (* (x (! (n APOSTROPH))
+ # (n Char)))
+ # (n APOSTROPH)
+ # (n SPACE))
+ ier_merge $old
+
+ if {$ok} return
+ ias_pop2mark $mrk
+ icl_rewind $pos
+
+ set mrk [ias_mark]
+ set old [ier_get]
+ eseq27 ; # (x (n DAPOSTROPH)
+ # (* (x (! (n DAPOSTROPH))
+ # (n Char)))
+ # (n DAPOSTROPH)
+ # (n SPACE))
+ ier_merge $old
+
+ if {$ok} return
+ ias_pop2mark $mrk
+ icl_rewind $pos
+
+ return
+}
+
+proc ::page::parse::peg::eseq23 {} {
+
+ # (x (n APOSTROPH)
+ # (* (x (! (n APOSTROPH))
+ # (n Char)))
+ # (n APOSTROPH)
+ # (n SPACE))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set old [ier_get]
+ matchSymbol_APOSTROPH ; # (n APOSTROPH)
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set mrk [ias_mark]
+
+ set old [ier_get]
+ ekleene22 ; # (* (x (! (n APOSTROPH))
+ # (n Char)))
+ ier_merge $old
+
+ if {!$ok} {
+ ias_pop2mark $mrk
+ icl_rewind $pos
+ return
+ }
+
+ set old [ier_get]
+ matchSymbol_APOSTROPH ; # (n APOSTROPH)
+ ier_merge $old
+
+ if {!$ok} {
+ ias_pop2mark $mrk
+ icl_rewind $pos
+ return
+ }
+
+ set old [ier_get]
+ matchSymbol_SPACE ; # (n SPACE)
+ ier_merge $old
+
+ if {!$ok} {
+ ias_pop2mark $mrk
+ icl_rewind $pos
+ return
+ }
+
+ return
+}
+
+proc ::page::parse::peg::ekleene22 {} {
+
+ # (* (x (! (n APOSTROPH))
+ # (n Char)))
+
+ variable ok
+
+ while {1} {
+ set pos [icl_get]
+
+ set old [ier_get]
+ eseq21 ; # (x (! (n APOSTROPH))
+ # (n Char))
+ ier_merge $old
+
+ if {$ok} continue
+ break
+ }
+
+ icl_rewind $pos
+ iok_ok
+ return
+}
+
+proc ::page::parse::peg::eseq21 {} {
+
+ # (x (! (n APOSTROPH))
+ # (n Char))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set old [ier_get]
+ ebang20
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set mrk [ias_mark]
+
+ set old [ier_get]
+ matchSymbol_Char ; # (n Char)
+ ier_merge $old
+
+ if {!$ok} {
+ ias_pop2mark $mrk
+ icl_rewind $pos
+ return
+ }
+
+ return
+}
+
+proc ::page::parse::peg::ebang20 {} {
+ set pos [icl_get]
+
+ matchSymbol_APOSTROPH ; # (n APOSTROPH)
+
+ icl_rewind $pos
+ iok_negate
+ return
+}
+
+proc ::page::parse::peg::eseq27 {} {
+
+ # (x (n DAPOSTROPH)
+ # (* (x (! (n DAPOSTROPH))
+ # (n Char)))
+ # (n DAPOSTROPH)
+ # (n SPACE))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set old [ier_get]
+ matchSymbol_DAPOSTROPH ; # (n DAPOSTROPH)
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set mrk [ias_mark]
+
+ set old [ier_get]
+ ekleene26 ; # (* (x (! (n DAPOSTROPH))
+ # (n Char)))
+ ier_merge $old
+
+ if {!$ok} {
+ ias_pop2mark $mrk
+ icl_rewind $pos
+ return
+ }
+
+ set old [ier_get]
+ matchSymbol_DAPOSTROPH ; # (n DAPOSTROPH)
+ ier_merge $old
+
+ if {!$ok} {
+ ias_pop2mark $mrk
+ icl_rewind $pos
+ return
+ }
+
+ set old [ier_get]
+ matchSymbol_SPACE ; # (n SPACE)
+ ier_merge $old
+
+ if {!$ok} {
+ ias_pop2mark $mrk
+ icl_rewind $pos
+ return
+ }
+
+ return
+}
+
+proc ::page::parse::peg::ekleene26 {} {
+
+ # (* (x (! (n DAPOSTROPH))
+ # (n Char)))
+
+ variable ok
+
+ while {1} {
+ set pos [icl_get]
+
+ set old [ier_get]
+ eseq25 ; # (x (! (n DAPOSTROPH))
+ # (n Char))
+ ier_merge $old
+
+ if {$ok} continue
+ break
+ }
+
+ icl_rewind $pos
+ iok_ok
+ return
+}
+
+proc ::page::parse::peg::eseq25 {} {
+
+ # (x (! (n DAPOSTROPH))
+ # (n Char))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set old [ier_get]
+ ebang24
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set mrk [ias_mark]
+
+ set old [ier_get]
+ matchSymbol_Char ; # (n Char)
+ ier_merge $old
+
+ if {!$ok} {
+ ias_pop2mark $mrk
+ icl_rewind $pos
+ return
+ }
+
+ return
+}
+
+proc ::page::parse::peg::ebang24 {} {
+ set pos [icl_get]
+
+ matchSymbol_DAPOSTROPH ; # (n DAPOSTROPH)
+
+ icl_rewind $pos
+ iok_negate
+ return
+}
+
+proc ::page::parse::peg::matchSymbol_MATCH {} {
+ # MATCH = (x (t m)
+ # (t a)
+ # (t t)
+ # (t c)
+ # (t h)
+ # (n SPACE))
+
+ variable ok
+ if {[inc_restore MATCH]} {
+ if {$ok} ias_push
+ return
+ }
+
+ set pos [icl_get]
+
+ eseq61 ; # (x (t m)
+ # (t a)
+ # (t t)
+ # (t c)
+ # (t h)
+ # (n SPACE))
+
+ isv_nonterminal_leaf MATCH $pos
+ inc_save MATCH $pos
+ if {$ok} ias_push
+ ier_nonterminal "Expected MATCH" $pos
+ return
+}
+
+proc ::page::parse::peg::eseq61 {} {
+
+ # (x (t m)
+ # (t a)
+ # (t t)
+ # (t c)
+ # (t h)
+ # (n SPACE))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set old [ier_get]
+ ict_advance "Expected m (got EOF)"
+ if {$ok} {ict_match_token m "Expected m"}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance "Expected a (got EOF)"
+ if {$ok} {ict_match_token a "Expected a"}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance "Expected t (got EOF)"
+ if {$ok} {ict_match_token t "Expected t"}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance "Expected c (got EOF)"
+ if {$ok} {ict_match_token c "Expected c"}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance "Expected h (got EOF)"
+ if {$ok} {ict_match_token h "Expected h"}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ matchSymbol_SPACE ; # (n SPACE)
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ return
+}
+
+proc ::page::parse::peg::matchSymbol_NOT {} {
+ # NOT = (x (t !)
+ # (n SPACE))
+
+ variable ok
+ if {[inc_restore NOT]} {
+ if {$ok} ias_push
+ return
+ }
+
+ set pos [icl_get]
+
+ eseq67 ; # (x (t !)
+ # (n SPACE))
+
+ isv_nonterminal_leaf NOT $pos
+ inc_save NOT $pos
+ if {$ok} ias_push
+ ier_nonterminal "Expected NOT" $pos
+ return
+}
+
+proc ::page::parse::peg::eseq67 {} {
+
+ # (x (t !)
+ # (n SPACE))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set old [ier_get]
+ ict_advance "Expected ! (got EOF)"
+ if {$ok} {ict_match_token ! "Expected !"}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ matchSymbol_SPACE ; # (n SPACE)
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ return
+}
+
+proc ::page::parse::peg::matchSymbol_OPEN {} {
+ # OPEN = (x (t \()
+ # (n SPACE))
+
+ if {[inc_restore OPEN]} return
+
+ set pos [icl_get]
+
+ eseq71 ; # (x (t \()
+ # (n SPACE))
+
+ isv_clear
+ inc_save OPEN $pos
+ ier_nonterminal "Expected OPEN" $pos
+ return
+}
+
+proc ::page::parse::peg::eseq71 {} {
+
+ # (x (t \()
+ # (n SPACE))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set old [ier_get]
+ ict_advance "Expected \( (got EOF)"
+ if {$ok} {ict_match_token \50 "Expected \("}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ matchSymbol_SPACE ; # (n SPACE)
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ return
+}
+
+proc ::page::parse::peg::matchSymbol_OPENB {} {
+ # OPENB = (t [)
+
+ variable ok
+ if {[inc_restore OPENB]} return
+
+ set pos [icl_get]
+
+ ict_advance "Expected \[ (got EOF)"
+ if {$ok} {ict_match_token \133 "Expected \["}
+
+ isv_clear
+ inc_save OPENB $pos
+ ier_nonterminal "Expected OPENB" $pos
+ return
+}
+
+proc ::page::parse::peg::matchSymbol_PEG {} {
+ # PEG = (x (t P)
+ # (t E)
+ # (t G)
+ # (n SPACE))
+
+ if {[inc_restore PEG]} return
+
+ set pos [icl_get]
+
+ eseq57 ; # (x (t P)
+ # (t E)
+ # (t G)
+ # (n SPACE))
+
+ isv_clear
+ inc_save PEG $pos
+ ier_nonterminal "Expected PEG" $pos
+ return
+}
+
+proc ::page::parse::peg::eseq57 {} {
+
+ # (x (t P)
+ # (t E)
+ # (t G)
+ # (n SPACE))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set old [ier_get]
+ ict_advance "Expected P (got EOF)"
+ if {$ok} {ict_match_token P "Expected P"}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance "Expected E (got EOF)"
+ if {$ok} {ict_match_token E "Expected E"}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance "Expected G (got EOF)"
+ if {$ok} {ict_match_token G "Expected G"}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ matchSymbol_SPACE ; # (n SPACE)
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ return
+}
+
+proc ::page::parse::peg::matchSymbol_PLUS {} {
+ # PLUS = (x (t +)
+ # (n SPACE))
+
+ variable ok
+ if {[inc_restore PLUS]} {
+ if {$ok} ias_push
+ return
+ }
+
+ set pos [icl_get]
+
+ eseq70 ; # (x (t +)
+ # (n SPACE))
+
+ isv_nonterminal_leaf PLUS $pos
+ inc_save PLUS $pos
+ if {$ok} ias_push
+ ier_nonterminal "Expected PLUS" $pos
+ return
+}
+
+proc ::page::parse::peg::eseq70 {} {
+
+ # (x (t +)
+ # (n SPACE))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set old [ier_get]
+ ict_advance "Expected + (got EOF)"
+ if {$ok} {ict_match_token + "Expected +"}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ matchSymbol_SPACE ; # (n SPACE)
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ return
+}
+
+proc ::page::parse::peg::matchSymbol_Prefix {} {
+ # Prefix = (x (? (/ (n AND)
+ # (n NOT)))
+ # (n Suffix))
+
+ variable ok
+ if {[inc_restore Prefix]} {
+ if {$ok} ias_push
+ return
+ }
+
+ set pos [icl_get]
+ set mrk [ias_mark]
+
+ eseq14 ; # (x (? (/ (n AND)
+ # (n NOT)))
+ # (n Suffix))
+
+ isv_nonterminal_reduce Prefix $pos $mrk
+ inc_save Prefix $pos
+ ias_pop2mark $mrk
+ if {$ok} ias_push
+ ier_nonterminal "Expected Prefix" $pos
+ return
+}
+
+proc ::page::parse::peg::eseq14 {} {
+
+ # (x (? (/ (n AND)
+ # (n NOT)))
+ # (n Suffix))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set mrk [ias_mark]
+
+ set old [ier_get]
+ eopt13 ; # (? (/ (n AND)
+ # (n NOT)))
+ ier_merge $old
+
+ if {!$ok} {
+ ias_pop2mark $mrk
+ icl_rewind $pos
+ return
+ }
+
+ set old [ier_get]
+ matchSymbol_Suffix ; # (n Suffix)
+ ier_merge $old
+
+ if {!$ok} {
+ ias_pop2mark $mrk
+ icl_rewind $pos
+ return
+ }
+
+ return
+}
+
+proc ::page::parse::peg::eopt13 {} {
+
+ # (? (/ (n AND)
+ # (n NOT)))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set old [ier_get]
+ ebra12 ; # (/ (n AND)
+ # (n NOT))
+ ier_merge $old
+
+ if {$ok} return
+ icl_rewind $pos
+ iok_ok
+ return
+}
+
+proc ::page::parse::peg::ebra12 {} {
+
+ # (/ (n AND)
+ # (n NOT))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set mrk [ias_mark]
+ set old [ier_get]
+ matchSymbol_AND ; # (n AND)
+ ier_merge $old
+
+ if {$ok} return
+ ias_pop2mark $mrk
+ icl_rewind $pos
+
+ set mrk [ias_mark]
+ set old [ier_get]
+ matchSymbol_NOT ; # (n NOT)
+ ier_merge $old
+
+ if {$ok} return
+ ias_pop2mark $mrk
+ icl_rewind $pos
+
+ return
+}
+
+proc ::page::parse::peg::matchSymbol_Primary {} {
+ # Primary = (/ (n ALNUM)
+ # (n ALPHA)
+ # (n Identifier)
+ # (x (n OPEN)
+ # (n Expression)
+ # (n CLOSE))
+ # (n Literal)
+ # (n Class)
+ # (n DOT))
+
+ variable ok
+ if {[inc_restore Primary]} {
+ if {$ok} ias_push
+ return
+ }
+
+ set pos [icl_get]
+ set mrk [ias_mark]
+
+ ebra19 ; # (/ (n ALNUM)
+ # (n ALPHA)
+ # (n Identifier)
+ # (x (n OPEN)
+ # (n Expression)
+ # (n CLOSE))
+ # (n Literal)
+ # (n Class)
+ # (n DOT))
+
+ isv_nonterminal_reduce Primary $pos $mrk
+ inc_save Primary $pos
+ ias_pop2mark $mrk
+ if {$ok} ias_push
+ ier_nonterminal "Expected Primary" $pos
+ return
+}
+
+proc ::page::parse::peg::ebra19 {} {
+
+ # (/ (n ALNUM)
+ # (n ALPHA)
+ # (n Identifier)
+ # (x (n OPEN)
+ # (n Expression)
+ # (n CLOSE))
+ # (n Literal)
+ # (n Class)
+ # (n DOT))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set mrk [ias_mark]
+ set old [ier_get]
+ matchSymbol_ALNUM ; # (n ALNUM)
+ ier_merge $old
+
+ if {$ok} return
+ ias_pop2mark $mrk
+ icl_rewind $pos
+
+ set mrk [ias_mark]
+ set old [ier_get]
+ matchSymbol_ALPHA ; # (n ALPHA)
+ ier_merge $old
+
+ if {$ok} return
+ ias_pop2mark $mrk
+ icl_rewind $pos
+
+ set mrk [ias_mark]
+ set old [ier_get]
+ matchSymbol_Identifier ; # (n Identifier)
+ ier_merge $old
+
+ if {$ok} return
+ ias_pop2mark $mrk
+ icl_rewind $pos
+
+ set mrk [ias_mark]
+ set old [ier_get]
+ eseq18 ; # (x (n OPEN)
+ # (n Expression)
+ # (n CLOSE))
+ ier_merge $old
+
+ if {$ok} return
+ ias_pop2mark $mrk
+ icl_rewind $pos
+
+ set mrk [ias_mark]
+ set old [ier_get]
+ matchSymbol_Literal ; # (n Literal)
+ ier_merge $old
+
+ if {$ok} return
+ ias_pop2mark $mrk
+ icl_rewind $pos
+
+ set mrk [ias_mark]
+ set old [ier_get]
+ matchSymbol_Class ; # (n Class)
+ ier_merge $old
+
+ if {$ok} return
+ ias_pop2mark $mrk
+ icl_rewind $pos
+
+ set mrk [ias_mark]
+ set old [ier_get]
+ matchSymbol_DOT ; # (n DOT)
+ ier_merge $old
+
+ if {$ok} return
+ ias_pop2mark $mrk
+ icl_rewind $pos
+
+ return
+}
+
+proc ::page::parse::peg::eseq18 {} {
+
+ # (x (n OPEN)
+ # (n Expression)
+ # (n CLOSE))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set old [ier_get]
+ matchSymbol_OPEN ; # (n OPEN)
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set mrk [ias_mark]
+
+ set old [ier_get]
+ matchSymbol_Expression ; # (n Expression)
+ ier_merge $old
+
+ if {!$ok} {
+ ias_pop2mark $mrk
+ icl_rewind $pos
+ return
+ }
+
+ set old [ier_get]
+ matchSymbol_CLOSE ; # (n CLOSE)
+ ier_merge $old
+
+ if {!$ok} {
+ ias_pop2mark $mrk
+ icl_rewind $pos
+ return
+ }
+
+ return
+}
+
+proc ::page::parse::peg::matchSymbol_QUESTION {} {
+ # QUESTION = (x (t ?)
+ # (n SPACE))
+
+ variable ok
+ if {[inc_restore QUESTION]} {
+ if {$ok} ias_push
+ return
+ }
+
+ set pos [icl_get]
+
+ eseq68 ; # (x (t ?)
+ # (n SPACE))
+
+ isv_nonterminal_leaf QUESTION $pos
+ inc_save QUESTION $pos
+ if {$ok} ias_push
+ ier_nonterminal "Expected QUESTION" $pos
+ return
+}
+
+proc ::page::parse::peg::eseq68 {} {
+
+ # (x (t ?)
+ # (n SPACE))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set old [ier_get]
+ ict_advance "Expected ? (got EOF)"
+ if {$ok} {ict_match_token ? "Expected ?"}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ matchSymbol_SPACE ; # (n SPACE)
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ return
+}
+
+proc ::page::parse::peg::matchSymbol_Range {} {
+ # Range = (/ (x (n Char)
+ # (n TO)
+ # (n Char))
+ # (n Char))
+
+ variable ok
+ if {[inc_restore Range]} {
+ if {$ok} ias_push
+ return
+ }
+
+ set pos [icl_get]
+ set mrk [ias_mark]
+
+ ebra34 ; # (/ (x (n Char)
+ # (n TO)
+ # (n Char))
+ # (n Char))
+
+ isv_nonterminal_reduce Range $pos $mrk
+ inc_save Range $pos
+ ias_pop2mark $mrk
+ if {$ok} ias_push
+ ier_nonterminal "Expected Range" $pos
+ return
+}
+
+proc ::page::parse::peg::ebra34 {} {
+
+ # (/ (x (n Char)
+ # (n TO)
+ # (n Char))
+ # (n Char))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set mrk [ias_mark]
+ set old [ier_get]
+ eseq33 ; # (x (n Char)
+ # (n TO)
+ # (n Char))
+ ier_merge $old
+
+ if {$ok} return
+ ias_pop2mark $mrk
+ icl_rewind $pos
+
+ set mrk [ias_mark]
+ set old [ier_get]
+ matchSymbol_Char ; # (n Char)
+ ier_merge $old
+
+ if {$ok} return
+ ias_pop2mark $mrk
+ icl_rewind $pos
+
+ return
+}
+
+proc ::page::parse::peg::eseq33 {} {
+
+ # (x (n Char)
+ # (n TO)
+ # (n Char))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set mrk [ias_mark]
+
+ set old [ier_get]
+ matchSymbol_Char ; # (n Char)
+ ier_merge $old
+
+ if {!$ok} {
+ ias_pop2mark $mrk
+ icl_rewind $pos
+ return
+ }
+
+ set old [ier_get]
+ matchSymbol_TO ; # (n TO)
+ ier_merge $old
+
+ if {!$ok} {
+ ias_pop2mark $mrk
+ icl_rewind $pos
+ return
+ }
+
+ set old [ier_get]
+ matchSymbol_Char ; # (n Char)
+ ier_merge $old
+
+ if {!$ok} {
+ ias_pop2mark $mrk
+ icl_rewind $pos
+ return
+ }
+
+ return
+}
+
+proc ::page::parse::peg::matchSymbol_SEMICOLON {} {
+ # SEMICOLON = (x (t ;)
+ # (n SPACE))
+
+ if {[inc_restore SEMICOLON]} return
+
+ set pos [icl_get]
+
+ eseq63 ; # (x (t ;)
+ # (n SPACE))
+
+ isv_clear
+ inc_save SEMICOLON $pos
+ ier_nonterminal "Expected SEMICOLON" $pos
+ return
+}
+
+proc ::page::parse::peg::eseq63 {} {
+
+ # (x (t ;)
+ # (n SPACE))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set old [ier_get]
+ ict_advance "Expected \; (got EOF)"
+ if {$ok} {ict_match_token \73 "Expected \;"}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ matchSymbol_SPACE ; # (n SPACE)
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ return
+}
+
+proc ::page::parse::peg::matchSymbol_Sequence {} {
+ # Sequence = (+ (n Prefix))
+
+ variable ok
+ if {[inc_restore Sequence]} {
+ if {$ok} ias_push
+ return
+ }
+
+ set pos [icl_get]
+ set mrk [ias_mark]
+
+ epkleene11 ; # (+ (n Prefix))
+
+ isv_nonterminal_reduce Sequence $pos $mrk
+ inc_save Sequence $pos
+ ias_pop2mark $mrk
+ if {$ok} ias_push
+ ier_nonterminal "Expected Sequence" $pos
+ return
+}
+
+proc ::page::parse::peg::epkleene11 {} {
+
+ # (+ (n Prefix))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set old [ier_get]
+ matchSymbol_Prefix ; # (n Prefix)
+ ier_merge $old
+
+ if {!$ok} {
+ icl_rewind $pos
+ return
+ }
+
+ while {1} {
+ set pos [icl_get]
+
+ set old [ier_get]
+ matchSymbol_Prefix ; # (n Prefix)
+ ier_merge $old
+
+ if {$ok} continue
+ break
+ }
+
+ icl_rewind $pos
+ iok_ok
+ return
+}
+
+proc ::page::parse::peg::matchSymbol_SLASH {} {
+ # SLASH = (x (t /)
+ # (n SPACE))
+
+ if {[inc_restore SLASH]} return
+
+ set pos [icl_get]
+
+ eseq65 ; # (x (t /)
+ # (n SPACE))
+
+ isv_clear
+ inc_save SLASH $pos
+ ier_nonterminal "Expected SLASH" $pos
+ return
+}
+
+proc ::page::parse::peg::eseq65 {} {
+
+ # (x (t /)
+ # (n SPACE))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set old [ier_get]
+ ict_advance "Expected / (got EOF)"
+ if {$ok} {ict_match_token / "Expected /"}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ matchSymbol_SPACE ; # (n SPACE)
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ return
+}
+
+proc ::page::parse::peg::matchSymbol_SPACE {} {
+ # SPACE = (* (/ (t <blank>)
+ # (t \t)
+ # (n EOL)
+ # (n COMMENT)))
+
+ if {[inc_restore SPACE]} return
+
+ set pos [icl_get]
+
+ ekleene77 ; # (* (/ (t <blank>)
+ # (t \t)
+ # (n EOL)
+ # (n COMMENT)))
+
+ isv_clear
+ inc_save SPACE $pos
+ ier_nonterminal "Expected SPACE" $pos
+ return
+}
+
+proc ::page::parse::peg::ekleene77 {} {
+
+ # (* (/ (t <blank>)
+ # (t \t)
+ # (n EOL)
+ # (n COMMENT)))
+
+ variable ok
+
+ while {1} {
+ set pos [icl_get]
+
+ set old [ier_get]
+ ebra76 ; # (/ (t <blank>)
+ # (t \t)
+ # (n EOL)
+ # (n COMMENT))
+ ier_merge $old
+
+ if {$ok} continue
+ break
+ }
+
+ icl_rewind $pos
+ iok_ok
+ return
+}
+
+proc ::page::parse::peg::ebra76 {} {
+
+ # (/ (t <blank>)
+ # (t \t)
+ # (n EOL)
+ # (n COMMENT))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set old [ier_get]
+ ict_advance "Expected <blank> (got EOF)"
+ if {$ok} {ict_match_token \40 "Expected <blank>"}
+ ier_merge $old
+
+ if {$ok} return
+ icl_rewind $pos
+
+ set old [ier_get]
+ ict_advance "Expected \\t (got EOF)"
+ if {$ok} {ict_match_token \t "Expected \\t"}
+ ier_merge $old
+
+ if {$ok} return
+ icl_rewind $pos
+
+ set old [ier_get]
+ matchSymbol_EOL ; # (n EOL)
+ ier_merge $old
+
+ if {$ok} return
+ icl_rewind $pos
+
+ set old [ier_get]
+ matchSymbol_COMMENT ; # (n COMMENT)
+ ier_merge $old
+
+ if {$ok} return
+ icl_rewind $pos
+
+ return
+}
+
+proc ::page::parse::peg::matchSymbol_STAR {} {
+ # STAR = (x (t *)
+ # (n SPACE))
+
+ variable ok
+ if {[inc_restore STAR]} {
+ if {$ok} ias_push
+ return
+ }
+
+ set pos [icl_get]
+
+ eseq69 ; # (x (t *)
+ # (n SPACE))
+
+ isv_nonterminal_leaf STAR $pos
+ inc_save STAR $pos
+ if {$ok} ias_push
+ ier_nonterminal "Expected STAR" $pos
+ return
+}
+
+proc ::page::parse::peg::eseq69 {} {
+
+ # (x (t *)
+ # (n SPACE))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set old [ier_get]
+ ict_advance "Expected * (got EOF)"
+ if {$ok} {ict_match_token * "Expected *"}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ matchSymbol_SPACE ; # (n SPACE)
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ return
+}
+
+proc ::page::parse::peg::matchSymbol_StartExpr {} {
+ # StartExpr = (x (n OPEN)
+ # (n Expression)
+ # (n CLOSE))
+
+ variable ok
+ if {[inc_restore StartExpr]} {
+ if {$ok} ias_push
+ return
+ }
+
+ set pos [icl_get]
+ set mrk [ias_mark]
+
+ eseq35 ; # (x (n OPEN)
+ # (n Expression)
+ # (n CLOSE))
+
+ isv_nonterminal_reduce StartExpr $pos $mrk
+ inc_save StartExpr $pos
+ ias_pop2mark $mrk
+ if {$ok} ias_push
+ ier_nonterminal "Expected StartExpr" $pos
+ return
+}
+
+proc ::page::parse::peg::eseq35 {} {
+
+ # (x (n OPEN)
+ # (n Expression)
+ # (n CLOSE))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set old [ier_get]
+ matchSymbol_OPEN ; # (n OPEN)
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set mrk [ias_mark]
+
+ set old [ier_get]
+ matchSymbol_Expression ; # (n Expression)
+ ier_merge $old
+
+ if {!$ok} {
+ ias_pop2mark $mrk
+ icl_rewind $pos
+ return
+ }
+
+ set old [ier_get]
+ matchSymbol_CLOSE ; # (n CLOSE)
+ ier_merge $old
+
+ if {!$ok} {
+ ias_pop2mark $mrk
+ icl_rewind $pos
+ return
+ }
+
+ return
+}
+
+proc ::page::parse::peg::matchSymbol_Suffix {} {
+ # Suffix = (x (n Primary)
+ # (? (/ (n QUESTION)
+ # (n STAR)
+ # (n PLUS))))
+
+ variable ok
+ if {[inc_restore Suffix]} {
+ if {$ok} ias_push
+ return
+ }
+
+ set pos [icl_get]
+ set mrk [ias_mark]
+
+ eseq17 ; # (x (n Primary)
+ # (? (/ (n QUESTION)
+ # (n STAR)
+ # (n PLUS))))
+
+ isv_nonterminal_reduce Suffix $pos $mrk
+ inc_save Suffix $pos
+ ias_pop2mark $mrk
+ if {$ok} ias_push
+ ier_nonterminal "Expected Suffix" $pos
+ return
+}
+
+proc ::page::parse::peg::eseq17 {} {
+
+ # (x (n Primary)
+ # (? (/ (n QUESTION)
+ # (n STAR)
+ # (n PLUS))))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set mrk [ias_mark]
+
+ set old [ier_get]
+ matchSymbol_Primary ; # (n Primary)
+ ier_merge $old
+
+ if {!$ok} {
+ ias_pop2mark $mrk
+ icl_rewind $pos
+ return
+ }
+
+ set old [ier_get]
+ eopt16 ; # (? (/ (n QUESTION)
+ # (n STAR)
+ # (n PLUS)))
+ ier_merge $old
+
+ if {!$ok} {
+ ias_pop2mark $mrk
+ icl_rewind $pos
+ return
+ }
+
+ return
+}
+
+proc ::page::parse::peg::eopt16 {} {
+
+ # (? (/ (n QUESTION)
+ # (n STAR)
+ # (n PLUS)))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set old [ier_get]
+ ebra15 ; # (/ (n QUESTION)
+ # (n STAR)
+ # (n PLUS))
+ ier_merge $old
+
+ if {$ok} return
+ icl_rewind $pos
+ iok_ok
+ return
+}
+
+proc ::page::parse::peg::ebra15 {} {
+
+ # (/ (n QUESTION)
+ # (n STAR)
+ # (n PLUS))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set mrk [ias_mark]
+ set old [ier_get]
+ matchSymbol_QUESTION ; # (n QUESTION)
+ ier_merge $old
+
+ if {$ok} return
+ ias_pop2mark $mrk
+ icl_rewind $pos
+
+ set mrk [ias_mark]
+ set old [ier_get]
+ matchSymbol_STAR ; # (n STAR)
+ ier_merge $old
+
+ if {$ok} return
+ ias_pop2mark $mrk
+ icl_rewind $pos
+
+ set mrk [ias_mark]
+ set old [ier_get]
+ matchSymbol_PLUS ; # (n PLUS)
+ ier_merge $old
+
+ if {$ok} return
+ ias_pop2mark $mrk
+ icl_rewind $pos
+
+ return
+}
+
+proc ::page::parse::peg::matchSymbol_TO {} {
+ # TO = (t -)
+
+ variable ok
+ if {[inc_restore TO]} return
+
+ set pos [icl_get]
+
+ ict_advance "Expected - (got EOF)"
+ if {$ok} {ict_match_token - "Expected -"}
+
+ isv_clear
+ inc_save TO $pos
+ ier_nonterminal "Expected TO" $pos
+ return
+}
+
+proc ::page::parse::peg::matchSymbol_VOID {} {
+ # VOID = (x (t v)
+ # (t o)
+ # (t i)
+ # (t d)
+ # (n SPACE))
+
+ variable ok
+ if {[inc_restore VOID]} {
+ if {$ok} ias_push
+ return
+ }
+
+ set pos [icl_get]
+
+ eseq59 ; # (x (t v)
+ # (t o)
+ # (t i)
+ # (t d)
+ # (n SPACE))
+
+ isv_nonterminal_leaf VOID $pos
+ inc_save VOID $pos
+ if {$ok} ias_push
+ ier_nonterminal "Expected VOID" $pos
+ return
+}
+
+proc ::page::parse::peg::eseq59 {} {
+
+ # (x (t v)
+ # (t o)
+ # (t i)
+ # (t d)
+ # (n SPACE))
+
+ variable ok
+
+ set pos [icl_get]
+
+ set old [ier_get]
+ ict_advance "Expected v (got EOF)"
+ if {$ok} {ict_match_token v "Expected v"}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance "Expected o (got EOF)"
+ if {$ok} {ict_match_token o "Expected o"}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance "Expected i (got EOF)"
+ if {$ok} {ict_match_token i "Expected i"}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ ict_advance "Expected d (got EOF)"
+ if {$ok} {ict_match_token d "Expected d"}
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ set old [ier_get]
+ matchSymbol_SPACE ; # (n SPACE)
+ ier_merge $old
+
+ if {!$ok} {icl_rewind $pos ; return}
+
+ return
+}
+
+# ### ### ### ######### ######### #########
+## Package Management
+
+package provide page::parse::peg 0.1
diff --git a/tcllib/modules/page/parse_peghb.tcl b/tcllib/modules/page/parse_peghb.tcl
new file mode 100644
index 0000000..ba9fab4
--- /dev/null
+++ b/tcllib/modules/page/parse_peghb.tcl
@@ -0,0 +1,118 @@
+# -*- tcl -*-
+#
+# Copyright (c) 2005 by Andreas Kupries <andreas_kupries@users.sourceforge.net>
+# Parser Generator / Frontend - Read halfbaked PEG container.
+
+# ### ### ### ######### ######### #########
+## Requisites
+
+namespace eval ::page::parse::peghb {
+ variable fixup {}
+ variable definitions
+}
+
+# ### ### ### ######### ######### #########
+## API
+
+proc ::page::parse::peghb {halfbaked t} {
+ variable peghb::fixup
+ variable peghb::definitions
+ array set definitions {}
+
+ set fixup {}
+
+ interp create -safe sb
+ # Should remove everything.
+ interp alias sb Start {} ::page::parse::peghb::Start $t
+ interp alias sb Define {} ::page::parse::peghb::Define $t
+ interp eval sb $halfbaked
+ interp delete sb
+
+ array set undefined {}
+ array set users {}
+ foreach {n sym} $fixup {
+ if {[info exists definitions($sym)]} {
+ set def $definitions($sym)
+ $t set $n def $def
+ lappend users($def) $n
+ } else {
+ lappend undefined($sym) $n
+ }
+ }
+
+ foreach def [array names users] {
+ $t set $def users $users($def)
+ }
+
+ $t set root definitions [array get definitions]
+ $t set root undefined [array get undefined]
+ $t set root symbol <StartExpression>
+ $t set root name <HalfBaked>
+
+ return
+}
+
+# ### ### ### ######### ######### #########
+## Internal. Helpers
+
+proc ::page::parse::peghb::Start {t pe} {
+ variable fixup
+ $t set root start [treeOf $t root $pe fixup]
+ return
+}
+
+proc ::page::parse::peghb::Define {t mode sym pe} {
+ variable fixup
+ variable definitions
+
+ set def [$t insert root end]
+
+ $t set $def users {}
+ $t set $def symbol $sym
+ $t set $def label $sym
+ $t set $def mode $mode
+
+ treeOf $t $def $pe fixup
+
+ set definitions($sym) $def
+ return
+}
+
+proc ::page::parse::peghb::treeOf {t root pe fv} {
+ upvar 1 $fv fixup
+
+ set n [$t insert $root end]
+ set op [lindex $pe 0]
+ $t set $n op $op
+
+ if {$op eq "t"} {
+ $t set $n char [lindex $pe 1]
+
+ } elseif {$op eq ".."} {
+ $t set $n begin [lindex $pe 1]
+ $t set $n end [lindex $pe 2]
+
+ } elseif {$op eq "n"} {
+
+ set sym [lindex $pe 1]
+ $t set $n sym $sym
+ $t set $n def ""
+
+ lappend fixup $n $sym
+ } else {
+ foreach sub [lrange $pe 1 end] {
+ treeOf $t $n $sub fixup
+ }
+ }
+ return $n
+}
+
+# ### ### ### ######### ######### #########
+## Internal. Strings.
+
+namespace eval ::page::parse::peghb {}
+
+# ### ### ### ######### ######### #########
+## Ready
+
+package provide page::parse::peghb 0.1
diff --git a/tcllib/modules/page/parse_pegser.tcl b/tcllib/modules/page/parse_pegser.tcl
new file mode 100644
index 0000000..b3814a7
--- /dev/null
+++ b/tcllib/modules/page/parse_pegser.tcl
@@ -0,0 +1,99 @@
+# -*- tcl -*-
+#
+# Copyright (c) 2005 by Andreas Kupries <andreas_kupries@users.sourceforge.net>
+# Parser Generator / Frontend - Read serialized PEG container.
+
+# ### ### ### ######### ######### #########
+## Requisites
+
+package require grammar::peg
+
+namespace eval ::page::parse::pegser {}
+
+# ### ### ### ######### ######### #########
+## API
+
+proc ::page::parse::pegser {serial t} {
+
+ ::grammar::peg gr deserialize $serial
+
+ $t set root start [pegser::treeOf $t root [gr start] fixup]
+
+ array set definitions {}
+ foreach sym [gr nonterminals] {
+ set def [$t insert root end]
+
+ $t set $def users {}
+ $t set $def symbol $sym
+ $t set $def label $sym
+ $t set $def mode [gr nonterminal mode $sym]
+ pegser::treeOf $t $def [gr nonterminal rule $sym] fixup
+
+ set definitions($sym) $def
+ }
+
+ array set undefined {}
+ array set users {}
+ foreach {n sym} $fixup {
+ if {[info exists definitions($sym)]} {
+ set def $definitions($sym)
+ $t set $n def $def
+ lappend users($def) $n
+ } else {
+ lappend undefined($sym) $n
+ }
+ }
+
+ foreach def [array names users] {
+ $t set $def users $users($def)
+ }
+
+ $t set root definitions [array get definitions]
+ $t set root undefined [array get undefined]
+ $t set root symbol <StartExpression>
+ $t set root name <Serialization>
+
+ return
+}
+
+# ### ### ### ######### ######### #########
+## Internal. Helpers
+
+proc ::page::parse::pegser::treeOf {t root pe fv} {
+ upvar 1 $fv fixup
+
+ set n [$t insert $root end]
+ set op [lindex $pe 0]
+ $t set $n op $op
+
+ if {$op eq "t"} {
+ $t set $n char [lindex $pe 1]
+
+ } elseif {$op eq ".."} {
+ $t set $n begin [lindex $pe 1]
+ $t set $n end [lindex $pe 2]
+
+ } elseif {$op eq "n"} {
+
+ set sym [lindex $pe 1]
+ $t set $n sym $sym
+ $t set $n def ""
+
+ lappend fixup $n $sym
+ } else {
+ foreach sub [lrange $pe 1 end] {
+ treeOf $t $n $sub fixup
+ }
+ }
+ return $n
+}
+
+# ### ### ### ######### ######### #########
+## Internal. Strings.
+
+namespace eval ::page::parse::pegser {}
+
+# ### ### ### ######### ######### #########
+## Ready
+
+package provide page::parse::pegser 0.1
diff --git a/tcllib/modules/page/peg_grammar.peg b/tcllib/modules/page/peg_grammar.peg
new file mode 100644
index 0000000..8ae4068
--- /dev/null
+++ b/tcllib/modules/page/peg_grammar.peg
@@ -0,0 +1,86 @@
+# -*- text -*-
+#
+# Parsing Expression Grammar declaring a syntax for Parsing Expression
+# Grammars, to use in a PEG-based parser generator. This specification
+# is self-referential, it uses the grammar described by to describe
+# said grammar.
+
+PEG pg::peg::grammar (Grammar)
+
+ # --------------------------------------------------------------------
+ # Syntactical constructs
+
+ Grammar <- SPACE Header Definition+ Final EOF ;
+
+ Header <- PEG Identifier StartExpr ;
+ Definition <- Attribute? Identifier IS Expression SEMICOLON ;
+ Attribute <- (VOID / LEAF / MATCH) COLON ;
+ Expression <- Sequence (SLASH Sequence)* ;
+ Sequence <- Prefix+ ;
+ Prefix <- (AND / NOT)? Suffix ;
+ Suffix <- Primary (QUESTION / STAR / PLUS)? ;
+ Primary <- ALNUM / ALPHA / Identifier
+ / OPEN Expression CLOSE
+ / Literal
+ / Class
+ / DOT
+ ;
+ Literal <- APOSTROPH (!APOSTROPH Char)* APOSTROPH SPACE
+ / DAPOSTROPH (!DAPOSTROPH Char)* DAPOSTROPH SPACE ;
+ Class <- OPENB (!CLOSEB Range)* CLOSEB SPACE ;
+ Range <- Char TO Char / Char ;
+
+ StartExpr <- OPEN Expression CLOSE ;
+void: Final <- END SEMICOLON SPACE ;
+
+ # --------------------------------------------------------------------
+ # Lexing constructs
+
+ Identifier <- Ident SPACE ;
+match: Ident <- ('_' / ':' / <alpha>) ('_' / ':' / <alnum>)* ;
+ Char <- CharSpecial / CharOctalFull / CharOctalPart
+ / CharUnicode / CharUnescaped
+ ;
+
+match: CharSpecial <- "\\" [nrt'"\[\]\\] ;
+match: CharOctalFull <- "\\" [0-2][0-7][0-7] ;
+match: CharOctalPart <- "\\" [0-7][0-7]? ;
+match: CharUnicode <- "\\" 'u' HexDigit (HexDigit (HexDigit HexDigit?)?)? ;
+match: CharUnescaped <- !"\\" . ;
+
+void: HexDigit <- [0-9a-fA-F] ;
+
+void: TO <- '-' ;
+void: OPENB <- "[" ;
+void: CLOSEB <- "]" ;
+void: APOSTROPH <- "'" ;
+void: DAPOSTROPH <- '"' ;
+void: PEG <- "PEG" SPACE ;
+void: IS <- "<-" SPACE ;
+leaf: VOID <- "void" SPACE ; # Implies that definition has no semantic value.
+leaf: LEAF <- "leaf" SPACE ; # Implies that definition has no terminals.
+leaf: MATCH <- "match" SPACE ; # Implies that semantic value is the matched string,
+ # not the parse tree from the symbol.
+void: END <- "END" SPACE ;
+void: SEMICOLON <- ";" SPACE ;
+void: COLON <- ":" SPACE ;
+void: SLASH <- "/" SPACE ;
+leaf: AND <- "&" SPACE ;
+leaf: NOT <- "!" SPACE ;
+leaf: QUESTION <- "?" SPACE ;
+leaf: STAR <- "*" SPACE ;
+leaf: PLUS <- "+" SPACE ;
+void: OPEN <- "(" SPACE ;
+void: CLOSE <- ")" SPACE ;
+leaf: DOT <- "." SPACE ;
+leaf: ALPHA <- "<alpha>" SPACE ;
+leaf: ALNUM <- "<alnum>" SPACE ;
+
+void: SPACE <- (" " / "\t" / EOL / COMMENT)* ;
+void: COMMENT <- '#' (!EOL .)* EOL ;
+void: EOL <- "\n\r" / "\n" / "\r" ;
+void: EOF <- !. ;
+
+ # --------------------------------------------------------------------
+END;
+
diff --git a/tcllib/modules/page/peg_grammar.tcl b/tcllib/modules/page/peg_grammar.tcl
new file mode 100644
index 0000000..b585125
--- /dev/null
+++ b/tcllib/modules/page/peg_grammar.tcl
@@ -0,0 +1,117 @@
+# -*- tcl -*-
+#
+# Copyright (c) 2005 by Andreas Kupries <andreas_kupries@users.sourceforge.net>
+# Parser Generator / Grammar for reading of PE grammars
+
+## Parsing Expression Grammar 'pg::peg::grammar'.
+
+# ### ### ### ######### ######### #########
+## Package description
+
+## It provides a single command returning the handle of a
+## grammar container in which the grammar 'pg::peg::grammar'
+## is stored. The container is usable by a PEG interpreter
+## or other packages taking PE grammars.
+
+# ### ### ### ######### ######### #########
+## Requisites.
+## - PEG container type
+
+package require grammar::peg
+
+namespace eval ::pg::peg::grammar {}
+
+# ### ### ### ######### ######### #########
+## API
+
+proc ::pg::peg::grammar {} {
+ return $grammar::gr
+}
+
+# ### ### ### ######### ######### #########
+# ### ### ### ######### ######### #########
+## Data and helpers.
+
+namespace eval ::pg::peg::grammar {
+ # Grammar container
+ variable gr [::grammar::peg gr]
+}
+
+proc ::pg::peg::grammar::Start {pe} {
+ variable gr
+ $gr start $pe
+ return
+}
+
+proc ::pg::peg::grammar::Define {mode nt pe} {
+ variable gr
+ $gr nonterminal add $nt $pe
+ $gr nonterminal mode $nt $mode
+ return
+}
+
+# ### ### ### ######### ######### #########
+## Initialization = Grammar definition
+
+namespace eval ::pg::peg::grammar {
+ Start {n Grammar}
+
+ Define leaf ALNUM {x {t <} {t a} {t l} {t n} {t u} {t m} {t >} {n SPACE}}
+ Define leaf ALPHA {x {t <} {t a} {t l} {t p} {t h} {t a} {t >} {n SPACE}}
+ Define leaf AND {x {t &} {n SPACE}}
+ Define discard APOSTROPH {t '}
+ Define value Attribute {x {/ {n VOID} {n LEAF} {n MATCH}} {n COLON}}
+ Define value Char {/ {n CharSpecial} {n CharOctalFull} {n CharOctalPart} {n CharUnicode} {n CharUnescaped}}
+ Define match CharOctalFull {x {t \134} {.. 0 2} {.. 0 7} {.. 0 7}}
+ Define match CharOctalPart {x {t \134} {.. 0 7} {? {.. 0 7}}}
+ Define match CharSpecial {x {t \134} {/ {t n} {t r} {t t} {t '} {t \42} {t \133} {t \135} {t \134}}}
+ Define match CharUnescaped {x {! {t \134}} dot}
+ Define match CharUnicode {x {t \134} {t u} {n HexDigit} {? {x {n HexDigit} {? {x {n HexDigit} {? {n HexDigit}}}}}}}
+ Define value Class {x {n OPENB} {* {x {! {n CLOSEB}} {n Range}}} {n CLOSEB} {n SPACE}}
+ Define discard CLOSE {x {t \51} {n SPACE}}
+ Define discard CLOSEB {t \135}
+ Define discard COLON {x {t :} {n SPACE}}
+ Define discard COMMENT {x {t #} {* {x {! {n EOL}} dot}} {n EOL}}
+ Define discard DAPOSTROPH {t \42}
+ Define value Definition {x {? {n Attribute}} {n Identifier} {n IS} {n Expression} {n SEMICOLON}}
+ Define leaf DOT {x {t .} {n SPACE}}
+ Define discard END {x {t E} {t N} {t D} {n SPACE}}
+ Define discard EOF {! dot}
+ Define discard EOL {/ {x {t \n} {t \r}} {t \n} {t \r}}
+ Define value Expression {x {n Sequence} {* {x {n SLASH} {n Sequence}}}}
+ Define discard Final {x {n END} {n SEMICOLON} {n SPACE}}
+ Define value Grammar {x {n SPACE} {n Header} {+ {n Definition}} {n Final} {n EOF}}
+ Define value Header {x {n PEG} {n Identifier} {n StartExpr}}
+ Define discard HexDigit {/ {.. 0 9} {.. a f} {.. A F}}
+ Define match Ident {x {/ {t _} {t :} alpha} {* {/ {t _} {t :} alnum}}}
+ Define value Identifier {x {n Ident} {n SPACE}}
+ Define discard IS {x {t <} {t -} {n SPACE}}
+ Define leaf LEAF {x {t l} {t e} {t a} {t f} {n SPACE}}
+ Define value Literal {/ {x {n APOSTROPH} {* {x {! {n APOSTROPH}} {n Char}}} {n APOSTROPH} {n SPACE}} {x {n DAPOSTROPH} {* {x {! {n DAPOSTROPH}} {n Char}}} {n DAPOSTROPH} {n SPACE}}}
+ Define leaf MATCH {x {t m} {t a} {t t} {t c} {t h} {n SPACE}}
+ Define leaf NOT {x {t !} {n SPACE}}
+ Define discard OPEN {x {t \50} {n SPACE}}
+ Define discard OPENB {t \133}
+ Define discard PEG {x {t P} {t E} {t G} {n SPACE}}
+ Define leaf PLUS {x {t +} {n SPACE}}
+ Define value Prefix {x {? {/ {n AND} {n NOT}}} {n Suffix}}
+ Define value Primary {/ {n ALNUM} {n ALPHA} {n Identifier} {x {n OPEN} {n Expression} {n CLOSE}} {n Literal} {n Class} {n DOT}}
+ Define leaf QUESTION {x {t ?} {n SPACE}}
+ Define value Range {/ {x {n Char} {n TO} {n Char}} {n Char}}
+ Define discard SEMICOLON {x {t \73} {n SPACE}}
+ Define value Sequence {+ {n Prefix}}
+ Define discard SLASH {x {t /} {n SPACE}}
+ Define discard SPACE {* {/ {t \40} {t \t} {n EOL} {n COMMENT}}}
+ Define leaf STAR {x {t *} {n SPACE}}
+ Define value StartExpr {x {n OPEN} {n Expression} {n CLOSE}}
+ Define value Suffix {x {n Primary} {? {/ {n QUESTION} {n STAR} {n PLUS}}}}
+ Define discard TO {t -}
+ Define leaf VOID {x {t v} {t o} {t i} {t d} {n SPACE}}
+}
+
+# ### ### ### ######### ######### #########
+## Package Management - Ready
+
+# @sak notprovided pg::peg::grammar
+package provide pg::peg::grammar 0.1
+
diff --git a/tcllib/modules/page/pkgIndex.tcl b/tcllib/modules/page/pkgIndex.tcl
new file mode 100644
index 0000000..71cb403
--- /dev/null
+++ b/tcllib/modules/page/pkgIndex.tcl
@@ -0,0 +1,80 @@
+# -- PAGE application packages --
+# -- ---- plugin management
+
+package ifneeded page::pluginmgr 0.2 [list source [file join $dir pluginmgr.tcl]]
+
+# -- PAGE plugin packages
+# -- ---- Canned configurations
+
+package ifneeded page::config::peg 0.1 [list source [file join $dir plugins/config_peg.tcl]]
+
+# -- PAGE plugin packages
+# -- ---- Readers
+
+package ifneeded page::reader::peg 0.1 [list source [file join $dir plugins/reader_peg.tcl]]
+package ifneeded page::reader::lemon 0.1 [list source [file join $dir plugins/reader_lemon.tcl]]
+package ifneeded page::reader::hb 0.1 [list source [file join $dir plugins/reader_hb.tcl]]
+package ifneeded page::reader::ser 0.1 [list source [file join $dir plugins/reader_ser.tcl]]
+package ifneeded page::reader::treeser 0.1 [list source [file join $dir plugins/reader_treeser.tcl]]
+
+# -- PAGE plugin packages
+# -- ---- Writers
+
+package ifneeded page::writer::null 0.1 [list source [file join $dir plugins/writer_null.tcl]]
+package ifneeded page::writer::me 0.1 [list source [file join $dir plugins/writer_me.tcl]]
+package ifneeded page::writer::mecpu 0.1.1 [list source [file join $dir plugins/writer_mecpu.tcl]]
+package ifneeded page::writer::tree 0.1 [list source [file join $dir plugins/writer_tree.tcl]]
+package ifneeded page::writer::tpc 0.1 [list source [file join $dir plugins/writer_tpc.tcl]]
+package ifneeded page::writer::hb 0.1 [list source [file join $dir plugins/writer_hb.tcl]]
+package ifneeded page::writer::ser 0.1 [list source [file join $dir plugins/writer_ser.tcl]]
+package ifneeded page::writer::peg 0.1 [list source [file join $dir plugins/writer_peg.tcl]]
+package ifneeded page::writer::identity 0.1 [list source [file join $dir plugins/writer_identity.tcl]]
+
+# -- PAGE plugin packages
+# -- ---- Transformations
+
+package ifneeded page::transform::reachable 0.1 \
+ [list source [file join $dir plugins/transform_reachable.tcl]]
+package ifneeded page::transform::realizable 0.1 \
+ [list source [file join $dir plugins/transform_realizable.tcl]]
+package ifneeded page::transform::mecpu 0.1 \
+ [list source [file join $dir plugins/transform_mecpu.tcl]]
+
+# -- PAGE packages --
+# -- --- Parsing and normalization packages used by the reader plugins.
+
+package ifneeded page::parse::peg 0.1 [list source [file join $dir parse_peg.tcl]]
+package ifneeded page::parse::lemon 0.1 [list source [file join $dir parse_lemon.tcl]]
+package ifneeded page::parse::pegser 0.1 [list source [file join $dir parse_pegser.tcl]]
+package ifneeded page::parse::peghb 0.1 [list source [file join $dir parse_peghb.tcl]]
+
+package ifneeded page::util::norm::peg 0.1 [list source [file join $dir util_norm_peg.tcl]]
+package ifneeded page::util::norm::lemon 0.1 [list source [file join $dir util_norm_lemon.tcl]]
+
+# @mdgen EXCLUDE: peg_grammar.tcl
+### package ifneeded pg::peg::grammar 0.1 [list source [file join $dir peg_grammar.tcl]]
+
+# -- PAGE packages --
+# -- --- Code generation packages used by the writer plugins.
+
+package ifneeded page::gen::tree::text 0.1 [list source [file join $dir gen_tree_text.tcl]]
+package ifneeded page::gen::peg::cpkg 0.1 [list source [file join $dir gen_peg_cpkg.tcl]]
+package ifneeded page::gen::peg::hb 0.1 [list source [file join $dir gen_peg_hb.tcl]]
+package ifneeded page::gen::peg::ser 0.1 [list source [file join $dir gen_peg_ser.tcl]]
+package ifneeded page::gen::peg::canon 0.1 [list source [file join $dir gen_peg_canon.tcl]]
+package ifneeded page::gen::peg::me 0.1 [list source [file join $dir gen_peg_me.tcl]]
+package ifneeded page::gen::peg::mecpu 0.1 [list source [file join $dir gen_peg_mecpu.tcl]]
+
+# -- Transformation Helper Packages --
+
+package ifneeded page::analysis::peg::minimize 0.1 [list source [file join $dir analysis_peg_minimize.tcl]]
+package ifneeded page::analysis::peg::reachable 0.1 [list source [file join $dir analysis_peg_reachable.tcl]]
+package ifneeded page::analysis::peg::realizable 0.1 [list source [file join $dir analysis_peg_realizable.tcl]]
+package ifneeded page::analysis::peg::emodes 0.1 [list source [file join $dir analysis_peg_emodes.tcl]]
+package ifneeded page::compiler::peg::mecpu 0.1.1 [list source [file join $dir compiler_peg_mecpu.tcl]]
+
+# -- Various other utilities --
+
+package ifneeded page::util::peg 0.1 [list source [file join $dir util_peg.tcl]]
+package ifneeded page::util::quote 0.1 [list source [file join $dir util_quote.tcl]]
+package ifneeded page::util::flow 0.1 [list source [file join $dir util_flow.tcl]]
diff --git a/tcllib/modules/page/pluginmgr.tcl b/tcllib/modules/page/pluginmgr.tcl
new file mode 100644
index 0000000..ac00192
--- /dev/null
+++ b/tcllib/modules/page/pluginmgr.tcl
@@ -0,0 +1,581 @@
+# -*- tcl -*-
+# ### ### ### ######### ######### #########
+
+## This package provides custom plugin management specific to PAGE. It
+## is built on top of the generic plugin management framework (See
+## ---> pluginmgr).
+
+# ### ### ### ######### ######### #########
+## Requisites
+
+package require fileutil
+package require pluginmgr ; # Generic plugin management framework
+
+namespace eval ::page::pluginmgr {}
+
+# ### ### ### ######### ######### #########
+## API (Public, exported)
+
+proc ::page::pluginmgr::reportvia {cmd} {
+ variable reportcmd $cmd
+ return
+}
+
+proc ::page::pluginmgr::log {cmd} {
+ variable reader
+ variable writer
+ variable transforms
+
+ set iplist {}
+ lappend iplist [$reader interpreter]
+ lappend iplist [$writer interpreter]
+ foreach t $transforms {
+ lappend iplist [$t interpreter]
+ }
+
+ if {$cmd eq ""} {
+ # No logging. Disable with empty command,
+ # to allow the system to completely remove
+ # them from the bytecode (= No execution
+ # overhead).
+
+ foreach ip $iplist {
+ $ip eval [list proc page_log_error args {}]
+ $ip eval [list proc page_log_warning args {}]
+ $ip eval [list proc page_log_info args {}]
+ }
+ } else {
+ # Activate logging. Make the commands in
+ # the interpreters aliases to us.
+
+ foreach ip $iplist {
+ interp alias $ip page_log_error {} ${cmd}::error
+ interp alias $ip page_log_warning {} ${cmd}::warning
+ interp alias $ip page_log_info {} ${cmd}::info
+ }
+ }
+ return
+}
+
+proc ::page::pluginmgr::reader {name} {
+ variable reader
+
+ $reader load $name
+ return [$reader do page_roptions]
+}
+
+proc ::page::pluginmgr::rconfigure {dict} {
+ variable reader
+ foreach {k v} $dict {
+ $reader do page_rconfigure $k $v
+ }
+ return
+}
+
+proc ::page::pluginmgr::rtimeable {} {
+ variable reader
+ return [$reader do page_rfeature timeable]
+}
+
+proc ::page::pluginmgr::rtime {} {
+ variable reader
+ $reader do page_rtime
+ return
+}
+
+proc ::page::pluginmgr::rgettime {} {
+ variable reader
+ return [$reader do page_rgettime]
+}
+
+proc ::page::pluginmgr::rhelp {} {
+ variable reader
+ return [$reader do page_rhelp]
+}
+
+proc ::page::pluginmgr::rlabel {} {
+ variable reader
+ return [$reader do page_rlabel]
+}
+
+proc ::page::pluginmgr::read {read eof {complete {}}} {
+ variable reader
+
+ #interp alias $ip page_read {} {*}$read
+ #interp alias $ip page_eof {} {*}$eof
+
+ set ip [$reader interpreter]
+ eval [linsert $read 0 interp alias $ip page_read {}]
+ eval [linsert $eof 0 interp alias $ip page_eof {}]
+
+ if {![llength $complete]} {
+ interp alias $ip page_read_done {} ::page::pluginmgr::Nop
+ } else {
+ eval [linsert $complete 0 interp alias $ip page_read_done {}]
+ }
+
+ return [$reader do page_rrun]
+}
+
+proc ::page::pluginmgr::writer {name} {
+ variable writer
+
+ $writer load $name
+ return [$writer do page_woptions]
+}
+
+proc ::page::pluginmgr::wconfigure {dict} {
+ variable writer
+ foreach {k v} $dict {
+ $writer do page_wconfigure $k $v
+ }
+ return
+}
+
+proc ::page::pluginmgr::wtimeable {} {
+ variable writer
+ return [$writer do page_wfeature timeable]
+}
+
+proc ::page::pluginmgr::wtime {} {
+ variable writer
+ $writer do page_wtime
+ return
+}
+
+proc ::page::pluginmgr::wgettime {} {
+ variable writer
+ return [$writer do page_wgettime]
+}
+
+proc ::page::pluginmgr::whelp {} {
+ variable writer
+ return [$writer do page_whelp]
+}
+
+proc ::page::pluginmgr::wlabel {} {
+ variable writer
+ return [$writer do page_wlabel]
+}
+
+proc ::page::pluginmgr::write {chan data} {
+ variable writer
+
+ $writer do page_wrun $chan $data
+ return
+}
+
+proc ::page::pluginmgr::transform {name} {
+ variable transform
+ variable transforms
+
+ $transform load $name
+
+ set id [llength $transforms]
+ set opt [$transform do page_toptions]
+ lappend transforms [$transform clone]
+
+ return [list $id $opt]
+}
+
+proc ::page::pluginmgr::tconfigure {id dict} {
+ variable transforms
+
+ set t [lindex $transforms $id]
+
+ foreach {k v} $dict {
+ $t do page_tconfigure $k $v
+ }
+ return
+}
+
+proc ::page::pluginmgr::ttimeable {id} {
+ variable transforms
+ set t [lindex $transforms $id]
+ return [$t do page_tfeature timeable]
+}
+
+proc ::page::pluginmgr::ttime {id} {
+ variable transforms
+ set t [lindex $transforms $id]
+ $t do page_ttime
+ return
+}
+
+proc ::page::pluginmgr::tgettime {id} {
+ variable transforms
+ set t [lindex $transforms $id]
+ return [$t do page_tgettime]
+}
+
+proc ::page::pluginmgr::thelp {id} {
+ variable transforms
+ set t [lindex $transforms $id]
+ return [$t do page_thelp]
+}
+
+proc ::page::pluginmgr::tlabel {id} {
+ variable transforms
+ set t [lindex $transforms $id]
+ return [$t do page_tlabel]
+}
+
+proc ::page::pluginmgr::transform_do {id data} {
+ variable transforms
+ variable reader
+
+ set t [lindex $transforms $id]
+
+ return [$t do page_trun $data]
+}
+
+proc ::page::pluginmgr::configuration {name} {
+ variable config
+
+ if {[file exists $name]} {
+ # Try as plugin first. On failure read it as list of options,
+ # separated by spaces and tabs, and possibly quoted with
+ # quotes and double-quotes.
+
+ if {[catch {$config load $name}]} {
+ set ch [open $name r]
+ set options [::read $ch]
+ close $ch
+
+ set def {}
+ while {[string length $options]} {
+ if {[regsub "^\[ \t\n\]+" $options {} options]} {
+ # Skip whitespace
+ continue
+ }
+ if {[regexp -indices {^'(([^']|(''))*)'} \
+ $options -> word]} {
+ foreach {__ end} $word break
+ lappend def [string map {'' '} [string range $options 1 $end]]
+ set options [string range $options [incr end 2] end]
+ } elseif {[regexp -indices {^"(([^"]|(""))*)"} \
+ $options -> word]} {
+ foreach {__ end} $word break
+ lappend def [string map {{""} {"}} [string range $options 1 $end]]
+ set options [string range $options [incr end 2] end]
+ } elseif {[regexp -indices "^(\[^ \t\n\]+)" \
+ $options -> word]} {
+ foreach {__ end} $word break
+ lappend def [string range $options 0 $end]
+ set options [string range $options [incr end] end]
+ }
+ }
+ return $def
+ }
+ } else {
+ $config load $name
+ }
+ set def [$config do page_cdefinition]
+ $config unload
+ return $def
+}
+
+proc ::page::pluginmgr::report {level text {from {}} {to {}}} {
+ variable replevel
+ variable reportcmd
+ uplevel #0 [linsert $reportcmd end $replevel($level) $text $from $to]
+ return
+}
+
+# ### ### ### ######### ######### #########
+## Internals
+
+## Data structures
+##
+## - reader | Instances of pluginmgr configured for input,
+## - transform | transformational, and output plugins. The
+## - writer | manager for transforms is actually a template
+## | from which the actual instances are cloned.
+
+## - reportcmd | Callback for reporting of input error and warnings.
+## - replevel | Mapping from chosen level to the right-padded text
+## | to use.
+
+namespace eval ::page::pluginmgr {
+ variable replevel
+ array set replevel {
+ info {info }
+ warning {warning}
+ error {error }
+ }
+}
+
+proc ::page::pluginmgr::Initialize {} {
+ InitializeReporting
+ InitializeConfig
+ InitializeReader
+ InitializeTransform
+ InitializeWriter
+ return
+}
+
+proc ::page::pluginmgr::InitializeReader {} {
+ variable commands
+ variable reader_api
+ variable reader [pluginmgr RD \
+ -setup ::page::pluginmgr::InitializeReaderIp \
+ -pattern page::reader::* \
+ -api $reader_api \
+ -cmdip {} \
+ -cmds $commands]
+
+ # The page_log_* commands are set later, when it is known if
+ # logging is active or not, as their implementation depends on
+ # this.
+
+ pluginmgr::paths $reader page::reader
+ return
+}
+
+proc ::page::pluginmgr::InitializeReaderIp {p ip} {
+ interp eval $ip {
+ # @sak notprovided page::plugin
+ # @sak notprovided page::plugin::reader
+ package provide page::plugin 1.0
+ package provide page::plugin::reader 1.0
+ }
+ interp alias $ip puts {} puts
+ interp alias $ip open {} ::page::pluginmgr::AliasOpen $ip
+ interp alias $ip write {} ::page::pluginmgr::WriteFile $ip
+ return
+}
+
+proc ::page::pluginmgr::InitializeWriter {} {
+ variable commands
+ variable writer_api
+ variable writer [pluginmgr WR \
+ -setup ::page::pluginmgr::InitializeWriterIp \
+ -pattern page::writer::* \
+ -api $writer_api \
+ -cmdip {} \
+ -cmds $commands]
+
+ # The page_log_* commands are set later, when it is known if
+ # logging is active or not, as their implementation depends on
+ # this.
+
+ pluginmgr::paths $writer page::writer
+ return
+}
+
+proc ::page::pluginmgr::InitializeWriterIp {p ip} {
+ interp eval $ip {
+ # @sak notprovided page::plugin
+ # @sak notprovided page::plugin::writer
+ package provide page::plugin 1.0
+ package provide page::plugin::writer 1.0
+ }
+ interp alias $ip puts {} puts
+ interp alias $ip open {} ::page::pluginmgr::AliasOpen $ip
+ interp alias $ip write {} ::page::pluginmgr::WriteFile $ip
+ return
+}
+
+proc ::page::pluginmgr::InitializeTransform {} {
+ variable transforms {}
+ variable commands
+ variable transform_api
+ variable transform [pluginmgr TR \
+ -setup ::page::pluginmgr::InitializeTransformIp \
+ -pattern page::transform::* \
+ -api $transform_api \
+ -cmdip {} \
+ -cmds $commands]
+
+ # The page_log_* commands are set later, when it is known if
+ # logging is active or not, as their implementation depends on
+ # this.
+
+ pluginmgr::paths $transform page::transform
+ return
+}
+
+proc ::page::pluginmgr::InitializeTransformIp {p ip} {
+ interp eval $ip {
+ # @sak notprovided page::plugin
+ # @sak notprovided page::plugin::transform
+ package provide page::plugin 1.0
+ package provide page::plugin::transform 1.0
+ }
+ interp alias $ip puts {} puts
+ interp alias $ip open {} ::page::pluginmgr::AliasOpen $ip
+ interp alias $ip write {} ::page::pluginmgr::WriteFile $ip
+ return
+}
+
+proc ::page::pluginmgr::InitializeConfig {} {
+ variable config [pluginmgr CO \
+ -pattern page::config::* \
+ -api {page_cdefinition}]
+
+ pluginmgr::paths $config page::config
+ return
+}
+
+proc ::page::pluginmgr::InitializeReporting {} {
+ variable reportcmd ::page::pluginmgr::ReportStderr
+ return
+}
+
+proc ::page::pluginmgr::ReportStderr {level text from to} {
+ # from = epsilon | list (line col)
+ # to = epsilon | list (line col)
+ # line = 5 digits, col = 3 digits
+
+ if {
+ ($text eq "") &&
+ ![llength $from] &&
+ ![llength $to]
+ } {
+ puts stderr ""
+ return
+ }
+
+ puts -nonewline stderr $level
+ WriteLocation $from
+ if {![llength $to]} {
+ puts -nonewline stderr { }
+ } else {
+ puts -nonewline stderr {-}
+ }
+ WriteLocation $to
+ puts -nonewline stderr " "
+ puts -nonewline stderr $text
+ puts stderr ""
+ return
+}
+
+proc ::page::pluginmgr::WriteLocation {loc} {
+ if {![llength $loc]} {
+ set text { }
+ } else {
+ set line [lindex $loc 0]
+ set col [lindex $loc 1]
+ set text {}
+ if {![string length $line]} {
+ append text _____
+ } else {
+ append text [string map {{ } _} [format %5d $line]]
+ }
+ append text @
+ if {![string length $col]} {
+ append text ___
+ } else {
+ append text [string map {{ } _} [format %3d $col]]
+ }
+ }
+ puts -nonewline stderr $text
+ return
+}
+
+proc ::page::pluginmgr::AliasOpen {slave file {acc {}} {perm {}}} {
+
+ if {$acc eq ""} {set acc r}
+
+ ::safe::Log $slave =============================================
+ ::safe::Log $slave "open $file $acc $perm"
+
+ if {[regexp {[wa+]|(WRONLY)|(RDWR)|(APPEND)|(CREAT)|(TRUNC)} $acc]} {
+ # Do not allow write acess.
+ ::safe::Log $slave "permission denied"
+ ::safe::Log $slave 0/============================================
+ return -code error "permission denied"
+ }
+
+ if {[catch {set file [::safe::TranslatePath $slave $file]} msg]} {
+ ::safe::Log $slave $msg
+ ::safe::Log $slave "permission denied"
+ ::safe::Log $slave 1/============================================
+ return -code error "permission denied"
+ }
+
+ # check that the path is in the access path of that slave
+
+ if {[catch {::safe::FileInAccessPath $slave $file} msg]} {
+ ::safe::Log $slave $msg
+ ::safe::Log $slave "permission denied"
+ ::safe::Log $slave 2/============================================
+ return -code error "permission denied"
+ }
+
+ # do the checks on the filename :
+
+ if {[catch {::safe::CheckFileName $slave $file} msg]} {
+ ::safe::Log $slave "$file: $msg"
+ ::safe::Log $slave "$msg"
+ ::safe::Log $slave 3/============================================
+ return -code error $msg
+ }
+
+ if {[catch {::interp invokehidden $slave open $file $acc} msg]} {
+ ::safe::Log $slave "Caught: $msg"
+ ::safe::Log $slave "script error"
+ ::safe::Log $slave 4/============================================
+ return -code error "script error"
+ }
+
+ ::safe::Log $slave =/============================================
+ return $msg
+
+}
+
+proc ::page::pluginmgr::Nop {args} {}
+
+proc ::page::pluginmgr::WriteFile {slave file text} {
+ if {[file pathtype $file] ne "relative"} {
+ set file [file join [pwd] [file tail $fail]]
+ }
+ file mkdir [file dirname $file]
+ fileutil::writeFile $file $text
+ return
+}
+
+# ### ### ### ######### ######### #########
+## Initialization
+
+namespace eval ::page::pluginmgr {
+
+ # List of functions in the various plugin APIs
+
+ variable reader_api {
+ page_rhelp
+ page_rlabel
+ page_roptions
+ page_rconfigure
+ page_rrun
+ page_rfeature
+ }
+ variable writer_api {
+ page_whelp
+ page_wlabel
+ page_woptions
+ page_wconfigure
+ page_wrun
+ page_wfeature
+ }
+ variable transform_api {
+ page_thelp
+ page_tlabel
+ page_toptions
+ page_tconfigure
+ page_trun
+ page_tfeature
+ }
+ variable commands {
+ page_info {::page::pluginmgr::report info}
+ page_warning {::page::pluginmgr::report warning}
+ page_error {::page::pluginmgr::report error}
+ }
+}
+
+::page::pluginmgr::Initialize
+
+# ### ### ### ######### ######### #########
+## Ready
+
+package provide page::pluginmgr 0.2
diff --git a/tcllib/modules/page/plugins/config_peg.tcl b/tcllib/modules/page/plugins/config_peg.tcl
new file mode 100644
index 0000000..517877f
--- /dev/null
+++ b/tcllib/modules/page/plugins/config_peg.tcl
@@ -0,0 +1,14 @@
+# -*- tcl -*- $Id: config_peg.tcl,v 1.2 2005/09/28 06:16:38 andreas_kupries Exp $
+
+package provide page::config::peg 0.1
+
+proc page_cdefinition {} {
+ return {
+ --reset
+ --append
+ --reader peg
+ --transform reachable
+ --transform realizable
+ --writer me
+ }
+}
diff --git a/tcllib/modules/page/plugins/pkgIndex.tcl b/tcllib/modules/page/plugins/pkgIndex.tcl
new file mode 100644
index 0000000..8b6332a
--- /dev/null
+++ b/tcllib/modules/page/plugins/pkgIndex.tcl
@@ -0,0 +1,34 @@
+#puts @plugins
+# -- PAGE plugin packages
+# -- ---- Canned configurations
+
+package ifneeded page::config::peg 0.1 [list source [file join $dir config_peg.tcl]]
+
+# -- PAGE plugin packages
+# -- ---- Readers
+
+package ifneeded page::reader::peg 0.1 [list source [file join $dir reader_peg.tcl]]
+package ifneeded page::reader::lemon 0.1 [list source [file join $dir reader_lemon.tcl]]
+package ifneeded page::reader::hb 0.1 [list source [file join $dir reader_hb.tcl]]
+package ifneeded page::reader::ser 0.1 [list source [file join $dir reader_ser.tcl]]
+package ifneeded page::reader::treeser 0.1 [list source [file join $dir reader_treeser.tcl]]
+
+# -- PAGE plugin packages
+# -- ---- Writers
+
+package ifneeded page::writer::null 0.1 [list source [file join $dir writer_null.tcl]]
+package ifneeded page::writer::me 0.1 [list source [file join $dir writer_me.tcl]]
+package ifneeded page::writer::mecpu 0.1.1 [list source [file join $dir writer_mecpu.tcl]]
+package ifneeded page::writer::tree 0.1 [list source [file join $dir writer_tree.tcl]]
+package ifneeded page::writer::tpc 0.1 [list source [file join $dir writer_tpc.tcl]]
+package ifneeded page::writer::hb 0.1 [list source [file join $dir writer_hb.tcl]]
+package ifneeded page::writer::ser 0.1 [list source [file join $dir writer_ser.tcl]]
+package ifneeded page::writer::peg 0.1 [list source [file join $dir writer_peg.tcl]]
+package ifneeded page::writer::identity 0.1 [list source [file join $dir writer_identity.tcl]]
+
+# -- PAGE plugin packages
+# -- ---- Transformations
+
+package ifneeded page::transform::reachable 0.1 [list source [file join $dir transform_reachable.tcl]]
+package ifneeded page::transform::realizable 0.1 [list source [file join $dir transform_realizable.tcl]]
+package ifneeded page::transform::mecpu 0.1 [list source [file join $dir transform_mecpu.tcl]]
diff --git a/tcllib/modules/page/plugins/reader_hb.tcl b/tcllib/modules/page/plugins/reader_hb.tcl
new file mode 100644
index 0000000..4cee18c
--- /dev/null
+++ b/tcllib/modules/page/plugins/reader_hb.tcl
@@ -0,0 +1,114 @@
+# -*- tcl -*-
+# -- $Id: reader_hb.tcl,v 1.1 2005/09/28 04:51:22 andreas_kupries Exp $ ---
+#
+# PAGE plugin - reader - HB ~ Half baked PEG Container
+#
+
+# ### ### ### ######### ######### #########
+## Imported API
+
+# -----------------+--
+# page_read | Access to the input stream.
+# page_read_done |
+# page_eof |
+# -----------------+--
+# page_info | Reporting to the user.
+# page_warning |
+# page_error |
+# -----------------+--
+# page_log_error | Reporting of internals.
+# page_log_warning |
+# page_log_info |
+# -----------------+--
+
+# ### ### ### ######### ######### #########
+## Exported API
+
+# -----------------+--
+# page_rfeature | Query for special plugin features page might wish to use.
+# page_rtime | Activate collection of timing statistics.
+# page_rgettime | Return the collected timing statistics.
+# page_rlabel | User readable label for the plugin.
+# page_rhelp | Doctools help text for plugin.
+# page_roptions | Options understood by plugin.
+# page_rconfigure | Option (re)configuration.
+# page_rdata | External access to processed input stream.
+# page_rrun | Process input stream per plugin configuration and hardwiring.
+# -----------------+--
+
+# ### ### ### ######### ######### #########
+## Requisites
+
+package require struct::tree ; # Data structure.
+package require page::parse::peghb
+
+global usec
+global timed
+set timed 0
+
+# ### ### ### ######### ######### #########
+## Implementation of exported API
+
+proc page_rlabel {} {
+ return {Halfbaked PEG Container}
+}
+
+proc page_rfeature {key} {
+ return [string eq $key timeable]
+}
+
+proc page_rtime {} {
+ global timed
+ set timed 1
+ return
+}
+
+proc page_rgettime {} {
+ global usec
+ return $usec
+}
+
+proc page_rhelp {} {
+ return {}
+}
+
+proc page_roptions {} {
+ return {}
+}
+
+proc page_rconfigure {option value} {
+ return -code error "Cannot set value of unknown option \"$option\""
+}
+
+## proc page_rdata {} {}
+## Created in 'Initialize'
+
+proc page_rrun {} {
+ global timed usec
+ page_log_info "reader/hb/run/parse"
+
+ struct::tree ::tree
+
+ if {$timed} {
+ set usec [lindex [time {
+ page::parse::peghb [page_read] ::tree
+ }] 0] ; #{}
+ } else {
+ page::parse::peghb [page_read] ::tree
+ }
+ page_read_done
+
+ set ast [::tree serialize]
+ ::tree destroy
+
+ page_log_info "reader/hb/run/ok"
+ return $ast
+}
+
+# ### ### ### ######### ######### #########
+## Internal helper code.
+
+# ### ### ### ######### ######### #########
+## Initialization
+
+package provide page::reader::hb 0.1
diff --git a/tcllib/modules/page/plugins/reader_lemon.tcl b/tcllib/modules/page/plugins/reader_lemon.tcl
new file mode 100644
index 0000000..16df290
--- /dev/null
+++ b/tcllib/modules/page/plugins/reader_lemon.tcl
@@ -0,0 +1,170 @@
+# -*- tcl -*-
+# -- $Id: reader_lemon.tcl,v 1.1 2005/09/28 04:51:22 andreas_kupries Exp $ ---
+#
+# PAGE plugin - reader - LEMON ~ Grammar specification as understood
+# by drh's lemon parser generator.
+#
+
+# ### ### ### ######### ######### #########
+## Imported API
+
+# -----------------+--
+# page_read | Access to the input stream.
+# page_read_done |
+# page_eof |
+# -----------------+--
+# page_info | Reporting to the user.
+# page_warning |
+# page_error |
+# -----------------+--
+# page_log_error | Reporting of internals.
+# page_log_warning |
+# page_log_info |
+# -----------------+--
+
+# ### ### ### ######### ######### #########
+## Exported API
+
+# -----------------+--
+# page_rfeature | Query for special plugin features page might wish to use.
+# page_rtime | Activate collection of timing statistics.
+# page_rgettime | Return the collected timing statistics.
+# page_rlabel | User readable label for the plugin.
+# page_rhelp | Doctools help text for plugin.
+# page_roptions | Options understood by plugin.
+# page_rconfigure | Option (re)configuration.
+# page_rdata | External access to processed input stream.
+# page_rrun | Process input stream per plugin configuration and hardwiring.
+# -----------------+--
+
+# ### ### ### ######### ######### #########
+## Requisites
+
+package require page::util::norm::lemon ; # Normalize AST generated by PE matcher.
+package require page::parse::lemon ; # Mengine based parser for Lemon grammars.
+package require struct::tree ; # Data structure.
+package require grammar::me::util ; # AST conversion
+
+global usec
+global timed
+set timed 0
+
+global cline
+global ccol
+
+# ### ### ### ######### ######### #########
+## Implementation of exported API
+
+proc page_rlabel {} {
+ return {Lemon specification}
+}
+
+proc page_rfeature {key} {
+ return [string eq $key timeable]
+}
+
+proc page_rtime {} {
+ global timed
+ set timed 1
+ return
+}
+
+proc page_rgettime {} {
+ global usec
+ return $usec
+}
+
+proc page_rhelp {} {
+ return {}
+}
+
+proc page_roptions {} {
+ return {}
+}
+
+proc page_rconfigure {option value} {
+ return -code error "Cannot set value of unknown option \"$option\""
+}
+
+## proc page_rdata {} {}
+## Created in 'Initialize'
+
+proc page_rrun {} {
+ global timed usec cline ccol
+ page_log_info "reader/lemon/run/parse"
+
+ set ast {}
+ set err {}
+
+ # Location of the next character to be read.
+ set cline 1
+ set ccol 0
+
+ if {$timed} {
+ set usec [lindex [time {
+ set ok [::page::parse::lemon::parse ::Next err ast]
+ }] 0] ; #{}
+ } else {
+ set ok [::page::parse::lemon::parse ::Next err ast]
+ }
+ page_read_done
+ page_log_info "reader/lemon/run/check-for-errors"
+
+ if {!$ok} {
+ foreach {olc messages} $err break
+ foreach {offset linecol} $olc break
+ foreach {line col} $linecol break
+
+ set olc [string map {{ } _} \
+ [format %5d $line]]@[string map {{ } _} \
+ [format %3d $col]]/([format %5d $offset])
+
+ foreach m $messages {
+ page_log_error "reader/lemon/run: $olc: $m"
+ page_error $m $linecol
+ }
+
+ page_log_info "reader/lemon/run/failed"
+ return {}
+ }
+
+ page_log_info "reader/lemon/run/ast-conversion"
+
+ struct::tree ::tree
+ ::grammar::me::util::ast2etree $ast ::grammar::me::tcl ::tree
+ ::page::util::norm::lemon ::tree
+
+ set ast [::tree serialize]
+ ::tree destroy
+
+ page_log_info "reader/lemon/run/ok"
+ return $ast
+}
+
+# ### ### ### ######### ######### #########
+## Internal helper code.
+
+proc Next {} {
+ global cline ccol
+
+ if {[page_eof]} {return {}}
+
+ set ch [page_read 1]
+
+ if {$ch eq ""} {return {}}
+
+ set tok [list $ch {} $cline $ccol]
+
+ if {$ch eq "\n"} {
+ incr cline ; set ccol 0
+ } else {
+ incr ccol
+ }
+
+ return $tok
+}
+
+# ### ### ### ######### ######### #########
+## Initialization
+
+package provide page::reader::lemon 0.1
diff --git a/tcllib/modules/page/plugins/reader_peg.tcl b/tcllib/modules/page/plugins/reader_peg.tcl
new file mode 100644
index 0000000..52fd6a8
--- /dev/null
+++ b/tcllib/modules/page/plugins/reader_peg.tcl
@@ -0,0 +1,169 @@
+# -*- tcl -*-
+# -- $Id: reader_peg.tcl,v 1.1 2005/09/28 04:51:22 andreas_kupries Exp $ ---
+#
+# PAGE plugin - reader - PEG ~ Parsing Expression Grammar
+#
+
+# ### ### ### ######### ######### #########
+## Imported API
+
+# -----------------+--
+# page_read | Access to the input stream.
+# page_read_done |
+# page_eof |
+# -----------------+--
+# page_info | Reporting to the user.
+# page_warning |
+# page_error |
+# -----------------+--
+# page_log_error | Reporting of internals.
+# page_log_warning |
+# page_log_info |
+# -----------------+--
+
+# ### ### ### ######### ######### #########
+## Exported API
+
+# -----------------+--
+# page_rfeature | Query for special plugin features page might wish to use.
+# page_rtime | Activate collection of timing statistics.
+# page_rgettime | Return the collected timing statistics.
+# page_rlabel | User readable label for the plugin.
+# page_rhelp | Doctools help text for plugin.
+# page_roptions | Options understood by plugin.
+# page_rconfigure | Option (re)configuration.
+# page_rdata | External access to processed input stream.
+# page_rrun | Process input stream per plugin configuration and hardwiring.
+# -----------------+--
+
+# ### ### ### ######### ######### #########
+## Requisites
+
+package require page::util::norm::peg ; # Normalize AST generated by reader of PEG grammars
+package require page::parse::peg ; # Mengine based parser for PE grammars.
+package require struct::tree ; # Data structure.
+package require grammar::me::util ; # AST conversion
+
+global usec
+global timed
+set timed 0
+
+global cline
+global ccol
+
+# ### ### ### ######### ######### #########
+## Implementation of exported API
+
+proc page_rlabel {} {
+ return {Parsing Expression Grammar}
+}
+
+proc page_rfeature {key} {
+ return [string eq $key timeable]
+}
+
+proc page_rtime {} {
+ global timed
+ set timed 1
+ return
+}
+
+proc page_rgettime {} {
+ global usec
+ return $usec
+}
+
+proc page_rhelp {} {
+ return {}
+}
+
+proc page_roptions {} {
+ return {}
+}
+
+proc page_rconfigure {option value} {
+ return -code error "Cannot set value of unknown option \"$option\""
+}
+
+## proc page_rdata {} {}
+## Created in 'Initialize'
+
+proc page_rrun {} {
+ global timed usec cline ccol
+ page_log_info "reader/peg/run/parse"
+
+ set ast {}
+ set err {}
+
+ # Location of the next character to be read.
+ set cline 1
+ set ccol 0
+
+ if {$timed} {
+ set usec [lindex [time {
+ set ok [::page::parse::peg::parse ::Next err ast]
+ }] 0] ; #{}
+ } else {
+ set ok [::page::parse::peg::parse ::Next err ast]
+ }
+ page_read_done
+ page_log_info "reader/peg/run/check-for-errors"
+
+ if {!$ok} {
+ foreach {olc messages} $err break
+ foreach {offset linecol} $olc break
+ foreach {line col} $linecol break
+
+ set olc [string map {{ } _} \
+ [format %5d $line]]@[string map {{ } _} \
+ [format %3d $col]]/([format %5d $offset])
+
+ foreach m $messages {
+ page_log_error "reader/peg/run: $olc: $m"
+ page_error $m $linecol
+ }
+
+ page_log_info "reader/peg/run/failed"
+ return {}
+ }
+
+ page_log_info "reader/peg/run/ast-conversion"
+
+ struct::tree ::tree
+ ::grammar::me::util::ast2etree $ast ::grammar::me::tcl ::tree
+ ::page::util::norm::peg ::tree
+
+ set ast [::tree serialize]
+ ::tree destroy
+
+ page_log_info "reader/peg/run/ok"
+ return $ast
+}
+
+# ### ### ### ######### ######### #########
+## Internal helper code.
+
+proc Next {} {
+ global cline ccol
+
+ if {[page_eof]} {return {}}
+
+ set ch [page_read 1]
+
+ if {$ch eq ""} {return {}}
+
+ set tok [list $ch {} $cline $ccol]
+
+ if {$ch eq "\n"} {
+ incr cline ; set ccol 0
+ } else {
+ incr ccol
+ }
+
+ return $tok
+}
+
+# ### ### ### ######### ######### #########
+## Initialization
+
+package provide page::reader::peg 0.1
diff --git a/tcllib/modules/page/plugins/reader_ser.tcl b/tcllib/modules/page/plugins/reader_ser.tcl
new file mode 100644
index 0000000..b4e1a68
--- /dev/null
+++ b/tcllib/modules/page/plugins/reader_ser.tcl
@@ -0,0 +1,114 @@
+# -*- tcl -*-
+# -- $Id: reader_ser.tcl,v 1.1 2005/09/28 04:51:22 andreas_kupries Exp $ ---
+#
+# PAGE plugin - reader - SER ~ Serialized PEG Container
+#
+
+# ### ### ### ######### ######### #########
+## Imported API
+
+# -----------------+--
+# page_read | Access to the input stream.
+# page_read_done |
+# page_eof |
+# -----------------+--
+# page_info | Reporting to the user.
+# page_warning |
+# page_error |
+# -----------------+--
+# page_log_error | Reporting of internals.
+# page_log_warning |
+# page_log_info |
+# -----------------+--
+
+# ### ### ### ######### ######### #########
+## Exported API
+
+# -----------------+--
+# page_rfeature | Query for special plugin features page might wish to use.
+# page_rtime | Activate collection of timing statistics.
+# page_rgettime | Return the collected timing statistics.
+# page_rlabel | User readable label for the plugin.
+# page_rhelp | Doctools help text for plugin.
+# page_roptions | Options understood by plugin.
+# page_rconfigure | Option (re)configuration.
+# page_rdata | External access to processed input stream.
+# page_rrun | Process input stream per plugin configuration and hardwiring.
+# -----------------+--
+
+# ### ### ### ######### ######### #########
+## Requisites
+
+package require struct::tree ; # Data structure.
+package require page::parse::pegser
+
+global usec
+global timed
+set timed 0
+
+# ### ### ### ######### ######### #########
+## Implementation of exported API
+
+proc page_rlabel {} {
+ return {Serialized PEG Container}
+}
+
+proc page_rfeature {key} {
+ return [string eq $key timeable]
+}
+
+proc page_rtime {} {
+ global timed
+ set timed 1
+ return
+}
+
+proc page_rgettime {} {
+ global usec
+ return $usec
+}
+
+proc page_rhelp {} {
+ return {}
+}
+
+proc page_roptions {} {
+ return {}
+}
+
+proc page_rconfigure {option value} {
+ return -code error "Cannot set value of unknown option \"$option\""
+}
+
+## proc page_rdata {} {}
+## Created in 'Initialize'
+
+proc page_rrun {} {
+ global timed usec
+ page_log_info "reader/ser/run/parse"
+
+ struct::tree ::tree
+
+ if {$timed} {
+ set usec [lindex [time {
+ page::parse::pegser [page_read] ::tree
+ }] 0] ; #{}
+ } else {
+ page::parse::pegser [page_read] ::tree
+ }
+ page_read_done
+
+ set ast [::tree serialize]
+ ::tree destroy
+
+ page_log_info "reader/ser/run/ok"
+ return $ast
+}
+
+# ### ### ### ######### ######### #########
+## Internal helper code.
+
+# ### ### ### ######### ######### #########
+## Initialization
+
+package provide page::reader::ser 0.1
diff --git a/tcllib/modules/page/plugins/reader_treeser.tcl b/tcllib/modules/page/plugins/reader_treeser.tcl
new file mode 100644
index 0000000..6394d7b
--- /dev/null
+++ b/tcllib/modules/page/plugins/reader_treeser.tcl
@@ -0,0 +1,116 @@
+# -*- tcl -*-
+# -- $Id: reader_treeser.tcl,v 1.1 2005/09/28 04:51:22 andreas_kupries Exp $ ---
+#
+# PAGE plugin - reader - TREESER ~ Serialized TREE
+#
+
+# ### ### ### ######### ######### #########
+## Imported API
+
+# -----------------+--
+# page_read | Access to the input stream.
+# page_read_done |
+# page_eof |
+# -----------------+--
+# page_info | Reporting to the user.
+# page_warning |
+# page_error |
+# -----------------+--
+# page_log_error | Reporting of internals.
+# page_log_warning |
+# page_log_info |
+# -----------------+--
+
+# ### ### ### ######### ######### #########
+## Exported API
+
+# -----------------+--
+# page_rfeature | Query for special plugin features page might wish to use.
+# page_rtime | Activate collection of timing statistics.
+# page_rgettime | Return the collected timing statistics.
+# page_rlabel | User readable label for the plugin.
+# page_rhelp | Doctools help text for plugin.
+# page_roptions | Options understood by plugin.
+# page_rconfigure | Option (re)configuration.
+# page_rdata | External access to processed input stream.
+# page_rrun | Process input stream per plugin configuration and hardwiring.
+# -----------------+--
+
+# ### ### ### ######### ######### #########
+## Requisites
+
+package require struct::tree ; # Data structure.
+
+global usec
+global timed
+set timed 0
+
+# ### ### ### ######### ######### #########
+## Implementation of exported API
+
+proc page_rlabel {} {
+ return {Serialized Tree}
+}
+
+proc page_rfeature {key} {
+ return [string eq $key timeable]
+}
+
+proc page_rtime {} {
+ global timed
+ set timed 1
+ return
+}
+
+proc page_rgettime {} {
+ global usec
+ return $usec
+}
+
+proc page_rhelp {} {
+ return {}
+}
+
+proc page_roptions {} {
+ return {}
+}
+
+proc page_rconfigure {option value} {
+ return -code error "Cannot set value of unknown option \"$option\""
+}
+
+## proc page_rdata {} {}
+## Created in 'Initialize'
+
+proc page_rrun {} {
+ global timed usec
+ page_log_info "reader/treeser/run/parse"
+
+ if {$timed} {
+ set usec [lindex [time {
+ set data [page_read]
+ }] 0] ; #{}
+ } else {
+ set data [page_read]
+ }
+ page_read_done
+
+ # Reading and passing it on is trivial.
+ # Here however we validate the we truly got
+ # a sensible serialization.
+
+ struct::tree ::tree
+ ::tree deserialize $data
+ ::tree destroy
+
+ page_log_info "reader/treeser/run/ok"
+ return $data
+}
+
+# ### ### ### ######### ######### #########
+## Internal helper code.
+
+# ### ### ### ######### ######### #########
+## Initialization
+
+package provide page::reader::treeser 0.1
diff --git a/tcllib/modules/page/plugins/transform_mecpu.tcl b/tcllib/modules/page/plugins/transform_mecpu.tcl
new file mode 100644
index 0000000..4c48e53
--- /dev/null
+++ b/tcllib/modules/page/plugins/transform_mecpu.tcl
@@ -0,0 +1,107 @@
+# -*- tcl -*-
+# -- $Id: transform_mecpu.tcl,v 1.1 2006/07/01 01:35:21 andreas_kupries Exp $ ---
+#
+# PAGE plugin - transform - mecpu ~ Translation of grammar to ME cpu instruction set.
+#
+
+# ### ### ### ######### ######### #########
+## Imported API
+
+# -----------------+--
+# page_tdata | Access to processed input stream.
+# -----------------+--
+# page_info | Reporting to the user.
+# page_warning |
+# page_error |
+# -----------------+--
+# page_log_error | Reporting of internals.
+# page_log_warning |
+# page_log_info |
+# -----------------+--
+
+# ### ### ### ######### ######### #########
+## Exported API
+
+# -----------------+--
+# page_tfeature | Query for special plugin features page might wish to use.
+# page_ttime | Activate collection of timing statistics.
+# page_tgettime | Return the collected timing statistics.
+# page_tlabel | User readable label for the plugin.
+# page_thelp | Doctools help text for plugin.
+# page_toptions | Options understood by plugin.
+# page_tconfigure | Option (re)configuration.
+# page_trun | Transform input data per plugin configuration and hardwiring.
+# -----------------+--
+
+# ### ### ### ######### ######### #########
+## Requisites
+
+package require page::compiler::peg::mecpu
+package require struct::tree ; # Data structure.
+
+global usec
+global timed
+set timed 0
+
+# ### ### ### ######### ######### #########
+## Implementation of exported API
+
+proc page_tlabel {} {
+ return {ME cpu Translation}
+}
+
+proc page_tfeature {key} {
+ return [string eq $key timeable]
+}
+
+proc page_ttime {} {
+ global timed
+ set timed 1
+ return
+}
+
+proc page_tgettime {} {
+ global usec
+ return $usec
+}
+
+proc page_thelp {} {
+ return {}
+}
+
+proc page_toptions {} {
+ return {}
+}
+
+proc page_tconfigure {option value} {
+ return -code error "Cannot set value of unknown option \"$option\""
+}
+
+proc page_trun {data} {
+ global timed usec
+ page_log_info "transform/mecpu/run/"
+
+ if {$timed} {
+ set usec [lindex [time {
+ ::struct::tree ::tree deserialize $data
+ page::compiler::peg::mecpu ::tree
+ }] 0] ; #{}
+ } else {
+ ::struct::tree ::tree deserialize $data
+ page::compiler::peg::mecpu ::tree
+ }
+ set name [::tree get root name]
+ set asm [::tree get root asm]
+ ::tree destroy
+
+ page_log_info "transform/mecpu/run/ok"
+ return [list $name $asm]
+}
+
+# ### ### ### ######### ######### #########
+## Internal helper code.
+
+# ### ### ### ######### ######### #########
+## Initialization
+
+package provide page::transform::mecpu 0.1
diff --git a/tcllib/modules/page/plugins/transform_reachable.tcl b/tcllib/modules/page/plugins/transform_reachable.tcl
new file mode 100644
index 0000000..2dee6dd
--- /dev/null
+++ b/tcllib/modules/page/plugins/transform_reachable.tcl
@@ -0,0 +1,107 @@
+# -*- tcl -*-
+# -- $Id: transform_reachable.tcl,v 1.1 2005/09/28 04:51:22 andreas_kupries Exp $ ---
+#
+# PAGE plugin - transform - reachable ~ Reachability Analysis
+#
+
+# ### ### ### ######### ######### #########
+## Imported API
+
+# -----------------+--
+# page_tdata | Access to processed input stream.
+# -----------------+--
+# page_info | Reporting to the user.
+# page_warning |
+# page_error |
+# -----------------+--
+# page_log_error | Reporting of internals.
+# page_log_warning |
+# page_log_info |
+# -----------------+--
+
+# ### ### ### ######### ######### #########
+## Exported API
+
+# -----------------+--
+# page_tfeature | Query for special plugin features page might wish to use.
+# page_ttime | Activate collection of timing statistics.
+# page_tgettime | Return the collected timing statistics.
+# page_tlabel | User readable label for the plugin.
+# page_thelp | Doctools help text for plugin.
+# page_toptions | Options understood by plugin.
+# page_tconfigure | Option (re)configuration.
+# page_trun | Transform input data per plugin configuration and hardwiring.
+# -----------------+--
+
+# ### ### ### ######### ######### #########
+## Requisites
+
+package require page::analysis::peg::reachable
+package require struct::tree ; # Data structure.
+
+global usec
+global timed
+set timed 0
+
+# ### ### ### ######### ######### #########
+## Implementation of exported API
+
+proc page_tlabel {} {
+ return Reachability
+}
+
+proc page_tfeature {key} {
+ return [string eq $key timeable]
+}
+
+proc page_ttime {} {
+ global timed
+ set timed 1
+ return
+}
+
+proc page_tgettime {} {
+ global usec
+ return $usec
+}
+
+proc page_thelp {} {
+ return {}
+}
+
+proc page_toptions {} {
+ return {}
+}
+
+proc page_tconfigure {option value} {
+ return -code error "Cannot set value of unknown option \"$option\""
+}
+
+proc page_trun {data} {
+ global timed usec
+ page_log_info "transform/reachable/run/"
+
+ if {$timed} {
+ set usec [lindex [time {
+ ::struct::tree ::tree deserialize $data
+ ::page::analysis::peg::reachable::remove! ::tree
+ }] 0] ; #{}
+ } else {
+ ::struct::tree ::tree deserialize $data
+ ::page::analysis::peg::reachable::remove! ::tree
+ }
+
+ set data [::tree serialize]
+ ::tree destroy
+
+ page_log_info "transform/reachable/run/ok"
+ return $data
+}
+
+# ### ### ### ######### ######### #########
+## Internal helper code.
+
+# ### ### ### ######### ######### #########
+## Initialization
+
+package provide page::transform::reachable 0.1
diff --git a/tcllib/modules/page/plugins/transform_realizable.tcl b/tcllib/modules/page/plugins/transform_realizable.tcl
new file mode 100644
index 0000000..38efaeb
--- /dev/null
+++ b/tcllib/modules/page/plugins/transform_realizable.tcl
@@ -0,0 +1,106 @@
+# -*- tcl -*-
+# -- $Id: transform_realizable.tcl,v 1.1 2005/09/28 04:51:22 andreas_kupries Exp $ ---
+#
+# PAGE plugin - transform - realizable ~ Realizability Analysis
+#
+
+# ### ### ### ######### ######### #########
+## Imported API
+
+# -----------------+--
+# page_tdata | Access to processed input stream.
+# -----------------+--
+# page_info | Reporting to the user.
+# page_warning |
+# page_error |
+# -----------------+--
+# page_log_error | Reporting of internals.
+# page_log_warning |
+# page_log_info |
+# -----------------+--
+
+# ### ### ### ######### ######### #########
+## Exported API
+
+# -----------------+--
+# page_tfeature | Query for special plugin features page might wish to use.
+# page_ttime | Activate collection of timing statistics.
+# page_tgettime | Return the collected timing statistics.
+# page_tlabel | User readable label for the plugin.
+# page_thelp | Doctools help text for plugin.
+# page_toptions | Options understood by plugin.
+# page_tconfigure | Option (re)configuration.
+# page_trun | Transform input data per plugin configuration and hardwiring.
+# -----------------+--
+
+# ### ### ### ######### ######### #########
+## Requisites
+
+package require page::analysis::peg::realizable
+package require struct::tree ; # Data structure.
+
+global usec
+global timed
+set timed 0
+
+# ### ### ### ######### ######### #########
+## Implementation of exported API
+
+proc page_tlabel {} {
+ return Realizability
+}
+
+proc page_tfeature {key} {
+ return [string eq $key timeable]
+}
+
+proc page_ttime {} {
+ global timed
+ set timed 1
+ return
+}
+
+proc page_tgettime {} {
+ global usec
+ return $usec
+}
+
+proc page_thelp {} {
+ return {}
+}
+
+proc page_toptions {} {
+ return {}
+}
+
+proc page_tconfigure {option value} {
+ return -code error "Cannot set value of unknown option \"$option\""
+}
+
+proc page_trun {data} {
+ global timed usec
+ page_log_info "transform/realizable/run/"
+
+ if {$timed} {
+ set usec [lindex [time {
+ ::struct::tree ::tree deserialize $data
+ ::page::analysis::peg::realizable::remove! ::tree
+ }] 0] ; #{}
+ } else {
+ ::struct::tree ::tree deserialize $data
+ ::page::analysis::peg::realizable::remove! ::tree
+ }
+ set data [::tree serialize]
+ ::tree destroy
+
+ page_log_info "transform/realizable/run/ok"
+ return $data
+}
+
+# ### ### ### ######### ######### #########
+## Internal helper code.
+
+# ### ### ### ######### ######### #########
+## Initialization
+
+package provide page::transform::realizable 0.1
diff --git a/tcllib/modules/page/plugins/writer_hb.tcl b/tcllib/modules/page/plugins/writer_hb.tcl
new file mode 100644
index 0000000..711e62a
--- /dev/null
+++ b/tcllib/modules/page/plugins/writer_hb.tcl
@@ -0,0 +1,106 @@
+# -*- tcl -*-
+# -- $Id: writer_hb.tcl,v 1.1 2005/09/28 04:51:22 andreas_kupries Exp $ ---
+#
+# PAGE plugin - writer - HB ~ Half Baked / Tcl Peg Container
+#
+
+# ### ### ### ######### ######### #########
+## Imported API
+
+# -----------------+--
+# page_wdata | Access to processed input stream.
+# -----------------+--
+# page_info | Reporting to the user.
+# page_warning |
+# page_error |
+# -----------------+--
+# page_log_error | Reporting of internals.
+# page_log_warning |
+# page_log_info |
+# -----------------+--
+
+# ### ### ### ######### ######### #########
+## Exported API
+
+# -----------------+--
+# page_wfeature | Query for special plugin features page might wish to use.
+# page_wtime | Activate collection of timing statistics.
+# page_wgettime | Return the collected timing statistics.
+# page_wlabel | User readable label for the plugin.
+# page_whelp | Doctools help text for plugin.
+# page_woptions | Options understood by plugin.
+# page_wconfigure | Option (re)configuration.
+# page_wrun | Generate output from data per plugin configuration and hardwiring.
+# -----------------+--
+
+# ### ### ### ######### ######### #########
+## Requisites
+
+package require page::gen::peg::hb
+package require struct::tree ; # Data structure.
+
+global usec
+global timed
+set timed 0
+
+# ### ### ### ######### ######### #########
+## Implementation of exported API
+
+proc page_wlabel {} {
+ return {Half baked PEG Container}
+}
+
+proc page_wfeature {key} {
+ return [string eq $key timeable]
+}
+
+proc page_wtime {} {
+ global timed
+ set timed 1
+ return
+}
+
+proc page_wgettime {} {
+ global usec
+ return $usec
+}
+
+proc page_whelp {} {
+ return {}
+}
+
+proc page_woptions {} {
+ return {}
+}
+
+proc page_wconfigure {option value} {
+ return -code error "Cannot set value of unknown option \"$option\""
+}
+
+proc page_wrun {chan data} {
+ global timed usec
+ page_log_info "writer/hb/run/"
+
+ if {$timed} {
+ set usec [lindex [time {
+ ::struct::tree ::tree deserialize $data
+ page::gen::peg::hb ::tree $chan
+ }] 0] ; #{}
+ } else {
+ ::struct::tree ::tree deserialize $data
+ page::gen::peg::hb ::tree $chan
+ }
+
+ page_log_info "writer/hb/run/ok"
+
+ ::tree destroy
+ return
+}
+
+# ### ### ### ######### ######### #########
+## Internal helper code.
+
+# ### ### ### ######### ######### #########
+## Initialization
+
+package provide page::writer::hb 0.1
diff --git a/tcllib/modules/page/plugins/writer_identity.tcl b/tcllib/modules/page/plugins/writer_identity.tcl
new file mode 100644
index 0000000..b5d9cd4
--- /dev/null
+++ b/tcllib/modules/page/plugins/writer_identity.tcl
@@ -0,0 +1,98 @@
+# -*- tcl -*-
+# -- $Id: writer_identity.tcl,v 1.1 2005/09/28 04:51:22 andreas_kupries Exp $ ---
+#
+# PAGE plugin - writer - Generic dump
+#
+
+# ### ### ### ######### ######### #########
+## Imported API
+
+# -----------------+--
+# page_wdata | Access to processed input stream.
+# -----------------+--
+# page_info | Reporting to the user.
+# page_warning |
+# page_error |
+# -----------------+--
+# page_log_error | Reporting of internals.
+# page_log_warning |
+# page_log_info |
+# -----------------+--
+
+# ### ### ### ######### ######### #########
+## Exported API
+
+# -----------------+--
+# page_wfeature | Query for special plugin features page might wish to use.
+# page_wtime | Activate collection of timing statistics.
+# page_wgettime | Return the collected timing statistics.
+# page_wlabel | User readable label for the plugin.
+# page_whelp | Doctools help text for plugin.
+# page_woptions | Options understood by plugin.
+# page_wconfigure | Option (re)configuration.
+# page_wrun | Generate output from data per plugin configuration and hardwiring.
+# -----------------+--
+
+# ### ### ### ######### ######### #########
+## Requisites
+
+global usec
+global timed
+set timed 0
+
+# ### ### ### ######### ######### #########
+## Implementation of exported API
+
+proc page_wlabel {} {
+ return {Raw data unchanged}
+}
+
+proc page_wfeature {key} {
+ return [string eq $key timeable]
+}
+
+proc page_wtime {} {
+ global timed
+ set timed 1
+ return
+}
+
+proc page_wgettime {} {
+ global usec
+ return $usec
+}
+proc page_whelp {} {
+ return {}
+}
+
+proc page_woptions {} {
+ return {}
+}
+
+proc page_wconfigure {option value} {
+ return -code error "Cannot set value of unknown option \"$option\""
+}
+
+proc page_wrun {chan data} {
+ global timed usec
+ page_log_info "writer/identity/run/"
+
+ if {$timed} {
+ set usec [lindex [time {
+ puts $chan $data
+ }] 0] ; #{}
+ } else {
+ puts $chan $data
+ }
+
+ page_log_info "writer/identity/run/ok"
+ return
+}
+
+# ### ### ### ######### ######### #########
+## Internal helper code.
+
+# ### ### ### ######### ######### #########
+## Initialization
+
+package provide page::writer::identity 0.1
diff --git a/tcllib/modules/page/plugins/writer_me.tcl b/tcllib/modules/page/plugins/writer_me.tcl
new file mode 100644
index 0000000..5e4d6b1
--- /dev/null
+++ b/tcllib/modules/page/plugins/writer_me.tcl
@@ -0,0 +1,115 @@
+# -*- tcl -*-
+# -- $Id: writer_me.tcl,v 1.1 2005/09/28 04:51:22 andreas_kupries Exp $ ---
+#
+# PAGE plugin - writer - ME ~ Match Engine
+#
+
+# ### ### ### ######### ######### #########
+## Imported API
+
+# -----------------+--
+# page_wdata | Access to processed input stream.
+# -----------------+--
+# page_info | Reporting to the user.
+# page_warning |
+# page_error |
+# -----------------+--
+# page_log_error | Reporting of internals.
+# page_log_warning |
+# page_log_info |
+# -----------------+--
+
+# ### ### ### ######### ######### #########
+## Exported API
+
+# -----------------+--
+# page_wfeature | Query for special plugin features page might wish to use.
+# page_wtime | Activate collection of timing statistics.
+# page_wgettime | Return the collected timing statistics.
+# page_wlabel | User readable label for the plugin.
+# page_whelp | Doctools help text for plugin.
+# page_woptions | Options understood by plugin.
+# page_wconfigure | Option (re)configuration.
+# page_wrun | Generate output from data per plugin configuration and hardwiring.
+# -----------------+--
+
+# ### ### ### ######### ######### #########
+## Requisites
+
+package require page::gen::peg::me
+package require struct::tree ; # Data structure.
+
+global usec
+global timed
+set timed 0
+
+# ### ### ### ######### ######### #########
+## Implementation of exported API
+
+proc page_wlabel {} {
+ return {MatchEngine RecDescent}
+}
+
+proc page_wfeature {key} {
+ return [string eq $key timeable]
+}
+
+proc page_wtime {} {
+ global timed
+ set timed 1
+ return
+}
+
+proc page_wgettime {} {
+ global usec
+ return $usec
+}
+
+proc page_whelp {} {
+ return {}
+}
+
+proc page_woptions {} {
+ return {--package --copyright}
+}
+
+proc page_wconfigure {option value} {
+ switch -exact -- $option {
+ --package {
+ page::gen::peg::me::package $value
+ }
+ --copyright {
+ page::gen::peg::me::copyright $value
+ }
+ default {
+ return -code error "Cannot set value of unknown option \"$option\""
+ }
+ }
+}
+
+proc page_wrun {chan data} {
+ global timed usec
+ page_log_info "writer/me/run/"
+
+ if {$timed} {
+ set usec [lindex [time {
+ ::struct::tree ::tree deserialize $data
+ page::gen::peg::me ::tree $chan
+ }] 0] ; #{}
+ } else {
+ ::struct::tree ::tree deserialize $data
+ page::gen::peg::me ::tree $chan
+ }
+ page_log_info "writer/me/run/ok"
+
+ ::tree destroy
+ return
+}
+
+# ### ### ### ######### ######### #########
+## Internal helper code.
+
+# ### ### ### ######### ######### #########
+## Initialization
+
+package provide page::writer::me 0.1
diff --git a/tcllib/modules/page/plugins/writer_mecpu.tcl b/tcllib/modules/page/plugins/writer_mecpu.tcl
new file mode 100644
index 0000000..00e5508
--- /dev/null
+++ b/tcllib/modules/page/plugins/writer_mecpu.tcl
@@ -0,0 +1,116 @@
+# -*- tcl -*-
+# -- $Id: writer_mecpu.tcl,v 1.2 2007/03/21 23:15:53 andreas_kupries Exp $ ---
+#
+# PAGE plugin - writer - ME cpu ~ Match Engine CPU
+#
+
+# ### ### ### ######### ######### #########
+## Imported API
+
+# -----------------+--
+# page_wdata | Access to processed input stream.
+# -----------------+--
+# page_info | Reporting to the user.
+# page_warning |
+# page_error |
+# -----------------+--
+# page_log_error | Reporting of internals.
+# page_log_warning |
+# page_log_info |
+# -----------------+--
+
+# ### ### ### ######### ######### #########
+## Exported API
+
+# -----------------+--
+# page_wfeature | Query for special plugin features page might wish to use.
+# page_wtime | Activate collection of timing statistics.
+# page_wgettime | Return the collected timing statistics.
+# page_wlabel | User readable label for the plugin.
+# page_whelp | Doctools help text for plugin.
+# page_woptions | Options understood by plugin.
+# page_wconfigure | Option (re)configuration.
+# page_wrun | Generate output from data per plugin configuration and hardwiring.
+# -----------------+--
+
+# ### ### ### ######### ######### #########
+## Requisites
+
+package require page::gen::peg::mecpu
+
+global usec
+global timed
+set timed 0
+
+# ### ### ### ######### ######### #########
+## Implementation of exported API
+
+proc page_wlabel {} {
+ return {ME cpu Assembler}
+}
+
+proc page_wfeature {key} {
+ return [string eq $key timeable]
+}
+
+proc page_wtime {} {
+ global timed
+ set timed 1
+ return
+}
+
+proc page_wgettime {} {
+ global usec
+ return $usec
+}
+
+proc page_whelp {} {
+ return {}
+}
+
+proc page_woptions {} {
+ return {--package --copyright --template --cmarker}
+}
+
+proc page_wconfigure {option value} {
+ switch -exact -- $option {
+ --package {
+ page::gen::peg::mecpu::package $value
+ }
+ --copyright {
+ page::gen::peg::mecpu::copyright $value
+ }
+ --template {
+ page::gen::peg::mecpu::template $value
+ }
+ --cmarker {
+ page::gen::peg::mecpu::cmarker $value
+ }
+ default {
+ return -code error "Cannot set value of unknown option \"$option\""
+ }
+ }
+}
+
+proc page_wrun {chan data} {
+ global timed usec
+ page_log_info "writer/me-cpu/run/"
+
+ if {$timed} {
+ set usec [lindex [time {
+ page::gen::peg::mecpu $data $chan
+ }] 0] ; #{}
+ } else {
+ page::gen::peg::mecpu $data $chan
+ }
+ page_log_info "writer/me-cpu/run/ok"
+ return
+}
+
+# ### ### ### ######### ######### #########
+## Internal helper code.
+
+# ### ### ### ######### ######### #########
+## Initialization
+
+package provide page::writer::mecpu 0.1.1
diff --git a/tcllib/modules/page/plugins/writer_null.tcl b/tcllib/modules/page/plugins/writer_null.tcl
new file mode 100644
index 0000000..7d15b25
--- /dev/null
+++ b/tcllib/modules/page/plugins/writer_null.tcl
@@ -0,0 +1,97 @@
+# -*- tcl -*-
+# -- $Id: writer_null.tcl,v 1.1 2005/09/28 04:51:22 andreas_kupries Exp $ ---
+#
+# PAGE plugin - writer - NULL ~ /dev/null the output
+#
+
+# ### ### ### ######### ######### #########
+## Imported API
+
+# -----------------+--
+# page_wdata | Access to processed input stream.
+# -----------------+--
+# page_info | Reporting to the user.
+# page_warning |
+# page_error |
+# -----------------+--
+# page_log_error | Reporting of internals.
+# page_log_warning |
+# page_log_info |
+# -----------------+--
+
+# ### ### ### ######### ######### #########
+## Exported API
+
+# -----------------+--
+# page_wfeature | Query for special plugin features page might wish to use.
+# page_wtime | Activate collection of timing statistics.
+# page_wgettime | Return the collected timing statistics.
+# page_wlabel | User readable label for the plugin.
+# page_whelp | Doctools help text for plugin.
+# page_woptions | Options understood by plugin.
+# page_wconfigure | Option (re)configuration.
+# page_wrun | Generate output from data per plugin configuration and hardwiring.
+# -----------------+--
+
+# ### ### ### ######### ######### #########
+## Requisites
+
+global usec
+global timed
+set timed 0
+
+# ### ### ### ######### ######### #########
+## Implementation of exported API
+
+proc page_wlabel {} {
+ return /dev/null
+}
+
+proc page_wfeature {key} {
+ return [string eq $key timeable]
+}
+
+proc page_wtime {} {
+ global timed
+ set timed 1
+ return
+}
+
+proc page_wgettime {} {
+ global usec
+ return $usec
+}
+
+proc page_whelp {} {
+ return {}
+}
+
+proc page_woptions {} {
+ return {}
+}
+
+proc page_wconfigure {option value} {
+ return -code error "Cannot set value of unknown option \"$option\""
+}
+
+proc page_wrun {chan data} {
+ global timed usec
+ if {$timed} {
+ set usec [lindex [time {
+ page_log_info "writer/null/run/"
+ page_log_info "writer/null/run/ok"
+ }] 0] ; #{}
+ } else {
+ page_log_info "writer/null/run/"
+ page_log_info "writer/null/run/ok"
+ }
+ return
+}
+
+# ### ### ### ######### ######### #########
+## Internal helper code.
+
+# ### ### ### ######### ######### #########
+## Initialization
+
+package provide page::writer::null 0.1
diff --git a/tcllib/modules/page/plugins/writer_peg.tcl b/tcllib/modules/page/plugins/writer_peg.tcl
new file mode 100644
index 0000000..f8cd060
--- /dev/null
+++ b/tcllib/modules/page/plugins/writer_peg.tcl
@@ -0,0 +1,106 @@
+# -*- tcl -*-
+# -- $Id: writer_peg.tcl,v 1.1 2005/09/28 04:51:22 andreas_kupries Exp $ ---
+#
+# PAGE plugin - writer - PEG ~ Canonical PE Grammar
+#
+
+# ### ### ### ######### ######### #########
+## Imported API
+
+# -----------------+--
+# page_wdata | Access to processed input stream.
+# -----------------+--
+# page_info | Reporting to the user.
+# page_warning |
+# page_error |
+# -----------------+--
+# page_log_error | Reporting of internals.
+# page_log_warning |
+# page_log_info |
+# -----------------+--
+
+# ### ### ### ######### ######### #########
+## Exported API
+
+# -----------------+--
+# page_wfeature | Query for special plugin features page might wish to use.
+# page_wtime | Activate collection of timing statistics.
+# page_wgettime | Return the collected timing statistics.
+# page_wlabel | User readable label for the plugin.
+# page_whelp | Doctools help text for plugin.
+# page_woptions | Options understood by plugin.
+# page_wconfigure | Option (re)configuration.
+# page_wrun | Generate output from data per plugin configuration and hardwiring.
+# -----------------+--
+
+# ### ### ### ######### ######### #########
+## Requisites
+
+package require page::gen::peg::canon
+package require struct::tree ; # Data structure.
+
+global usec
+global timed
+set timed 0
+
+# ### ### ### ######### ######### #########
+## Implementation of exported API
+
+proc page_wlabel {} {
+ return {Canonical PEG}
+}
+
+proc page_wfeature {key} {
+ return [string eq $key timeable]
+}
+
+proc page_wtime {} {
+ global timed
+ set timed 1
+ return
+}
+
+proc page_wgettime {} {
+ global usec
+ return $usec
+}
+
+proc page_whelp {} {
+ return {}
+}
+
+proc page_woptions {} {
+ return {}
+}
+
+proc page_wconfigure {option value} {
+ return -code error "Cannot set value of unknown option \"$option\""
+}
+
+proc page_wrun {chan data} {
+ global timed usec
+ page_log_info "writer/peg/run/"
+
+ if {$timed} {
+ set usec [lindex [time {
+ ::struct::tree ::tree deserialize $data
+ page::gen::peg::canon ::tree $chan
+ }] 0] ; #{}
+ } else {
+ ::struct::tree ::tree deserialize $data
+ page::gen::peg::canon ::tree $chan
+ }
+
+ page_log_info "writer/peg/run/ok"
+
+ ::tree destroy
+ return
+}
+
+# ### ### ### ######### ######### #########
+## Internal helper code.
+
+# ### ### ### ######### ######### #########
+## Initialization
+
+package provide page::writer::peg 0.1
diff --git a/tcllib/modules/page/plugins/writer_ser.tcl b/tcllib/modules/page/plugins/writer_ser.tcl
new file mode 100644
index 0000000..3b977a2
--- /dev/null
+++ b/tcllib/modules/page/plugins/writer_ser.tcl
@@ -0,0 +1,104 @@
+# -*- tcl -*-
+# -- $Id: writer_ser.tcl,v 1.1 2005/09/28 04:51:22 andreas_kupries Exp $ ---
+#
+# PAGE plugin - writer - SER ~ Serialized PEG Container
+#
+
+# ### ### ### ######### ######### #########
+## Imported API
+
+# -----------------+--
+# page_wdata | Access to processed input stream.
+# -----------------+--
+# page_info | Reporting to the user.
+# page_warning |
+# page_error |
+# -----------------+--
+# page_log_error | Reporting of internals.
+# page_log_warning |
+# page_log_info |
+# -----------------+--
+
+# ### ### ### ######### ######### #########
+## Exported API
+
+# -----------------+--
+# page_wfeature | Query for special plugin features page might wish to use.
+# page_wtime | Activate collection of timing statistics.
+# page_wgettime | Return the collected timing statistics.
+# page_wlabel | User readable label for the plugin.
+# page_whelp | Doctools help text for plugin.
+# page_woptions | Options understood by plugin.
+# page_wconfigure | Option (re)configuration.
+# page_wrun | Generate output from data per plugin configuration and hardwiring.
+# -----------------+--
+
+# ### ### ### ######### ######### #########
+## Requisites
+
+package require page::gen::peg::ser
+package require struct::tree ; # Data structure.
+
+global usec
+global timed
+set timed 0
+
+# ### ### ### ######### ######### #########
+## Implementation of exported API
+
+proc page_wlabel {} {
+ return {Serialized PEG Container}
+}
+
+proc page_wfeature {key} {
+ return [string eq $key timeable]
+}
+
+proc page_wtime {} {
+ global timed
+ set timed 1
+ return
+}
+
+proc page_wgettime {} {
+ global usec
+ return $usec
+}
+proc page_whelp {} {
+ return {}
+}
+
+proc page_woptions {} {
+ return {}
+}
+
+proc page_wconfigure {option value} {
+ return -code error "Cannot set value of unknown option \"$option\""
+}
+
+proc page_wrun {chan data} {
+ global timed usec
+ page_log_info "writer/ser/run/"
+
+ if {$timed} {
+ set usec [lindex [time {
+ ::struct::tree ::tree deserialize $data
+ page::gen::peg::ser ::tree $chan
+ }] 0] ; #{}
+ } else {
+ ::struct::tree ::tree deserialize $data
+ page::gen::peg::ser ::tree $chan
+ }
+ page_log_info "writer/ser/run/ok"
+
+ ::tree destroy
+ return
+}
+
+# ### ### ### ######### ######### #########
+## Internal helper code.
+
+# ### ### ### ######### ######### #########
+## Initialization
+
+package provide page::writer::ser 0.1
diff --git a/tcllib/modules/page/plugins/writer_tpc.tcl b/tcllib/modules/page/plugins/writer_tpc.tcl
new file mode 100644
index 0000000..6b14328
--- /dev/null
+++ b/tcllib/modules/page/plugins/writer_tpc.tcl
@@ -0,0 +1,105 @@
+# -*- tcl -*-
+# -- $Id: writer_tpc.tcl,v 1.1 2005/09/28 04:51:22 andreas_kupries Exp $ ---
+#
+# PAGE plugin - writer - TPC ~ Tcl Peg Container
+#
+
+# ### ### ### ######### ######### #########
+## Imported API
+
+# -----------------+--
+# page_wdata | Access to processed input stream.
+# -----------------+--
+# page_info | Reporting to the user.
+# page_warning |
+# page_error |
+# -----------------+--
+# page_log_error | Reporting of internals.
+# page_log_warning |
+# page_log_info |
+# -----------------+--
+
+# ### ### ### ######### ######### #########
+## Exported API
+
+# -----------------+--
+# page_wfeature | Query for special plugin features page might wish to use.
+# page_wtime | Activate collection of timing statistics.
+# page_wgettime | Return the collected timing statistics.
+# page_wlabel | User readable label for the plugin.
+# page_whelp | Doctools help text for plugin.
+# page_woptions | Options understood by plugin.
+# page_wconfigure | Option (re)configuration.
+# page_wrun | Generate output from data per plugin configuration and hardwiring.
+# -----------------+--
+
+# ### ### ### ######### ######### #########
+## Requisites
+
+package require page::gen::peg::cpkg
+package require struct::tree ; # Data structure.
+
+global usec
+global timed
+set timed 0
+
+# ### ### ### ######### ######### #########
+## Implementation of exported API
+
+proc page_wlabel {} {
+ return {Tcl PEG Container (Package)}
+}
+
+proc page_wfeature {key} {
+ return [string eq $key timeable]
+}
+
+proc page_wtime {} {
+ global timed
+ set timed 1
+ return
+}
+
+proc page_wgettime {} {
+ global usec
+ return $usec
+}
+proc page_whelp {} {
+ return {}
+}
+
+proc page_woptions {} {
+ return {}
+}
+
+proc page_wconfigure {option value} {
+ return -code error "Cannot set value of unknown option \"$option\""
+}
+
+proc page_wrun {chan data} {
+ global timed usec
+ page_log_info "writer/tpc/run/"
+
+ if {$timed} {
+ set usec [lindex [time {
+ ::struct::tree ::tree deserialize $data
+ page::gen::peg::cpkg ::tree $chan
+ }] 0] ; #{}
+ } else {
+ ::struct::tree ::tree deserialize $data
+ page::gen::peg::cpkg ::tree $chan
+ }
+
+ page_log_info "writer/tpc/run/ok"
+
+ ::tree destroy
+ return
+}
+
+# ### ### ### ######### ######### #########
+## Internal helper code.
+
+# ### ### ### ######### ######### #########
+## Initialization
+
+package provide page::writer::tpc 0.1
diff --git a/tcllib/modules/page/plugins/writer_tree.tcl b/tcllib/modules/page/plugins/writer_tree.tcl
new file mode 100644
index 0000000..d02458e
--- /dev/null
+++ b/tcllib/modules/page/plugins/writer_tree.tcl
@@ -0,0 +1,105 @@
+# -*- tcl -*-
+# -- $Id: writer_tree.tcl,v 1.1 2005/09/28 04:51:22 andreas_kupries Exp $ ---
+#
+# PAGE plugin - writer - TREE ~ Generic Tree dump
+#
+
+# ### ### ### ######### ######### #########
+## Imported API
+
+# -----------------+--
+# page_wdata | Access to processed input stream.
+# -----------------+--
+# page_info | Reporting to the user.
+# page_warning |
+# page_error |
+# -----------------+--
+# page_log_error | Reporting of internals.
+# page_log_warning |
+# page_log_info |
+# -----------------+--
+
+# ### ### ### ######### ######### #########
+## Exported API
+
+# -----------------+--
+# page_wfeature | Query for special plugin features page might wish to use.
+# page_wtime | Activate collection of timing statistics.
+# page_wgettime | Return the collected timing statistics.
+# page_wlabel | User readable label for the plugin.
+# page_whelp | Doctools help text for plugin.
+# page_woptions | Options understood by plugin.
+# page_wconfigure | Option (re)configuration.
+# page_wrun | Generate output from data per plugin configuration and hardwiring.
+# -----------------+--
+
+# ### ### ### ######### ######### #########
+## Requisites
+
+package require page::gen::tree::text
+package require struct::tree ; # Data structure.
+
+global usec
+global timed
+set timed 0
+
+# ### ### ### ######### ######### #########
+## Implementation of exported API
+
+proc page_wlabel {} {
+ return {Tree Dump}
+}
+
+proc page_wfeature {key} {
+ return [string eq $key timeable]
+}
+
+proc page_wtime {} {
+ global timed
+ set timed 1
+ return
+}
+
+proc page_wgettime {} {
+ global usec
+ return $usec
+}
+proc page_whelp {} {
+ return {}
+}
+
+proc page_woptions {} {
+ return {}
+}
+
+proc page_wconfigure {option value} {
+ return -code error "Cannot set value of unknown option \"$option\""
+}
+
+proc page_wrun {chan data} {
+ global timed usec
+ page_log_info "writer/tree/run/"
+
+ if {$timed} {
+ set usec [lindex [time {
+ ::struct::tree ::tree deserialize $data
+ page::gen::tree::text ::tree $chan
+ }] 0] ; #{}
+ } else {
+ ::struct::tree ::tree deserialize $data
+ page::gen::tree::text ::tree $chan
+ }
+
+ page_log_info "writer/tree/run/ok"
+
+ ::tree destroy
+ return
+}
+
+# ### ### ### ######### ######### #########
+## Internal helper code.
+
+# ### ### ### ######### ######### #########
+## Initialization
+
+package provide page::writer::tree 0.1
diff --git a/tcllib/modules/page/util_flow.tcl b/tcllib/modules/page/util_flow.tcl
new file mode 100644
index 0000000..d8245ff
--- /dev/null
+++ b/tcllib/modules/page/util_flow.tcl
@@ -0,0 +1,90 @@
+# -*- tcl -*-
+# General tree iterative walking for dataflow algorithms.
+
+# ### ### ### ######### ######### #########
+## Requisites
+
+package require snit
+
+# ### ### ### ######### ######### #########
+## API
+
+namespace eval ::page::util::flow {}
+
+proc ::page::util::flow {start fvar nvar script} {
+ set f [uplevel 1 [list ::page::util::flow::iter %AUTO% $start $fvar $nvar $script]]
+ $f destroy
+ return
+}
+
+# ### ### ### ######### ######### #########
+## Internals
+
+snit::type ::page::util::flow::iter {
+ constructor {startset fvar nvar script} {
+ $self visitl $startset
+
+ # Export the object for use by the flow script
+ upvar 3 $fvar flow ; set flow $self
+ upvar 3 $nvar current
+
+ while {[array size visit]} {
+ set nodes [array names visit]
+ array unset visit *
+
+ foreach n $nodes {
+ set current $n
+ set code [catch {uplevel 3 $script} result]
+
+ # decide what to do upon the return code:
+ #
+ # 0 - the body executed successfully
+ # 1 - the body raised an error
+ # 2 - the body invoked [return]
+ # 3 - the body invoked [break]
+ # 4 - the body invoked [continue]
+ # everything else - return and pass on the results
+
+ switch -exact -- $code {
+ 0 {}
+ 1 {
+ return -errorinfo $::errorInfo \
+ -errorcode $::errorCode -code error $result
+ }
+ 3 {
+ # FRINK: nocheck
+ return -code break
+ }
+ 4 {}
+ default {
+ # This includes code 2 (return).
+ return -code $code $result
+ }
+ }
+ }
+ }
+ return
+ }
+
+ method visit {n} {
+ set visit($n) .
+ return
+ }
+
+ method visitl {nodelist} {
+ foreach n $nodelist {set visit($n) .}
+ return
+ }
+
+ method visita {args} {
+ foreach n $args {set visit($n) .}
+ return
+ }
+
+ variable visit -array {}
+}
+
+# ### ### ### ######### ######### #########
+## Ready
+
+package provide page::util::flow 0.1
diff --git a/tcllib/modules/page/util_norm_lemon.tcl b/tcllib/modules/page/util_norm_lemon.tcl
new file mode 100644
index 0000000..f604f81
--- /dev/null
+++ b/tcllib/modules/page/util_norm_lemon.tcl
@@ -0,0 +1,427 @@
+# -*- tcl -*-
+#
+# Copyright (c) 2005 by Andreas Kupries <andreas_kupries@users.sourceforge.net>
+# Parser Generator / Transformation - Normalize PEG AST for later.
+
+# This package assumes to be used from within a PAGE plugin. It uses
+# the API commands listed below. These are identical across the major
+# types of PAGE plugins, allowing this package to be used in reader,
+# transform, and writer plugins. It cannot be used in a configuration
+# plugin, and this makes no sense either.
+#
+# To ensure that our assumption is ok we require the relevant pseudo
+# package setup by the PAGE plugin management code.
+#
+# -----------------+--
+# page_info | Reporting to the user.
+# page_warning |
+# page_error |
+# -----------------+--
+# page_log_error | Reporting of internals.
+# page_log_warning |
+# page_log_info |
+# -----------------+--
+
+# ### ### ### ######### ######### #########
+## Requisites
+
+# @mdgen NODEP: page::plugin
+
+package require page::plugin ; # S.a. pseudo-package.
+package require treeql
+package require page::util::quote
+package require page::util::peg
+
+namespace eval ::page::util::norm::lemon {
+ # Get the peg char de/encoder commands.
+ # (unquote, quote'tcl)
+
+ namespace import ::page::util::quote::*
+ namespace import ::page::util::peg::*
+}
+
+# ### ### ### ######### ######### #########
+## API
+
+proc ::page::util::norm::lemon {t} {
+ set q [treeql q -tree $t]
+
+ page_info {[Lemon Normalization]}
+
+ # Retrieve grammar name out of one directive.
+ # Or from LHS of first rule.
+
+ page_log_info ..Startsymbol
+
+ set start {}
+
+ $q query tree \
+ withatt type nonterminal \
+ withatt detail StartSymbol \
+ descendants \
+ withatt type terminal \
+ over n {
+
+ lemon::TokReduce $t $n detail
+ set start [$t get $n detail]
+
+ page_info " StartSymbol: $start"
+ }
+
+ $q query tree \
+ withatt type nonterminal \
+ withatt detail Name \
+ descendants \
+ withatt type terminal \
+ over n {
+
+ lemon::TokReduce $t $n detail
+ set name [$t get $n detail]
+
+ page_info " Name: $name"
+
+ $t set root name $name
+ }
+
+ page_log_info ..Drop ; lemon::Drop $q $t
+ page_log_info ..Terminals ; lemon::Terminals $q $t
+ page_log_info ..Definitions ; lemon::Definitions $q $t
+ page_log_info ..Rules ; lemon::Rules $q $t start
+ page_log_info ..Epsilon ; lemon::ElimEpsilon $q $t
+ page_log_info ..Autoclass ; lemon::AutoClassId $q $t
+ page_log_info ..Chains
+
+ # Find and cut operator chains, very restricted. Cut only chains
+ # of x- and /-operators. The other operators have only one child
+ # by definition and are thus not chains.
+
+ #set q [treeql q -tree $t]
+ # q query tree over n
+ foreach n [$t children -all root] {
+ if {[$t keyexists $n symbol]} continue
+ if {[llength [$t children $n]] != 1} continue
+
+ set op [$t get $n op]
+ if {($op ne "/") && ($op ne "x")} continue
+ $t cut $n
+ }
+
+ page_log_info ..Flatten
+
+ lemon::flatten $q $t
+
+ # Analysis: Left recursion, and where.
+ # Manual: Definitions for terminals.
+ # Definitions for space, comments.
+ # Integration of this into the grammar.
+
+ # Sentinel for PE algorithms.
+ $t set root symbol <StartExpression>
+
+ if {$start eq ""} {
+ page_error " Startsymbol missing"
+ } else {
+ set s [$t insert root end]
+ $t set $s op n
+ $t set $s sym $start
+ $t set root start $s
+
+ array set def [$t get root definitions]
+
+ if {![info exists def($start)]} {
+ page_error " Startsymbol is undefined"
+ $t set $s def ""
+ } else {
+ $t set $s def $def($start)
+ }
+ unset def
+ }
+
+ $q destroy
+
+ page_log_info Ok
+ return
+}
+
+# ### ### ### ######### ######### #########
+## Documentation
+#
+## See doc_normalize.txt for the specification of the publicly visible
+## attributes.
+##
+## Internal attributes
+## - DATA - Transient storage for terminal data.
+
+# ### ### ### ######### ######### #########
+## Internal. Helpers
+
+proc ::page::util::norm::lemon::Drop {q t} {
+ # Simple normalization.
+ # All lemon specific data is dropped completely.
+
+ foreach drop {
+ Directive Codeblock Label Precedence
+ } {
+ $q query tree withatt type nonterminal \
+ withatt detail $drop over n {
+ $t delete $n
+ }
+ }
+
+ # Some nodes can be dropped, but not their children.
+
+ $q query tree withatt type nonterminal \
+ withatt detail Statement over n {
+ $t cut $n
+ }
+
+ # Cut the ALL and LemonGrammar nodes, direct access, no search
+ # needed.
+
+ $t cut [lindex [$t children root] 0]
+ $t cut [lindex [$t children root] 0]
+
+ return
+}
+
+proc ::page::util::norm::lemon::Terminals {q t} {
+ # The data for all terminals is stored in their grandparental
+ # nodes. We get rid of both terminals and their parents.
+
+ $q query tree withatt type terminal over n {
+ set p [$t parent $n]
+ set gp [$t parent $p]
+
+ CopyLocation $t $n $gp
+ AttrCopy $t $n detail $gp DATA
+ TokReduce $t $gp DATA
+ $t delete $p
+ }
+
+ # We can now drop the type attribute, as all the remaining nodes
+ # (which have it) will contain the value 'nonterminal'.
+
+ $q query tree hasatt type over n {
+ $t unset $n type
+ }
+ return
+}
+
+proc ::page::util::norm::lemon::Definitions {q t} {
+ # Convert 'Definition' into the sequences they are.
+ # Sequences of length one will be flattened later.
+ # Empty sequences (Length zero) are epsilon.
+ # Epsilon will be later converted to ? of the
+ # whole choice they are part of.
+
+ $q query tree withatt detail Definition over n {
+ $t unset $n detail
+
+ if {[$t children $n] < 1} {
+ $t set $n op epsilon
+ } else {
+ $t set $n op x
+ }
+ }
+ return
+}
+
+proc ::page::util::norm::lemon::Rules {q t sv} {
+ upvar $sv start
+ # We move nonterminal hint information from nodes into attributes,
+ # and delete the now irrelevant nodes.
+
+ # Like with the global metadata we move definition specific
+ # information out of nodes into attributes, get rid of the
+ # superfluous nodes, and tag the definition roots with marker
+ # attributes.
+
+ array set defs {}
+ $q query tree withatt detail Rule over n {
+ set first [Child $t $n 0]
+
+ set sym [$t get $first DATA]
+ $t set $n symbol $sym
+ $t set $n label $sym
+ $t set $n users {}
+ $t set $n mode value
+
+ if {$start eq ""} {
+ page_info " StartSymbol: $sym"
+ set start $sym
+ }
+
+ # We get the left extend of the definition from the terminal
+ # for the symbol it defines.
+
+ MergeLocations $t $first [Rightmost $t $n] $n
+ $t unset $n detail
+
+ lappend defs($sym) $n
+ $t cut $first
+ }
+
+ set d {}
+ foreach sym [array names defs] {
+ set nodes $defs($sym)
+ if {[llength $nodes] == 1} {
+ lappend d $sym [lindex $nodes 0]
+ } else {
+ # Merge multi-node definition together, under a choice.
+
+ set r [$t insert root end]
+ set c [$t insert $r end]
+
+ $t set $r symbol $sym
+ $t set $r label $sym
+ $t set $r users {}
+ $t set $r mode value
+ $t set $c op /
+
+ foreach n $nodes {
+ set seq [lindex [$t children $n] 0]
+ $t move $c end $seq
+ $t delete $n
+ }
+
+ lappend d $sym $r
+ }
+ }
+
+ # We remember a mapping from nonterminal names to their defining
+ # nodes in the root as well, for quick reference later, when we
+ # build nonterminal usage references
+
+ $t set root definitions $d
+ return
+}
+
+proc ::page::util::norm::lemon::Rightmost {t n} {
+ # Determine the rightmost leaf under the specified node.
+
+ if {[$t isleaf $n]} {return $n}
+ return [Rightmost $t [lindex [$t children $n] end]]
+}
+
+proc ::page::util::norm::lemon::ElimEpsilon {q t} {
+ # We convert choices with an epsilon in them into
+ # optional choices without an epsilon branch.
+
+ $q query tree withatt op epsilon over n {
+ set choice [$t parent $n]
+
+ # Move branches into the epsilon, which becomes the new
+ # choice. And the choice becomes an option.
+ foreach c [$t children $choice] {
+ if {$c eq $n} continue
+ $t move $n end $c
+ }
+ $t set $n op /
+ $t set $choice op ?
+ }
+ return
+}
+
+proc ::page::util::norm::lemon::AutoClassId {q t} {
+
+ array set defs [$t get root definitions]
+ array set use {}
+
+ $q query tree \
+ withatt op x \
+ children \
+ hasatt DATA \
+ over n {
+ # All identifiers are nonterminals, and for the
+ # undefined ones we create rules which define
+ # them as terminal sequences.
+
+ set sym [$t get $n DATA]
+ $t unset $n DATA
+
+ $t set $n op n
+ $t set $n sym $sym
+
+ if {![info exists defs($sym)]} {
+ set defs($sym) [NewTerminal $t $sym]
+ }
+ $t set $n def $defs($sym)
+
+ lappend use($sym) $n
+ $t unset $n detail
+ }
+
+ $t set root definitions [array get defs]
+
+ foreach sym [array names use] {
+ $t set $defs($sym) users $use($sym)
+ }
+
+ $t set root undefined {}
+ return
+}
+
+proc ::page::util::norm::lemon::NewTerminal {t sym} {
+ page_log_info " Terminal: $sym"
+
+ set r [$t insert root end]
+ $t set $r symbol $sym
+ $t set $r label $sym
+ $t set $r users {}
+ $t set $r mode leaf
+
+ set s [$t insert $r end]
+ $t set $s op x
+
+ foreach ch [split $sym {}] {
+ set c [$t insert $s end]
+ $t set $c op t
+ $t set $c char $ch
+ }
+ return $r
+}
+
+# ### ### ### ######### ######### #########
+## Internal. Low-level helpers.
+
+proc ::page::util::norm::lemon::CopyLocation {t src dst} {
+ $t set $dst range [$t get $src range]
+ $t set $dst range_lc [$t get $src range_lc]
+ return
+}
+
+proc ::page::util::norm::lemon::MergeLocations {t srca srcb dst} {
+ set ar [$t get $srca range]
+ set arlc [$t get $srca range_lc]
+
+ set br [$t get $srcb range]
+ set brlc [$t get $srcb range_lc]
+
+ $t set $dst range [list [lindex $ar 0] [lindex $br 1]]
+ $t set $dst range_lc [list [lindex $arlc 0] [lindex $brlc 1]]
+ return
+}
+
+proc ::page::util::norm::lemon::AttrCopy {t src asrc dst adst} {
+ $t set $dst $adst [$t get $src $asrc]
+ return
+}
+
+proc ::page::util::norm::lemon::Child {t n index} {
+ return [lindex [$t children $n] $index]
+}
+
+proc ::page::util::norm::lemon::TokReduce {t src attr} {
+ set tokens [$t get $src $attr]
+ set ch {}
+ foreach tok $tokens {
+ lappend ch [lindex $tok 0]
+ }
+ $t set $src $attr [join $ch {}]
+ return
+}
+
+# ### ### ### ######### ######### #########
+## Ready
+
+package provide page::util::norm::lemon 0.1
diff --git a/tcllib/modules/page/util_norm_peg.tcl b/tcllib/modules/page/util_norm_peg.tcl
new file mode 100644
index 0000000..90405be
--- /dev/null
+++ b/tcllib/modules/page/util_norm_peg.tcl
@@ -0,0 +1,415 @@
+# -*- tcl -*-
+#
+# Copyright (c) 2005 by Andreas Kupries <andreas_kupries@users.sourceforge.net>
+# Parser Generator / Transformation - Normalize PEG AST for later.
+
+# This package assumes to be used from within a PAGE plugin. It uses
+# the API commands listed below. These are identical across the major
+# types of PAGE plugins, allowing this package to be used in reader,
+# transform, and writer plugins. It cannot be used in a configuration
+# plugin, and this makes no sense either.
+#
+# To ensure that our assumption is ok we require the relevant pseudo
+# package setup by the PAGE plugin management code.
+#
+# -----------------+--
+# page_info | Reporting to the user.
+# page_warning |
+# page_error |
+# -----------------+--
+# page_log_error | Reporting of internals.
+# page_log_warning |
+# page_log_info |
+# -----------------+--
+
+# ### ### ### ######### ######### #########
+## Requisites
+
+# @mdgen NODEP: page::plugin
+
+package require page::plugin ; # S.a. pseudo-package.
+package require treeql
+package require page::util::quote
+
+namespace eval ::page::util::norm::peg {
+ # Get the peg char de/encoder commands.
+ # (unquote, quote'tcl)
+
+ namespace import ::page::util::quote::*
+}
+
+# ### ### ### ######### ######### #########
+## API
+
+proc ::page::util::norm::peg {t} {
+ set q [treeql q -tree $t]
+
+ page_info {[PEG Normalization]}
+ page_log_info ..Terminals ; peg::Terminals $q $t
+ page_log_info ..Chains ; peg::CutChains $q $t
+ page_log_info ..Metadata ; peg::Metadata $q $t
+ page_log_info ..Definitions ; peg::Definitions $q $t
+ page_log_info ..Expressions ; peg::Expressions $q $t
+
+ # Sentinel for PE algorithms.
+ $t set root symbol <StartExpression>
+ $q destroy
+
+ page_log_info Ok
+ return
+}
+
+# ### ### ### ######### ######### #########
+## Documentation
+#
+## See doc_normalize.txt for the specification of the publicly visible
+## attributes.
+##
+## Internal attributes
+## - DATA - Transient storage for terminal data.
+
+# ### ### ### ######### ######### #########
+## Internal. Helpers
+
+proc ::page::util::norm::peg::Terminals {q t} {
+ # The data for all terminals is stored in their grandparental
+ # nodes. We get rid of both terminals and their parents.
+
+ $q query tree withatt type terminal over n {
+ set p [$t parent $n]
+ set gp [$t parent $p]
+
+ CopyLocation $t $n $gp
+ AttrCopy $t $n detail $gp DATA
+ TokReduce $t $gp DATA
+ $t delete $p
+ }
+
+ # We can now drop the type attribute, as all the remaining nodes
+ # (which have it) will contain the value 'nonterminal'.
+
+ $q query tree hasatt type over n {
+ $t unset $n type
+ }
+ return
+}
+
+proc ::page::util::norm::peg::CutChains {q t} {
+ # All nodes which have exactly one child are irrelevant. We get
+ # rid of them. The root node is the sole exception. The immediate
+ # child of the root however is superfluous as well.
+
+ $q query tree notq {root} over n {
+ if {[llength [$t children $n]] != 1} continue
+ $t cut $n
+ }
+
+ foreach n [$t children root] {$t cut $n}
+ return
+}
+
+proc ::page::util::norm::peg::Metadata {q t} {
+ # Having the name of the grammar in a tree node is overkill. We
+ # move this information into an attribute of the root node.
+ # The node keeping the start expression separate is irrelevant as
+ # well. We get rid of it, and tag the root of the start expression
+ # with a marker attribute.
+
+ $q query tree withatt detail Header over n {
+ set tmp [Child $t $n 0]
+ set sexpr [Child $t $n 1]
+
+ AttrCopy $t $tmp DATA root name
+ $t cut $tmp
+ $t cut $n
+ break
+ }
+
+ # Remember the node for the start expression in the root for quick
+ # access by later stages.
+
+ $t set root start $sexpr
+ return
+}
+
+proc ::page::util::norm::peg::Definitions {q t} {
+ # We move nonterminal hint information from nodes into attributes,
+ # and delete the now irrelevant nodes.
+
+ # NOTE: This transformation is dependent on the removal of all
+ # nodes with exactly one child, as it removes the all 'Attribute'
+ # nodes already. Otherwise this transformation would have to put
+ # the information into the grandparental node.
+
+ # The default mode for nonterminals is 'value'.
+
+ $q query tree withatt detail Definition over n {
+ $t set $n mode value
+ }
+
+ foreach {a mode} {
+ VOID discard
+ MATCH match
+ LEAF leaf
+ } {
+ $q query tree withatt detail $a over n {
+ set p [$t parent $n]
+ $t set $p mode $mode
+ $t delete $n
+ }
+ }
+
+ # Like with the global metadata we move definition specific
+ # information out of nodes into attributes, get rid of the
+ # superfluous nodes, and tag the definition roots with marker
+ # attributes.
+
+ set defs {}
+ $q query tree withatt detail Definition over n {
+ # Define mode information for all nonterminals without an
+ # explicit specification. We also save the mode information
+ # from deletion when we redo the definition node.
+
+ set first [Child $t $n 0]
+
+ set sym [$t get $first DATA]
+ $t set $n symbol $sym
+ $t set $n label $sym
+ $t set $n users {}
+
+ # Now determine the range in the input covered by the
+ # definition. The left extent comes from the terminal for the
+ # nonterminal symbol it defines. The right extent comes from
+ # the rightmost child under the definition. While this not an
+ # expression tree yet the location data is sound already.
+
+ MergeLocations $t $first [Rightmost $t $n] $n
+ $t unset $n detail
+
+ lappend defs $sym $n
+ $t cut $first
+ }
+
+ # We remember a mapping from nonterminal names to their defining
+ # nodes in the root as well, for quick reference later, when we
+ # build nonterminal usage references
+
+ $t set root definitions $defs
+ return
+}
+
+proc ::page::util::norm::peg::Rightmost {t n} {
+ # Determine the rightmost leaf under the specified node.
+
+ if {[$t isleaf $n]} {return $n}
+ return [Rightmost $t [lindex [$t children $n] end]]
+}
+
+proc ::page::util::norm::peg::Expressions {q t} {
+ # We now transform the remaining nodes into proper expression
+ # trees. The order matters, to shed as much nodes as possible
+ # early, and to avoid unncessary work.
+
+ ExprRanges $q $t
+ ExprUnaryOps $q $t
+ ExprChars $q $t
+ ExprNonterminals $q $t
+ ExprOperators $q $t
+ ExprFlatten $q $t
+ return
+}
+
+proc ::page::util::norm::peg::ExprRanges {q t} {
+ # Ranges = .. operator
+
+ $q query tree withatt detail Range over n {
+ # Two the children, both of text 'Char', their data is what we
+ # take. The children become irrelevant and are removed.
+
+ foreach {b e} [$t children $n] break
+ set begin [unquote [$t get $b DATA]]
+ set end [unquote [$t get $e DATA]]
+
+ $t set $n op ..
+ $t set $n begin $begin
+ $t set $n end $end
+
+ MergeLocations $t $b $e $n
+
+ $t unset $n detail
+
+ $t delete $b
+ $t delete $e
+ }
+ return
+}
+
+proc ::page::util::norm::peg::ExprUnaryOps {q t} {
+ # Unary operators ... Their transformation sheds more nodes.
+
+ foreach {a op} {
+ QUESTION ?
+ STAR *
+ PLUS +
+ AND &
+ NOT !
+ } {
+ $q query tree withatt detail $a over n {
+ set p [$t parent $n]
+
+ $t set $p op $op
+ $t cut $n
+
+ $t unset $p detail
+ }
+ }
+ return
+}
+
+proc ::page::util::norm::peg::ExprChars {q t} {
+ # Chars = t operator (The remaining Char'acters are plain terminal
+ # symbols.
+
+ $q query tree withatt detail Char over n {
+ set ch [unquote [$t get $n DATA]]
+
+ $t set $n op t
+ $t set $n char $ch
+
+ $t unset $n detail
+ $t unset $n DATA
+ }
+ return
+}
+
+proc ::page::util::norm::peg::ExprNonterminals {q t} {
+ # Identifiers = n operator (nonterminal references) ...
+
+ array set defs [$t get root definitions]
+ array set undefined {}
+
+ $q query tree withatt detail Identifier over n {
+ set sym [$t get $n DATA]
+
+ $t set $n op n
+ $t set $n sym $sym
+
+ $t unset $n detail
+ $t unset $n DATA
+
+ # Create x-references between the users and the definition of
+ # a nonterminal symbol.
+
+ if {![info exists defs($sym)]} {
+ $t set $n def {}
+ lappend undefined($sym) $n
+ continue
+ } else {
+ set def $defs($sym)
+ $t set $n def $def
+ }
+
+ set users [$t get $def users]
+ lappend users $n
+ $t set $def users $users
+ }
+
+ $t set root undefined [array get undefined]
+ return
+}
+
+proc ::page::util::norm::peg::ExprOperators {q t} {
+ # The remaining operator nodes can be changed directly from node
+ # text to operator. Se we do.
+
+ foreach {a op} {
+ EPSILON epsilon
+ ALNUM alnum
+ ALPHA alpha
+ DOT dot
+ Literal x
+ Class /
+ Sequence x
+ Expression /
+ } {
+ $q query tree withatt detail $a over n {
+ $t set $n op $op
+ $t unset $n detail
+ }
+ }
+ return
+}
+
+proc ::page::util::norm::peg::ExprFlatten {q t} {
+ # Last tweaks of the expressions. Classes inside of Expressions,
+ # and Literals in Sequences create nested / or x expressions. We
+ # locate such and flatten the nested expression, cutting out the
+ # superfluous operator.
+
+ foreach op {x /} {
+ # Locate all x operators, whose parents are x operators as
+ # well, then go back to the child operators and cut them out.
+
+ $q query tree withatt op $op \
+ parent unique withatt op $op \
+ children withatt op $op \
+ over n {
+ $t cut $n
+ }
+
+ # Locate all x operators without children and convert them
+ # into epsilon operators. Because that is what they accept,
+ # nothing.
+
+ $q query tree withatt op $op over n {
+ if {[$t numchildren $n]} continue
+ $t set $n op epsilon
+ }
+ }
+ return
+}
+
+# ### ### ### ######### ######### #########
+## Internal. Low-level helpers.
+
+proc ::page::util::norm::peg::CopyLocation {t src dst} {
+ $t set $dst range [$t get $src range]
+ $t set $dst range_lc [$t get $src range_lc]
+ return
+}
+
+proc ::page::util::norm::peg::MergeLocations {t srca srcb dst} {
+ set ar [$t get $srca range]
+ set arlc [$t get $srca range_lc]
+
+ set br [$t get $srcb range]
+ set brlc [$t get $srcb range_lc]
+
+ $t set $dst range [list [lindex $ar 0] [lindex $br 1]]
+ $t set $dst range_lc [list [lindex $arlc 0] [lindex $brlc 1]]
+ return
+}
+
+proc ::page::util::norm::peg::TokReduce {t src attr} {
+ set tokens [$t get $src $attr]
+ set ch {}
+ foreach tok $tokens {
+ lappend ch [lindex $tok 0]
+ }
+ $t set $src $attr [join $ch {}]
+ return
+}
+
+proc ::page::util::norm::peg::AttrCopy {t src asrc dst adst} {
+ $t set $dst $adst [$t get $src $asrc]
+ return
+}
+
+proc ::page::util::norm::peg::Child {t n index} {
+ return [lindex [$t children $n] $index]
+}
+
+# ### ### ### ######### ######### #########
+## Ready
+
+package provide page::util::norm::peg 0.1
diff --git a/tcllib/modules/page/util_peg.tcl b/tcllib/modules/page/util_peg.tcl
new file mode 100644
index 0000000..172c26e
--- /dev/null
+++ b/tcllib/modules/page/util_peg.tcl
@@ -0,0 +1,209 @@
+# -*- tcl -*-
+# ### ### ### ######### ######### #########
+
+## This package provides a number of utility commands to
+## transformations for common operations. It assumes a 'Normalized PE
+## Grammar Tree' as input, possibly augmented with attributes coming
+## from transformation not in conflict with the base definition.
+
+# ### ### ### ######### ######### #########
+## Requisites
+
+package require page::util::quote
+
+namespace eval ::page::util::peg {
+ namespace export \
+ symbolOf symbolNodeOf \
+ updateUndefinedDueRemoval \
+ flatten peOf printTclExpr \
+ getWarnings printWarnings
+
+ # Get the peg char de/encoder commands.
+ # (unquote, quote'tcl).
+
+ namespace import ::page::util::quote::*
+}
+
+# ### ### ### ######### ######### #########
+## API
+
+proc ::page::util::peg::symbolNodeOf {t n} {
+ # Given an arbitrary root it determines the node (itself or an
+ # ancestor) containing the name of the nonterminal symbol the node
+ # belongs to, and returns its id. The result is either the root of
+ # the tree (for the start expression), or a definition mode.
+
+ while {![$t keyexists $n symbol]} {
+ set n [$t parent $n]
+ }
+ return $n
+}
+
+proc ::page::util::peg::symbolOf {t n} {
+ # As above, but returns the symbol name.
+
+ return [$t get [symbolNodeOf $t $n] symbol]
+}
+
+proc ::page::util::peg::updateUndefinedDueRemoval {t} {
+ # The removal of nodes may have caused symbols to lose one or more
+ # users. Example: A used by B and C, B is reachable, C is not, so A
+ # now loses a node in the expression for C calling it, or rather
+ # not anymore.
+
+ foreach {sym def} [$t get root definitions] {
+ set res {}
+ foreach u [$t get $def users] {
+ if {![$t exists $u]} continue
+ lappend res $u
+ }
+ $t set $def users $res
+ }
+
+ # Update the knowledge of undefined nonterminals. To be used when
+ # a transformation can remove invokations of undefined symbols,
+ # and is not able to generate such invokations.
+
+ set res {}
+ foreach {sym invokers} [$t get root undefined] {
+ set sres {}
+ foreach n $invokers {
+ if {![$t exists $n]} continue
+ lappend sres $n
+ }
+ if {[llength $sres]} {
+ lappend res $sym $sres
+ }
+ }
+ $t set root undefined $res
+ return
+}
+
+proc ::page::util::peg::flatten {q t} {
+ # Flatten nested x-, or /-operators.
+ # See peg_normalize.tcl, peg::normalize::ExprFlatten
+
+ foreach op {x /} {
+ # Locate all x operators, whose parents are x oerators as
+ # well, then go back to the child operators and cut them out.
+
+ $q query \
+ tree withatt op $op \
+ parent unique withatt op $op \
+ children withatt op $op \
+ over n {
+ $t cut $n
+ }
+ }
+ return
+}
+
+proc ::page::util::peg::getWarnings {t} {
+ # Look at the attributes for problems with the grammar and issue
+ # warnings. They do not prevent us from writing the grammar, but
+ # still represent problems with it the user should be made aware
+ # of.
+
+ array set msg {}
+ array set undefined [$t get root undefined]
+ foreach sym [array names undefined] {
+ set msg($sym) {}
+ foreach ref $undefined($sym) {
+ lappend msg($sym) "Undefined symbol used by the definition of '[symbolOf $t $ref]'."
+ }
+ }
+
+ foreach {sym def} [$t get root definitions] {
+ if {[llength [$t get $def users]] == 0} {
+ set msg($sym) [list "This symbol has been defined, but is not used."]
+ }
+ }
+
+ return [array get msg]
+}
+
+proc ::page::util::peg::printWarnings {msg} {
+ if {![llength $msg]} return
+
+ set dict {}
+ set max -1
+ foreach {k v} $msg {
+ set l [string length [list $k]]
+ if {$l > $max} {set max $l}
+ lappend dict [list $k $v $l]
+ }
+
+ foreach e [lsort -dict -index 0 $dict] {
+ foreach {k msgs l} $e break
+
+ set off [string repeat " " [expr {$max - $l}]]
+ page_info "[list $k]$off : [lindex $msgs 0]"
+
+ if {[llength $msgs] > 1} {
+ set indent [string repeat " " [string length [list $k]]]
+ foreach m [lrange $msgs 1 end] {
+ puts stderr " $indent$off : $m"
+ }
+ }
+ }
+ return
+}
+
+proc ::page::util::peg::peOf {t eroot} {
+ set op [$t get $eroot op]
+ set pe [list $op]
+
+ set ch [$t children $eroot]
+
+ if {[llength $ch]} {
+ foreach c $ch {
+ lappend pe [peOf $t $c]
+ }
+ } elseif {$op eq "n"} {
+ lappend pe [$t get $eroot sym]
+ } elseif {$op eq "t"} {
+ lappend pe [unquote [$t get $eroot char]]
+ } elseif {$op eq ".."} {
+ lappend pe \
+ [unquote [$t get $eroot begin]] \
+ [unquote [$t get $eroot end]]
+
+ }
+ return $pe
+}
+
+proc ::page::util::peg::printTclExpr {pe} {
+ list [PrintExprSub $pe]
+}
+
+# ### ### ### ######### ######### #########
+## Internal
+
+proc ::page::util::peg::PrintExprSub {pe} {
+ set op [lindex $pe 0]
+ set args [lrange $pe 1 end]
+
+ #puts stderr "PE [llength $args] $op | $args"
+
+ if {$op eq "t"} {
+ set a [lindex $args 0]
+ return "$op [quote'tcl $a]"
+ } elseif {$op eq ".."} {
+ set a [lindex $args 0]
+ set b [lindex $args 1]
+ return "$op [quote'tcl $a] [quote'tcl $b]"
+ } elseif {$op eq "n"} {
+ return $pe
+ } else {
+ set res $op
+ foreach a $args {
+ lappend res [PrintExprSub $a]
+ }
+ return $res
+ }
+}
+
+# ### ### ### ######### ######### #########
+## Ready
+
+package provide page::util::peg 0.1
diff --git a/tcllib/modules/page/util_quote.tcl b/tcllib/modules/page/util_quote.tcl
new file mode 100644
index 0000000..6c7b65e
--- /dev/null
+++ b/tcllib/modules/page/util_quote.tcl
@@ -0,0 +1,173 @@
+# -*- tcl -*-
+#
+# Copyright (c) 2005 by Andreas Kupries <andreas_kupries@users.sourceforge.net>
+# Parser Generator / (Un)quoting characters.
+
+# ### ### ### ######### ######### #########
+## Requisites
+
+namespace eval ::page::util::quote {
+ namespace export unquote \
+ quote'tcl quote'tclstr quote'tclcom
+}
+
+# ### ### ### ######### ######### #########
+## API
+
+proc ::page::util::quote::unquote {ch} {
+ # A character, as stored in the grammar tree
+ # by the frontend is transformed into a proper
+ # Tcl character (internal representation).
+
+ switch -exact -- $ch {
+ "\\n" {return \n}
+ "\\t" {return \t}
+ "\\r" {return \r}
+ "\\[" {return \[}
+ "\\]" {return \]}
+ "\\'" {return '}
+ "\\\"" {return "\""}
+ "\\\\" {return \\}
+ }
+
+ if {[regexp {^\\([0-2][0-7][0-7])$} $ch -> ocode]} {
+ return [format %c $ocode]
+ } elseif {[regexp {^\\([0-7][0-7]?)$} $ch -> ocode]} {
+ return [format %c 0$ocode]
+ } elseif {[regexp {^\\u([0-9a-fA-F][0-9a-fA-F]?[0-9a-fA-F]?[0-9a-fA-F]?)$} $ch -> hcode]} {
+ return [format %c 0x$hcode]
+ }
+
+ return $ch
+}
+
+proc ::page::util::quote::quote'tcl {ch} {
+ # Converts a Tcl character (internal representation)
+ # into a string which is accepted by the Tcl parser,
+ # will regenerate the character in question and is
+ # 7bit ASCII. 'quoted' is a boolean flag and set if
+ # the returned representation is a \-quoted form.
+ # Because they have to be treated specially when
+ # creating a list containing the reperesentation.
+
+ # Special characters
+
+ switch -exact -- $ch {
+ "\n" {return "\\n"}
+ "\r" {return "\\r"}
+ "\t" {return "\\t"}
+ "\\" - "\;" -
+ " " - "\"" -
+ "(" - ")" -
+ "\{" - "\}" -
+ "\[" - "\]" {
+ # Quote space and all the brackets as well, using octal,
+ # for easy impure list-ness.
+
+ scan $ch %c chcode
+ return \\[format %o $chcode]
+ }
+ }
+
+ scan $ch %c chcode
+
+ # Control characters: Octal
+ if {[string is control -strict $ch]} {
+ return \\[format %o $chcode]
+ }
+
+ # Beyond 7-bit ASCII: Unicode
+
+ if {$chcode > 127} {
+ return \\u[format %04x $chcode]
+ }
+
+ # Regular character: Is its own representation.
+
+ return $ch
+}
+
+proc ::page::util::quote::quote'tclstr {ch} {
+ # Converts a Tcl character (internal representation)
+ # into a string which is accepted by the Tcl parser and will
+ # generate a human readable representation of the character in
+ # question, one which when puts to a channel describes the
+ # character without using any unprintable characters. It may use
+ # \-quoting. High utf characters are quoted to avoid problem with
+ # the still prevalent ascii terminals. It is assumed that the
+ # string will be used in a ""-quoted environment.
+
+ # Special characters
+
+ switch -exact -- $ch {
+ " " {return "<blank>"}
+ "\n" {return "\\\\n"}
+ "\r" {return "\\\\r"}
+ "\t" {return "\\\\t"}
+ "\"" - "\\" - "\;" -
+ "(" - ")" -
+ "\{" - "\}" -
+ "\[" - "\]" {
+ return \\$ch
+ }
+ }
+
+ scan $ch %c chcode
+
+ # Control characters: Octal
+ if {[string is control -strict $ch]} {
+ return \\\\[format %o $chcode]
+ }
+
+ # Beyond 7-bit ASCII: Unicode
+
+ if {$chcode > 127} {
+ return \\\\u[format %04x $chcode]
+ }
+
+ # Regular character: Is its own representation.
+
+ return $ch
+}
+
+proc ::page::util::quote::quote'tclcom {ch} {
+ # Converts a Tcl character (internal representation)
+ # into a string which is accepted by the Tcl parser when used
+ # within a Tcl comment.
+
+ # Special characters
+
+ switch -exact -- $ch {
+ " " {return "<blank>"}
+ "\n" {return "\\n"}
+ "\r" {return "\\r"}
+ "\t" {return "\\t"}
+ "\"" -
+ "\{" - "\}" -
+ "(" - ")" {
+ return \\$ch
+ }
+ }
+
+ scan $ch %c chcode
+
+ # Control characters: Octal
+ if {[string is control -strict $ch]} {
+ return \\[format %o $chcode]
+ }
+
+ # Beyond 7-bit ASCII: Unicode
+
+ if {$chcode > 127} {
+ return \\u[format %04x $chcode]
+ }
+
+ # Regular character: Is its own representation.
+
+ return $ch
+}
+
+# ### ### ### ######### ######### #########
+## Ready
+
+package provide page::util::quote 0.1