summaryrefslogtreecommitdiff
path: root/support/splint/cweb/fo.w
diff options
context:
space:
mode:
Diffstat (limited to 'support/splint/cweb/fo.w')
-rw-r--r--support/splint/cweb/fo.w702
1 files changed, 702 insertions, 0 deletions
diff --git a/support/splint/cweb/fo.w b/support/splint/cweb/fo.w
new file mode 100644
index 0000000000..81694024c3
--- /dev/null
+++ b/support/splint/cweb/fo.w
@@ -0,0 +1,702 @@
+@q Copyright (c) 1990 The Regents of the University of California. @>
+@q All rights reserved. @>
+
+@q This code is derived from software contributed to Berkeley by @>
+@q Vern Paxson. @>
+
+@q The United States Government has rights in this work pursuant @>
+@q to contract no. DE-AC03-76SF00098 between the United States @>
+@q Department of Energy and the University of California. @>
+
+@q This file is part of SPLinT. @>
+
+@q Redistribution and use in source and binary forms, with or without @>
+@q modification, are permitted provided that the following conditions @>
+@q are met: @>
+
+@q 1. Redistributions of source code must retain the above copyright @>
+@q notice, this list of conditions and the following disclaimer. @>
+@q 2. Redistributions in binary form must reproduce the above copyright @>
+@q notice, this list of conditions and the following disclaimer in the @>
+@q documentation and/or other materials provided with the distribution. @>
+
+@q Neither the name of the University nor the names of its contributors @>
+@q may be used to endorse or promote products derived from this software @>
+@q without specific prior written permission. @>
+
+@q THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR @>
+@q IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED @>
+@q WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR @>
+@q PURPOSE. @>
+
+@**The \ifbootstrapmode flex \else\flex\ \fi parser stack.
+\ifbootstrapmode % this is a bootstrap run to generate the tables
+ \input limbo.sty
+ \def\optimization{5}
+ \input yy.sty
+ \modebootstrap
+\else % otherwise set up the pretty printing of tokens
+ \let\hostparsernamespace\flexnamespace
+\fi
+The scanner generator, \flex, uses \bison\ to produce a parser for its
+input language. Its lexer is output by \flex\ itself so both are
+reused to generate the parser and the scanner for pretty printing
+\flex\ input.
+
+This task is made somewhat complicated by the dependence of the \flex\
+input scanner on the correctly placed whitespace\footnote{For example,
+each regular expression definition in section~1 must start at the
+beginning of the line.}, as well as the reliance of the said scanner
+on rather involved state switching. Therefore, making subparsers for
+different fragments of \flex\ input involves not only choosing an
+appropriate subset of grammar rules to correctly process the
+grammatic constructs but also setting up the correct lexer states.
+
+The first subparser is designed to process a complete \flex\
+file. This parser is not currently part of any parser stack and is
+only used for testing. This is the only parser that does not rely on
+any custom adjustments to the lexer state to operate correctly.
+@(fip.yy@>=
+@G
+%{@> @<Preamble for the \flex\ parser@> @=%}
+ @> @<Options for \flex\ parser@> @=
+%union {@> @=}
+%{@> @<Postamble for \flex\ parser@> @=%}
+ @> @<Token definitions for \flex\ input parser@>@=
+%%
+ @> @<Productions for \flex\ parser@> @=
+%%
+@g
+
+@ The selection of options for \bison\ parsers suitable for \splint\
+have been discussed
+\ifbootstrapmode\else\locallink{bison.options}earlier \endlink\fi so we
+list them here without further comments.
+@<Options for \flex\ parser@>=
+@G
+%token-table
+%debug
+%start goal
+@g
+
+@ A parser for section~1 (definitions and declarations). This parser requires a custom
+lexer, as discussed above, to properly set up the state. Short of
+this, the lexer may produce the wrong kind of tokens or even generate
+an error.
+@(ddp.yy@>=
+@G
+%{@> @<Preamble for the \flex\ parser@> @=%}
+ @> @<Options for \flex\ parser@> @=
+%union {@> @=}
+%{@> @<Postamble for \flex\ parser@> @=%}
+ @> @<Token definitions for \flex\ input parser@>@=
+%%
+ @> @<Exclusive productions for \flex\ section~1 parser@> @=
+ @> @<Productions for \flex\ section~1 parser@> @=
+%%
+
+@ A parser for section~2 (rules and actions). This subparser must also
+use a custom set up for its lexer as discussed above.
+@(rap.yy@>=
+@G
+%{@> @<Preamble for the \flex\ parser@> @=%}
+ @> @<Options for \flex\ parser@> @=
+%union {@> @=}
+%{@> @<Postamble for \flex\ parser@> @=%}
+ @> @<Token definitions for \flex\ input parser@>@=
+%%
+ @> @<Special \flex\ section~2 parser productions@> @=
+ @> @<Productions for \flex\ section~2 parser@> @=
+%%
+@g
+
+@ A parser for just the regular expression syntax. A custom
+lexer initialization must precede the use of this parser, as well.
+@(rep.yy@>=
+@G
+%{@> @<Preamble for the \flex\ parser@> @=%}
+ @> @<Options for \flex\ parser@> @=
+%union {@> @=}
+%{@> @<Postamble for \flex\ parser@> @=%}
+ @> @<Token definitions for \flex\ input parser@>@=
+%%
+ @> @<Special productions for regular expressions@> @=
+ @> @<Rules for \flex\ regular expressions@> @=
+%%
+
+@*1 Token and state declarations for the \eatone{flex}\flex\ input scanner.
+Needless to say, the original grammar used by \flex\ was not designed
+with pretty printing in mind (and why would it be?). Instead, efficiency
+was the goal which resulted in a number of lexical constructs being
+processed `on the fly', as the lexer encounters them. Such syntax
+fragments never reach the parser, and would not have a chance to be
+displayed by our routines, unless some grammar extensions and
+alterations were introduced.
+
+To make the pretty printing possible, a number of new tokens have been
+introduced below that are later used in a few altered or entirely new
+grammar productions.
+@<Token definitions for \flex\ input parser@>=
+@G
+%token CHAR NUMBER SECTEND SCDECL XSCDECL NAME PREVCCL EOF_OP
+%token OPTION_OP OPT_OUTFILE OPT_PREFIX OPT_YYCLASS OPT_HEADER OPT_EXTRA_TYPE
+%token OPT_TABLES
+
+%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
+
+@ We introduce an additional option type to capture all the non-parametric options used
+by the \flex\ lexer. The original lexer processes these options at the
+point of recognition, while the typesetting parser needs to be aware of them.
+@<Token definitions for \flex\ input parser@>=
+@G
+%token TOP_OP POINTER_OP ARRAY_OP DEF_OP RE_DEF OPT_OTHER OPT_DEPRECATED
+
+@ {\em \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 {\rm 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, \prodstyle{BEGIN_REPEAT_POSIX} and\/ \prodstyle{END_REPEAT_POSIX}. The lexical scanner chooses
+which tokens to return based on whether {\let\it\itbold\prodstyle{posix\_compat} or \prodstyle{lex\_compat}
+are specified. Specifying either \prodstyle{posix\_compat} or \prodstyle{lex\_compat}} will
+cause \flex\ to parse scanner files as per the \.{AT\&T} and \POSIX-mandated behavior.}
+@<Token definitions for \flex\ input parser@>=
+@G
+%token BEGIN_REPEAT_POSIX END_REPEAT_POSIX BEGIN_REPEAT_FLEX END_REPEAT_FLEX
+
+@*1 The grammar for \eatone{flex}\flex\ input.
+The original grammar has been carefully split into sections to
+facilitate the assembly of various subparsers in the \flex's
+stack. Neither the \flex\ parser nor its scanner are part of the
+bootstrap procedure which simplifies both the input file organization,
+as well as the macro design. Some amount of preprocessing is still
+necessary, however, to extract the state names from the lexer file
+(see \ifbootstrapmode\else\locallink{state.grabbing}above \endlink\fi for the
+explanation). We can nevertheless get away with an empty \Cee\ preamble.
+@<Preamble for the \flex\ parser@>=
+
+@ @<Productions for \flex\ parser@>=
+@G
+@t}\vb{\inline\flatten}{@>
+goal:
+ initlex sect1 sect1end
+ sect2 initforrule {@> @<Assemble a \flex\ input file@> @=}
+ ;
+
+sect1end:
+ SECTEND {@> @<Copy the value@> @=}
+ ;
+
+initlex:
+ {@> @=}
+ ;
+@g
+
+@ @<Assemble a \flex\ input file@>=
+ @[TeX_( "/yy0{/the/yy(2)/the/yy(4)}" );@]@;
+
+@ @<Productions for \flex\ parser@>=
+@<Productions for \flex\ section~1 parser@>@;
+@<Productions for \flex\ section~2 parser@>@;
+
+@ @<Exclusive productions for \flex\ section~1 parser@>=
+@G
+@t}\vb{\inline\flatten}{@>
+goal:
+ sect1 {@> @<Assemble a \flex\ section~1 file@> @=}
+ ;
+
+@ @<Assemble a \flex\ section~1 file@>=
+ @[TeX_( "/table/expandafter{/the/yy(1)}" );@]@;
+
+@ @<Productions for \flex\ section~1 parser@>=
+@G
+sect1:
+ sect1 startconddecl namelist1 {@> @<Add start condition declarations@> @=}
+ | sect1 options {@> @<Add options to section~1@> @=}
+ | {@> @<Create an empty section~1@> @=}
+ | error {@> @<Report an error in section~1 and quit@> @=}
+ ;
+
+startconddecl:
+ SCDECL {@> @<Prepare a state declaration@> @=}
+ | XSCDECL {@> @<Prepare an exclusive state declaration@> @=}
+ ;
+
+namelist1:
+ namelist1 NAME {@> @<Add a name to a list@> @=}
+ | NAME {@> @<Start a \prodstylens{namelist1}{\flexnamespace} with a name@> @=}
+ | error {@> @<Report an error in \prodstylens{namelist1}{\flexnamespace} and quit@> @=}
+ ;
+@g
+
+@ @<Add start condition declarations@>=
+ @[TeX_( "/yy0{/the/yy(1)/nx/flscondecl/the/yy(2){/the/yy(3)}}" );@]@;
+
+@ @<Add options to section~1@>=
+ @[TeX_( "/yy0{/the/yy(1)/the/yy(2)}" );@]@;
+
+@ @<Create an empty section~1@>=
+ @[TeX_( "/yy0{}" );@]@;
+
+@ @<Report an error in section~1 and quit@>=
+ @[TeX_( "/yyerror" );@]@;
+
+@ @<Prepare a state declaration@>=
+ @[TeX_( "/yy0{{s}/the/yy(1)}" );@]@;
+
+@ @<Prepare an exclusive state declaration@>=
+ @[TeX_( "/yy0{{x}/the/yy(1)}" );@]@;
+
+@ @<Add a name to a list@>=
+ @[TeX_( "/yy0{/the/yy(1)/nx/flnamesep{}{}/nx/flname/the/yy(2)}" );@]@;
+
+@ @<Start a \prodstylens{namelist1}{\flexnamespace} with a name@>=
+ @[TeX_( "/yy0{/nx/flname/the/yy(1)}" );@]@;
+
+@ @<Report an error in \prodstylens{namelist1}{\flexnamespace} and quit@>=
+ @[TeX_( "/yyerror" );@]@;
+
+@ @<Productions for \flex\ section~1 parser@>=
+@G
+options:
+ OPTION_OP optionlist {@> @<Start an options list@> @=}
+ | POINTER_OP {@> @<Add a pointer option@> @=}
+ | ARRAY_OP {@> @<Add an array option@> @=}
+ | TOP_OP '\n' {@> @<Add a \prodstylens{\%top}{\flexnamespace} directive@> @=}
+ | DEF_OP RE_DEF {@> @<Add a regular expression definition@> @=}
+ | OPT_DEPRECATED {@> @<Output a deprecated option@> @=}
+ ;
+@t}\vb{\inline\flatten}{@>
+optionlist:
+ optionlist option {@> @<Add an option to a list@> @=}
+ | {@> @<Make an empty option list@> @=}
+ ;
+@t}\vb{\resetf}{@>
+option:
+ OPT_OUTFILE '=' NAME {@> @<Record the name of the output file@> @=}
+ | OPT_EXTRA_TYPE '=' NAME {@> @<Declare an extra type@> @=}
+ | OPT_PREFIX '=' NAME {@> @<Declare a prefix@> @=}
+ | OPT_YYCLASS '=' NAME {@> @<Declare a class@> @=}
+ | OPT_HEADER '=' NAME {@> @<Declare the name of a header@> @=}
+ | OPT_TABLES '=' NAME {@> @<Declare the name for the tables@> @=}
+ | OPT_OTHER {@> @<Output a non-parametric option@> @=}
+ ;
+@g
+
+@ @<Start an options list@>=
+ @[TeX_( "/yy0{/nx/floptions{/the/yy(2)}}" );@]@;
+
+@ @<Add a pointer option@>=
+ @[TeX_( "/yy0{/nx/flptropt/the/yy(1)}" );@]@;
+
+@ @<Add an array option@>=
+ @[TeX_( "/yy0{/nx/flarrayopt/the/yy(1)}" );@]@;
+
+@ @<Add a \prodstylens{\%top}{\flexnamespace} directive@>=
+ @[TeX_( "/yy0{/nx/fltopopt/the/yy(1)/the/yy(2)}" );@]@;
+
+@ @<Add a regular expression definition@>=
+ @[TeX_( "/yy0{/nx/flredef/the/yy(1)/the/yy(2)}" );@]@;
+
+@ @<Add an option to a list@>=
+ @[TeX_( "/yy0{/the/yy(1)/the/yy(2)}" );@]@;
+
+@ @<Make an empty option list@>=
+ @[TeX_( "/yy0{}" );@]@;
+
+@ @<Record the name of the output file@>=
+ @[TeX_( "/yy0{/nx/flopt{file}/the/yy(3)}" );@]@;
+
+@ @<Declare an extra type@>=
+ @[TeX_( "/yy0{/nx/flopt{xtype}/the/yy(3)}" );@]@;
+
+@ @<Declare a prefix@>=
+ @[TeX_( "/yy0{/nx/flopt{prefix}/the/yy(3)}" );@]@;
+
+@ @<Declare a class@>=
+ @[TeX_( "/yy0{/nx/flopt{yyclass}/the/yy(3)}" );@]@;
+
+@ @<Declare the name of a header@>=
+ @[TeX_( "/yy0{/nx/flopt{header}/the/yy(3)}" );@]@;
+
+@ @<Declare the name for the tables@>=
+ @[TeX_( "/yy0{/nx/flopt{tables}/the/yy(3)}" );@]@;
+
+@ @<Output a non-parametric option@>=
+ @[TeX_( "/yy0{/nx/flopt{other}/the/yy(1)}" );@]@;
+
+@ @<Output a deprecated option@>=
+ @[TeX_( "/yy0{/nx/flopt{deprecated}/the/yy(1)}" );@]@;
+
+@ @<Special \flex\ section~2 parser productions@>=
+@G
+goal:
+ sect2 {@> @<Output section~2@> @=}
+ ;
+@g
+
+@ @<Output section~2@>=
+ @[TeX_( "/table/yy(1)" );@]@;
+
+@ This portion of the grammar was changed to make it possible to read the
+action code.
+@<Productions for \flex\ section~2 parser@>=
+@G
+sect2:
+ sect2 scon initforrule flexrule '\n' '\n' {@> @<Add a rule to section~2@> @=}
+ | sect2 scon '{' sect2 '}' {@> @<Add a group of rules to section~2@> @=}
+ | {@> @<Start an empty section~2@> @=}
+ | sect2 '\n' {@> @<Add a bare action@> @=}
+ ;
+@t}\vb{\inline\flatten}{@>
+initforrule:
+ {@> @[TeX_( "/flin@@ruletrue/yylexnext" );@] @=}
+ ;
+@g
+
+@ @<Add a rule to section~2@>=
+ @[TeX_( "/ifflcontinued@@action" );@]@;
+ @[TeX_( " /toksb{/flactionc}" );@]@;
+ @[TeX_( "/else" );@]@;
+ @[TeX_( " /toksb{/flaction}" );@]@;
+ @[TeX_( "/fi" );@]@;
+ @[TeX_( "/toksa/expandafter{/astformat@@flaction}" );@]@; /* capture the formatting action */
+ @[TeX_( "/yypushx{/the/yy(1)/the/toksb{/the/yy(2)}{/the/yy(4)}/the/yy(5)/the/yy(6){/the/toksa}}/on/astarray" );@]@;
+ @[TeX_( "/yy0{/astarraylastcs}" );@]@;
+ @[TeX_( "/let/astformat@@flaction/empty" );@]@; /* reset the format */
+
+@ @<Add a group of rules to section~2@>=
+ @[TeX_( "/yy0{/the/yy(1)/nx/flactiongroup{/the/yy(2)}/the/yy(3){/the/yy(4)}/the/yy(5)}" );@]@;
+
+@ @<Start an empty section~2@>=
+ @[TeX_( "/yy0{}" );@]@;
+
+@ @<Add a bare action@>=
+ @[TeX_( "/yy0{/the/yy(1)/nx/flbareaction/the/yy(2)}" );@]@;
+
+@ @<Productions for \flex\ section~2 parser@>=
+@G
+@t}\vb{\inline\flatten}{@>
+scon_stk_ptr:
+ {@> @=}
+ ;
+@t}\vb{\resetf}{@>
+scon:
+ '<' scon_stk_ptr namelist2 '>' {@> @<Create a list of start conditions@> @=}
+ | '<' '*' '>' {@> @<Create a universal start condition@> @=}
+ | {@> @<Create an empty start condition@> @=}
+ ;
+
+namelist2:
+ namelist2 ',' sconname {@> @<Add a start condition to a list@> @=}
+ | sconname {@> @<Start a list with a start condition name@> @=}
+ | error {@> @<Report an error compiling a start condition list@> @=}
+ ;
+@t}\vb{\inline\flatten}{@>
+sconname:
+ NAME {@> @<Make a \prodstylens{NAME}{\flexnamespace} into a start condition@> @=}
+ ;
+
+@ @<Create a list of start conditions@>=
+ @[TeX_( "/yy0{/nx/flsconlist{/the/yy(1)}{/the/yy(3)}{/the/yy(4)}}" );@]@;
+
+@ @<Create a universal start condition@>=
+ @[TeX_( "/yy0{/nx/flsconuniv/the/yy(3)}" );@]@;
+
+@ @<Create an empty start condition@>=
+ @[TeX_( "/yy0{}" );@]@;
+
+@ @<Add a start condition to a list@>=
+ @[TeX_( "/yy0{/the/yy(1)/nx/flnamesep/the/yy(2)/the/yy(3)}" );@]@;
+
+@ @<Start a list with a start condition name@>=
+ @<Copy the value@>@;
+
+@ @<Report an error compiling a start condition list@>=
+ @[TeX_( "/yyerror" );@]@;
+
+@ @<Make a \prodstylens{NAME}{\flexnamespace} into a start condition@>=
+ @[TeX_( "/yy0{/nx/flname/the/yy(1)}" );@]@;
+
+@ @<Productions for \flex\ section~2 parser@>=
+ @<Rules for \flex\ regular expressions@>@;
+
+@ @<Special productions for regular expressions@>=
+@G
+goal:
+ flexrule {@> @<Output a regular expression@> @=}
+ ;
+@g
+
+@ The parsed regular expression is output in the \.{\\table}
+register. It is important to ensure that whenever this parser is used
+inside another parser that uses \.{\\table} for output, the changes to
+this register stay local. The \.{\\frexproc} macro in \.{yyunion.sty}
+ensures that all the changes are local to the parsing macro.
+@<Output a regular expression@>=
+ @[TeX_( "/table/yy(1)" );@]@;
+
+@ @<Rules for \flex\ regular expressions@>=
+@G
+flexrule:
+ '^' rule {@> @<Match a rule at the beginning of the line@> @=}
+ | rule {@> @<Match an ordinary rule@> @=}
+ | EOF_OP {@> @<Match an end of file@> @=}
+ | error {@> @<Report an error and quit@> @=}
+ ;
+
+@ @<Match a rule at the beginning of the line@>=
+ @[TeX_( "/toksa/expandafter{/astformat@@flrule}" );@]@;
+ @[TeX_( "/let/astformat@@flrule/empty" );@]@;
+ @[TeX_( "/yy0{/nx/flbolrule{/the/yy(2)}{/the/toksa}}" );@]@;
+
+@ @<Match an ordinary rule@>=
+ @[TeX_( "/toksa/expandafter{/astformat@@flrule}" );@]@;
+ @[TeX_( "/let/astformat@@flrule/empty" );@]@;
+ @[TeX_( "/yy0{/nx/flrule{/the/yy(1)}{/the/toksa}}" );@]@;
+
+@ @<Match an end of file@>=
+ @[TeX_( "/yy0{/nx/fleof/the/yy(1)}" );@]@;
+
+@ @<Report an error and quit@>=
+ @[TeX_( "/yyerror" );@]@;
+
+@ @<Rules for \flex\ regular expressions@>=
+@G
+rule:
+ re2 re {@> @<Match a regular expression with a trailing context@> @=}
+ | re2 re '$' {@> @<Disallow a repeated trailing context@> @=}
+ | re '$' {@> @<Match a regular expression at the end of the line@> @=}
+ | re {@> @<Match an ordinary regular expression@> @=}
+ ;
+
+re:
+ re '|' series {@> @<Match a sequence of alternatives@> @=}
+ | series {@> @<Match a sequence of singletons@> @=}
+ ;
+@t}\vb{\inline\flatten}{@>
+re2:
+ re '/' {@> @<Prepare to match a trailing context@> @=}
+ ;
+@g
+
+@ @<Match a regular expression with a trailing context@>=
+ @[TeX_( "/getsecond{/yy(1)}/to/toksa/getthird{/yy(1)}/to/toksb" );@]@;
+ @[TeX_( "/yy0{/nx/flretrail{/the/toksa}{/the/toksb}{/the/yy(2)}}" );@]@;
+
+@ @<Disallow a repeated trailing context@>=
+ @[TeX_( "/yyerror" );@]@;
+
+@ @<Match a regular expression at the end of the line@>=
+ @[TeX_( "/yy0{/nx/flreateol{/the/yy(1)}/the/yy(2)}" );@]@;
+
+@ @<Match an ordinary regular expression@>=
+ @<Copy the value@>@;
+
+@ @<Match a sequence of alternatives@>=
+ @[TeX_( "/yy0{/the/yy(1)/nx/flor/the/yy(2)/the/yy(3)}" );@]@;
+
+@ @<Match a sequence of singletons@>=
+ @<Copy the value@>@;
+
+@ @<Prepare to match a trailing context@>=
+ @[TeX_( "/yy0{/nx/fltrail{/the/yy(1)}{/the/yy(2)}}" );@]@;
+
+@ @<Rules for \flex\ regular expressions@>=
+@G
+series:
+ series singleton {@> @<Extend a series by a singleton@> @=}
+ | singleton {@> @<Match a singleton@> @=}
+ | series BEGIN_REPEAT_POSIX
+ NUMBER ',' NUMBER END_REPEAT_POSIX {@> @<Match a series of specific length@> @=}
+ | series BEGIN_REPEAT_POSIX
+ NUMBER ',' END_REPEAT_POSIX {@> @<Match a series of minimal length@> @=}
+ | series BEGIN_REPEAT_POSIX
+ NUMBER END_REPEAT_POSIX {@> @<Match a series of exact length@> @=}
+ ;
+@g
+
+@ @<Extend a series by a singleton@>=
+ @[TeX_( "/yy0{/the/yy(1)/the/yy(2)}" );@]@;
+
+@ @<Match a singleton@>=
+ @<Copy the value@>@;
+
+@ @<Match a series of specific length@>=
+ @<Create a series of specific length@>@;
+
+@ @<Match a series of minimal length@>=
+ @<Create a series of minimal length@>@;
+
+@ @<Match a series of exact length@>=
+ @<Create a series of exact length@>@;
+
+@ @<Rules for \flex\ regular expressions@>=
+@G
+singleton:
+ singleton '*' {@> @<Create a lazy series match@> @=}
+ | singleton '+' {@> @<Create a nonempty series match@> @=}
+ | singleton '?' {@> @<Create a possible single match@> @=}
+ | singleton BEGIN_REPEAT_FLEX
+ NUMBER ',' NUMBER END_REPEAT_FLEX {@> @<Create a series of specific length@> @=}
+ | singleton BEGIN_REPEAT_FLEX
+ NUMBER ',' END_REPEAT_FLEX {@> @<Create a series of minimal length@> @=}
+ | singleton BEGIN_REPEAT_FLEX
+ NUMBER END_REPEAT_FLEX {@> @<Create a series of exact length@> @=}
+ | '.' {@> @<Match (almost) any character@> @=}
+ | fullccl {@> @<Match a character class@> @=}
+ | PREVCCL {@> @<Match a \prodstylens{PREVCCL}{\flexnamespace}@> @=}
+ | '"' string '"' {@> @<Match a string@> @=}
+ | '(' re ')' {@> @<Match an atom@> @=}
+ | CHAR {@> @<Match a specific character@> @=}
+ ;
+@g
+
+@ @<Create a lazy series match@>=
+ @[TeX_( "/yy0{/nx/flrepeat{/the/yy(1)}}" );@]@;
+
+@ @<Create a nonempty series match@>=
+ @[TeX_( "/yy0{/nx/flrepeatstrict{/the/yy(1)}}" );@]@;
+
+@ @<Create a possible single match@>=
+ @[TeX_( "/yy0{/nx/flrepeatonce{/the/yy(1)}}" );@]@;
+
+@ @<Create a series of specific length@>=
+ @[TeX_( "/yy0{/nx/flrepeatnm{/the/yy(1)}{/the/yy(3)}{/the/yy(5)}}" );@]@;
+
+@ @<Create a series of minimal length@>=
+ @[TeX_( "/yy0{/nx/flrepeatgen{/the/yy(1)}{/the/yy(3)}}" );@]@;
+
+@ @<Create a series of exact length@>=
+ @[TeX_( "/yy0{/nx/flrepeatn{/the/yy(1)}{/the/yy(3)}}" );@]@;
+
+@ @<Match (almost) any character@>=
+ @[TeX_( "/yy0{/nx/fldot/the/yy(1)}" );@]@;
+
+@ @<Match a character class@>=
+ @<Copy the value@>@;
+
+@ @<Match a \prodstylens{PREVCCL}{\flexnamespace}@>=
+ @<Copy the value@>@;
+
+@ @<Match a string@>=
+ @[TeX_( "/yy0{/nx/flstring{/the/yy(1)}{/the/yy(2)}{/the/yy(3)}}" );@]@;
+
+@ @<Match an atom@>=
+ @[TeX_( "/toksa/expandafter{/astformat@@flparens}" );@]@;
+ @[TeX_( "/let/astformat@@flparens/empty" );@]@;
+ @[TeX_( "/yy0{/nx/flparens{/the/yy(1)}{/the/yy(2)}{/the/yy(3)}{/the/toksa}}" );@]@;
+
+@ @<Match a specific character@>=
+ @[TeX_( "/yy0{/nx/flchar/the/yy(1)}" );@]@;
+
+@ @<Rules for \flex\ regular expressions@>=
+@G
+fullccl:
+ fullccl CCL_OP_DIFF braceccl {@> @<Subtract a character class@> @=}
+ | fullccl CCL_OP_UNION braceccl {@> @<Create a union of character classes@> @=}
+ | braceccl {@> @<Turn a basic character class into a character class@> @=}
+ ;
+
+braceccl:
+ '[' ccl ']' {@> @<Create a character class@> @=}
+ | '[' '^' ccl ']' {@> @<Create a complementary character class@> @=}
+ ;
+
+ccl:
+ ccl CHAR '-' CHAR {@> @<Add a range to a character class@> @=}
+ | ccl CHAR {@> @<Add a character to a character class@> @=}
+ | ccl ccl_expr {@> @<Add an expression to a character class@> @=}
+ | {@> @<Create an empty character class@> @=}
+ ;
+@g
+
+@ @<Subtract a character class@>=
+ @[TeX_( "/yy0{/nx/flccldiff{/the/yy(1)}{/the/yy(3)}}" );@]@;
+
+@ @<Create a union of character classes@>=
+ @[TeX_( "/yy0{/nx/flcclunion{/the/yy(1)}{/the/yy(3)}}" );@]@;
+
+@ @<Turn a basic character class into a character class@>=
+ @<Copy the value@>@;
+
+@ @<Create a character class@>=
+ @[TeX_( "/yy0{/nx/flbraceccl{/the/yy(1)}{/the/yy(2)}{/the/yy(3)}}" );@]@;
+
+@ @<Create a complementary character class@>=
+ @[TeX_( "/yy0{/nx/flbracecclneg{/the/yy(1)}{/the/yy(3)}{/the/yy(4)}}" );@]@;
+
+@ @<Add a range to a character class@>=
+ @[TeX_( "/yy0{/the/yy(1)/nx/flcclrnge{/nx/flchar/the/yy(2)}{/nx/flchar/the/yy(4)}}" );@]@;
+
+@ @<Add a character to a character class@>=
+ @[TeX_( "/yy0{/the/yy(1)/nx/flchar/the/yy(2)}" );@]@;
+
+@ @<Add an expression to a character class@>=
+ @[TeX_( "/yy0{/the/yy(1)/nx/flcclexpr/the/yy(2)}" );@]@;
+
+@ @<Create an empty character class@>=
+ @[TeX_( "/yy0{}" );@]@;
+
+@ @<Rules for \flex\ regular expressions@>=
+@G
+ccl_expr:
+@t}\vb{\flatten}{@>
+ CCE_ALNUM {@> @<Copy the value@> @=}
+ | CCE_ALPHA {@> @<Copy the value@> @=}
+ | CCE_BLANK {@> @<Copy the value@> @=}
+ | CCE_CNTRL {@> @<Copy the value@> @=}
+ | CCE_DIGIT {@> @<Copy the value@> @=}
+ | CCE_GRAPH {@> @<Copy the value@> @=}
+ @t}\vb{\fold\flatten}{@>
+ | CCE_LOWER {@> @<Copy the value@> @=}
+ | CCE_PRINT {@> @<Copy the value@> @=}
+ | CCE_PUNCT {@> @<Copy the value@> @=}
+ | CCE_SPACE {@> @<Copy the value@> @=}
+ | CCE_XDIGIT {@> @<Copy the value@> @=}
+ | CCE_UPPER {@> @<Copy the value@> @=}
+@t}\vb{\fold\flatten}{@>
+ | CCE_NEG_ALNUM {@> @<Copy the value@> @=}
+ | CCE_NEG_ALPHA {@> @<Copy the value@> @=}
+ | CCE_NEG_BLANK {@> @<Copy the value@> @=}
+ | CCE_NEG_CNTRL {@> @<Copy the value@> @=}
+ | CCE_NEG_DIGIT {@> @<Copy the value@> @=}
+ | CCE_NEG_GRAPH {@> @<Copy the value@> @=}
+ @t}\vb{\fold\flatten}{@>
+ | CCE_NEG_PRINT {@> @<Copy the value@> @=}
+ | CCE_NEG_PUNCT {@> @<Copy the value@> @=}
+ | CCE_NEG_SPACE {@> @<Copy the value@> @=}
+ | CCE_NEG_XDIGIT {@> @<Copy the value@> @=}
+ | CCE_NEG_LOWER {@> @<Copy the value@> @=}
+ | CCE_NEG_UPPER {@> @<Copy the value@> @=}
+ ;
+@t}\vb{\inline}{@>
+string:
+ string CHAR {@> @<Extend a \flex\ string by a character@> @=}
+ | {@> @<Make an empty regular expression string@> @=}
+ ;
+@g
+
+@ @<Copy the value@>=
+ @[TeX_( "/yy0{/the/yy(1)}" );@]@;
+
+@ @<Extend a \flex\ string by a character@>=
+ @[TeX_( "/yy0{/the/yy(1)/nx/flchar/the/yy(2)}" );@]@;
+
+@ @<Make an empty regular expression string@>=
+ @[TeX_( "/yy0{}" );@]@;
+
+@ This is needed to get the |yytoknum| array. A trivial declaration suffices.
+@<Postamble for \flex\ parser@>=
+#define YYPRINT(file, type, value) @[yyprint (file, type, value)@]
+ static void yyprint (FILE *file, int type, YYSTYPE value){}