Move everything into ndcode/pilex/, import from ndcode.pilex, add packaging
authorNick Downing <nick.downing@lifx.co>
Sun, 26 Jan 2020 23:56:40 +0000 (10:56 +1100)
committerNick Downing <nick.downing@lifx.co>
Sun, 26 Jan 2020 23:56:40 +0000 (10:56 +1100)
43 files changed:
.gitignore
Makefile [deleted file]
README.md [new file with mode: 0644]
bootstrap/Makefile [deleted file]
bootstrap/element.py [deleted file]
bootstrap/markup.py [deleted file]
bootstrap/n.sh [deleted file]
bootstrap/parse.y [deleted file]
bootstrap/scan.l [deleted file]
bootstrap/skel_lex_yy.py [deleted file]
bootstrap/skel_y_tab.py [deleted file]
bootstrap/state.py [deleted file]
markup.py [deleted file]
n.sh [deleted file]
ndcode/__init__.py [new file with mode: 0644]
ndcode/pilex/Makefile [new file with mode: 0644]
ndcode/pilex/__init__.py [new file with mode: 0644]
ndcode/pilex/bisect_set.py [moved from bisect_set.py with 100% similarity]
ndcode/pilex/cli.py [new file with mode: 0755]
ndcode/pilex/dfa.py [moved from dfa.py with 99% similarity]
ndcode/pilex/flex_dfa.py [moved from flex_dfa.py with 100% similarity]
ndcode/pilex/generate_flex.py [moved from generate_flex.py with 99% similarity]
ndcode/pilex/generate_py.py [moved from generate_py.py with 99% similarity]
ndcode/pilex/nfa.py [moved from nfa.py with 99% similarity]
ndcode/pilex/numpy_heap.py [moved from numpy_heap.py with 100% similarity]
ndcode/pilex/parse.y [moved from parse.y with 99% similarity]
ndcode/pilex/pilex.t [moved from pilex.t with 99% similarity]
ndcode/pilex/regex.t [moved from regex.t with 99% similarity]
ndcode/pilex/scan.l [moved from scan.l with 99% similarity]
ndcode/pilex/skel/Makefile [moved from skel/Makefile with 55% similarity]
ndcode/pilex/skel/skel_flex.c [moved from skel/skel_flex.c with 100% similarity]
ndcode/pilex/skel/skel_flex.c.patch [moved from skel/skel_flex.c.patch with 100% similarity]
ndcode/pilex/skel/skel_flex.l [moved from skel/skel_flex.l with 100% similarity]
ndcode/pilex/skel/skel_py.py [moved from skel/skel_py.py with 100% similarity]
ndcode/pilex/skel/skel_py_element.py [moved from skel/skel_py_element.py with 100% similarity]
ndcode/pilex/state.py [moved from state.py with 100% similarity]
ndcode/pilex/wrap_repr.py [moved from wrap_repr.py with 100% similarity]
pilex.py [deleted file]
reserialize.py [deleted file]
setup.py [new file with mode: 0755]
skel_lex_yy.py
skel_t_def.py [new file with mode: 0644]
skel_y_tab.py [new file with mode: 0644]

index c05688f..15764dc 100644 (file)
@@ -1,20 +1,19 @@
 __pycache__
-/bootstrap/*.xml
-/bootstrap/lex_yy.py
-/bootstrap/out
-/bootstrap/y_tab.py
-/element.py
+/build
+/dist
 /lex-yacc-examples/*.c
 /lex-yacc-examples/*.h
 /lex-yacc-examples/*.o
 /lex-yacc-examples/*.xml
 /lex-yacc-examples/example4
 /lex-yacc-examples/example7
-/lex_yy.py
-/out
-/regex.py
-/skel/skel_flex.c.orig
-/t_def.py
+/ndcode/pilex/element.py
+/ndcode/pilex/lex_yy.py
+/ndcode/pilex/regex.py
+/ndcode/pilex/skel/skel_flex.c.orig
+/ndcode/pilex/t_def.py
+/ndcode/pilex/y_tab.py
+/pilex.egg-info
 /tests/*.c
 /tests/*.o
 /tests/cal
@@ -24,4 +23,3 @@ __pycache__
 /tests_ast/element.py
 /tests_ast/lex_yy.py
 /tests_ast/t_def.py
-/y_tab.py
diff --git a/Makefile b/Makefile
deleted file mode 100644 (file)
index 9c0a2fa..0000000
--- a/Makefile
+++ /dev/null
@@ -1,19 +0,0 @@
-all: element.py lex_yy.py regex.py t_def.py y_tab.py
-
-element.py: bootstrap_pitree/skel/element.py
-       cat $< >$@
-
-lex_yy.py: scan.l skel_lex_yy.py
-       bootstrap_pilex/pilex.py --element --python --skel skel_lex_yy.py $<
-
-regex.py: regex.t
-       bootstrap_pitree/pitree.py --python -o $@ $<
-
-t_def.py: pilex.t
-       bootstrap_pitree/pitree.py --python $<
-
-y_tab.py: parse.y
-       bootstrap_piyacc/piyacc.py --element --python $<
-
-clean:
-       rm -f element.py lex_yy.py regex.py t_def.py y_tab.py
diff --git a/README.md b/README.md
new file mode 100644 (file)
index 0000000..2915cd7
--- /dev/null
+++ b/README.md
@@ -0,0 +1,42 @@
+# πlex scanner generator
+
+The πlex program is in general a replacement for the `lex` utility from AT&T
+or Berkeley Unix, or the open-source Flex equivalent. πlex takes an input file
+with the extension .l and produces a lexical scanner in the form of C or Python
+source code.
+
+πlex takes the same input syntax as Flex. Many of the more obscure Flex
+features are not implemented, and are ignored and/or will cause a warning or
+error message. Enough of the standard functionality is implemented to be able
+to build a correctly working Bison and Flex, and we can likely add more Flex
+features if your project happens to depend on them.
+
+The scanners generated by πlex are DFA-based. When generating C source code, we
+use a Flex skeleton, and therefore, provided you use the supported feature set
+such that we can correctly populate the skeleton, the result should be a simple
+drop-in replacement for the Flex-generated scanner with few compatibility
+issues (we modified the skeleton slightly but this should not be user-visible).
+
+When generating Python source code, we use our own skeleton which has many more
+features than Flex's. The most important feature is that we can process
+annotations in the .l input file which instruct the scanner on how to generate
+an abstract syntax tree automatically during parsing. This is a huge time-saver
+since in the common case you do not need to write any action code to run when
+a rule is matched (we write the action code for you). You may write action code
+as well, since some scanners need to maintain state or change things during the
+execution of the scanner in order to correctly scan the input. For example, you
+may change the start condition during scanning, which we don't do automatically.
+
+The Python skeleton is designed to be highly compatible with the Flex
+skeleton, with fairly direct translations of each Flex construct that you
+could have invoked from your Flex .l source. In particular we don't force you
+to generate a re-entrant parser, even though Python does this very well. This
+is to make it easy to convert legacy .l specifications over to Python and
+πlex. We also provide a tool called c_to_python (created using πlex), which
+is capable of identifying the C code in your .l specification and translating
+it. The translation is pretty rough at present, but gives you a starting point.
+
+Further detailed documentation and tutorials will be added to the project in
+due course. For the present, the software is in active development, so it would
+be premature to document everything exactly as it is now. Please do contact the
+author Nick Downing <nick@ndcode.org>, should you have questions or feedback.
diff --git a/bootstrap/Makefile b/bootstrap/Makefile
deleted file mode 100644 (file)
index df720b4..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-all: lex_yy.py y_tab.py
-
-lex_yy.py: scan.l skel_lex_yy.py
-       ../../bootstrap_flex.git/src/flex -o /dev/null $< 2>$<.xml
-       ../pilex.py --python --skel skel_lex_yy.py $<.xml
-
-y_tab.py: parse.y skel_y_tab.py
-       ../../bootstrap_bison.git/src/bison -o /dev/null $< 2>$<.xml
-       ../../piyacc.git/piyacc.py --python --skel skel_y_tab.py $<.xml
-
-clean:
-       rm -f lex_yy.py y_tab.py *.xml
diff --git a/bootstrap/element.py b/bootstrap/element.py
deleted file mode 100644 (file)
index 2d02217..0000000
+++ /dev/null
@@ -1,179 +0,0 @@
-# Copyright (C) 2018 Nick Downing <nick@ndcode.org>
-# SPDX-License-Identifier: GPL-2.0-only
-#
-# This program is free software; you can redistribute it and/or modify it under
-# the terms of the GNU General Public License as published by the Free Software
-# Foundation; version 2.
-#
-# This program is distributed in the hope that it will be useful, but WITHOUT
-# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
-# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
-# details.
-#
-# You should have received a copy of the GNU General Public License along with
-# this program; if not, write to the Free Software Foundation, Inc., 51
-# Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
-
-import xml.etree.ElementTree
-
-class Element(xml.etree.ElementTree._Element_Py):
-  def __init__(self, tag = 'Element', attrib = {}, text = '', children = []):
-    xml.etree.ElementTree._Element_Py.__init__(self, tag, attrib)
-    self.ref = -1
-    self.seen = False
-    set_text(self, 0, text)
-    self[:] = children
-  def serialize(self, ref_list):
-    for i in self:
-      # parented, enforce that child can only be parented at most once
-      # (although there can be unlimited numbers of numeric refs to it)
-      assert not i.seen
-      i.seen = True
-      if i.ref == -1:
-        i.serialize(ref_list)
-  def deserialize(self, ref_list):
-    for i in self:
-      i.deserialize(ref_list)
-  def copy(self, factory = None):
-    result = (Element if factory is None else factory)(self.tag, self.attrib)
-    result.text = self.text
-    result.tail = self.tail
-    result[:] = [i.copy() for i in self]
-    return result
-  def repr_serialize(self, params):
-    if len(self):
-      params.append(
-        'children = [{0:s}]'.format(
-          ', '.join([repr(i) for i in self])
-        )
-      )
-  def __repr__(self):
-    params = []
-    self.repr_serialize(params)
-    return 'element.Element({0:s})'.format(', '.join(params))
-
-bool_to_str = ['false', 'true']
-def serialize_bool(value):
-  return bool_to_str[int(value)]
-
-str_to_bool = {'false': False, 'true': True}
-def deserialize_bool(text):
-  return str_to_bool[text]
-
-def serialize_int(value):
-  return str(value)
-
-def deserialize_int(text):
-  return int(text)
-
-def serialize_ref(value, ref_list):
-  if value is None:
-    ref = -1
-  else:
-    ref = value.ref
-    if ref == -1:
-      ref = len(ref_list)
-      ref_list.append(value)
-      value.ref = ref
-      value.set('ref', str(ref))
-      # this doesn't set the seen flag, so it will be parented by the
-      # root, unless it is already parented or gets parented later on
-      if not value.seen:
-        value.serialize(ref_list)
-  return str(ref)
-
-def deserialize_ref(text, ref_list):
-  ref = int(text)
-  return None if ref < 0 else ref_list[ref]
-
-def serialize_str(value):
-  return value
-
-def deserialize_str(text):
-  return text
-
-def serialize(value, fout, encoding = 'unicode'):
-  ref_list = []
-  serialize_ref(value, ref_list)
-  parents = [i for i in ref_list if not i.seen]
-  root = Element('root', children = parents)
-  for i in range(len(root)):
-    set_text(root, i, '\n  ')
-  set_text(root, len(root), '\n')
-  root.tail = '\n'
-  xml.etree.ElementTree.ElementTree(root).write(fout, encoding)
-  for i in root:
-    i.tail = None
-  for i in ref_list:
-    i.ref = -1
-    del i.attrib['ref']
-  i = 0
-  while i < len(parents):
-    for j in parents[i]:
-      j.seen = False
-      parents.append(j)
-    i += 1
-
-def deserialize(fin, factory = Element, encoding = 'unicode'):
-  root = xml.etree.ElementTree.parse(
-    fin,
-    xml.etree.ElementTree.XMLParser(
-      target = xml.etree.ElementTree.TreeBuilder(factory),
-      encoding = encoding
-    )
-  ).getroot()
-  assert root.tag == 'root'
-  for i in root:
-    i.tail = None
-  i = 0
-  parents = root[:]
-  ref_list = []
-  while i < len(parents):
-    j = parents[i]
-    if 'ref' in j.attrib:
-      ref = int(j.attrib['ref'])
-      del j.attrib['ref']
-      if len(ref_list) < ref + 1:
-        ref_list.extend([None] * (ref + 1 - len(ref_list)))
-      ref_list[ref] = j
-    parents.extend(j[:])
-    i += 1
-  for i in root:
-    i.deserialize(ref_list)
-  return ref_list[0]
-
-# compatibility scheme to access arbitrary xml.etree.ElementTree.Element-like
-# objects (not just Element defined above) using a more consistent interface:
-def get_text(root, i):
-  if i < 0:
-    i += len(root) + 1
-  text = root.text if i == 0 else root[i - 1].tail
-  return '' if text is None else text
-
-def set_text(root, i, text):
-  if i < 0:
-    i += len(root) + 1
-  if len(text) == 0:
-    text = None
-  if i == 0:
-    root.text = text
-  else:
-    root[i - 1].tail = text
-
-def to_text(root):
-  return ''.join(
-    [
-      j
-      for i in range(len(root))
-      for j in [get_text(root, i), to_text(root[i])]
-    ] +
-    [get_text(root, len(root))]
-  )
-
-def concatenate(children, factory = Element, *args, **kwargs):
-  root = factory(*args, **kwargs)
-  for child in children:
-    i = len(root)
-    set_text(root, i, get_text(root, i) + get_text(child, 0))
-    root[i:] = child[:]
-  return root
diff --git a/bootstrap/markup.py b/bootstrap/markup.py
deleted file mode 100755 (executable)
index d65f9d3..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-#!/usr/bin/env python3
-
-import lex_yy
-import y_tab
-import sys
-
-y_tab.yyparse()
-lex_yy.piece_insert(0, '<root>\n  <AST ref=\"0\">')
-lex_yy.piece_append('</AST>\n</root>\n')
-sys.stdout.write(''.join(lex_yy.piece))
diff --git a/bootstrap/n.sh b/bootstrap/n.sh
deleted file mode 100755 (executable)
index 4208f2f..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-#!/bin/sh
-if ! test -d out
-then
-  mkdir out
-  ../../bootstrap_flex.git/src/flex -o /dev/null ../tests/cal.l 2>out/cal.l.xml.ok
-  ../../bootstrap_flex.git/src/flex -o /dev/null ../tests_ast/cal_py.l 2>out/cal_py.l.xml.ok
-  ../../bootstrap_flex.git/src/flex -o /dev/null ../../bootstrap_flex.git/src/scan.l 2>out/scan.l.xml.ok
-  ../../bootstrap_flex.git/src/flex ../../bootstrap_bison.git/src/scan-code.l 2>out/scan-code.l.xml.ok
-  rm lex.yy.c
-  ../../bootstrap_flex.git/src/flex ../../bootstrap_bison.git/src/scan-gram.l 2>out/scan-gram.l.xml.ok
-  rm lex.yy.c
-  ../../bootstrap_flex.git/src/flex ../../bootstrap_bison.git/src/scan-skel.l 2>out/scan-skel.l.xml.ok
-  rm lex.yy.c
-fi
-./markup.py <../tests/cal.l >out/cal.l.xml
-diff -q out/cal.l.xml.ok out/cal.l.xml
-./markup.py <../tests_ast/cal_py.l >out/cal_py.l.xml
-diff -q out/cal_py.l.xml.ok out/cal_py.l.xml
-./markup.py <../../bootstrap_flex.git/src/scan.l >out/scan.l.xml
-diff -q out/scan.l.xml.ok out/scan.l.xml
-./markup.py <../../bootstrap_bison.git/src/scan-code.l >out/scan-code.l.xml
-diff -q out/scan-code.l.xml.ok out/scan-code.l.xml
-./markup.py <../../bootstrap_bison.git/src/scan-gram.l >out/scan-gram.l.xml
-diff -q out/scan-gram.l.xml.ok out/scan-gram.l.xml
-./markup.py <../../bootstrap_bison.git/src/scan-skel.l >out/scan-skel.l.xml
-diff -q out/scan-skel.l.xml.ok out/scan-skel.l.xml
diff --git a/bootstrap/parse.y b/bootstrap/parse.y
deleted file mode 100644 (file)
index 27f2008..0000000
+++ /dev/null
@@ -1,1173 +0,0 @@
-/* parse.y - parser for flex input */
-
-%token CHAR NUMBER SECTEND SCDECL XSCDECL NAME PREVCCL EOF_OP
-%token TOK_OPTION TOK_OUTFILE TOK_PREFIX TOK_YYCLASS TOK_HEADER_FILE TOK_EXTRA_TYPE
-%token TOK_TABLES_FILE
-
-%token CCE_ALNUM CCE_ALPHA CCE_BLANK CCE_CNTRL CCE_DIGIT CCE_GRAPH
-%token CCE_LOWER CCE_PRINT CCE_PUNCT CCE_SPACE CCE_UPPER CCE_XDIGIT
-
-%token CCE_NEG_ALNUM CCE_NEG_ALPHA CCE_NEG_BLANK CCE_NEG_CNTRL CCE_NEG_DIGIT CCE_NEG_GRAPH
-%token CCE_NEG_LOWER CCE_NEG_PRINT CCE_NEG_PUNCT CCE_NEG_SPACE CCE_NEG_UPPER CCE_NEG_XDIGIT
-
-%left CCL_OP_DIFF CCL_OP_UNION
-
-/* Nick extra rules for action groups */
-%token TOK_ACTION_GROUP TOK_ELEMENT_GROUP
-
-/* Nick temporary, until options processing moved fully into parser */
-%token TOK_OPTION_OTHER
-
-/*
- *POSIX and AT&T lex place the
- * precedence of the repeat operator, {}, below that of concatenation.
- * Thus, ab{3} is ababab.  Most other POSIX utilities use an Extended
- * Regular Expression (ERE) precedence that has the repeat operator
- * higher than concatenation.  This causes ab{3} to yield abbb.
- *
- * In order to support the POSIX and AT&T precedence and the flex
- * precedence we define two token sets for the begin and end tokens of
- * the repeat operator, '{' and '}'.  The lexical scanner chooses
- * which tokens to return based on whether posix_compat or lex_compat
- * are specified. Specifying either posix_compat or lex_compat will
- * cause flex to parse scanner files as per the AT&T and
- * POSIX-mandated behavior.
- */
-
-%token BEGIN_REPEAT_POSIX END_REPEAT_POSIX BEGIN_REPEAT_FLEX END_REPEAT_FLEX
-
-
-%{
-  import state
-
-  #pat = 0
-  #scnum = 0
-  #eps = 0
-  #headcnt = 0
-  #trailcnt = 0
-  #lastchar = 0
-  #i = 0
-  #rulelen = 0
-  trlcontxt = False
-  xcluflg = 0
-  #currccl = 0
-  #cclsorted = 0
-  #varlength = 0
-  #variable_trail_rule = 0
-  #scon_stk = []
-  #scon_stk_ptr = 0
-  #madeany = False
-  #ccldot = 0
-  #cclany = 0
-  #previous_continued_action = 0
-  piece2 = 0
-  piece3 = 0
-%}
-
-%%
-
-goal
-  : initlex sect1 sect1end sect2 sect2end initforrule
-    {
-      #def_rule = None
-      #pat = cclinit()
-      #cclnegate(pat)
-      #def_rule = mkstate(-pat)
-      #default_rule = num_rules
-      #finish_rule(def_rule, False, 0, 0, 0)
-      #i = 1
-      #while i <= lastsc:
-      #  scset[i] = mkbranch(scset[i], def_rule)
-      #  i += 1
-      #if spprdflt:
-      #  add_action('YY_FATAL_ERROR( "flex scanner jammed" )')
-      #else:
-      #  add_action('ECHO')
-      #add_action(';\n\tYY_BREAK]]\n')
-      insert_before(4, '</AST_Section2>')
-      insert_after(2, '<AST_Section2>')
-      insert_before(2, '</AST_Section1>')
-      insert_before(0, '<AST_Section1>')
-    }
-  ;
-
-initlex
-  :
-    {
-      #scinstal('INITIAL', False)
-    }
-  ;
-
-sect1
-  : sect1 startconddecl namelist1
-    {
-      insert_after(2, '</AST_Section1_StartConditions>')
-      insert_before(1, '<AST_Section1_StartConditions exclusive="{0:s}">'.format('true' if xcluflg else 'false'))
-    }
-  | sect1 options
-    {
-      insert_after(1, '</AST_Section1_Options>')
-      insert_before(1, '<AST_Section1_Options>')
-    }
-  |
-  | error
-    {
-      state.synerr('unknown error processing section 1')
-    }
-  ;
-
-sect1end
-  : SECTEND
-    {
-      #check_options()
-      #scon_stk = allocate_array(lastsc + 1, 4)
-      #scon_stk_ptr = 0
-    }
-  ;
-
-/* Nick */
-sect2end
-  : SECTEND
-    {
-      global yychar
-      if yychar == YYEMPTY:
-        yychar = lex_yy.flexscan()
-        #print('yyy yychar', yychar, 'yylval', yylval, 'yylloc', yylloc, 'lex_yy.yytext', lex_yy.yytext)
-      insert_before(1, '</AST_Section3>')
-      insert_after(0, '<AST_Section3>')
-    }
-  |
-  ;
-
-startconddecl
-  : SCDECL
-    {
-      global xcluflg
-      xcluflg = False
-    }
-  | XSCDECL
-    {
-      global xcluflg
-      xcluflg = True
-    }
-  ;
-
-namelist1
-  : namelist1 NAME
-    {
-      #scinstal(nmstr, xcluflg)
-    }
-  | NAME
-    {
-      #scinstal(nmstr, xcluflg)
-    }
-  | error
-    {
-      state.synerr('bad start condition list')
-    }
-  ;
-
-options
-  : TOK_OPTION optionlist
-  ;
-
-optionlist
-  : optionlist option
-  |
-  ;
-
-option
-  : TOK_OUTFILE '=' NAME
-    {
-      #outfilename = xstrdup(nmstr)
-      #did_outfilename = 1
-      insert_after(2, '</AST_Section1_Options_OutFile>')
-      insert_before(0, '<AST_Section1_Options_OutFile>')
-    }
-  | TOK_EXTRA_TYPE '=' NAME
-    {
-      #extra_type = xstrdup(nmstr)
-      insert_after(2, '</AST_Section1_Options_ExtraType>')
-      insert_before(0, '<AST_Section1_Options_ExtraType>')
-    }
-  | TOK_PREFIX '=' NAME
-    {
-      #prefix = xstrdup(nmstr)
-      #if strchr(prefix, ord('[')) or strchr(prefix, ord(']')):
-      #  flexerror('Prefix must not contain [ or ]')
-      insert_after(2, '</AST_Section1_Options_Prefix>')
-      insert_before(0, '<AST_Section1_Options_Prefix>')
-    }
-  | TOK_YYCLASS '=' NAME
-    {
-      #yyclass = xstrdup(nmstr)
-      insert_after(2, '</AST_Section1_Options_YYClass>')
-      insert_before(0, '<AST_Section1_Options_YYClass>')
-    }
-  | TOK_HEADER_FILE '=' NAME
-    {
-      #headerfilename = xstrdup(nmstr)
-      insert_after(2, '</AST_Section1_Options_HeaderFile>')
-      insert_before(0, '<AST_Section1_Options_HeaderFile>')
-    }
-  | TOK_TABLES_FILE '=' NAME
-    {
-      #tablesext = True
-      #tablesfilename = xstrdup(nmstr)
-      insert_after(2, '</AST_Section1_Options_TablesFile>')
-      insert_before(0, '<AST_Section1_Options_TablesFile>')
-    }
-  /* Nick */
-  | TOK_OPTION_OTHER
-  ;
-
-sect2
-  : sect2 scon initforrule flexrule '\n'
-    {
-      #scon_stk_ptr = $2
-      insert_after(4, '</AST_Section2_Rule>')
-      insert_before(1, '<AST_Section2_Rule>')
-    }
-  | sect2 scon '{' sect2 '}'
-    {
-      #scon_stk_ptr = $2
-      insert_after(4, '</AST_Section2_CompoundRule>')
-      insert_before(1, '<AST_Section2_CompoundRule>')
-    }
-  |
-  ;
-
-initforrule
-  :
-    {
-      global trlcontxt
-      trlcontxt = False #variable_trail_rule = varlength = False
-      #trailcnt = headcnt = rulelen = 0
-      #current_state_type = 0x1
-      #previous_continued_action = continued_action
-      state.in_rule = True
-      #new_rule()
-    }
-  ;
-
-flexrule
-  : '^' rule
-    {
-      #pat = $2
-      #finish_rule(pat, variable_trail_rule, headcnt, trailcnt, previous_continued_action)
-      #if scon_stk_ptr > 0:
-      #  i = 1
-      #  while i <= scon_stk_ptr:
-      #    scbol[scon_stk[i]] = mkbranch(scbol[scon_stk[i]], pat)
-      #    i += 1
-      #else:
-      #  i = 1
-      #  while i <= lastsc:
-      #    if not scxclu[i]:
-      #      scbol[i] = mkbranch(scbol[i], pat)
-      #    i += 1
-      #if not bol_needed:
-      #  bol_needed = True
-      #  if performance_report > 1:
-      #    pinpoint_message('\'^\' operator results in sub-optimal performance')
-      insert_after(1, '</AST_Section2_Rule_FLexRule>')
-      insert_before(0, '<AST_Section2_Rule_FLexRule bol="true">')
-    }
-  | rule
-    {
-      #pat = $1
-      #finish_rule(pat, variable_trail_rule, headcnt, trailcnt, previous_continued_action)
-      #if scon_stk_ptr > 0:
-      #  i = 1
-      #  while i <= scon_stk_ptr:
-      #    scset[scon_stk[i]] = mkbranch(scset[scon_stk[i]], pat)
-      #    i += 1
-      #else:
-      #  i = 1
-      #  while i <= lastsc:
-      #    if not scxclu[i]:
-      #      scset[i] = mkbranch(scset[i], pat)
-      #    i += 1
-      insert_after(0, '</AST_Section2_Rule_FLexRule>')
-      insert_before(0, '<AST_Section2_Rule_FLexRule bol="false">')
-    }
-  | EOF_OP
-    {
-      #if scon_stk_ptr > 0:
-      #  build_eof_action()
-      #else:
-      #  i = 1
-      #  while i <= lastsc:
-      #    if not sceof[i]:
-      #      scon_stk[++scon_stk_ptr] = i
-      #    i += 1
-      #  if scon_stk_ptr == 0:
-      #    lwarn('all start conditions already have <<EOF>> rules')
-      #  else:
-      #    build_eof_action()
-      insert_after(0, '</AST_Section2_Rule_EOFRule>')
-      insert_before(0, '<AST_Section2_Rule_EOFRule>')
-    }
-  | error
-    {
-      state.synerr('unrecognized rule')
-    }
-  ;
-
-scon_stk_ptr
-  :
-    {
-      #$$ = scon_stk_ptr
-    }
-  ;
-
-scon
-  : '<' scon_stk_ptr namelist2 '>'
-    {
-      #$$ = $2
-      insert_after(3, '</AST_Section2_StartConditions>')
-      insert_before(0, '<AST_Section2_StartConditions>')
-    }
-  | '<' '*' '>'
-    {
-      #$$ = scon_stk_ptr
-      #i = 1
-      #while i <= lastsc:
-      #  j = None
-      #  j = 1
-      #  while j <= scon_stk_ptr:
-      #    if scon_stk[j] == i:
-      #      break
-      #    j += 1
-      #  if j > scon_stk_ptr:
-      #    scon_stk[++scon_stk_ptr] = i
-      #  i += 1
-      insert_after(2, '</AST_Section2_StartConditions>')
-      insert_before(0, '<AST_Section2_StartConditions wildcard="true">')
-    }
-  |
-    {
-      global yychar
-      #$$ = scon_stk_ptr
-      if yychar == YYEMPTY:
-        yychar = lex_yy.flexscan()
-        #print('xxx yychar', yychar, 'yylval', yylval, 'yylloc', yylloc, 'lex_yy.yytext', lex_yy.yytext)
-      temp = lex_yy.piece[piece2 + 1]
-      lex_yy.piece[piece2 + 1] = lex_yy.piece[piece2]
-      lex_yy.piece[piece2] = lex_yy.piece[piece2 - 1]
-      lex_yy.piece[piece2 - 1] = temp
-      insert_before(0, '<AST_Section2_StartConditions />')
-    }
-  ;
-
-namelist2
-  : namelist2 ',' sconname
-  | sconname
-  | error
-    {
-      state.synerr('bad start condition list')
-    }
-  ;
-
-sconname
-  : NAME
-    {
-      #if (scnum = sclookup(nmstr)) == 0:
-      #  format_pinpoint_message('undeclared start condition %s', nmstr)
-      #else:
-      #  i = 1
-      #  while i <= scon_stk_ptr:
-      #    if scon_stk[i] == scnum:
-      #      format_warn('<%s> specified twice', scname[scnum])
-      #      break
-      #    i += 1
-      #  if i > scon_stk_ptr:
-      #    scon_stk[++scon_stk_ptr] = scnum
-    }
-  ;
-
-/* this rule handles trailing context, it must produce two separate regexes,
- * where the first is the expression to be matched, and the second is the
- * trailing context, RegexEmpty (matches empty string) if no trailing context
- */
-rule
-  : re2 re
-    {
-      #if transchar[lastst[$2]] != 256 + 1:
-      #  $2 = link_machines($2, mkstate(256 + 1))
-      #mark_beginning_as_normal($2)
-      #current_state_type = 0x1
-      #if previous_continued_action:
-      #  if not varlength or headcnt != 0:
-      #    lwarn('trailing context made variable due to preceding \'|\' action')
-      #  varlength = True
-      #  headcnt = 0
-      #if lex_compat or varlength and headcnt == 0:
-      #  add_accept($1, num_rules | 0x4000)
-      #  variable_trail_rule = True
-      #else:
-      #  trailcnt = rulelen
-      #$$ = link_machines($1, $2)
-    }
-  | re2 re '$'
-    {
-      state.synerr('trailing context used twice')
-    }
-  | re '$'
-    {
-      global trlcontxt
-      #headcnt = 0
-      #trailcnt = 1
-      #rulelen = 1
-      #varlength = False
-      #current_state_type = 0x2
-      #if trlcontxt:
-      #  state.synerr('trailing context used twice')
-      #  $$ = mkstate(256 + 1)
-      #else:
-      #  if previous_continued_action:
-      #    lwarn('trailing context made variable due to preceding \'|\' action')
-      #    varlength = True
-      #if lex_compat or varlength:
-      #  add_accept($1, num_rules | 0x4000)
-      #  variable_trail_rule = True
-      trlcontxt = True
-      #eps = mkstate(256 + 1)
-      #$$ = link_machines($1, link_machines(eps, mkstate(ord('\n'))))
-      insert_after(1, '</RegexCharacterLiteral>')
-      insert_before(1, '<RegexCharacterLiteral character_set="10 11">')
-    }
-  | re
-    {
-      #$$ = $1
-      #if trlcontxt:
-      #  if lex_compat or varlength and headcnt == 0:
-      #    variable_trail_rule = True
-      #  else:
-      #    trailcnt = rulelen
-      insert_after(0, '<RegexEmpty />')
-    }
-  ;
-
-re
-  : re '|' series
-    {
-      #varlength = True
-      #$$ = mkor($1, $3)
-      insert_after(2, '</RegexOr>')
-      insert_before(0, '<RegexOr>')
-    }
-  | series
-    {
-      #$$ = $1
-    }
-  ;
-
-re2
-  : re '/'
-    {
-      global trlcontxt
-      if trlcontxt:
-        state.synerr('trailing context used twice')
-      else:
-        trlcontxt = True
-      #if varlength:
-      #  varlength = False
-      #else:
-      #  headcnt = rulelen
-      #rulelen = 0
-      #current_state_type = 0x2
-      #$$ = $1
-    }
-  ;
-
-series
-  : series singleton
-    {
-      #$$ = link_machines($1, $2)
-      insert_after(1, '</RegexSequence>')
-      insert_before(0, '<RegexSequence>')
-    }
-  | singleton
-    {
-      #$$ = $1
-    }
-  | series BEGIN_REPEAT_POSIX NUMBER ',' NUMBER END_REPEAT_POSIX
-    {
-      #varlength = True
-      #if $3 > $5 or $3 < 0:
-      #  state.synerr('bad iteration values')
-      #  $$ = $1
-      #else:
-      #  if $3 == 0:
-      #    if $5 <= 0:
-      #      state.synerr('bad iteration values')
-      #      $$ = $1
-      #    else:
-      #      $$ = mkopt(mkrep($1, 1, $5))
-      #  else:
-      #    $$ = mkrep($1, $3, $5)
-      insert_after(5, '</RegexRepeat>')
-      insert_before(0, '<RegexRepeat count0="{0:d}" count1="{1:d}">'.format($3, $5))
-    }
-  | series BEGIN_REPEAT_POSIX NUMBER ',' END_REPEAT_POSIX
-    {
-      #varlength = True
-      #if $3 <= 0:
-      #  state.synerr('iteration value must be positive')
-      #  $$ = $1
-      #else:
-      #  $$ = mkrep($1, $3, -1)
-      insert_after(4, '</RegexRepeat>')
-      insert_before(0, '<RegexRepeat count0="{0:d}">'.format($3))
-    }
-  | series BEGIN_REPEAT_POSIX NUMBER END_REPEAT_POSIX
-    {
-      #varlength = True
-      #if $3 <= 0:
-      #  state.synerr('iteration value must be positive')
-      #  $$ = $1
-      #else:
-      #  $$ = link_machines($1, copysingl($1, $3 - 1))
-      insert_after(3, '</RegexRepeat>')
-      insert_before(0, '<RegexRepeat count0="{0:d}" count1="{1:d}">'.format($3, $3))
-    }
-  ;
-
-singleton
-  : singleton '*'
-    {
-      #varlength = True
-      #$$ = mkclos($1)
-      insert_after(1, '</RegexRepeat>')
-      insert_before(0, '<RegexRepeat count0="0">')
-    }
-  | singleton '+'
-    {
-      #varlength = True
-      #$$ = mkposcl($1)
-      insert_after(1, '</RegexRepeat>')
-      insert_before(0, '<RegexRepeat count0="1">')
-    }
-  | singleton '?'
-    {
-      #varlength = True
-      #$$ = mkopt($1)
-      insert_after(1, '</RegexRepeat>')
-      insert_before(0, '<RegexRepeat count0="0" count1="1">')
-    }
-  | singleton BEGIN_REPEAT_FLEX NUMBER ',' NUMBER END_REPEAT_FLEX
-    {
-      #varlength = True
-      #if $3 > $5 or $3 < 0:
-      #  state.synerr('bad iteration values')
-      #  $$ = $1
-      #else:
-      #  if $3 == 0:
-      #    if $5 <= 0:
-      #      state.synerr('bad iteration values')
-      #      $$ = $1
-      #    else:
-      #      $$ = mkopt(mkrep($1, 1, $5))
-      #  else:
-      #    $$ = mkrep($1, $3, $5)
-      insert_after(5, '</RegexRepeat>')
-      insert_before(0, '<RegexRepeat count0="{0:d}" count1="{1:d}">'.format($3, $5))
-    }
-  | singleton BEGIN_REPEAT_FLEX NUMBER ',' END_REPEAT_FLEX
-    {
-      #varlength = True
-      #if $3 <= 0:
-      #  state.synerr('iteration value must be positive')
-      #  $$ = $1
-      #else:
-      #  $$ = mkrep($1, $3, -1)
-      insert_after(4, '</RegexRepeat>')
-      insert_before(0, '<RegexRepeat count0="{0:d}">'.format($3))
-    }
-  | singleton BEGIN_REPEAT_FLEX NUMBER END_REPEAT_FLEX
-    {
-      #varlength = True
-      #if $3 <= 0:
-      #  state.synerr('iteration value must be positive')
-      #  $$ = $1
-      #else:
-      #  $$ = link_machines($1, copysingl($1, $3 - 1))
-      insert_after(3, '</RegexRepeat>')
-      insert_before(0, '<RegexRepeat count0="{0:d}" count1="{1:d}">'.format($3, $3))
-    }
-  | '.'
-    {
-      #if not madeany:
-      #  ccldot = cclinit()
-      #  ccladd(ccldot, ord('\n'))
-      #  cclnegate(ccldot)
-      #  if useecs:
-      #    mkeccl(ccltbl + cclmap[ccldot], ccllen[ccldot], nextecm, ecgroup, csize, csize)
-      #  cclany = cclinit()
-      #  cclnegate(cclany)
-      #  if useecs:
-      #    mkeccl(ccltbl + cclmap[cclany], ccllen[cclany], nextecm, ecgroup, csize, csize)
-      #  madeany = True
-      #rulelen += 1
-      if state._sf_stk[-1] & 2:
-        #$$ = mkstate(-cclany)
-        insert_after(0, '</RegexCharacterLiteral>')
-        insert_before(0, '<RegexCharacterLiteral character_set="0 256">')
-      else:
-        #$$ = mkstate(-ccldot)
-        insert_after(0, '</RegexCharacterLiteral>')
-        insert_before(0, '<RegexCharacterLiteral character_set="0 10 11 256">')
-    }
-  | fullccl
-    {
-      #qsort(ccltbl + cclmap[$1], int(ccllen[$1]), sizeof *ccltbl, cclcmp)
-      #if useecs:
-      #  mkeccl(ccltbl + cclmap[$1], ccllen[$1], nextecm, ecgroup, csize, csize)
-      #rulelen += 1
-      #if ccl_has_nl[$1]:
-      #  rule_has_nl[num_rules] = True
-      #$$ = mkstate(-$1)
-    }
-  | PREVCCL
-    {
-      #rulelen += 1
-      #if ccl_has_nl[$1]:
-      #  rule_has_nl[num_rules] = True
-      #$$ = mkstate(-$1)
-    }
-  | '"' string '"'
-    {
-      #$$ = $2
-    }
-  | '(' re ')'
-    {
-      #$$ = $2
-      insert_after(2, '</RegexGroup>')
-      insert_before(0, '<RegexGroup>')
-    }
-  /* Nick extra rules for unnumbered groups */
-  | '(' ':' re ')'
-    {
-      #$$ = $3
-    }
-  /* Nick extra rules for named groups */
-  | '(' NAME re ')'
-    {
-      #$$ = $3
-      insert_after(3, '</RegexGroupName>')
-      insert_before(0, '<RegexGroupName>')
-    }
-  /* Nick extra rules for action groups */
-  | '(' TOK_ACTION_GROUP re ')'
-    {
-      #$$ = $3
-      insert_after(3, '</RegexGroupAction>')
-      insert_before(0, '<RegexGroupAction>')
-    }
-  | '(' TOK_ELEMENT_GROUP re ')'
-    {
-      #$$ = $3
-      insert_after(3, '</RegexGroupElement>')
-      insert_before(0, '<RegexGroupElement>')
-    }
-  | CHAR
-    {
-      #rulelen += 1
-      #if $1 == nlch:
-      #  rule_has_nl[num_rules] = True
-      #if state._sf_stk[-1] & 1 and has_case($1):
-      #  $$ = mkor(mkstate($1), mkstate(reverse_case($1)))
-      #else:
-      #  $$ = mkstate($1)
-      insert_after(0, '</RegexCharacterLiteral>')
-      insert_before(0, '<RegexCharacterLiteral character_set="{0:d} {1:d}">'.format($1, $1 + 1))
-    }
-  ;
-
-fullccl
-  : fullccl CCL_OP_DIFF braceccl
-    {
-      #$$ = ccl_set_diff($1, $3)
-      insert_after(2, '</RegexCharacterAnd>')
-      insert_after(2, '</RegexCharacterNot>')
-      insert_before(2, '<RegexCharacterNot>')
-      insert_before(0, '<RegexCharacterAnd>')
-    }
-  | fullccl CCL_OP_UNION braceccl
-    {
-      #$$ = ccl_set_union($1, $3)
-      insert_after(2, '</RegexCharacterOr>')
-      insert_before(0, '<RegexCharacterOr>')
-    }
-  | braceccl
-  ;
-
-braceccl
-  : '[' ccl ']'
-    {
-      #$$ = $2
-    }
-  | '[' '^' ccl ']'
-    {
-      #cclnegate($3)
-      #$$ = $3
-      insert_after(2, '</RegexCharacterNot>')
-      insert_before(1, '<RegexCharacterNot>')
-    }
-  ;
-
-ccl
-  : ccl CHAR '-' CHAR
-    {
-      #if state._sf_stk[-1] & 1:
-      #  if has_case($2) != has_case($4) or has_case($2) and (True if (*__ctype_b_loc())[int($2)] & int(_ISlower) else False) != (True if (*__ctype_b_loc())[int($4)] & int(_ISlower) else False) or has_case($2) and (True if (*__ctype_b_loc())[int($2)] & int(_ISupper) else False) != (True if (*__ctype_b_loc())[int($4)] & int(_ISupper) else False):
-      #    fw3_msg = []
-      #    snprintf(fw3_msg, 2048, 'the character range [%c-%c] is ambiguous in a case-insensitive scanner', $2, $4)
-      #    lwarn(fw3_msg)
-      #  else:
-      #    if not has_case($2) and not has_case($4) and not range_covers_case($2, $4):
-      #      fw3_msg = []
-      #      snprintf(fw3_msg, 2048, 'the character range [%c-%c] is ambiguous in a case-insensitive scanner', $2, $4)
-      #      lwarn(fw3_msg)
-      #if $2 > $4:
-      #  state.synerr('negative range in character class')
-      #else:
-      #  i = $2
-      #  while i <= $4:
-      #    ccladd($1, i)
-      #    i += 1
-      #  cclsorted = cclsorted and $2 > lastchar
-      #  lastchar = $4
-      #  if state._sf_stk[-1] & 1 and has_case($2) and has_case($4):
-      #    $2 = reverse_case($2)
-      #    $4 = reverse_case($4)
-      #    i = $2
-      #    while i <= $4:
-      #      ccladd($1, i)
-      #      i += 1
-      #    cclsorted = cclsorted and $2 > lastchar
-      #    lastchar = $4
-      #$$ = $1
-      insert_after(3, '</RegexCharacterOr>')
-      insert_after(3, '</RegexCharacterLiteral>')
-      insert_before(1, '<RegexCharacterLiteral character_set="{0:d} {1:d}">'.format($2, $4 + 1))
-      insert_before(0, '<RegexCharacterOr>')
-    }
-  | ccl CHAR
-    {
-      #ccladd($1, $2)
-      #cclsorted = cclsorted and $2 > lastchar
-      #lastchar = $2
-      #if state._sf_stk[-1] & 1 and has_case($2):
-      #  $2 = reverse_case($2)
-      #  ccladd($1, $2)
-      #  cclsorted = cclsorted and $2 > lastchar
-      #  lastchar = $2
-      #$$ = $1
-      insert_after(1, '</RegexCharacterOr>')
-      insert_after(1, '</RegexCharacterLiteral>')
-      insert_before(1, '<RegexCharacterLiteral character_set="{0:d} {1:d}">'.format($2, $2 + 1))
-      insert_before(0, '<RegexCharacterOr>')
-    }
-  | ccl ccl_expr
-    {
-      #cclsorted = False
-      #$$ = $1
-      insert_after(1, '</RegexCharacterOr>')
-      insert_before(0, '<RegexCharacterOr>')
-    }
-  |
-    {
-      #cclsorted = True
-      #lastchar = 0
-      #currccl = $$ = cclinit()
-      insert_before(0, '<RegexCharacterLiteral character_set="" />')
-    }
-  ;
-
-ccl_expr
-  : CCE_ALNUM
-    {
-      #c = None
-      #c = 0
-      #while c < csize:
-      #  if (c & ~0x7f) == 0 and (*__ctype_b_loc())[int(c)] & int(_ISalnum):
-      #    ccladd(currccl, c)
-      #  c += 1
-      insert_after(0, '</RegexCharacterLiteral>')
-      insert_before(0, '<RegexCharacterLiteral character_set="48 58 65 91 97 123">')
-    }
-  | CCE_ALPHA
-    {
-      #c = None
-      #c = 0
-      #while c < csize:
-      #  if (c & ~0x7f) == 0 and (*__ctype_b_loc())[int(c)] & int(_ISalpha):
-      #    ccladd(currccl, c)
-      #  c += 1
-      insert_after(0, '</RegexCharacterLiteral>')
-      insert_before(0, '<RegexCharacterLiteral character_set="65 91 97 123">')
-    }
-  | CCE_BLANK
-    {
-      #c = None
-      #c = 0
-      #while c < csize:
-      #  if (c & ~0x7f) == 0 and (c == ord(' ') or c == ord('\t')):
-      #    ccladd(currccl, c)
-      #  c += 1
-      insert_after(0, '</RegexCharacterLiteral>')
-      insert_before(0, '<RegexCharacterLiteral character_set="9 10 32 33">')
-    }
-  | CCE_CNTRL
-    {
-      #c = None
-      #c = 0
-      #while c < csize:
-      #  if (c & ~0x7f) == 0 and (*__ctype_b_loc())[int(c)] & int(_IScntrl):
-      #    ccladd(currccl, c)
-      #  c += 1
-      insert_after(0, '</RegexCharacterLiteral>')
-      insert_before(0, '<RegexCharacterLiteral character_set="0 32">')
-    }
-  | CCE_DIGIT
-    {
-      #c = None
-      #c = 0
-      #while c < csize:
-      #  if (c & ~0x7f) == 0 and (*__ctype_b_loc())[int(c)] & int(_ISdigit):
-      #    ccladd(currccl, c)
-      #  c += 1
-      insert_after(0, '</RegexCharacterLiteral>')
-      insert_before(0, '<RegexCharacterLiteral character_set="48 58">')
-    }
-  | CCE_GRAPH
-    {
-      #c = None
-      #c = 0
-      #while c < csize:
-      #  if (c & ~0x7f) == 0 and (*__ctype_b_loc())[int(c)] & int(_ISgraph):
-      #    ccladd(currccl, c)
-      #  c += 1
-      insert_after(0, '</RegexCharacterLiteral>')
-      insert_before(0, '<RegexCharacterLiteral character_set="33 127">')
-    }
-  | CCE_LOWER
-    {
-      #c = None
-      #c = 0
-      #while c < csize:
-      #  if (c & ~0x7f) == 0 and (*__ctype_b_loc())[int(c)] & int(_ISlower):
-      #    ccladd(currccl, c)
-      #  c += 1
-      if state._sf_stk[-1] & 1:
-        #c = None
-        #c = 0
-        #while c < csize:
-        #  if (c & ~0x7f) == 0 and (*__ctype_b_loc())[int(c)] & int(_ISupper):
-        #    ccladd(currccl, c)
-        #  c += 1
-        insert_after(0, '</RegexCharacterLiteral>')
-        insert_before(0, '<RegexCharacterLiteral character_set="65 91 97 123">')
-      else:
-        insert_after(0, '</RegexCharacterLiteral>')
-        insert_before(0, '<RegexCharacterLiteral character_set="97 123">')
-    }
-  | CCE_PRINT
-    {
-      #c = None
-      #c = 0
-      #while c < csize:
-      #  if (c & ~0x7f) == 0 and (*__ctype_b_loc())[int(c)] & int(_ISprint):
-      #    ccladd(currccl, c)
-      #  c += 1
-      insert_after(0, '</RegexCharacterLiteral>')
-      insert_before(0, '<RegexCharacterLiteral character_set="32 127">')
-    }
-  | CCE_PUNCT
-    {
-      #c = None
-      #c = 0
-      #while c < csize:
-      #  if (c & ~0x7f) == 0 and (*__ctype_b_loc())[int(c)] & int(_ISpunct):
-      #    ccladd(currccl, c)
-      #  c += 1
-      insert_after(0, '</RegexCharacterLiteral>')
-      insert_before(0, '<RegexCharacterLiteral character_set="33 48 58 65 91 97 123 127">')
-    }
-  | CCE_SPACE
-    {
-      #c = None
-      #c = 0
-      #while c < csize:
-      #  if (c & ~0x7f) == 0 and (*__ctype_b_loc())[int(c)] & int(_ISspace):
-      #    ccladd(currccl, c)
-      #  c += 1
-      insert_after(0, '</RegexCharacterLiteral>')
-      insert_before(0, '<RegexCharacterLiteral character_set="9 14 32 33">')
-    }
-  | CCE_XDIGIT
-    {
-      #c = None
-      #c = 0
-      #while c < csize:
-      #  if (c & ~0x7f) == 0 and (*__ctype_b_loc())[int(c)] & int(_ISxdigit):
-      #    ccladd(currccl, c)
-      #  c += 1
-      insert_after(0, '</RegexCharacterLiteral>')
-      insert_before(0, '<RegexCharacterLiteral character_set="48 58 65 71 97 103">')
-    }
-  | CCE_UPPER
-    {
-      #c = None
-      #c = 0
-      #while c < csize:
-      #  if (c & ~0x7f) == 0 and (*__ctype_b_loc())[int(c)] & int(_ISupper):
-      #    ccladd(currccl, c)
-      #  c += 1
-      if state._sf_stk[-1] & 1:
-        #c = None
-        #c = 0
-        #while c < csize:
-        #  if (c & ~0x7f) == 0 and (*__ctype_b_loc())[int(c)] & int(_ISlower):
-        #    ccladd(currccl, c)
-        #  c += 1
-        insert_after(0, '</RegexCharacterLiteral>')
-        insert_before(0, '<RegexCharacterLiteral character_set="65 91 97 123">')
-      else:
-        insert_after(0, '</RegexCharacterLiteral>')
-        insert_before(0, '<RegexCharacterLiteral character_set="65 91">')
-    }
-  | CCE_NEG_ALNUM
-    {
-      #c = None
-      #c = 0
-      #while c < csize:
-      #  if not ((*__ctype_b_loc())[int(c)] & int(_ISalnum)):
-      #    ccladd(currccl, c)
-      #  c += 1
-      insert_after(0, '</RegexCharacterLiteral>')
-      insert_before(0, '<RegexCharacterLiteral character_set="0 48 58 65 91 97 123 256">')
-    }
-  | CCE_NEG_ALPHA
-    {
-      #c = None
-      #c = 0
-      #while c < csize:
-      #  if not ((*__ctype_b_loc())[int(c)] & int(_ISalpha)):
-      #    ccladd(currccl, c)
-      #  c += 1
-      insert_after(0, '</RegexCharacterLiteral>')
-      insert_before(0, '<RegexCharacterLiteral character_set="0 65 91 97 123 256">')
-    }
-  | CCE_NEG_BLANK
-    {
-      #c = None
-      #c = 0
-      #while c < csize:
-      #  if not (c == ord(' ') or c == ord('\t')):
-      #    ccladd(currccl, c)
-      #  c += 1
-      insert_after(0, '</RegexCharacterLiteral>')
-      insert_before(0, '<RegexCharacterLiteral character_set="0 9 10 32 33 256">')
-    }
-  | CCE_NEG_CNTRL
-    {
-      #c = None
-      #c = 0
-      #while c < csize:
-      #  if not ((*__ctype_b_loc())[int(c)] & int(_IScntrl)):
-      #    ccladd(currccl, c)
-      #  c += 1
-      insert_after(0, '</RegexCharacterLiteral>')
-      insert_before(0, '<RegexCharacterLiteral character_set="32 256">')
-    }
-  | CCE_NEG_DIGIT
-    {
-      #c = None
-      #c = 0
-      #while c < csize:
-      #  if not ((*__ctype_b_loc())[int(c)] & int(_ISdigit)):
-      #    ccladd(currccl, c)
-      #  c += 1
-      insert_after(0, '</RegexCharacterLiteral>')
-      insert_before(0, '<RegexCharacterLiteral character_set="0 48 58 256">')
-    }
-  | CCE_NEG_GRAPH
-    {
-      #c = None
-      #c = 0
-      #while c < csize:
-      #  if not ((*__ctype_b_loc())[int(c)] & int(_ISgraph)):
-      #    ccladd(currccl, c)
-      #  c += 1
-      insert_after(0, '</RegexCharacterLiteral>')
-      insert_before(0, '<RegexCharacterLiteral character_set="0 33 127 256">')
-    }
-  | CCE_NEG_PRINT
-    {
-      #c = None
-      #c = 0
-      #while c < csize:
-      #  if not ((*__ctype_b_loc())[int(c)] & int(_ISprint)):
-      #    ccladd(currccl, c)
-      #  c += 1
-      insert_after(0, '</RegexCharacterLiteral>')
-      insert_before(0, '<RegexCharacterLiteral character_set="0 32 127 256">')
-    }
-  | CCE_NEG_PUNCT
-    {
-      #c = None
-      #c = 0
-      #while c < csize:
-      #  if not ((*__ctype_b_loc())[int(c)] & int(_ISpunct)):
-      #    ccladd(currccl, c)
-      #  c += 1
-      insert_after(0, '</RegexCharacterLiteral>')
-      insert_before(0, '<RegexCharacterLiteral character_set="0 33 48 58 65 91 97 123 127 256">')
-    }
-  | CCE_NEG_SPACE
-    {
-      #c = None
-      #c = 0
-      #while c < csize:
-      #  if not ((*__ctype_b_loc())[int(c)] & int(_ISspace)):
-      #    ccladd(currccl, c)
-      #  c += 1
-      insert_after(0, '</RegexCharacterLiteral>')
-      insert_before(0, '<RegexCharacterLiteral character_set="0 9 14 32 33 256">')
-    }
-  | CCE_NEG_XDIGIT
-    {
-      #c = None
-      #c = 0
-      #while c < csize:
-      #  if not ((*__ctype_b_loc())[int(c)] & int(_ISxdigit)):
-      #    ccladd(currccl, c)
-      #  c += 1
-      insert_after(0, '</RegexCharacterLiteral>')
-      insert_before(0, '<RegexCharacterLiteral character_set="0 48 58 65 71 97 103 256">')
-    }
-  | CCE_NEG_LOWER
-    {
-      #if state._sf_stk[-1] & 1:
-      #  lwarn('[:^lower:] is ambiguous in case insensitive scanner')
-      #else:
-      #  c = None
-      #  c = 0
-      #  while c < csize:
-      #    if not ((*__ctype_b_loc())[int(c)] & int(_ISlower)):
-      #      ccladd(currccl, c)
-      #    c += 1
-      insert_after(0, '</RegexCharacterLiteral>')
-      insert_before(0, '<RegexCharacterLiteral character_set="0 97 123 256">')
-    }
-  | CCE_NEG_UPPER
-    {
-      #if state._sf_stk[-1] & 1:
-      #  lwarn('[:^upper:] ambiguous in case insensitive scanner')
-      #else:
-      #  c = None
-      #  c = 0
-      #  while c < csize:
-      #    if not ((*__ctype_b_loc())[int(c)] & int(_ISupper)):
-      #      ccladd(currccl, c)
-      #    c += 1
-      insert_after(0, '</RegexCharacterLiteral>')
-      insert_before(0, '<RegexCharacterLiteral character_set="0 65 91 256">')
-    }
-  ;
-
-string
-  : string CHAR
-    {
-      #if $2 == nlch:
-      #  rule_has_nl[num_rules] = True
-      #rulelen += 1
-      #if state._sf_stk[-1] & 1 and has_case($2):
-      #  $$ = mkor(mkstate($2), mkstate(reverse_case($2)))
-      #else:
-      #  $$ = mkstate($2)
-      #$$ = link_machines($1, $$)
-      insert_after(1, '</RegexSequence>')
-      insert_after(1, '</RegexCharacterLiteral>')
-      insert_before(1, '<RegexCharacterLiteral character_set="{0:d} {1:d}">'.format($2, $2 + 1))
-      insert_before(0, '<RegexSequence>')
-    }
-  |
-    {
-      #$$ = mkstate(256 + 1)
-      insert_before(0, '<RegexEmpty />')
-    }
-  ;
-
-%%
-
-#def build_eof_action():
-#  i = None
-#  action_text = []
-#  i = 1
-#  while i <= scon_stk_ptr:
-#    if sceof[scon_stk[i]]:
-#      format_pinpoint_message('multiple <<EOF>> rules for start condition %s', scname[scon_stk[i]])
-#    else:
-#      sceof[scon_stk[i]] = True
-#      if previous_continued_action:
-#        add_action('YY_RULE_SETUP\n')
-#      snprintf(action_text, sizeof action_text, 'case YY_STATE_EOF(%s):\n', scname[scon_stk[i]])
-#      add_action(action_text)
-#    i += 1
-#  line_directive_out(None, 1)
-#  add_action('[[')
-#  num_rules -= 1
-#  num_eof_rules += 1
-#
-#def format_state.synerr(msg, arg):
-#  errmsg = []
-#  NoneType(snprintf(errmsg, sizeof errmsg, msg, arg))
-#  state.synerr(errmsg)
-#
-#def synerr(str):
-#  syntaxerror = True
-#  pinpoint_message(str)
-#
-#def format_warn(msg, arg):
-#  warn_msg = []
-#  snprintf(warn_msg, sizeof warn_msg, msg, arg)
-#  lwarn(warn_msg)
-#
-#def lwarn(str):
-#  line_warning(str, linenum)
-#
-#def format_pinpoint_message(msg, arg):
-#  errmsg = []
-#  snprintf(errmsg, sizeof errmsg, msg, arg)
-#  pinpoint_message(errmsg)
-#
-#def pinpoint_message(str):
-#  line_pinpoint(str, linenum)
-#
-#def line_warning(str, line):
-#  warning = []
-#  if not nowarn:
-#    snprintf(warning, sizeof warning, 'warning, %s', str)
-#    line_pinpoint(warning, line)
-#
-#def line_pinpoint(str, line):
-#  fprintf(stderr, '%s:%d: %s\n', infilename, line, str)
-
-def yyerror(msg):
-  pass
-
-def insert_before(n, str):
-  global piece3
-  lex_yy.piece_insert(piece2 + n * 2, str)
-  lex_yy.piece0 += 1
-  piece3 += 1
-
-def insert_after(n, str):
-  global piece3
-  lex_yy.piece_insert(piece2 + n * 2 + 1, str)
-  lex_yy.piece0 += 1
-  piece3 += 1
diff --git a/bootstrap/scan.l b/bootstrap/scan.l
deleted file mode 100644 (file)
index bc407f2..0000000
+++ /dev/null
@@ -1,2072 +0,0 @@
-/* scan.l - scanner for flex input -*-C-*- */
-
-%{
-  import state
-  import y_tab
-
-  piece = []
-  piece0 = 0
-  markup_stack = []
-
-  # these should be yylex()-local, but moved to here, see further down:
-  bracelevel = 0
-  didadef = False
-  indented_code = False
-  doing_rule_action = False
-  #option_sense = False
-
-  doing_codeblock = False
-  brace_depth = 0
-  brace_start_line = 0
-%}
-
-%option caseless nodefault noreject stack noyy_top_state
-%option nostdinit
-
-%x SECT2 SECT2PROLOG SECT3 CODEBLOCK PICKUPDEF SC CARETISBOL NUM QUOTE
-%x FIRSTCCL CCL ACTION RECOVER COMMENT ACTION_STRING PERCENT_BRACE_ACTION
-%x OPTION LINEDIR CODEBLOCK_MATCH_BRACE
-%x GROUP_WITH_PARAMS
-%x GROUP_MINUS_PARAMS
-%x EXTENDED_COMMENT
-%x COMMENT_DISCARD CODE_COMMENT
-%x SECT3_NOESCAPE
-%x CHARACTER_CONSTANT
-/* Nick extra rules for action groups */
-%x ACTION_GROUP ELEMENT_GROUP DOUBLE_QUOTED SINGLE_QUOTED
-
-WS             [[:blank:]]+
-OPTWS          [[:blank:]]*
-NOT_WS         [^[:blank:]\r\n]
-
-NL             \r?\n
-
-NAME           ([[:alpha:]_][[:alnum:]_-]*)
-NOT_NAME       [^[:alpha:]_*\n]+
-
-SCNAME         {NAME}
-
-ESCSEQ         (\\([^\n]|[0-7]{1,3}|x[[:xdigit:]]{1,2}))
-
-FIRST_CCL_CHAR ([^\\\n]|{ESCSEQ})
-CCL_CHAR       ([^\\\n\]]|{ESCSEQ})
-CCL_EXPR       ("[:"^?[[:alpha:]]+":]")
-
-LEXOPT         [aceknopr]
-
-M4QSTART    "[""["
-M4QEND      "]""]"
-
-%%
-
-  # these should be here, but we can't access yylex()-local variables
-  # from an action since the action functions are not nested to yylex():
-  #bracelevel = 0
-  #didadef = False
-  #indented_code = False
-  #doing_rule_action = False
-  #option_sense = False
-
-  #doing_codeblock = False
-  #brace_depth = 0
-  #brace_start_line = 0
-
-<INITIAL>{
-  ^{WS} {
-    global indented_code
-    if not indented_code:
-      state.linenum += 1
-      #line_directive_out(None, 1)
-    #add_action('[' '[')
-    yy_push_state(CODEBLOCK)
-    indented_code = True
-    #add_action(yytext)
-    markup_stack.append(len(piece)) # <AST_Section1Or2_CodeBlock>
-    markup_stack.append(len(piece)) # <AST_Text>
-  }
-  ^"/*" {
-    #add_action('/*[' '[')
-    yy_push_state(COMMENT)
-  }
-  ^#{OPTWS}line{WS} yy_push_state(LINEDIR)
-  ^"%s"{NAME}? return y_tab.SCDECL
-  ^"%x"{NAME}? return y_tab.XSCDECL
-  ^"%{".*{NL} {
-    global indented_code
-    if not indented_code:
-      state.linenum += 1
-      #line_directive_out(None, 1)
-    #add_action('[' '[')
-    yy_push_state(CODEBLOCK)
-    indented_code = False
-    markup_stack.append(len(piece)) # <AST_Section1Or2_CodeBlock>
-    piece_flush(len(yytext))
-    markup_stack.append(len(piece)) # <AST_Text>
-  }
-  ^"%top"[[:blank:]]*"{"[[:blank:]]*{NL} {
-    global brace_start_line, brace_depth
-    brace_start_line = state.linenum
-    state.linenum += 1
-    #buf_linedir(&top_buf, infilename if infilename else '<stdin>', state.linenum)
-    brace_depth = 1
-    yy_push_state(CODEBLOCK_MATCH_BRACE)
-  }
-
-  ^"%top".*                    state.synerr('malformed \'%top\' directive')
-
-  {WS}
-
-  ^"%%".* {
-    global bracelevel
-    sectnum = 2
-    bracelevel = 0
-    #mark_defs1()
-    #line_directive_out(None, 1)
-    BEGIN(SECT2PROLOG)
-    return y_tab.SECTEND
-  }
-
-  ^"%pointer".*{NL} {
-    #yytext_is_array = False
-    state.linenum += 1
-    piece_append('<AST_Section1_Options><AST_Section1_Options_Array>')
-    piece_flush(len(yytext) - 1)
-    piece_append('</AST_Section1_Options_Array></AST_Section1_Options>')
-  }
-  ^"%array".*{NL} {
-    #yytext_is_array = True
-    state.linenum += 1
-    piece_append('<AST_Section1_Options><AST_Section1_Options_Array value="true">')
-    piece_flush(len(yytext) - 1)
-    piece_append('</AST_Section1_Options_Array></AST_Section1_Options>')
-  }
-
-  ^"%option" {
-    BEGIN(OPTION)
-    return y_tab.TOK_OPTION
-  }
-
-  ^"%"{LEXOPT}{OPTWS}[[:digit:]]*{OPTWS}{NL} state.linenum += 1
-  ^"%"{LEXOPT}{WS}.*{NL}       state.linenum += 1
-
-       /* xgettext: no-c-format */
-  ^"%"[^sxaceknopr{}].*                state.synerr('unrecognized \'%\' directive')
-
-  ^{NAME} {
-    global didadef
-    state.nmstr = yytext
-    didadef = False
-    BEGIN(PICKUPDEF)
-  }
-
-  {SCNAME} {
-    state.nmstr = yytext
-    piece_pack()
-    piece_append('<AST_Name>')
-    piece_escape(yytext)
-    piece_append('</AST_Name>')
-    piece_pack()
-    return ~y_tab.NAME
-  }
-  ^{OPTWS}{NL}                 state.linenum += 1
-  {OPTWS}{NL} {
-    #add_action(yytext)
-    state.linenum += 1
-  }
-}
-
-
-<COMMENT,CODE_COMMENT>{ /* */
-  [^\[\]\*\n]*                 #add_action(yytext)
-  .                            #add_action(yytext)
-
-  {NL} {
-    state.linenum += 1
-    #add_action(yytext)
-  }
-}
-<COMMENT>{
-  "*/" {
-    #add_action('*/]' ']')
-    yy_pop_state()
-  }
-}
-<CODE_COMMENT>{
-  "*/" {
-    #add_action(yytext)
-    yy_pop_state()
-  }
-}
-
-<COMMENT_DISCARD>{
-        /* This is the same as COMMENT, but is discarded rather than output. */
-  "*/"                         yy_pop_state()
-  "*"
-  [^*\n]
-  {NL}                         state.linenum += 1
-}
-
-<EXTENDED_COMMENT>{
-  ")"                          yy_pop_state()
-  [^\n\)]+
-  {NL}                         state.linenum += 1
-}
-
-<LINEDIR>{
-  \n                           yy_pop_state()
-  [[:digit:]]+ {
-    state.linenum = int(yytext)
-  }
-
-  \"[^"\n]*\" {
-    state.infilename = yytext[1:-1]
-  }
-  .
-}
-<ACTION,CODEBLOCK,ACTION_STRING,PERCENT_BRACE_ACTION,CHARACTER_CONSTANT,COMMENT,CODE_COMMENT>{
-  {M4QSTART}                   #add_action('[' ']' ']' '[' '[' '[' ']' ']' '[' '[')
-  {M4QEND}                     #add_action(']' ']' ']' '[' '[' ']' ']' ']' '[' '[')
-}
-
-<CODEBLOCK>{
-  ^"%}".*{NL} {
-    state.linenum += 1
-    yy_pop_state()
-    #add_action(']' ']')
-    #if not indented_code:
-    #  line_directive_out(None, 0)
-    piece_insert(markup_stack.pop(), '<AST_Text>')
-    piece_append('</AST_Text>')
-    piece_flush(len(yytext))
-    piece_insert(markup_stack.pop(), '<AST_Section1Or2_CodeBlock>')
-    piece_append('</AST_Section1Or2_CodeBlock>')
-  }
-  [^\n%\[\]]*                  #add_action(yytext)
-  .                            #add_action(yytext)
-  {NL} {
-    state.linenum += 1
-    #add_action(yytext)
-    if indented_code:
-      yy_pop_state()
-      #add_action(']' ']')
-      #if not indented_code:
-      #  line_directive_out(None, 0)
-      piece_flush(len(yytext))
-      piece_insert(markup_stack.pop(), '<AST_Text>')
-      piece_append('</AST_Text>')
-      piece_insert(markup_stack.pop(), '<AST_Section1Or2_CodeBlock>')
-      piece_append('</AST_Section1Or2_CodeBlock>')
-  }
-}
-
-<CODEBLOCK_MATCH_BRACE>{
-  "}" {
-    global brace_depth
-    brace_depth -= 1
-    if brace_depth == 0:
-      yy_pop_state()
-    #else:
-    #  buf_strnappend(&top_buf, yytext, len(yytext))
-  }
-
-  "{" {
-    global brace_depth
-    brace_depth += 1
-    #buf_strnappend(&top_buf, yytext, len(yytext))
-  }
-
-  {NL} {
-    state.linenum += 1
-    #buf_strnappend(&top_buf, yytext, len(yytext))
-  }
-
-  {M4QSTART}                   #buf_strnappend(&top_buf, escaped_qstart, int(len(escaped_qstart)))
-  {M4QEND}                     #buf_strnappend(&top_buf, escaped_qend, int(len(escaped_qend)))
-  ([^{}\r\n\[\]]+)|[^{}\r\n]   #buf_strnappend(&top_buf, yytext, len(yytext))
-
-  <<EOF>> {
-    state.linenum = brace_start_line
-    state.synerr('Unmatched \'{\'')
-    yyterminate()
-  }
-}
-
-
-<PICKUPDEF>{
-  {WS}
-
-  {NOT_WS}[^\r\n]* {
-    global didadef
-    state.ndinstal(state.nmstr, yytext.rstrip('\t '))
-    didadef = True
-  }
-
-  {NL} {
-    if not didadef:
-      state.synerr('incomplete name definition')
-    BEGIN(INITIAL)
-    state.linenum += 1
-  }
-}
-
- /* Nick added ("no"*) prefix to all, instead of it being a separate rule */
-<OPTION>{
-  {NL} {
-    state.linenum += 1
-    BEGIN(INITIAL)
-  }
-  {WS} {
-    #global option_sense
-    #option_sense = True
-  }
-
-  "="                  return ord('=')
-
-  /*no {
-    global option_sense
-    option_sense = not option_sense
-  }*/
-
-  ("no"*)7bit {
-    option_sense = (len(yy_groups[1]) & 2) == 0
-    #csize = 128 if option_sense else 256
-    piece_append(
-      '<AST_Section1_Options_SevenBit{0:s}>'.format(
-        ' value="true"' if option_sense else ''
-      )
-    )
-    piece_flush(len(yytext))
-    piece_append('</AST_Section1_Options_SevenBit>')
-    return y_tab.TOK_OPTION_OTHER # Nick
-  }
-  ("no"*)8bit {
-    option_sense = (len(yy_groups[1]) & 2) == 0
-    #csize = 256 if option_sense else 128
-    piece_append(
-      '<AST_Section1_Options_SevenBit{0:s}>'.format(
-        ' value="true"' if not option_sense else ''
-      )
-    )
-    piece_flush(len(yytext))
-    piece_append('</AST_Section1_Options_SevenBit>')
-    return y_tab.TOK_OPTION_OTHER # Nick
-  }
-
-  ("no"*)align {
-    option_sense = (len(yy_groups[1]) & 2) == 0
-    #long_align = option_sense
-    piece_append(
-      '<AST_Section1_Options_Align{0:s}>'.format(
-        ' value="true"' if option_sense else ''
-      )
-    )
-    piece_flush(len(yytext))
-    piece_append('</AST_Section1_Options_Align>')
-    return y_tab.TOK_OPTION_OTHER # Nick
-  }
-  ("no"*)always-interactive {
-    option_sense = (len(yy_groups[1]) & 2) == 0
-    #if option_sense:
-    #  buf_m4_define(&m4defs_buf, 'M4' '_YY_ALWAYS_INTERACTIVE', None)
-    #else:
-    #  buf_m4_undefine(&m4defs_buf, 'M4' '_YY_ALWAYS_INTERACTIVE')
-    #interactive = option_sense
-    piece_append(
-      '<AST_Section1_Options_AlwaysInteractive{0:s}>'.format(
-        ' value="true"' if option_sense else ''
-      )
-    )
-    piece_flush(len(yytext))
-    piece_append('</AST_Section1_Options_AlwaysInteractive>')
-    return y_tab.TOK_OPTION_OTHER # Nick
-  }
-  ("no"*)array {
-    option_sense = (len(yy_groups[1]) & 2) == 0
-    #yytext_is_array = option_sense
-    piece_append(
-      '<AST_Section1_Options_Array{0:s}>'.format(
-        ' value="true"' if option_sense else ''
-      )
-    )
-    piece_flush(len(yytext))
-    piece_append('</AST_Section1_Options_Array>')
-    return y_tab.TOK_OPTION_OTHER # Nick
-  }
-  ("no"*)backup {
-    option_sense = (len(yy_groups[1]) & 2) == 0
-    #backing_up_report = option_sense
-    piece_append(
-      '<AST_Section1_Options_Backup{0:s}>'.format(
-        ' value="true"' if option_sense else ''
-      )
-    )
-    piece_flush(len(yytext))
-    piece_append('</AST_Section1_Options_Backup>')
-    return y_tab.TOK_OPTION_OTHER # Nick
-  }
-  ("no"*)batch {
-    option_sense = (len(yy_groups[1]) & 2) == 0
-    #interactive = not option_sense
-    piece_append(
-      '<AST_Section1_Options_Interactive{0:s}>'.format(
-        ' value="true"' if not option_sense else ''
-      )
-    )
-    piece_flush(len(yytext))
-    piece_append('</AST_Section1_Options_Interactive>')
-    return y_tab.TOK_OPTION_OTHER # Nick
-  }
-  ("no"*)bison-bridge {
-    option_sense = (len(yy_groups[1]) & 2) == 0
-    #bison_bridge_lval = option_sense
-    piece_append(
-      '<AST_Section1_Options_BisonBridge{0:s}>'.format(
-        ' value="true"' if option_sense else ''
-      )
-    )
-    piece_flush(len(yytext))
-    piece_append('</AST_Section1_Options_BisonBridge>')
-    return y_tab.TOK_OPTION_OTHER # Nick
-  }
-  ("no"*)bison-locations {
-    option_sense = (len(yy_groups[1]) & 2) == 0
-    #if bison_bridge_lloc = option_sense:
-    #  bison_bridge_lval = True
-    piece_append(
-      '<AST_Section1_Options_BisonLocations{0:s}>'.format(
-        ' value="true"' if option_sense else ''
-      )
-    )
-    piece_flush(len(yytext))
-    piece_append('</AST_Section1_Options_BisonLocations>')
-    return y_tab.TOK_OPTION_OTHER # Nick
-  }
-  ("no"*)"c++" {
-    option_sense = (len(yy_groups[1]) & 2) == 0
-    #C_plus_plus = option_sense
-    piece_append(
-      '<AST_Section1_Options_CPlusPlus{0:s}>'.format(
-        ' value="true"' if option_sense else ''
-      )
-    )
-    piece_flush(len(yytext))
-    piece_append('</AST_Section1_Options_CPlusPlus>')
-    return y_tab.TOK_OPTION_OTHER # Nick
-  }
-  ("no"*)caseful|case-sensitive {
-    option_sense = (len(yy_groups[1]) & 2) == 0
-    if not option_sense:
-      state._sf_stk[-1] |= 1
-    else:
-      state._sf_stk[-1] &= ~1
-    piece_append(
-      '<AST_Section1_Options_Caseless{0:s}>'.format(
-        ' value="true"' if not option_sense else ''
-      )
-    )
-    piece_flush(len(yytext))
-    piece_append('</AST_Section1_Options_Caseless>')
-    return y_tab.TOK_OPTION_OTHER # Nick
-  }
-  ("no"*)caseless|case-insensitive {
-    option_sense = (len(yy_groups[1]) & 2) == 0
-    if option_sense:
-      state._sf_stk[-1] |= 1
-    else:
-      state._sf_stk[-1] &= ~1
-    piece_append(
-      '<AST_Section1_Options_Caseless{0:s}>'.format(
-        ' value="true"' if option_sense else ''
-      )
-    )
-    piece_flush(len(yytext))
-    piece_append('</AST_Section1_Options_Caseless>')
-    return y_tab.TOK_OPTION_OTHER # Nick
-  }
-  ("no"*)debug {
-    option_sense = (len(yy_groups[1]) & 2) == 0
-    #ddebug = option_sense
-    piece_append(
-      '<AST_Section1_Options_Debug{0:s}>'.format(
-        ' value="true"' if option_sense else ''
-      )
-    )
-    piece_flush(len(yytext))
-    piece_append('</AST_Section1_Options_Debug>')
-    return y_tab.TOK_OPTION_OTHER # Nick
-  }
-  ("no"*)default {
-    option_sense = (len(yy_groups[1]) & 2) == 0
-    #spprdflt = not option_sense
-    piece_append(
-      '<AST_Section1_Options_Default{0:s}>'.format(
-        ' value="true"' if option_sense else ''
-      )
-    )
-    piece_flush(len(yytext))
-    piece_append('</AST_Section1_Options_Default>')
-    return y_tab.TOK_OPTION_OTHER # Nick
-  }
-  ("no"*)ecs {
-    option_sense = (len(yy_groups[1]) & 2) == 0
-    #useecs = option_sense
-    piece_append(
-      '<AST_Section1_Options_ECS{0:s}>'.format(
-        ' value="true"' if option_sense else ''
-      )
-    )
-    piece_flush(len(yytext))
-    piece_append('</AST_Section1_Options_ECS>')
-    return y_tab.TOK_OPTION_OTHER # Nick
-  }
-  ("no"*)fast {
-    option_sense = (len(yy_groups[1]) & 2) == 0
-    #useecs = usemecs = False
-    #use_read = fullspd = True
-    piece_append(
-      '<AST_Section1_Options_Fast{0:s}>'.format(
-        ' value="true"' if option_sense else ''
-      )
-    )
-    piece_flush(len(yytext))
-    piece_append('</AST_Section1_Options_Fast>')
-    return y_tab.TOK_OPTION_OTHER # Nick
-  }
-  ("no"*)full {
-    option_sense = (len(yy_groups[1]) & 2) == 0
-    #useecs = usemecs = False
-    #use_read = fulltbl = True
-    piece_append(
-      '<AST_Section1_Options_Full{0:s}>'.format(
-        ' value="true"' if option_sense else ''
-      )
-    )
-    piece_flush(len(yytext))
-    piece_append('</AST_Section1_Options_Full>')
-    return y_tab.TOK_OPTION_OTHER # Nick
-  }
-  ("no"*)input {
-    option_sense = (len(yy_groups[1]) & 2) == 0
-    #if not option_sense:
-    #  action_define('YY_NO_INPUT', 1)
-    piece_append(
-      '<AST_Section1_Options_Input{0:s}>'.format(
-        ' value="true"' if option_sense else ''
-      )
-    )
-    piece_flush(len(yytext))
-    piece_append('</AST_Section1_Options_Input>')
-    return y_tab.TOK_OPTION_OTHER # Nick
-  }
-  ("no"*)interactive {
-    option_sense = (len(yy_groups[1]) & 2) == 0
-    #interactive = option_sense
-    piece_append(
-      '<AST_Section1_Options_Interactive{0:s}>'.format(
-        ' value="true"' if option_sense else ''
-      )
-    )
-    piece_flush(len(yytext))
-    piece_append('</AST_Section1_Options_Interactive>')
-    return y_tab.TOK_OPTION_OTHER # Nick
-  }
-  ("no"*)lex-compat {
-    option_sense = (len(yy_groups[1]) & 2) == 0
-    state.lex_compat = option_sense
-    piece_append(
-      '<AST_Section1_Options_LexCompat{0:s}>'.format(
-        ' value="true"' if option_sense else ''
-      )
-    )
-    piece_flush(len(yytext))
-    piece_append('</AST_Section1_Options_LexCompat>')
-    return y_tab.TOK_OPTION_OTHER # Nick
-  }
-  ("no"*)posix-compat {
-    option_sense = (len(yy_groups[1]) & 2) == 0
-    state.posix_compat = option_sense
-    piece_append(
-      '<AST_Section1_Options_PosixCompat{0:s}>'.format(
-        ' value="true"' if option_sense else ''
-      )
-    )
-    piece_flush(len(yytext))
-    piece_append('</AST_Section1_Options_PosixCompat>')
-    return y_tab.TOK_OPTION_OTHER # Nick
-  }
-  ("no"*)line {
-    option_sense = (len(yy_groups[1]) & 2) == 0
-    #gen_line_dirs = option_sense
-    piece_append(
-      '<AST_Section1_Options_Line{0:s}>'.format(
-        ' value="true"' if option_sense else ''
-      )
-    )
-    piece_flush(len(yytext))
-    piece_append('</AST_Section1_Options_Line>')
-    return y_tab.TOK_OPTION_OTHER # Nick
-  }
-  ("no"*)main {
-    option_sense = (len(yy_groups[1]) & 2) == 0
-    #if option_sense:
-    #  buf_m4_define(&m4defs_buf, 'M4' '_YY_MAIN', None)
-    #else:
-    #  buf_m4_undefine(&m4defs_buf, 'M4' '_YY_MAIN')
-    #if option_sense:
-    #  do_yywrap = False
-    piece_append(
-      '<AST_Section1_Options_Main{0:s}>'.format(
-        ' value="true"' if option_sense else ''
-      )
-    )
-    piece_flush(len(yytext))
-    piece_append('</AST_Section1_Options_Main>')
-    return y_tab.TOK_OPTION_OTHER # Nick
-  }
-  ("no"*)meta-ecs {
-    option_sense = (len(yy_groups[1]) & 2) == 0
-    #usemecs = option_sense
-    piece_append(
-      '<AST_Section1_Options_MetaECS{0:s}>'.format(
-        ' value="true"' if option_sense else ''
-      )
-    )
-    piece_flush(len(yytext))
-    piece_append('</AST_Section1_Options_MetaECS>')
-    return y_tab.TOK_OPTION_OTHER # Nick
-  }
-  ("no"*)never-interactive {
-    option_sense = (len(yy_groups[1]) & 2) == 0
-    #if option_sense:
-    #  buf_m4_define(&m4defs_buf, 'M4' '_YY_NEVER_INTERACTIVE', None)
-    #else:
-    #  buf_m4_undefine(&m4defs_buf, 'M4' '_YY_NEVER_INTERACTIVE')
-    #interactive = not option_sense
-    piece_append(
-      '<AST_Section1_Options_NeverInteractive{0:s}>'.format(
-        ' value="true"' if option_sense else ''
-      )
-    )
-    piece_flush(len(yytext))
-    piece_append('</AST_Section1_Options_NeverInteractive>')
-    return y_tab.TOK_OPTION_OTHER # Nick
-  }
-  ("no"*)perf-report {
-    option_sense = (len(yy_groups[1]) & 2) == 0
-    #performance_report += 1 if option_sense else -1
-    piece_append(
-      '<AST_Section1_Options_PerfReport{0:s}>'.format(
-        ' value="true"' if option_sense else ''
-      )
-    )
-    piece_flush(len(yytext))
-    piece_append('</AST_Section1_Options_PerfReport>')
-    return y_tab.TOK_OPTION_OTHER # Nick
-  }
-  ("no"*)pointer {
-    option_sense = (len(yy_groups[1]) & 2) == 0
-    #yytext_is_array = not option_sense
-    piece_append(
-      '<AST_Section1_Options_Array{0:s}>'.format(
-        ' value="true"' if not option_sense else ''
-      )
-    )
-    piece_flush(len(yytext))
-    piece_append('</AST_Section1_Options_Array>')
-    return y_tab.TOK_OPTION_OTHER # Nick
-  }
-  ("no"*)read {
-    option_sense = (len(yy_groups[1]) & 2) == 0
-    #use_read = option_sense
-    piece_append(
-      '<AST_Section1_Options_Read{0:s}>'.format(
-        ' value="true"' if option_sense else ''
-      )
-    )
-    piece_flush(len(yytext))
-    piece_append('</AST_Section1_Options_Read>')
-    return y_tab.TOK_OPTION_OTHER # Nick
-  }
-  ("no"*)reentrant {
-    option_sense = (len(yy_groups[1]) & 2) == 0
-    #reentrant = option_sense
-    piece_append(
-      '<AST_Section1_Options_Reentrant{0:s}>'.format(
-        ' value="true"' if option_sense else ''
-      )
-    )
-    piece_flush(len(yytext))
-    piece_append('</AST_Section1_Options_Reentrant>')
-    return y_tab.TOK_OPTION_OTHER # Nick
-  }
-  ("no"*)reject {
-    option_sense = (len(yy_groups[1]) & 2) == 0
-    #reject_really_used = option_sense
-    piece_append(
-      '<AST_Section1_Options_Reject{0:s}>'.format(
-        ' value="true"' if option_sense else ''
-      )
-    )
-    piece_flush(len(yytext))
-    piece_append('</AST_Section1_Options_Reject>')
-    return y_tab.TOK_OPTION_OTHER # Nick
-  }
-  ("no"*)stack {
-    option_sense = (len(yy_groups[1]) & 2) == 0
-    #if option_sense:
-    #  buf_m4_define(&m4defs_buf, 'M4' '_YY_STACK_USED', None)
-    #else:
-    #  buf_m4_undefine(&m4defs_buf, 'M4' '_YY_STACK_USED')
-    piece_append(
-      '<AST_Section1_Options_Stack{0:s}>'.format(
-        ' value="true"' if option_sense else ''
-      )
-    )
-    piece_flush(len(yytext))
-    piece_append('</AST_Section1_Options_Stack>')
-    return y_tab.TOK_OPTION_OTHER # Nick
-  }
-  ("no"*)stdinit {
-    option_sense = (len(yy_groups[1]) & 2) == 0
-    #do_stdinit = option_sense
-    piece_append(
-      '<AST_Section1_Options_StdInit{0:s}>'.format(
-        ' value="true"' if option_sense else ''
-      )
-    )
-    piece_flush(len(yytext))
-    piece_append('</AST_Section1_Options_StdInit>')
-    return y_tab.TOK_OPTION_OTHER # Nick
-  }
-  ("no"*)stdout {
-    option_sense = (len(yy_groups[1]) & 2) == 0
-    #use_stdout = option_sense
-    piece_append(
-      '<AST_Section1_Options_StdOut{0:s}>'.format(
-        ' value="true"' if option_sense else ''
-      )
-    )
-    piece_flush(len(yytext))
-    piece_append('</AST_Section1_Options_StdOut>')
-    return y_tab.TOK_OPTION_OTHER # Nick
-  }
-  ("no"*)unistd {
-    option_sense = (len(yy_groups[1]) & 2) == 0
-    #if not option_sense:
-    #  action_define('YY_NO_UNISTD_H', 1)
-    piece_append(
-      '<AST_Section1_Options_UniStd{0:s}>'.format(
-        ' value="true"' if option_sense else ''
-      )
-    )
-    piece_flush(len(yytext))
-    piece_append('</AST_Section1_Options_UniStd>')
-    return y_tab.TOK_OPTION_OTHER # Nick
-  }
-  ("no"*)unput {
-    option_sense = (len(yy_groups[1]) & 2) == 0
-    #if not option_sense:
-    #  buf_m4_define(&m4defs_buf, 'M4' '_YY_NO_UNPUT', None)
-    #else:
-    #  buf_m4_undefine(&m4defs_buf, 'M4' '_YY_NO_UNPUT')
-    piece_append(
-      '<AST_Section1_Options_Unput{0:s}>'.format(
-        ' value="true"' if option_sense else ''
-      )
-    )
-    piece_flush(len(yytext))
-    piece_append('</AST_Section1_Options_Unput>')
-    return y_tab.TOK_OPTION_OTHER # Nick
-  }
-  ("no"*)verbose {
-    option_sense = (len(yy_groups[1]) & 2) == 0
-    #printstats = option_sense
-    piece_append(
-      '<AST_Section1_Options_Verbose{0:s}>'.format(
-        ' value="true"' if option_sense else ''
-      )
-    )
-    piece_flush(len(yytext))
-    piece_append('</AST_Section1_Options_Verbose>')
-    return y_tab.TOK_OPTION_OTHER # Nick
-  }
-  ("no"*)warn {
-    option_sense = (len(yy_groups[1]) & 2) == 0
-    #nowarn = not option_sense
-    piece_append(
-      '<AST_Section1_Options_Warn{0:s}>'.format(
-        ' value="true"' if option_sense else ''
-      )
-    )
-    piece_flush(len(yytext))
-    piece_append('</AST_Section1_Options_Warn>')
-    return y_tab.TOK_OPTION_OTHER # Nick
-  }
-  ("no"*)yylineno {
-    option_sense = (len(yy_groups[1]) & 2) == 0
-    #do_yylineno = option_sense
-    #if option_sense:
-    #  buf_m4_define(&m4defs_buf, 'M4' '_YY_USE_LINENO', None)
-    #else:
-    #  buf_m4_undefine(&m4defs_buf, 'M4' '_YY_USE_LINENO')
-    piece_append(
-      '<AST_Section1_Options_YYLineNo{0:s}>'.format(
-        ' value="true"' if option_sense else ''
-      )
-    )
-    piece_flush(len(yytext))
-    piece_append('</AST_Section1_Options_YYLineNo>')
-    return y_tab.TOK_OPTION_OTHER # Nick
-  }
-  ("no"*)yymore {
-    option_sense = (len(yy_groups[1]) & 2) == 0
-    #yymore_really_used = option_sense
-    piece_append(
-      '<AST_Section1_Options_YYMore{0:s}>'.format(
-        ' value="true"' if option_sense else ''
-      )
-    )
-    piece_flush(len(yytext))
-    piece_append('</AST_Section1_Options_YYMore>')
-    return y_tab.TOK_OPTION_OTHER # Nick
-  }
-  ("no"*)yywrap {
-    option_sense = (len(yy_groups[1]) & 2) == 0
-    #do_yywrap = option_sense
-    piece_append(
-      '<AST_Section1_Options_YYWrap{0:s}>'.format(
-        ' value="true"' if option_sense else ''
-      )
-    )
-    piece_flush(len(yytext))
-    piece_append('</AST_Section1_Options_YYWrap>')
-    return y_tab.TOK_OPTION_OTHER # Nick
-  }
-
-  ("no"*)yy_push_state {
-    option_sense = (len(yy_groups[1]) & 2) == 0
-    #if not option_sense:
-    #  buf_m4_define(&m4defs_buf, 'M4' '_YY_NO_PUSH_STATE', None)
-    #else:
-    #  buf_m4_undefine(&m4defs_buf, 'M4' '_YY_NO_PUSH_STATE')
-    piece_append(
-      '<AST_Section1_Options_YYPushState{0:s}>'.format(
-        ' value="true"' if option_sense else ''
-      )
-    )
-    piece_flush(len(yytext))
-    piece_append('</AST_Section1_Options_YYPushState>')
-    return y_tab.TOK_OPTION_OTHER # Nick
-  }
-  ("no"*)yy_pop_state {
-    option_sense = (len(yy_groups[1]) & 2) == 0
-    #if not option_sense:
-    #  buf_m4_define(&m4defs_buf, 'M4' '_YY_NO_POP_STATE', None)
-    #else:
-    #  buf_m4_undefine(&m4defs_buf, 'M4' '_YY_NO_POP_STATE')
-    piece_append(
-      '<AST_Section1_Options_YYPopState{0:s}>'.format(
-        ' value="true"' if option_sense else ''
-      )
-    )
-    piece_flush(len(yytext))
-    piece_append('</AST_Section1_Options_YYPopState>')
-    return y_tab.TOK_OPTION_OTHER # Nick
-  }
-  ("no"*)yy_top_state {
-    option_sense = (len(yy_groups[1]) & 2) == 0
-    #if not option_sense:
-    #  buf_m4_define(&m4defs_buf, 'M4' '_YY_NO_TOP_STATE', None)
-    #else:
-    #  buf_m4_undefine(&m4defs_buf, 'M4' '_YY_NO_TOP_STATE')
-    piece_append(
-      '<AST_Section1_Options_YYTopState{0:s}>'.format(
-        ' value="true"' if option_sense else ''
-      )
-    )
-    piece_flush(len(yytext))
-    piece_append('</AST_Section1_Options_YYTopState>')
-    return y_tab.TOK_OPTION_OTHER # Nick
-  }
-
-  ("no"*)yy_scan_buffer {
-    option_sense = (len(yy_groups[1]) & 2) == 0
-    #if not option_sense:
-    #  buf_m4_define(&m4defs_buf, 'M4' '_YY_NO_SCAN_BUFFER', None)
-    #else:
-    #  buf_m4_undefine(&m4defs_buf, 'M4' '_YY_NO_SCAN_BUFFER')
-    piece_append(
-      '<AST_Section1_Options_YYScanBuffer{0:s}>'.format(
-        ' value="true"' if option_sense else ''
-      )
-    )
-    piece_flush(len(yytext))
-    piece_append('</AST_Section1_Options_YYScanBuffer>')
-    return y_tab.TOK_OPTION_OTHER # Nick
-  }
-  ("no"*)yy_scan_bytes {
-    option_sense = (len(yy_groups[1]) & 2) == 0
-    #if not option_sense:
-    #  buf_m4_define(&m4defs_buf, 'M4' '_YY_NO_SCAN_BYTES', None)
-    #else:
-    #  buf_m4_undefine(&m4defs_buf, 'M4' '_YY_NO_SCAN_BYTES')
-    piece_append(
-      '<AST_Section1_Options_YYScanBytes{0:s}>'.format(
-        ' value="true"' if option_sense else ''
-      )
-    )
-    piece_flush(len(yytext))
-    piece_append('</AST_Section1_Options_YYScanBytes>')
-    return y_tab.TOK_OPTION_OTHER # Nick
-  }
-  ("no"*)yy_scan_string {
-    option_sense = (len(yy_groups[1]) & 2) == 0
-    #if not option_sense:
-    #  buf_m4_define(&m4defs_buf, 'M4' '_YY_NO_SCAN_STRING', None)
-    #else:
-    #  buf_m4_undefine(&m4defs_buf, 'M4' '_YY_NO_SCAN_STRING')
-    piece_append(
-      '<AST_Section1_Options_YYScanString{0:s}>'.format(
-        ' value="true"' if option_sense else ''
-      )
-    )
-    piece_flush(len(yytext))
-    piece_append('</AST_Section1_Options_YYScanString>')
-    return y_tab.TOK_OPTION_OTHER # Nick
-  }
-
-  ("no"*)yyalloc {
-    option_sense = (len(yy_groups[1]) & 2) == 0
-    #if not option_sense:
-    #  buf_m4_define(&m4defs_buf, 'M4' '_YY_NO_FLEX_ALLOC', None)
-    #else:
-    #  buf_m4_undefine(&m4defs_buf, 'M4' '_YY_NO_FLEX_ALLOC')
-    piece_append(
-      '<AST_Section1_Options_YYAlloc{0:s}>'.format(
-        ' value="true"' if option_sense else ''
-      )
-    )
-    piece_flush(len(yytext))
-    piece_append('</AST_Section1_Options_YYAlloc>')
-    return y_tab.TOK_OPTION_OTHER # Nick
-  }
-  ("no"*)yyrealloc {
-    option_sense = (len(yy_groups[1]) & 2) == 0
-    #if not option_sense:
-    #  buf_m4_define(&m4defs_buf, 'M4' '_YY_NO_FLEX_REALLOC', None)
-    #else:
-    #  buf_m4_undefine(&m4defs_buf, 'M4' '_YY_NO_FLEX_REALLOC')
-    piece_append(
-      '<AST_Section1_Options_YYRealloc{0:s}>'.format(
-        ' value="true"' if option_sense else ''
-      )
-    )
-    piece_flush(len(yytext))
-    piece_append('</AST_Section1_Options_YYRealloc>')
-    return y_tab.TOK_OPTION_OTHER # Nick
-  }
-  ("no"*)yyfree {
-    option_sense = (len(yy_groups[1]) & 2) == 0
-    #if not option_sense:
-    #  buf_m4_define(&m4defs_buf, 'M4' '_YY_NO_FLEX_FREE', None)
-    #else:
-    #  buf_m4_undefine(&m4defs_buf, 'M4' '_YY_NO_FLEX_FREE')
-    piece_append(
-      '<AST_Section1_Options_YYFree{0:s}>'.format(
-        ' value="true"' if option_sense else ''
-      )
-    )
-    piece_flush(len(yytext))
-    piece_append('</AST_Section1_Options_YYFree>')
-    return y_tab.TOK_OPTION_OTHER # Nick
-  }
-
-  ("no"*)yyget_debug {
-    option_sense = (len(yy_groups[1]) & 2) == 0
-    #if not option_sense:
-    #  buf_m4_define(&m4defs_buf, 'M4' '_YY_NO_GET_DEBUG', None)
-    #else:
-    #  buf_m4_undefine(&m4defs_buf, 'M4' '_YY_NO_GET_DEBUG')
-    piece_append(
-      '<AST_Section1_Options_YYGetDebug{0:s}>'.format(
-        ' value="true"' if option_sense else ''
-      )
-    )
-    piece_flush(len(yytext))
-    piece_append('</AST_Section1_Options_YYGetDebug>')
-    return y_tab.TOK_OPTION_OTHER # Nick
-  }
-  ("no"*)yyset_debug {
-    option_sense = (len(yy_groups[1]) & 2) == 0
-    #if not option_sense:
-    #  buf_m4_define(&m4defs_buf, 'M4' '_YY_NO_SET_DEBUG', None)
-    #else:
-    #  buf_m4_undefine(&m4defs_buf, 'M4' '_YY_NO_SET_DEBUG')
-    piece_append(
-      '<AST_Section1_Options_YYSetDebug{0:s}>'.format(
-        ' value="true"' if option_sense else ''
-      )
-    )
-    piece_flush(len(yytext))
-    piece_append('</AST_Section1_Options_YYSetDebug>')
-    return y_tab.TOK_OPTION_OTHER # Nick
-  }
-  ("no"*)yyget_extra {
-    option_sense = (len(yy_groups[1]) & 2) == 0
-    #if not option_sense:
-    #  buf_m4_define(&m4defs_buf, 'M4' '_YY_NO_GET_EXTRA', None)
-    #else:
-    #  buf_m4_undefine(&m4defs_buf, 'M4' '_YY_NO_GET_EXTRA')
-    piece_append(
-      '<AST_Section1_Options_YYGetExtra{0:s}>'.format(
-        ' value="true"' if option_sense else ''
-      )
-    )
-    piece_flush(len(yytext))
-    piece_append('</AST_Section1_Options_YYGetExtra>')
-    return y_tab.TOK_OPTION_OTHER # Nick
-  }
-  ("no"*)yyset_extra {
-    option_sense = (len(yy_groups[1]) & 2) == 0
-    #if not option_sense:
-    #  buf_m4_define(&m4defs_buf, 'M4' '_YY_NO_SET_EXTRA', None)
-    #else:
-    #  buf_m4_undefine(&m4defs_buf, 'M4' '_YY_NO_SET_EXTRA')
-    piece_append(
-      '<AST_Section1_Options_YYSetExtra{0:s}>'.format(
-        ' value="true"' if option_sense else ''
-      )
-    )
-    piece_flush(len(yytext))
-    piece_append('</AST_Section1_Options_YYSetExtra>')
-    return y_tab.TOK_OPTION_OTHER # Nick
-  }
-  ("no"*)yyget_leng {
-    option_sense = (len(yy_groups[1]) & 2) == 0
-    #if not option_sense:
-    #  buf_m4_define(&m4defs_buf, 'M4' '_YY_NO_GET_LENG', None)
-    #else:
-    #  buf_m4_undefine(&m4defs_buf, 'M4' '_YY_NO_GET_LENG')
-    piece_append(
-      '<AST_Section1_Options_YYGetLeng{0:s}>'.format(
-        ' value="true"' if option_sense else ''
-      )
-    )
-    piece_flush(len(yytext))
-    piece_append('</AST_Section1_Options_YYGetLeng>')
-    return y_tab.TOK_OPTION_OTHER # Nick
-  }
-  ("no"*)yyget_text {
-    option_sense = (len(yy_groups[1]) & 2) == 0
-    #if not option_sense:
-    #  buf_m4_define(&m4defs_buf, 'M4' '_YY_NO_GET_TEXT', None)
-    #else:
-    #  buf_m4_undefine(&m4defs_buf, 'M4' '_YY_NO_GET_TEXT')
-    piece_append(
-      '<AST_Section1_Options_YYGetText{0:s}>'.format(
-        ' value="true"' if option_sense else ''
-      )
-    )
-    piece_flush(len(yytext))
-    piece_append('</AST_Section1_Options_YYGetText>')
-    return y_tab.TOK_OPTION_OTHER # Nick
-  }
-  ("no"*)yyget_lineno {
-    option_sense = (len(yy_groups[1]) & 2) == 0
-    #if not option_sense:
-    #  buf_m4_define(&m4defs_buf, 'M4' '_YY_NO_GET_LINENO', None)
-    #else:
-    #  buf_m4_undefine(&m4defs_buf, 'M4' '_YY_NO_GET_LINENO')
-    piece_append(
-      '<AST_Section1_Options_YYGetLineNo{0:s}>'.format(
-        ' value="true"' if option_sense else ''
-      )
-    )
-    piece_flush(len(yytext))
-    piece_append('</AST_Section1_Options_YYGetLineNo>')
-    return y_tab.TOK_OPTION_OTHER # Nick
-  }
-  ("no"*)yyset_lineno {
-    option_sense = (len(yy_groups[1]) & 2) == 0
-    #if not option_sense:
-    #  buf_m4_define(&m4defs_buf, 'M4' '_YY_NO_SET_LINENO', None)
-    #else:
-    #  buf_m4_undefine(&m4defs_buf, 'M4' '_YY_NO_SET_LINENO')
-    piece_append(
-      '<AST_Section1_Options_YYSetLineNo{0:s}>'.format(
-        ' value="true"' if option_sense else ''
-      )
-    )
-    piece_flush(len(yytext))
-    piece_append('</AST_Section1_Options_YYSetLineNo>')
-    return y_tab.TOK_OPTION_OTHER # Nick
-  }
-  ("no"*)yyget_in {
-    option_sense = (len(yy_groups[1]) & 2) == 0
-    #if not option_sense:
-    #  buf_m4_define(&m4defs_buf, 'M4' '_YY_NO_GET_IN', None)
-    #else:
-    #  buf_m4_undefine(&m4defs_buf, 'M4' '_YY_NO_GET_IN')
-    piece_append(
-      '<AST_Section1_Options_YYGetIn{0:s}>'.format(
-        ' value="true"' if option_sense else ''
-      )
-    )
-    piece_flush(len(yytext))
-    piece_append('</AST_Section1_Options_YYGetIn>')
-    return y_tab.TOK_OPTION_OTHER # Nick
-  }
-  ("no"*)yyset_in {
-    option_sense = (len(yy_groups[1]) & 2) == 0
-    #if not option_sense:
-    #  buf_m4_define(&m4defs_buf, 'M4' '_YY_NO_SET_IN', None)
-    #else:
-    #  buf_m4_undefine(&m4defs_buf, 'M4' '_YY_NO_SET_IN')
-    piece_append(
-      '<AST_Section1_Options_YYSetIn{0:s}>'.format(
-        ' value="true"' if option_sense else ''
-      )
-    )
-    piece_flush(len(yytext))
-    piece_append('</AST_Section1_Options_YYSetIn>')
-    return y_tab.TOK_OPTION_OTHER # Nick
-  }
-  ("no"*)yyget_out {
-    option_sense = (len(yy_groups[1]) & 2) == 0
-    #if not option_sense:
-    #  buf_m4_define(&m4defs_buf, 'M4' '_YY_NO_GET_OUT', None)
-    #else:
-    #  buf_m4_undefine(&m4defs_buf, 'M4' '_YY_NO_GET_OUT')
-    piece_append(
-      '<AST_Section1_Options_YYGetOut{0:s}>'.format(
-        ' value="true"' if option_sense else ''
-      )
-    )
-    piece_flush(len(yytext))
-    piece_append('</AST_Section1_Options_YYGetOut>')
-    return y_tab.TOK_OPTION_OTHER # Nick
-  }
-  ("no"*)yyset_out {
-    option_sense = (len(yy_groups[1]) & 2) == 0
-    #if not option_sense:
-    #  buf_m4_define(&m4defs_buf, 'M4' '_YY_NO_SET_OUT', None)
-    #else:
-    #  buf_m4_undefine(&m4defs_buf, 'M4' '_YY_NO_SET_OUT')
-    piece_append(
-      '<AST_Section1_Options_YYSetOut{0:s}>'.format(
-        ' value="true"' if option_sense else ''
-      )
-    )
-    piece_flush(len(yytext))
-    piece_append('</AST_Section1_Options_YYSetOut>')
-    return y_tab.TOK_OPTION_OTHER # Nick
-  }
-  ("no"*)yyget_lval {
-    option_sense = (len(yy_groups[1]) & 2) == 0
-    #if not option_sense:
-    #  buf_m4_define(&m4defs_buf, 'M4' '_YY_NO_GET_LVAL', None)
-    #else:
-    #  buf_m4_undefine(&m4defs_buf, 'M4' '_YY_NO_GET_LVAL')
-    piece_append(
-      '<AST_Section1_Options_YYGetLVal{0:s}>'.format(
-        ' value="true"' if option_sense else ''
-      )
-    )
-    piece_flush(len(yytext))
-    piece_append('</AST_Section1_Options_YYGetLVal>')
-    return y_tab.TOK_OPTION_OTHER # Nick
-  }
-  ("no"*)yyset_lval {
-    option_sense = (len(yy_groups[1]) & 2) == 0
-    #if not option_sense:
-    #  buf_m4_define(&m4defs_buf, 'M4' '_YY_NO_SET_LVAL', None)
-    #else:
-    #  buf_m4_undefine(&m4defs_buf, 'M4' '_YY_NO_SET_LVAL')
-    piece_append(
-      '<AST_Section1_Options_YYSetLVal{0:s}>'.format(
-        ' value="true"' if option_sense else ''
-      )
-    )
-    piece_flush(len(yytext))
-    piece_append('</AST_Section1_Options_YYSetLVal>')
-    return y_tab.TOK_OPTION_OTHER # Nick
-  }
-  ("no"*)yyget_lloc {
-    option_sense = (len(yy_groups[1]) & 2) == 0
-    #if not option_sense:
-    #  buf_m4_define(&m4defs_buf, 'M4' '_YY_NO_GET_LLOC', None)
-    #else:
-    #  buf_m4_undefine(&m4defs_buf, 'M4' '_YY_NO_GET_LLOC')
-    piece_append(
-      '<AST_Section1_Options_YYGetLLoc{0:s}>'.format(
-        ' value="true"' if option_sense else ''
-      )
-    )
-    piece_flush(len(yytext))
-    piece_append('</AST_Section1_Options_YYGetLLoc>')
-    return y_tab.TOK_OPTION_OTHER # Nick
-  }
-  ("no"*)yyset_lloc {
-    option_sense = (len(yy_groups[1]) & 2) == 0
-    #if not option_sense:
-    #  buf_m4_define(&m4defs_buf, 'M4' '_YY_NO_SET_LLOC', None)
-    #else:
-    #  buf_m4_undefine(&m4defs_buf, 'M4' '_YY_NO_SET_LLOC')
-    piece_append(
-      '<AST_Section1_Options_YYSetLLoc{0:s}>'.format(
-        ' value="true"' if option_sense else ''
-      )
-    )
-    piece_flush(len(yytext))
-    piece_append('</AST_Section1_Options_YYSetLLoc>')
-    return y_tab.TOK_OPTION_OTHER # Nick
-  }
-
-  extra-type           return y_tab.TOK_EXTRA_TYPE
-  outfile              return y_tab.TOK_OUTFILE
-  prefix               return y_tab.TOK_PREFIX
-  yyclass              return y_tab.TOK_YYCLASS
-  header(-file)?       return y_tab.TOK_HEADER_FILE
-  tables-file          return y_tab.TOK_TABLES_FILE
-  ("no"*)tables-verify {
-    option_sense = (len(yy_groups[1]) & 2) == 0
-    #tablesverify = option_sense
-    #if not tablesext and option_sense:
-    #  tablesext = True
-    piece_append(
-      '<AST_Section1_Options_TablesVerify{0:s}>'.format(
-        ' value="true"' if option_sense else ''
-      )
-    )
-    piece_flush(len(yytext))
-    piece_append('</AST_Section1_Options_TablesVerify>')
-    return y_tab.TOK_OPTION_OTHER # Nick
-  }
-
-  \"[^"\n]*\" {
-    state.nmstr = yytext[1:-1]
-    piece_pack()
-    piece_append('<AST_String>"<AST_Text>')
-    piece_escape(yytext[1:-1])
-    piece_append('</AST_Text>"</AST_String>')
-    piece_pack()
-    return ~y_tab.NAME
-  }
-
-  (([a-mo-z]|n[a-np-z])[[:alpha:]\-+]*)|. {
-    state.synerr('unrecognized %option: {0:s}'.format(yytext))
-    BEGIN(RECOVER)
-  }
-}
-
-<RECOVER>.*{NL} {
-  state.linenum += 1
-  BEGIN(INITIAL)
-}
-
-
-<SECT2PROLOG>{
-  ^"%{".* {
-    global bracelevel
-    bracelevel += 1
-    yyless(2)
-  }
-  ^"%}".* {
-    global bracelevel
-    bracelevel -= 1
-    yyless(2)
-  }
-
-  ^{WS} {
-    global indented_code
-    if not indented_code:
-      state.linenum += 1
-      #line_directive_out(None, 1)
-    #add_action('[' '[')
-    yy_push_state(CODEBLOCK)
-    indented_code = True
-    #add_action(yytext)
-    markup_stack.append(len(piece)) # <AST_Section1Or2_CodeBlock>
-    markup_stack.append(len(piece)) # <AST_Text>
-  }
-
-  ^{NOT_WS}.* {
-    global indented_code
-    if bracelevel <= 0:
-      yyless(0)
-      yy_set_bol(True)
-      #mark_prolog()
-      BEGIN(SECT2)
-    else:
-      if not indented_code:
-        state.linenum += 1
-        #line_directive_out(None, 1)
-      #add_action('[' '[')
-      yy_push_state(CODEBLOCK)
-      indented_code = True
-      #add_action(yytext)
-      markup_stack.append(len(piece)) # <AST_Section1Or2_CodeBlock>
-      markup_stack.append(len(piece)) # <AST_Text>
-  }
-
-  .                            #add_action(yytext)
-  {NL} {
-    state.linenum += 1
-    #add_action(yytext)
-  }
-
-  <<EOF>> {
-    #mark_prolog()
-    sectnum = 0
-    piece_pack()
-    return ~YY_NULL
-  }
-}
-
-<SECT2>{
-  ^{OPTWS}{NL}                 state.linenum += 1
-
-  ^{OPTWS}"%{" {
-    global indented_code, doing_codeblock, bracelevel
-    indented_code = False
-    doing_codeblock = True
-    bracelevel = 1
-    BEGIN(PERCENT_BRACE_ACTION)
-    piece_flush(len(yytext) - 2)
-    markup_stack.append(len(piece)) # <AST_Section1Or2_CodeBlock>
-    piece_flush(2)
-    markup_stack.append(len(piece)) # <AST_Text>
-  }
-
-  ^{OPTWS}"<" {
-    if not (state._sf_stk[-1] & 4):
-      BEGIN(SC)
-    piece_flush(len(yytext) - 1)
-    return ord('<')
-  }
-  ^{OPTWS}"^" {
-    piece_flush(len(yytext) - 1)
-    return ord('^')
-  }
-  \" {
-    BEGIN(QUOTE)
-    return ord('"')
-  }
-  "{"/[[:digit:]] {
-    BEGIN(NUM)
-    if state.lex_compat or state.posix_compat:
-      return y_tab.BEGIN_REPEAT_POSIX
-    else:
-      return y_tab.BEGIN_REPEAT_FLEX
-  }
-  "$"/([[:blank:]]|{NL}) return ord('$')
-
-  {WS}"%{" {
-    global bracelevel, doing_rule_action
-    if not state.in_rule:
-      state.synerr('action outside rule')
-    bracelevel = 1
-    BEGIN(PERCENT_BRACE_ACTION)
-    piece_flush(len(yytext) - 2)
-    markup_stack.append(len(piece)) # <AST_Section2_Rule_Action>
-    doing_rule_action = True
-    state.in_rule = False
-    piece_flush(2)
-    markup_stack.append(len(piece)) # <AST_Text>
-  }
-  {WS}"|".*{NL} {
-    if state._sf_stk[-1] & 4:
-      yyless(yytext.index('|'))
-    else:
-      #add_action(']' ']')
-      continued_action = True
-      state.linenum += 1
-      i = 0
-      while i < len(yytext) and yytext[i] in '\t ':
-        i += 1
-      piece_flush(i)
-      piece_append('<AST_Section2_Rule_Action continued="true">')
-      piece_flush(len(yytext))
-      piece_append('</AST_Section2_Rule_Action>')
-      return ord('\n')
-  }
-
-  ^{WS}"/*" {
-    global bracelevel
-    if state._sf_stk[-1] & 4:
-      yy_push_state(COMMENT_DISCARD)
-    else:
-      yyless(len(yytext) - 2)
-      bracelevel = 0
-      continued_action = False
-      BEGIN(ACTION)
-  }
-
-  ^{WS}
-
-  {WS} {
-    global bracelevel, doing_rule_action
-    if not (state._sf_stk[-1] & 4):
-      bracelevel = 0
-      continued_action = False
-      BEGIN(ACTION)
-      if state.in_rule:
-        doing_rule_action = True
-        state.in_rule = False
-        piece_flush(len(yytext))
-        markup_stack.append(len(piece)) # <AST_Section2_Rule_Action>
-        markup_stack.append(len(piece)) # <AST_Text>
-  }
-
-  {OPTWS}{NL} {
-    global bracelevel, doing_rule_action
-    if state._sf_stk[-1] & 4:
-      state.linenum += 1
-    else:
-      bracelevel = 0
-      continued_action = False
-      BEGIN(ACTION)
-      yyless(len(yytext) - 1)
-      if state.in_rule:
-        doing_rule_action = True
-        state.in_rule = False
-        piece_flush(len(yytext))
-        markup_stack.append(len(piece)) # <AST_Section2_Rule_Action>
-        markup_stack.append(len(piece)) # <AST_Text>
-  }
-
-  ^{OPTWS}"<<EOF>>" |
-  "<<EOF>>" {
-    piece_flush(len(yytext) - 7)
-    return y_tab.EOF_OP
-  }
-
-  ^"%%".* {
-    sectnum = 3
-    BEGIN(SECT3_NOESCAPE if state.no_section3_escape else SECT3)
-    #outn('/* Begin user sect3 */')
-    return y_tab.SECTEND
-  }
-
-  "["({FIRST_CCL_CHAR}|{CCL_EXPR})({CCL_CHAR}|{CCL_EXPR})* {
-    #cclval = None
-    state.nmstr = yytext
-    #if 0 and (cclval = ccllookup(state.nmstr)) != 0:
-    #  if input() != ord(']'):
-    #    state.synerr('bad character class')
-    #  y_tab.yylval = cclval
-    #  cclreuse += 1
-    #  return y_tab.PREVCCL
-    if True: #else:
-      #cclinstal(state.nmstr, lastccl + 1)
-      yyless(1)
-      BEGIN(FIRSTCCL)
-      return ord('[')
-  }
-  "{-}"                                return y_tab.CCL_OP_DIFF
-  "{+}"                                return y_tab.CCL_OP_UNION
-
-
-    /* Check for :space: at the end of the rule so we don't
-     * wrap the expanded regex in '(' ')' -- breaking trailing
-     * context.
-     */
-  "{"{NAME}"}"[[:space:]]? {
-    end_ch = yytext[-1]
-    end_is_ws = end_ch != '}'
-    state.nmstr = yytext[1:-1 - int(end_is_ws)]
-    nmdef = state.ndlookup(state.nmstr)
-    if nmdef is None:
-      state.synerr('undefined definition {{{0:s}}}'.format(state.nmstr))
-    else:
-      if end_is_ws:
-        yyless(len(yytext) - 1)
-      if state.lex_compat or len(nmdef) and (nmdef[0] == '^' or nmdef[-1] == '$') or end_is_ws and y_tab.trlcontxt and not (state._sf_stk[-1] & 4):
-        unput(nmdef)
-        if len(nmdef) and nmdef[0] == '^':
-          BEGIN(CARETISBOL)
-      else:
-        unput(
-          '({0:s}{1:s})'.format(
-            '' if state.lex_compat or state.posix_compat else '?:',
-            nmdef
-          )
-        )
-  }
-
-  "/*" {
-    if state._sf_stk[-1] & 4:
-      yy_push_state(COMMENT_DISCARD)
-    else:
-      yyless(1)
-      return ord('/')
-  }
-
-  "(?#" {
-    if state.lex_compat or state.posix_compat:
-      yyless(1)
-      state.sf_push()
-      return ord('(')
-    else:
-      yy_push_state(EXTENDED_COMMENT)
-  }
-  "(?" {
-    state.sf_push()
-    if state.lex_compat or state.posix_compat:
-      yyless(1)
-    else:
-      BEGIN(GROUP_WITH_PARAMS)
-    return ord('(')
-  }
-  "(" {
-    state.sf_push()
-    return ord('(')
-  }
-  ")" {
-    if len(state._sf_stk) > 1:
-      state.sf_pop()
-      return ord(')')
-    else:
-      state.synerr('unbalanced parenthesis')
-  }
-
-  [/|*+?.(){}]                 return ord(yytext[0])
-  . {
-    y_tab.yylval = ord(yytext[0])
-    return y_tab.CHAR
-  }
-}
-
-
-<SC>{
-  {OPTWS}{NL}{OPTWS}           state.linenum += 1
-  [,*]                         return ord(yytext[0])
-  ">" {
-    BEGIN(SECT2)
-    return ord('>')
-  }
-  ">"/^ {
-    BEGIN(CARETISBOL)
-    return ord('>')
-  }
-  {SCNAME} {
-    state.nmstr = yytext
-    piece_pack()
-    piece_append('<AST_Name>')
-    piece_escape(yytext)
-    piece_append('</AST_Name>')
-    piece_pack()
-    return ~y_tab.NAME
-  }
-  .                            state.synerr('bad <start condition>: {0:s}'.format(yytext))
-}
-
-<CARETISBOL>"^" {
-  BEGIN(SECT2)
-  return ord('^')
-}
-
-
-<QUOTE>{
-  [^"\n] {
-    y_tab.yylval = ord(yytext[0])
-    return y_tab.CHAR
-  }
-  \" {
-    BEGIN(SECT2)
-    return ord('"')
-  }
-
-  {NL} {
-    state.synerr('missing quote')
-    BEGIN(SECT2)
-    state.linenum += 1
-    return ord('"')
-  }
-}
-
-<GROUP_WITH_PARAMS>{
-    /* Nick extra rules for named groups */
-  "'"{NAME}"'" |
-  "<"{NAME}">" {
-    BEGIN(SECT2)
-    piece_pack()
-    piece_flush(1)
-    piece_append('<RegexGroupName_Text>')
-    piece_flush(len(yytext) - 1)
-    piece_append('</RegexGroupName_Text>')
-    piece_flush(1)
-    piece_pack()
-    return ~y_tab.NAME
-  }
-    /* Nick extra rules for action groups */
-  "A{" {
-    global bracelevel
-    BEGIN(SECT2)
-    yy_push_state(ACTION_GROUP)
-    bracelevel = 1
-    piece_flush(len(yytext))
-    markup_stack.append(len(piece)) # <RegexGroupAction_Text>
-  }
-  "E{" {
-    global bracelevel
-    BEGIN(SECT2)
-    yy_push_state(ELEMENT_GROUP)
-    bracelevel = 1
-    piece_flush(len(yytext))
-    markup_stack.append(len(piece)) # <RegexGroupElement_Text>
-  }
-  ":" {
-    BEGIN(SECT2)
-    return ord(':')
-  }
-  "-"                          BEGIN(GROUP_MINUS_PARAMS)
-  i                            state._sf_stk[-1] |= 1
-  s                            state._sf_stk[-1] |= 2
-  x                            state._sf_stk[-1] |= 4
-}
-<GROUP_MINUS_PARAMS>{
-  ":" {
-    BEGIN(SECT2)
-    return ord(':')
-  }
-  i                            state._sf_stk[-1] &= ~1
-  s                            state._sf_stk[-1] &= ~2
-  x                            state._sf_stk[-1] &= ~4
-}
-
-<FIRSTCCL>{
-  "^"/[^-\]\n] {
-    BEGIN(CCL)
-    return ord('^')
-  }
-  "^"/("-"|"]")                        return ord('^')
-  . {
-    BEGIN(CCL)
-    y_tab.yylval = ord(yytext[0])
-    return y_tab.CHAR
-  }
-}
-
-<CCL>{
-  -/[^\]\n]                    return ord('-')
-  [^\]\n] {
-    y_tab.yylval = ord(yytext[0])
-    return y_tab.CHAR
-  }
-  "]" {
-    BEGIN(SECT2)
-    return ord(']')
-  }
-  .|{NL} {
-    state.synerr('bad character class')
-    BEGIN(SECT2)
-    return ord(']')
-  }
-}
-
-<FIRSTCCL,CCL>{
-  "[:alnum:]" {
-    BEGIN(CCL)
-    return y_tab.CCE_ALNUM
-  }
-  "[:alpha:]" {
-    BEGIN(CCL)
-    return y_tab.CCE_ALPHA
-  }
-  "[:blank:]" {
-    BEGIN(CCL)
-    return y_tab.CCE_BLANK
-  }
-  "[:cntrl:]" {
-    BEGIN(CCL)
-    return y_tab.CCE_CNTRL
-  }
-  "[:digit:]" {
-    BEGIN(CCL)
-    return y_tab.CCE_DIGIT
-  }
-  "[:graph:]" {
-    BEGIN(CCL)
-    return y_tab.CCE_GRAPH
-  }
-  "[:lower:]" {
-    BEGIN(CCL)
-    return y_tab.CCE_LOWER
-  }
-  "[:print:]" {
-    BEGIN(CCL)
-    return y_tab.CCE_PRINT
-  }
-  "[:punct:]" {
-    BEGIN(CCL)
-    return y_tab.CCE_PUNCT
-  }
-  "[:space:]" {
-    BEGIN(CCL)
-    return y_tab.CCE_SPACE
-  }
-  "[:upper:]" {
-    BEGIN(CCL)
-    return y_tab.CCE_UPPER
-  }
-  "[:xdigit:]" {
-    BEGIN(CCL)
-    return y_tab.CCE_XDIGIT
-  }
-
-  "[:^alnum:]" {
-    BEGIN(CCL)
-    return y_tab.CCE_NEG_ALNUM
-  }
-  "[:^alpha:]" {
-    BEGIN(CCL)
-    return y_tab.CCE_NEG_ALPHA
-  }
-  "[:^blank:]" {
-    BEGIN(CCL)
-    return y_tab.CCE_NEG_BLANK
-  }
-  "[:^cntrl:]" {
-    BEGIN(CCL)
-    return y_tab.CCE_NEG_CNTRL
-  }
-  "[:^digit:]" {
-    BEGIN(CCL)
-    return y_tab.CCE_NEG_DIGIT
-  }
-  "[:^graph:]" {
-    BEGIN(CCL)
-    return y_tab.CCE_NEG_GRAPH
-  }
-  "[:^lower:]" {
-    BEGIN(CCL)
-    return y_tab.CCE_NEG_LOWER
-  }
-  "[:^print:]" {
-    BEGIN(CCL)
-    return y_tab.CCE_NEG_PRINT
-  }
-  "[:^punct:]" {
-    BEGIN(CCL)
-    return y_tab.CCE_NEG_PUNCT
-  }
-  "[:^space:]" {
-    BEGIN(CCL)
-    return y_tab.CCE_NEG_SPACE
-  }
-  "[:^upper:]" {
-    BEGIN(CCL)
-    return y_tab.CCE_NEG_UPPER
-  }
-  "[:^xdigit:]" {
-    BEGIN(CCL)
-    return y_tab.CCE_NEG_XDIGIT
-  }
-  {CCL_EXPR} {
-    state.synerr('bad character class expression: {0:s}'.format(yytext))
-    BEGIN(CCL)
-    return y_tab.CCE_ALNUM
-  }
-}
-
-<NUM>{
-  [[:digit:]]+ {
-    y_tab.yylval = int(yytext)
-    return y_tab.NUMBER
-  }
-
-  ","                          return ord(',')
-  "}" {
-    BEGIN(SECT2)
-    if state.lex_compat or state.posix_compat:
-      return y_tab.END_REPEAT_POSIX
-    else:
-      return y_tab.END_REPEAT_FLEX
-  }
-
-  . {
-    state.synerr('bad character inside {}\'s')
-    BEGIN(SECT2)
-    return ord('}')
-  }
-
-  {NL} {
-    state.synerr('missing }')
-    BEGIN(SECT2)
-    state.linenum += 1
-    return ord('}')
-  }
-}
-
-
-<PERCENT_BRACE_ACTION>{
-  {OPTWS}"%}".* {
-    global bracelevel
-    bracelevel = 0
-    piece_insert(markup_stack.pop(), '<AST_Text>')
-    piece_append('</AST_Text>')
-  }
-
-  <ACTION>"/*" {
-    #add_action(yytext)
-    yy_push_state(CODE_COMMENT)
-  }
-
-    <CODEBLOCK,ACTION>{
-    "reject" {
-      #add_action(yytext)
-      if yytext.isupper():
-        reject = True
-    }
-    "yymore" {
-      #add_action(yytext)
-      if yytext.islower():
-        yymore_used = True
-    }
-  }
-
-  .                            #add_action(yytext)
-  {NL} {
-    global doing_rule_action, doing_codeblock
-    state.linenum += 1
-    #add_action(yytext)
-    if bracelevel <= 0 or doing_codeblock and indented_code:
-      #if doing_rule_action:
-      #  add_action('\tYY_BREAK]' ']\n')
-      doing_rule_action = False
-      BEGIN(SECT2)
-      piece_flush(len(yytext))
-      if doing_codeblock:
-        piece_insert(markup_stack.pop(), '<AST_Section1Or2_CodeBlock>')
-        piece_append('</AST_Section1Or2_CodeBlock>')
-        doing_codeblock = False
-      else:
-        piece_insert(markup_stack.pop(), '<AST_Section2_Rule_Action>')
-        piece_append('</AST_Section2_Rule_Action>')
-        return ord('\n')
-  }
-}
-
-
-       /* Reject and YYmore() are checked for above, in PERCENT_BRACE_ACTION */
-<ACTION>{
-  "{" {
-    global bracelevel
-    #add_action(yytext)
-    bracelevel += 1
-  }
-  "}" {
-    global bracelevel
-    #add_action(yytext)
-    bracelevel -= 1
-  }
-  [^[:alpha:]_{}\"'/\n\[\]]+   #add_action(yytext)
-  {NAME}                       #add_action(yytext)
-  "'"([^\'\\\n]|\\.)"'"                #add_action(yytext)
-  "'" {
-    #add_action(yytext)
-    BEGIN(CHARACTER_CONSTANT)
-  }
-  \" {
-    #add_action(yytext)
-    BEGIN(ACTION_STRING)
-  }
-  {NL} {
-    global doing_rule_action
-    state.linenum += 1
-    #add_action(yytext)
-    if bracelevel <= 0:
-      BEGIN(SECT2)
-      if doing_rule_action:
-        doing_rule_action = False
-        #add_action('\tYY_BREAK]' ']\n')
-        piece_flush(len(yytext))
-        piece_insert(markup_stack.pop(), '<AST_Text>')
-        piece_append('</AST_Text>')
-        piece_insert(markup_stack.pop(), '<AST_Section2_Rule_Action>')
-        piece_append('</AST_Section2_Rule_Action>')
-        return ord('\n')
-  }
-  .                            #add_action(yytext)
-}
-
-<ACTION_STRING>{
-  [^\[\]\"\\\n]+               #add_action(yytext)
-  \" {
-    #add_action(yytext)
-    BEGIN(ACTION)
-  }
-}
-<CHARACTER_CONSTANT>{
-  [^\[\]\'\\\n]+               #add_action(yytext)
-  \' {
-    #add_action(yytext)
-    BEGIN(ACTION)
-  }
-}
-<ACTION_STRING,CHARACTER_CONSTANT>{
-  (\\\n)*                      #add_action(yytext)
-  \\(\\\n)*.                   #add_action(yytext)
-  {NL} {
-    state.linenum += 1
-    #add_action(yytext)
-    if bracelevel <= 0:
-      BEGIN(SECT2)
-      piece_flush(len(yytext))
-      if doing_rule_action:
-        doing_rule_action = False # Nick added, error in the original?
-        piece_insert(markup_stack.pop(), '<AST_Text>')
-        piece_append('</AST_Text>')
-        piece_insert(markup_stack.pop(), '<AST_Section2_Rule_Action>')
-        piece_append('</AST_Section2_Rule_Action>')
-        return '\n'
-    else:
-      BEGIN(ACTION)
-  }
-  .                            #add_action(yytext)
-}
-
- /* Nick extra rules for action groups */
- /* Nick added: ACTION_GROUP,ELEMENT_GROUP,DOUBLE_QUOTED,SINGLE_QUOTED */
-<COMMENT,CODE_COMMENT,COMMENT_DISCARD,ACTION,ACTION_STRING,CHARACTER_CONSTANT,ACTION_GROUP,ELEMENT_GROUP,DOUBLE_QUOTED,SINGLE_QUOTED><<EOF>> {
-  state.synerr('EOF encountered inside an action')
-  yyterminate()
-}
-
-<EXTENDED_COMMENT,GROUP_WITH_PARAMS,GROUP_MINUS_PARAMS><<EOF>> {
-  state.synerr('EOF encountered inside pattern')
-  yyterminate()
-}
-
-<SECT2,QUOTE,FIRSTCCL,CCL>{ESCSEQ} {
-  y_tab.yylval = state.myesc(yytext)
-  if YY_START() == FIRSTCCL:
-    BEGIN(CCL)
-  return y_tab.CHAR
-}
-
-<SECT3>{
-  {M4QSTART}                   #yyout.write(escaped_qstart)
-  {M4QEND}                     #yyout.write(escaped_qend)
-  [^\[\]]*                     #ECHO()
-  [][]                         #ECHO()
-  <<EOF>> {
-    sectnum = 0
-    piece_pack()
-    return ~YY_NULL
-  }
-}
-<SECT3_NOESCAPE>{
-  {M4QSTART}                   #yyout.write('[' '[{0:s}]' ']'.format(escaped_qstart))
-  {M4QEND}                     #yyout.write('[' '[{0:s}]' ']'.format(escaped_qend))
-  [^][]*                       #ECHO()
-  [][]                         #ECHO()
-  <<EOF>> {
-    sectnum = 0
-    piece_pack()
-    return ~YY_NULL
-  }
-}
-
- /* Nick extra rules for action groups */
-<ACTION_GROUP,ELEMENT_GROUP>{
-  "{" {
-    global bracelevel
-    bracelevel += 1
-  }
-}
-<ACTION_GROUP>{
-  "}" {
-    global bracelevel
-    bracelevel -= 1
-    if bracelevel == 0:
-      yy_pop_state()
-      piece_insert(markup_stack.pop(), '<RegexGroupAction_Text>')
-      piece_append('</RegexGroupAction_Text>')
-      return y_tab.TOK_ACTION_GROUP
-  }
-}
-<ELEMENT_GROUP>{
-  "}" {
-    global bracelevel
-    bracelevel -= 1
-    if bracelevel == 0:
-      yy_pop_state()
-      piece_insert(markup_stack.pop(), '<RegexGroupElement_Text>')
-      piece_append('</RegexGroupElement_Text>')
-      return y_tab.TOK_ELEMENT_GROUP
-  }
-}
-<ACTION_GROUP,ELEMENT_GROUP>{
-  "'"                          yy_push_state(SINGLE_QUOTED)
-  \"                           yy_push_state(DOUBLE_QUOTED)
-  "/*"                         yy_push_state(COMMENT_DISCARD)
-}
-<SINGLE_QUOTED>{
-  [^\[\]\'\\\n]+
-  \'                           yy_pop_state()
-}
-<DOUBLE_QUOTED>{
-  [^\[\]\"\\\n]+
-  \"                           yy_pop_state()
-}
-<SINGLE_QUOTED,DOUBLE_QUOTED>{
-  (\\\n)*
-  \\(\\\n)*.
-}
-<ACTION_GROUP,ELEMENT_GROUP,SINGLE_QUOTED,DOUBLE_QUOTED>{
-  {NL}                         state.linenum += 1
-  .
-}
-
-<*>.|\n                                state.synerr('bad character: {0:s}'.format(yytext))
-
-%%
-
-#def yywrap():
-#  if --num_input_files > 0:
-#    set_input_file(*++input_files)
-#    return 0
-#  else:
-#    return 1
-#
-#def set_input_file(file):
-#  if file and strcmp(file, '-'):
-#    state.infilename = xstrdup(file)
-#    yyin = fopen(infilename, 'r')
-#    if yyin == None:
-#      lerr('can\'t open %s', file)
-#  else:
-#    yyin = stdin
-#    state.infilename = xstrdup('<stdin>')
-#  state.linenum = 1
-
-def piece_append(str):
-  piece.append(str)
-
-def piece_insert(n, str):
-  piece[n:n] = [str]
-
-xml_escape = {'<': '&lt;', '>': '&gt;', '&': '&amp;'}
-def piece_escape(str):
-  piece.append(''.join([xml_escape.get(i, i) for i in str]))
-
-def piece_flush(n):
-  global yytext
-  piece_escape(yytext[:n])
-  yytext = yytext[n:]
-
-def piece_pack():
-  global piece0
-  piece[piece0:] = [''.join(piece[piece0:])]
-  piece0 += 1
-
-def flexscan():
-  result = yylex()
-  if result < 0:
-    return ~result
-  piece_pack()
-  piece_escape(yytext)
-  piece_pack()
-  return result
diff --git a/bootstrap/skel_lex_yy.py b/bootstrap/skel_lex_yy.py
deleted file mode 100644 (file)
index 36c9d57..0000000
+++ /dev/null
@@ -1,287 +0,0 @@
-import bisect
-import sys
-
-# GENERATE SECTION1
-
-# GENERATE STARTCONDDECL
-
-class YYReject(Exception):
-  pass
-
-class YYContinue(Exception):
-  pass
-
-class YYTerminate(Exception):
-  pass
-
-class YYBufferList:
-  def __init__(self, next = None):
-    self.next = next
-
-class YYBufferBlock(YYBufferList):
-  def __init__(self, next = None, pos = 0, text = ''):
-    YYBufferList.__init__(self, next)
-    self.pos = pos
-    self.text = text
-
-class YYBufferState(YYBufferList):
-  def __init__(self, next = None, file_in = None, at_bol = True):
-    YYBufferList.__init__(self, next)
-    self.file_in = file_in
-    self.at_bol = at_bol
-
-yyin = sys.stdin
-yyout = sys.stdout
-yy_buffer_stack = [YYBufferState()]
-
-yystart = INITIAL
-yystart_stack = []
-yy_threads0 = [None]
-yy_threads1 = [None]
-yy_prefix_slop = 1
-
-yy_group_text = None
-yy_group_stack = None
-yy_groups = None
-yy_groups_by_name = None
-yy_action = None
-yytext = ''
-yytext_len = 0
-
-YY_NULL = 0
-
-def REJECT():
-  raise YYReject()
-
-def yyterminate():
-  raise YYTerminate()
-
-def yyless(i):
-  global yytext, yytext_len
-  assert yytext_len >= i
-  yytext = yytext[:i]
-  yytext_len = i
-
-def unput(text):
-  global yyin, yytext_len
-  piece_flush(len(yytext))
-  while yytext_len:
-    block = yy_buffer_stack[-1].next
-    while block is None or block.pos >= len(block.text):
-      if block is None:
-        yy_buffer_stack.pop()
-        block = yy_buffer_stack[-1].next
-        yyin = yy_buffer_stack[-1].file_in
-      else:
-        block = block.next
-        yy_buffer_stack[-1].next = block
-    i = min(yytext_len, len(block.text) - block.pos)
-    block.pos += i
-    yytext_len -= i
-  yy_buffer_stack[-1].next = YYBufferBlock(yy_buffer_stack[-1].next, 0, text)
-
-def ECHO():
-  yyout.write(yytext)
-
-def yy_rule_start():
-  global yytext, yytext_len
-  yytext = yy_group_text[:yy_group_stack[-1]]
-  yytext_len = yy_group_stack[-1]
-  del yy_group_stack[-2:]
-  # note that this should also be done after yyless() and REJECT(),
-  # and state should be saved in case they result in a null string,
-  # however, it doesn't seem to be in flex, maintain compatibility:
-  if len(yytext):
-    yy_buffer_stack[-1].at_bol = yytext[-1] == '\n'
-
-def yy_group_end():
-  pass
-
-def BEGIN(start):
-  global yystart
-  yystart = start
-
-def YY_START():
-  return yystart
-
-def yy_push_state(start):
-  global yystart
-  yystart_stack.append(yystart)
-  yystart = start
-
-def yy_pop_state():
-  global yystart
-  yystart = yystart_stack.pop()
-
-def YY_AT_BOL():
-  return yy_buffer_stack[-1].at_bol
-
-def yy_set_bol(at_bol):
-  yy_buffer_stack[-1].at_bol = at_bol
-
-# GENERATE SECTION2
-
-def yylex():
-  global \
-    yyin, \
-    yy_threads0, \
-    yy_threads1, \
-    yy_prefix_slop, \
-    yy_group_text, \
-    yy_group_stack, \
-    yy_action, \
-    yytext, \
-    yytext_len
-
-  # GENERATE SECTION2INITIAL
-
-  while True:
-    while yytext_len:
-      block = yy_buffer_stack[-1].next
-      while block is None or block.pos >= len(block.text):
-        if block is None:
-          yy_buffer_stack.pop()
-          block = yy_buffer_stack[-1].next
-          yyin = yy_buffer_stack[-1].file_in
-        else:
-          block = block.next
-          yy_buffer_stack[-1].next = block
-      i = min(yytext_len, len(block.text) - block.pos)
-      block.pos += i
-      yytext_len -= i
-
-    match = ''
-    match_len = 0
-
-    del yy_threads0[yy_prefix_slop:]
-    yy_threads0.append(None)
-
-    buffer_ptr = len(yy_buffer_stack) - 1
-    block_prev = yy_buffer_stack[buffer_ptr]
-    block = block_prev.next
-    if block is not None:
-      block_pos = block.pos
-
-    action = yy_dfa_start_action[
-      yystart * 2 + int(yy_buffer_stack[-1].at_bol)
-    ]
-    while action != -1:
-      state, transition = yy_dfa_actions[action]
-      #print('i', i, 'action', action, 'state', state, 'transition', transition)
-
-      i = yy_prefix_slop
-      assert len(yy_threads1) == yy_prefix_slop
-      for trans in transition:
-        if trans[0] == 0: #DFA.TRANSITION_POP:
-          i += trans[1]
-        elif trans[0] == 1: #DFA.TRANSITION_DUP:
-          while i < trans[1]:
-            yy_threads0[:0] = [None] * yy_prefix_slop
-            yy_threads1[:0] = [None] * yy_prefix_slop
-            i += yy_prefix_slop
-            yy_prefix_slop *= 2
-          yy_threads0[i - trans[1]:i] = yy_threads0[i:i + trans[1]]
-          i -= trans[1]
-        elif trans[0] == 2: #DFA.TRANSITION_MARK:
-          yy_threads0[i:i + trans[1]] = [
-            (match_len, trans[2], thread)
-            for thread in yy_threads0[i:i + trans[1]]
-          ]
-        elif trans[0] == 3: #DFA.TRANSITION_MOVE:
-          yy_threads1.extend(yy_threads0[i:i + trans[1]])
-          i += trans[1]
-        #elif trans[0] == DFA.TRANSITION_DEL:
-        #  del yy_threads1[-trans[1]:]
-        else:
-          assert False
-      assert i == len(yy_threads0)
-      yy_threads0, yy_threads1 = yy_threads1, yy_threads0
-      del yy_threads1[yy_prefix_slop:]
-
-      if state == 0:
-        # there is only one match, which is complete
-        assert len(yy_threads0) == yy_prefix_slop + 1
-        assert yy_dfa_states[state][2] == [0]
-        break
-
-      yy_buffer_stack[-1].file_in = yyin
-      while block is None or block_pos >= len(block.text):
-        if block is None:
-          file_in = yy_buffer_stack[buffer_ptr].file_in
-          text = '' if file_in is None else file_in.readline()
-          if len(text):
-            block = YYBufferBlock(None, 0, text)
-            block_pos = 0
-            block_prev.next = block
-          else:
-            # do not re-attempt read once EOF is reached
-            yy_buffer_stack[buffer_ptr].file_in = None
-            yyin = yy_buffer_stack[-1].file_in
-            buffer_ptr -= 1
-            if buffer_ptr < 0:
-              break # EOF
-            block_prev = yy_buffer_stack[buffer_ptr]
-            block = block_prev.next
-            if block is not None:
-              block_pos = block.pos
-        else:
-          i = match_len - len(match)
-          if i:
-            match += block.text[block_pos - i:]
-          block_prev = block
-          block = block_prev.next
-          if block is not None:
-            block_pos = block.pos
-      else: 
-        #print('block_pos', block_pos, 'block.text', block.text)
-        action = yy_dfa_states[state][1][
-          bisect.bisect_right(
-            yy_dfa_states[state][0],
-            ord(block.text[block_pos])
-          )
-        ]
-        block_pos += 1
-        match_len += 1
-        continue
-      # EOF
-      if i == 0:
-        try:
-          return yy_eof_actions[yystart]()
-        except YYTerminate:
-          return 0
-      break
-
-    i = match_len - len(match)
-    if i:
-      assert block is not None
-      match += block.text[block_pos - i:]
-
-    for i in yy_dfa_states[state][2]:
-      yy_group_text = match
-      yy_group_stack = []
-      yy_groups = None
-      yy_groups_by_name = None
-      yy_action = None
-      yytext = None
-      yytext_len = None
-
-      thread = yy_threads0[yy_prefix_slop + i]
-      #print('thread', thread)
-      while thread is not None:
-        pos, ref_data, thread = thread
-        yy_group_stack.append(pos)
-        ref_data()
-
-      try:
-        return yy_action()
-      except YYReject:
-        pass
-      except YYContinue:
-        piece_escape(yytext)
-        break
-      except YYTerminate:
-        return 0
-    else:
-      raise Exception('scanner jammed')
-
-# GENERATE SECTION3
diff --git a/bootstrap/skel_y_tab.py b/bootstrap/skel_y_tab.py
deleted file mode 100644 (file)
index b55e87d..0000000
+++ /dev/null
@@ -1,100 +0,0 @@
-# Copyright (C) 2018 Nick Downing <nick@ndcode.org>
-# SPDX-License-Identifier: GPL-2.0-with-bison-exception
-#
-# This program is free software; you can redistribute it and/or modify it under
-# the terms of the GNU General Public License as published by the Free Software
-# Foundation; version 2.
-#
-# This program is distributed in the hope that it will be useful, but WITHOUT
-# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
-# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
-# details.
-#
-# You should have received a copy of the GNU General Public License along with
-# this program; if not, write to the Free Software Foundation, Inc., 51
-# Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
-#
-# As a special exception, you may create a larger work that contains part or
-# all of the Bison or piyacc parser skeleton and distribute that work under
-# terms of your choice, so long as that work isn't itself a parser generator
-# using the skeleton or a modified version thereof as a parser skeleton.
-# Alternatively, if you modify or redistribute the parser skeleton itself, you
-# may (at your option) remove this special exception, which will cause the
-# skeleton and the resulting Bison or piyacc output files to be licensed under
-# the GNU General Public License without this special exception.
-
-import bisect
-import lex_yy
-
-# GENERATE SECTION1
-
-# GENERATE TOKENS
-
-yystack = None
-yychar = None
-YYEMPTY = -1
-
-yyval = None
-yyloc = None
-
-yylval = None
-yylloc = None
-
-# GENERATE SECTION2
-
-def yyparse():
-  global yystack, yychar, yyval, yyloc, yylval, yylloc, piece2, piece3
-
-  # GENERATE INITIALACTION
-
-  state = 0
-  yystack = []
-  yylval = None
-  yychar = -1
-  while True:
-    #print('state', state, 'yystack', yystack)
-    reduce = yy_lr1dfa_states[state][4]
-    if reduce == -1:
-      if yychar == -1:
-        yylval = None
-        yylloc = None
-        yychar = lex_yy.flexscan()
-        #print('yychar', yychar, 'yylval', yylval, 'yylloc', yylloc, 'lex_yy.yytext', lex_yy.yytext)
-      action = yy_lr1dfa_states[state][1][
-        bisect.bisect_right(yy_lr1dfa_states[state][0], yychar)
-      ]
-      if action == -1:
-        raise Exception('syntax error')
-      if (action & 1) == 0:
-        yystack.append((state, yylval, yylloc))
-        state = action >> 1
-        #print('shift', state)
-        yychar = -1
-        continue
-      reduce = action >> 1
-    #print('reduce', reduce)
-    len_symbols, ref_data = yy_lr1dfa_productions[reduce]
-    base = len(yystack) - len_symbols
-    yystack.append((state, None, None))
-    state, yyval, yyloc = yystack[base]
-    n = base * 2
-    piece2 = n + 1
-    piece3 = n + len_symbols * 2
-    if len_symbols == 0:
-      lex_yy.piece[n:n] = ['', '']
-      piece3 = n + 2
-      lex_yy.piece0 += 2
-    ref_data()
-    lex_yy.piece[piece2:piece3] = [''.join(lex_yy.piece[piece2:piece3])]
-    lex_yy.piece0 += piece2 + 1 - piece3
-    del yystack[base:]
-    if reduce == 0:
-      assert base == 0
-      break
-    yystack.append((state, yyval, yyloc))
-    state = yy_lr1dfa_states[state][3][
-      bisect.bisect_right(yy_lr1dfa_states[state][2], reduce)
-    ]
-    assert state != -1
-
-# GENERATE SECTION3
diff --git a/bootstrap/state.py b/bootstrap/state.py
deleted file mode 100644 (file)
index 5608fca..0000000
+++ /dev/null
@@ -1,59 +0,0 @@
-import sys
-
-# miscellaneous state accessed by scan.l and parse.y
-in_rule = False
-lex_compat = False
-nmstr = ''
-no_section3_escape = False
-posix_compat = False
-
-_sf_stk = [0]
-def sf_push():
-  _sf_stk.append(_sf_stk[-1])
-def sf_pop():
-  _sf_stk.pop()
-
-name_defs = {}
-def ndinstal(key, value):
-  if key in name_defs:
-    synerr('name defined twice')
-  else:
-    name_defs[key] = value
-def ndlookup(key):
-  return name_defs.get(key)
-
-infilename = '<stdin>'
-linenum = 1
-def synerr(str):
-  sys.stderr.write(
-    '{0:s}:{1:d}: {2:s}\n'.format(infilename, linenum, str)
-  )
-
-esc = {
-  'b': ord('\b'),
-  'f': ord('\f'),
-  'n': ord('\n'),
-  'r': ord('\r'),
-  't': ord('\t'),
-  'a': ord('\a'),
-  'v': ord('\v')
-}
-def myesc(str):
-  assert str[0] == '\\'
-  result = esc.get(str[1])
-  if result is None:
-    if str[1] == '0':
-      i = 2
-      j = min(5, len(str))
-      while i < j and str[i] in '01234567':
-        i += 1
-      result = int(str[1:i], 8)
-    elif str[1] == 'x':
-      i = 2
-      j = min(4, len(str))
-      while i < j and str[i] in '0123456789ABCDEFabcdef':
-        i += 1
-      result = int(str[2:i], 16)
-    else:
-      result = ord(str[1])
-  return result 
diff --git a/markup.py b/markup.py
deleted file mode 100755 (executable)
index 54ef8ed..0000000
--- a/markup.py
+++ /dev/null
@@ -1,24 +0,0 @@
-#!/usr/bin/env python3
-
-# Copyright (C) 2019 Nick Downing <nick@ndcode.org>
-# SPDX-License-Identifier: GPL-2.0-only
-#
-# This program is free software; you can redistribute it and/or modify it under
-# the terms of the GNU General Public License as published by the Free Software
-# Foundation; version 2.
-#
-# This program is distributed in the hope that it will be useful, but WITHOUT
-# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
-# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
-# details.
-#
-# You should have received a copy of the GNU General Public License along with
-# this program; if not, write to the Free Software Foundation, Inc., 51
-# Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
-
-import t_def
-import element
-import y_tab
-import sys
-
-element.serialize(y_tab.yyparse(t_def.AST), sys.stdout)
diff --git a/n.sh b/n.sh
deleted file mode 100755 (executable)
index b751478..0000000
--- a/n.sh
+++ /dev/null
@@ -1,23 +0,0 @@
-#!/bin/sh
-if ! test -d out
-then
-  mkdir out
-  bootstrap/markup.py <tests/cal.l |./reserialize.py >out/cal.l.xml.ok
-  bootstrap/markup.py <tests_ast/cal_py.l |./reserialize.py >out/cal_py.l.xml.ok
-  bootstrap/markup.py <../bootstrap_flex.git/src/scan.l |./reserialize.py >out/scan.l.xml.ok
-  bootstrap/markup.py <../bootstrap_bison.git/src/scan-code.l |./reserialize.py >out/scan-code.l.xml.ok
-  bootstrap/markup.py <../bootstrap_bison.git/src/scan-gram.l |./reserialize.py >out/scan-gram.l.xml.ok
-  bootstrap/markup.py <../bootstrap_bison.git/src/scan-skel.l |./reserialize.py >out/scan-skel.l.xml.ok
-fi
-./markup.py <tests/cal.l >out/cal.l.xml
-diff -q out/cal.l.xml.ok out/cal.l.xml
-./markup.py <tests_ast/cal_py.l >out/cal_py.l.xml
-diff -q out/cal_py.l.xml.ok out/cal_py.l.xml
-./markup.py <../bootstrap_flex.git/src/scan.l >out/scan.l.xml
-diff -q out/scan.l.xml.ok out/scan.l.xml
-./markup.py <../bootstrap_bison.git/src/scan-code.l >out/scan-code.l.xml
-diff -q out/scan-code.l.xml.ok out/scan-code.l.xml
-./markup.py <../bootstrap_bison.git/src/scan-gram.l >out/scan-gram.l.xml
-diff -q out/scan-gram.l.xml.ok out/scan-gram.l.xml
-./markup.py <../bootstrap_bison.git/src/scan-skel.l >out/scan-skel.l.xml
-diff -q out/scan-skel.l.xml.ok out/scan-skel.l.xml
diff --git a/ndcode/__init__.py b/ndcode/__init__.py
new file mode 100644 (file)
index 0000000..de40ea7
--- /dev/null
@@ -0,0 +1 @@
+__import__('pkg_resources').declare_namespace(__name__)
diff --git a/ndcode/pilex/Makefile b/ndcode/pilex/Makefile
new file mode 100644 (file)
index 0000000..8bb8dd4
--- /dev/null
@@ -0,0 +1,19 @@
+all: element.py lex_yy.py regex.py t_def.py y_tab.py
+
+element.py: ../../bootstrap_pitree/skel/element.py
+       cat $< >$@
+
+lex_yy.py: scan.l ../../skel_lex_yy.py
+       ../../bootstrap_pilex/pilex.py --element --python --skel ../../skel_lex_yy.py $<
+
+regex.py: regex.t ../../skel_t_def.py
+       ../../bootstrap_pitree/pitree.py --python --skel ../../skel_t_def.py -o $@ $<
+
+t_def.py: pilex.t ../../skel_t_def.py
+       ../../bootstrap_pitree/pitree.py --python --skel ../../skel_t_def.py $<
+
+y_tab.py: parse.y ../../skel_y_tab.py
+       ../../bootstrap_piyacc/piyacc.py --element --python --skel ../../skel_y_tab.py $<
+
+clean:
+       rm -f element.py lex_yy.py regex.py t_def.py y_tab.py
diff --git a/ndcode/pilex/__init__.py b/ndcode/pilex/__init__.py
new file mode 100644 (file)
index 0000000..1bb8bf6
--- /dev/null
@@ -0,0 +1 @@
+# empty
similarity index 100%
rename from bisect_set.py
rename to ndcode/pilex/bisect_set.py
diff --git a/ndcode/pilex/cli.py b/ndcode/pilex/cli.py
new file mode 100755 (executable)
index 0000000..ef2b7d9
--- /dev/null
@@ -0,0 +1,91 @@
+#!/usr/bin/env python3
+
+# Copyright (C) 2019 Nick Downing <nick@ndcode.org>
+# SPDX-License-Identifier: GPL-2.0-only
+#
+# This program is free software; you can redistribute it and/or modify it under
+# the terms of the GNU General Public License as published by the Free Software
+# Foundation; version 2.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+# details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program; if not, write to the Free Software Foundation, Inc., 51
+# Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+
+import getopt
+import os
+import sys
+from ndcode.pilex import t_def
+from ndcode.pilex import element
+from ndcode.pilex import generate_flex
+from ndcode.pilex import generate_py
+
+EXIT_SUCCESS = 0
+EXIT_FAILURE = 1
+
+def main():
+  home_dir = os.path.dirname(__file__)
+  try:
+    opts, args = getopt.getopt(
+      sys.argv[1:],
+      'eo:pS:',
+      ['element', 'outfile=', 'python', 'skel=']
+    )
+  except getopt.GetoptError as err:
+    sys.stderr.write('{0:s}\n'.format(str(err)))
+    return EXIT_FAILURE
+
+  out_file = None
+  _element = False
+  python = False
+  skel_file = None
+  for opt, arg in opts:
+    if opt == '-e' or opt == '--element':
+      _element = True
+    elif opt == '-o' or opt == '--outfile':
+      out_file = arg
+    elif opt == '-p' or opt == '--python':
+      python = True
+    elif opt == '-S' or opt == '--skel':
+      skel_file = arg
+    else:
+      assert False
+  if len(args) < 1:
+    sys.stdout.write(
+      'usage: {0:s} [options] rules.l\n'.format(
+        sys.argv[0]
+      )
+    )
+    return EXIT_FAILURE
+  in_file = args[0]
+
+  with open(in_file) as fin:
+    if in_file[-4:] == '.xml':
+      _ast = element.deserialize(fin, t_def.factory)
+    else:
+      from ndcode.pilex import lex_yy
+      from ndcode.pilex import state
+      from ndcode.pilex import y_tab
+      state.infilename = in_file
+      lex_yy.yyin = fin
+      _ast = y_tab.yyparse(t_def.AST)
+  #element.serialize(_ast, 'a.xml', 'utf-8')
+  #_ast = element.deserialize('a.xml', t_def.factory, 'utf-8')
+  _ast.post_process()
+  #element.serialize(_ast, 'b.xml', 'utf-8')
+  #_ast = element.deserialize('b.xml', t_def.factory, 'utf-8')
+  (generate_py.generate_py if python else generate_flex.generate_flex)(
+    _ast,
+    _element,
+    home_dir,
+    skel_file,
+    out_file
+  )
+  return EXIT_SUCCESS
+
+if __name__ == '__main__':
+  sys.exit(main())
similarity index 99%
rename from dfa.py
rename to ndcode/pilex/dfa.py
index 1943fe6..c52b4d7 100644 (file)
--- a/dfa.py
 # Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
 
 import bisect
-#import element
-import flex_dfa
 import numpy
-import numpy_heap
-#import work
 import sys
+#from ndcode.pilex import element
+from ndcode.pilex import flex_dfa
+from ndcode.pilex import numpy_heap
+#from ndcode.pilex import work
 
 # defines the alphabet size, set this to 0x11000 for unicode
 n_characters = 0x100
similarity index 100%
rename from flex_dfa.py
rename to ndcode/pilex/flex_dfa.py
similarity index 99%
rename from generate_flex.py
rename to ndcode/pilex/generate_flex.py
index c99bcf3..d48dc9b 100644 (file)
@@ -15,7 +15,7 @@
 # Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
 
 import os
-import regex
+from ndcode.pilex import regex
 
 def generate_flex(_ast, _element, home_dir, skel_file, out_file):
   # generate group_ref_data which emulates the old way where
similarity index 99%
rename from generate_py.py
rename to ndcode/pilex/generate_py.py
index 718a148..a21c43b 100644 (file)
@@ -15,8 +15,8 @@
 # Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
 
 import os
-import regex
-import wrap_repr
+from ndcode.pilex import regex
+from ndcode.pilex import wrap_repr
 
 def text_to_python(text, indent):
   text_strip = text.strip()
similarity index 99%
rename from nfa.py
rename to ndcode/pilex/nfa.py
index 4cdb477..8582a13 100644 (file)
--- a/nfa.py
@@ -15,8 +15,8 @@
 # Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
 
 import bisect
-import dfa
-#import element
+from ndcode.pilex import dfa
+#from ndcode.pilex import element
 
 # defines the alphabet size, set this to 0x11000 for unicode
 n_characters = 0x100
similarity index 100%
rename from numpy_heap.py
rename to ndcode/pilex/numpy_heap.py
similarity index 99%
rename from parse.y
rename to ndcode/pilex/parse.y
index 802d4e1..266e9c1 100644 (file)
--- a/parse.y
@@ -38,9 +38,9 @@
 
 
 %{
-  import t_def
-  import regex
-  import state
+  from ndcode.pilex import t_def
+  from ndcode.pilex import regex
+  from ndcode.pilex import state
 
   #pat = 0
   #scnum = 0
similarity index 99%
rename from pilex.t
rename to ndcode/pilex/pilex.t
index 320da89..e27c013 100644 (file)
--- a/pilex.t
@@ -17,9 +17,9 @@
  */
 
 %{
-  import nfa
-  import regex
   import sys
+  from ndcode.pilex import nfa
+  from ndcode.pilex import regex
 %}
 
 %%
similarity index 99%
rename from regex.t
rename to ndcode/pilex/regex.t
index 7608205..0ea9985 100644 (file)
--- a/regex.t
@@ -17,9 +17,9 @@
  */
 
 %{
-  import bisect_set
-  import element
-  import nfa
+  from ndcode.pilex import bisect_set
+  from ndcode.pilex import element
+  from ndcode.pilex import nfa
 %}
 
 %%
similarity index 99%
rename from scan.l
rename to ndcode/pilex/scan.l
index f8c1d59..7ab1839 100644 (file)
--- a/scan.l
@@ -1,10 +1,10 @@
 /* scan.l - scanner for flex input -*-C-*- */
 
 %{
-  import t_def
-  import regex
-  import state
-  import y_tab
+  from ndcode.pilex import t_def
+  from ndcode.pilex import regex
+  from ndcode.pilex import state
+  from ndcode.pilex import y_tab
 
   markup_stack = []
 
similarity index 55%
rename from skel/Makefile
rename to ndcode/pilex/skel/Makefile
index d11843c..9175da4 100644 (file)
@@ -1,5 +1,8 @@
 skel_flex.c: skel_flex.l
-       ../../bootstrap_flex.git/src/flex -o $@ $<
+       ../../../../bootstrap_flex/src/flex -o $@ $<
        grep -v "^#line " <$@ >$@.orig
        cp $@.orig $@
        patch $@ <$@.patch
+
+clean:
+       rm -f skel_flex.c
similarity index 100%
rename from skel/skel_py.py
rename to ndcode/pilex/skel/skel_py.py
similarity index 100%
rename from state.py
rename to ndcode/pilex/state.py
similarity index 100%
rename from wrap_repr.py
rename to ndcode/pilex/wrap_repr.py
diff --git a/pilex.py b/pilex.py
deleted file mode 100755 (executable)
index fcb7789..0000000
--- a/pilex.py
+++ /dev/null
@@ -1,83 +0,0 @@
-#!/usr/bin/env python3
-
-# Copyright (C) 2019 Nick Downing <nick@ndcode.org>
-# SPDX-License-Identifier: GPL-2.0-only
-#
-# This program is free software; you can redistribute it and/or modify it under
-# the terms of the GNU General Public License as published by the Free Software
-# Foundation; version 2.
-#
-# This program is distributed in the hope that it will be useful, but WITHOUT
-# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
-# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
-# details.
-#
-# You should have received a copy of the GNU General Public License along with
-# this program; if not, write to the Free Software Foundation, Inc., 51
-# Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
-
-import t_def
-import element
-import generate_flex
-import generate_py
-import getopt
-import os
-import sys
-
-home_dir = os.path.dirname(sys.argv[0])
-try:
-  opts, args = getopt.getopt(
-    sys.argv[1:],
-    'eo:pS:',
-    ['element', 'outfile=', 'python', 'skel=']
-  )
-except getopt.GetoptError as err:
-  sys.stderr.write('{0:s}\n'.format(str(err)))
-  sys.exit(1)
-
-out_file = None
-_element = False
-python = False
-skel_file = None
-for opt, arg in opts:
-  if opt == '-e' or opt == '--element':
-    _element = True
-  elif opt == '-o' or opt == '--outfile':
-    out_file = arg
-  elif opt == '-p' or opt == '--python':
-    python = True
-  elif opt == '-S' or opt == '--skel':
-    skel_file = arg
-  else:
-    assert False
-if len(args) < 1:
-  sys.stdout.write(
-    'usage: {0:s} [options] rules.l\n'.format(
-      sys.argv[0]
-    )
-  )
-  sys.exit(1)
-in_file = args[0]
-
-with open(in_file) as fin:
-  if in_file[-4:] == '.xml':
-    _ast = element.deserialize(fin, t_def.factory)
-  else:
-    import lex_yy
-    import state
-    import y_tab
-    state.infilename = in_file
-    lex_yy.yyin = fin
-    _ast = y_tab.yyparse(t_def.AST)
-#element.serialize(_ast, 'a.xml', 'utf-8')
-#_ast = element.deserialize('a.xml', t_def.factory, 'utf-8')
-_ast.post_process()
-#element.serialize(_ast, 'b.xml', 'utf-8')
-#_ast = element.deserialize('b.xml', t_def.factory, 'utf-8')
-(generate_py.generate_py if python else generate_flex.generate_flex)(
-  _ast,
-  _element,
-  home_dir,
-  skel_file,
-  out_file
-)
diff --git a/reserialize.py b/reserialize.py
deleted file mode 100755 (executable)
index b89b8a6..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-#!/usr/bin/env python3
-
-# Copyright (C) 2019 Nick Downing <nick@ndcode.org>
-# SPDX-License-Identifier: GPL-2.0-only
-#
-# This program is free software; you can redistribute it and/or modify it under
-# the terms of the GNU General Public License as published by the Free Software
-# Foundation; version 2.
-#
-# This program is distributed in the hope that it will be useful, but WITHOUT
-# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
-# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
-# details.
-#
-# You should have received a copy of the GNU General Public License along with
-# this program; if not, write to the Free Software Foundation, Inc., 51
-# Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
-
-import t_def
-import element
-import sys
-
-element.serialize(element.deserialize(sys.stdin, t_def.factory), sys.stdout)
diff --git a/setup.py b/setup.py
new file mode 100755 (executable)
index 0000000..a55c214
--- /dev/null
+++ b/setup.py
@@ -0,0 +1,207 @@
+#!/usr/bin/env python3
+
+import setuptools
+import os.path
+
+here = os.path.abspath(os.path.dirname(__file__))
+
+with open(os.path.join(here, 'README.md'), encoding = 'utf-8') as fin:
+  long_description = fin.read()
+
+setuptools.setup(
+  # This is the name of your project. The first time you publish this
+  # package, this name will be registered for you. It will determine how
+  # users can install this project, e.g.:
+  #
+  # $ pip install sampleproject
+  #
+  # And where it will live on PyPI: https://pypi.org/project/sampleproject/
+  #
+  # There are some restrictions on what makes a valid project name
+  # specification here:
+  # https://packaging.python.org/specifications/core-metadata/#name
+  name = 'pilex', # required
+
+  # Versions should comply with PEP 440:
+  # https://www.python.org/dev/peps/pep-0440/
+  #
+  # For a discussion on single-sourcing the version across setup.py and the
+  # project code, see
+  # https://packaging.python.org/en/latest/single_source_version.html
+  version = '0.0.1', # required
+
+  # This is a one-line description or tagline of what your project does. This
+  # corresponds to the "Summary" metadata field:
+  # https://packaging.python.org/specifications/core-metadata/#summary
+  description='Lexical scanner generator with automatic tree generation', # optional
+
+  # This is an optional longer description of your project that represents
+  # the body of text which users will see when they visit PyPI.
+  #
+  # Often, this is the same as your README, so you can just read it in from
+  # that file directly (as we have already done above)
+  #
+  # This field corresponds to the "Description" metadata field:
+  # https://packaging.python.org/specifications/core-metadata/#description-optional
+  long_description = long_description, # optional
+
+  # Denotes that our long_description is in Markdown; valid values are
+  # text/plain, text/x-rst, and text/markdown
+  #
+  # Optional if long_description is written in reStructuredText (rst) but
+  # required for plain-text or Markdown; if unspecified, "applications should
+  # attempt to render [the long_description] as text/x-rst; charset=UTF-8 and
+  # fall back to text/plain if it is not valid rst" (see link below)
+  #
+  # This field corresponds to the "Description-Content-Type" metadata field:
+  # https://packaging.python.org/specifications/core-metadata/#description-content-type-optional
+  long_description_content_type = 'text/markdown', # optional (see note above)
+
+  # This should be a valid link to your project's main homepage.
+  #
+  # This field corresponds to the "Home-Page" metadata field:
+  # https://packaging.python.org/specifications/core-metadata/#home-page-optional
+  url = 'https://git.ndcode.org/public/pilex.git', # optional
+
+  # This should be your name or the name of the organization which owns the
+  # project.
+  author = 'Nick Downing', # optional
+
+  # This should be a valid email address corresponding to the author listed
+  # above.
+  author_email = 'nick@ndcode.org', # optional
+
+  ## Classifiers help users find your project by categorizing it.
+  ##
+  ## For a list of valid classifiers, see https://pypi.org/classifiers/
+  #classifiers=[ # optional
+  #  # How mature is this project? Common values are
+  #  #   3 - Alpha
+  #  #   4 - Beta
+  #  #   5 - Production/Stable
+  #  'Development Status :: 3 - Alpha',
+
+  #  # Indicate who your project is intended for
+  #  'Intended Audience :: Developers',
+  #  'Topic :: Software Development :: Build Tools',
+
+  #  # Pick your license as you wish
+  #  'License :: OSI Approved :: MIT License',
+
+  #  # Specify the Python versions you support here. In particular, ensure
+  #  # that you indicate whether you support Python 2, Python 3 or both.
+  #  # These classifiers are *not* checked by 'pip install'. See instead
+  #  # 'python_requires' below.
+  #  'Programming Language :: Python :: 2',
+  #  'Programming Language :: Python :: 2.7',
+  #  'Programming Language :: Python :: 3',
+  #  'Programming Language :: Python :: 3.4',
+  #  'Programming Language :: Python :: 3.5',
+  #  'Programming Language :: Python :: 3.6',
+  #  'Programming Language :: Python :: 3.7',
+  #],
+
+  # This field adds keywords for your project which will appear on the
+  # project page. What does your project relate to?
+  #
+  # Note that this is a string of words separated by whitespace, not a list.
+  keywords = 'specification language abstract syntax tree xml', # optional
+
+  # You can just specify package directories manually here if your project is
+  # simple. Or you can use find_packages().
+  #
+  # Alternatively, if you just want to distribute a single Python file, use
+  # the `py_modules` argument instead as follows, which will expect a file
+  # called `my_module.py` to exist:
+  #
+  #   py_modules=["my_module"],
+  #
+  packages = setuptools.find_packages(
+    exclude = ['contrib', 'docs', 'tests']
+  ), # required
+
+  # Specify which Python versions you support. In contrast to the
+  # 'Programming Language' classifiers above, 'pip install' will check this
+  # and refuse to install the project if the version does not match. If you
+  # do not support Python 2, you can simplify this to '>=3.5' or similar, see
+  # https://packaging.python.org/guides/distributing-packages-using-setuptools/#python-requires
+  python_requires = '>=3.5',
+
+  ## This field lists other packages that your project depends on to run.
+  ## Any package you put here will be installed by pip when your project is
+  ## installed, so they must be valid existing projects.
+  ##
+  ## For an analysis of "install_requires" vs pip's requirements files see:
+  ## https://packaging.python.org/en/latest/requirements.html
+  #install_requires = ['peppercorn'], # optional
+
+  ## List additional groups of dependencies here (e.g. development
+  ## dependencies). Users will be able to install these using the "extras"
+  ## syntax, for example:
+  ##
+  ##   $ pip install sampleproject[dev]
+  ##
+  ## Similar to `install_requires` above, these must be valid existing
+  ## projects.
+  #extras_require = { # optional
+  #  'dev': ['check-manifest'],
+  #  'test': ['coverage'],
+  #},
+
+  ## If there are data files included in your packages that need to be
+  ## installed, specify them here.
+  ##
+  ## If using Python 2.6 or earlier, then these have to be included in
+  ## MANIFEST.in as well.
+  #package_data = { # optional
+  #  'sample': ['package_data.dat'],
+  #},
+
+  # Although 'package_data' is the preferred approach, in some case you may
+  # need to place data files outside of your packages. See:
+  # http://docs.python.org/3.4/distutils/setupscript.html#installing-additional-files
+  #
+  # In this case, 'data_file' will be installed into '<sys.prefix>/my_data'
+  data_files = [
+    (
+      'ndcode/pilex/skel',
+      [
+        'ndcode/pilex/skel/skel_flex.c',
+        'ndcode/pilex/skel/skel_py.py',
+        'ndcode/pilex/skel/skel_py_element.py'
+      ]
+    )
+  ], # optional
+
+  # To provide executable scripts, use entry points in preference to the
+  # "scripts" keyword. Entry points provide cross-platform support and allow
+  # `pip` to create the appropriate form of executable for the target
+  # platform.
+  #
+  # For example, the following would provide a command called `sample` which
+  # executes the function `main` from this package when invoked:
+  entry_points = {  # Optional
+    'console_scripts': [
+      'pilex=ndcode.pilex.cli:main',
+    ],
+  },
+
+  ## List additional URLs that are relevant to your project as a dict.
+  ##
+  ## This field corresponds to the "Project-URL" metadata fields:
+  ## https://packaging.python.org/specifications/core-metadata/#project-url-multiple-use
+  ##
+  ## Examples listed include a pattern for specifying where the package tracks
+  ## issues, where the source is hosted, where to say thanks to the package
+  ## maintainers, and where to support the project financially. The key is
+  ## what's used to render the link text on PyPI.
+  #project_urls = { # optional
+  #  'Bug Reports': 'https://github.com/pypa/sampleproject/issues',
+  #  'Funding': 'https://donate.pypi.org',
+  #  'Say Thanks!': 'http://saythanks.io/to/example',
+  #  'Source': 'https://github.com/pypa/sampleproject/',
+  #},
+
+  # Nick
+  namespace_packages = ['ndcode']
+)
index 688fc95..1724c2e 100644 (file)
@@ -25,8 +25,8 @@
 # special exception.
 
 import bisect
-import element
 import sys
+from ndcode.pilex import element
 
 # GENERATE SECTION1
 
diff --git a/skel_t_def.py b/skel_t_def.py
new file mode 100644 (file)
index 0000000..2abb887
--- /dev/null
@@ -0,0 +1,40 @@
+# Copyright (C) 2019 Nick Downing <nick@ndcode.org>
+# SPDX-License-Identifier: GPL-2.0-with-bison-exception
+#
+# This program is free software; you can redistribute it and/or modify it under
+# the terms of the GNU General Public License as published by the Free Software
+# Foundation; version 2.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+# details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program; if not, write to the Free Software Foundation, Inc., 51
+# Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+#
+# As a special exception, you may create a larger work that contains part or
+# all of the pitree class definition skeleton and distribute that work under
+# terms of your choice, so long as that work isn't itself a class definition
+# generator using the skeleton or a modified version thereof as a class
+# definition skeleton. Alternatively, if you modify or redistribute the class
+# definition skeleton itself, you may (at your option) remove this special
+# exception, which will cause the skeleton and the resulting pitree output
+# files to be licensed under the GNU General Public License without this
+# special exception.
+
+import json
+from ndcode.pilex import element
+
+# GENERATE SECTION1
+
+# GENERATE SECTION2
+
+def method(_class):
+  def decorator(func):
+    setattr(_class, func.__name__, func)
+    return func
+  return decorator
+
+# GENERATE SECTION3
diff --git a/skel_y_tab.py b/skel_y_tab.py
new file mode 100644 (file)
index 0000000..0b9f636
--- /dev/null
@@ -0,0 +1,138 @@
+# Copyright (C) 2019 Nick Downing <nick@ndcode.org>
+# SPDX-License-Identifier: GPL-2.0-with-bison-exception
+#
+# This program is free software; you can redistribute it and/or modify it under
+# the terms of the GNU General Public License as published by the Free Software
+# Foundation; version 2.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+# details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program; if not, write to the Free Software Foundation, Inc., 51
+# Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+#
+# As a special exception, you may create a larger work that contains part or
+# all of the piyacc parser skeleton and distribute that work under terms of
+# your choice, so long as that work isn't itself a parser generator using the
+# skeleton or a modified version thereof as a parser skeleton. Alternatively,
+# if you modify or redistribute the parser skeleton itself, you may (at your
+# option) remove this special exception, which will cause the skeleton and the
+# resulting piyacc output files to be licensed under the GNU General Public
+# License without this special exception.
+
+import bisect
+#import xml.etree.ElementTree
+from ndcode.pilex import element
+from ndcode.pilex import lex_yy
+
+# this can be redefined in SECTION1
+class YYLTYPE:
+  def __init__(
+    self,
+    first_line = 0,
+    first_column = 0,
+    last_line = 0,
+    last_column = 0
+  ):
+    self.first_line = first_line
+    self.first_column = first_column
+    self.last_line = last_line
+    self.last_column = last_column
+# GENERATE SECTION1
+
+# GENERATE TOKENS
+
+yystack = None
+yychar = None
+YYEMPTY = -1
+
+yyval = None
+yyloc = None
+
+yylval = None
+yylloc = YYLTYPE()
+
+yy_element_stack = None
+
+# GENERATE SECTION2
+
+def yyparse(factory, *args, **kwargs):
+  global yystack, yychar, yyval, yyloc, yylval, yylloc, yy_element_stack
+
+  # GENERATE INITIALACTION
+
+  state = 0
+  yystack = []
+  yylval = None
+  yychar = -1
+  yy_element_stack = []
+  while True:
+    #print('state', state, 'yystack', yystack)
+    assert len(yy_element_stack) == len(yystack) * 2
+    reduce = yy_lr1dfa_states[state][4]
+    if reduce == -1:
+      if yychar == -1:
+        yylval = None
+        yylloc = YYLTYPE() # temporary until lex_yy updated, should be None
+        yychar = lex_yy.yylex()
+        #print('yychar', yychar, 'yylval', yylval, 'yylloc', yylloc, 'lex_yy.yytext', lex_yy.yytext)
+        #print('lex_yy.yy_element_space')
+        #xml.etree.ElementTree.dump(lex_yy.yy_element_space)
+        #print('lex_yy.yy_element_token')
+        #xml.etree.ElementTree.dump(lex_yy.yy_element_token)
+      action = yy_lr1dfa_states[state][1][
+        bisect.bisect_right(yy_lr1dfa_states[state][0], yychar)
+      ]
+      if action == -1:
+        raise Exception('syntax error')
+      if (action & 1) == 0:
+        yystack.append((state, yylval, yylloc))
+
+        # push space then AST element contiguously onto yy_element_stack
+        # even numbered elements are spaces, odd numbered elements are AST
+        yy_element_stack.extend(
+          [lex_yy.yy_element_space, lex_yy.yy_element_token]
+        )
+
+        state = action >> 1
+        #print('shift', state)
+        yychar = -1
+        continue
+      reduce = action >> 1
+    #print('reduce', reduce)
+    len_symbols, ref_data = yy_lr1dfa_productions[reduce]
+    base = len(yystack) - len_symbols
+    yystack.append((state, None, None))
+    state, yyval, yyloc = yystack[base]
+    ref_data()
+    del yystack[base:]
+    if reduce == 0:
+      assert base == 0
+      break
+    yystack.append((state, yyval, yyloc))
+
+    # action creates empty space in yy_element_stack[base * 2] if needed
+    assert len(yy_element_stack) > base * 2
+
+    # concatenate yy_element_stack[base * 2 + 1:] to a single AST element
+    yy_element_stack[base * 2 + 1:] = [
+      element.concatenate(
+        yy_element_stack[base * 2 + 1:],
+        element.Element
+      )
+    ]
+
+    state = yy_lr1dfa_states[state][3][
+      bisect.bisect_right(yy_lr1dfa_states[state][2], reduce)
+    ]
+    assert state != -1
+
+  # return space then AST then space in the user's choice of element type
+  yy_element_stack.append(lex_yy.yy_element_space)
+  return element.concatenate(yy_element_stack, factory, *args, **kwargs)
+
+# GENERATE SECTION3