summaryrefslogtreecommitdiff
path: root/support/splint/examples
diff options
context:
space:
mode:
Diffstat (limited to 'support/splint/examples')
-rw-r--r--support/splint/examples/count/count.sty552
-rw-r--r--support/splint/examples/expression/Makefile59
-rw-r--r--support/splint/examples/expression/etoks.sty3
-rw-r--r--support/splint/examples/expression/expression.sty25
-rw-r--r--support/splint/examples/expression/expression.w262
-rw-r--r--support/splint/examples/ld/Makefile118
-rw-r--r--support/splint/examples/ld/ldfrontmatter.sty2
-rw-r--r--support/splint/examples/ld/ldgram.w1083
-rw-r--r--support/splint/examples/ld/ldgramo.w1645
-rw-r--r--support/splint/examples/ld/ldint.sty259
-rw-r--r--support/splint/examples/ld/ldlex.w550
-rw-r--r--support/splint/examples/ld/ldlexo.w763
-rw-r--r--support/splint/examples/ld/ldman.w572
-rw-r--r--support/splint/examples/ld/ldnp.w362
-rw-r--r--support/splint/examples/ld/ldnump.w306
-rw-r--r--support/splint/examples/ld/ldunion.sty351
-rw-r--r--support/splint/examples/ld/lstokenset.sty23
-rw-r--r--support/splint/examples/ld/ltokenset.sty91
-rw-r--r--support/splint/examples/symbols/Makefile37
-rw-r--r--support/splint/examples/symbols/symbols.w193
-rw-r--r--support/splint/examples/symbols/symmap.sty164
-rw-r--r--support/splint/examples/symbols/symtoks.sty8
-rw-r--r--support/splint/examples/types/basic.sty464
-rw-r--r--support/splint/examples/types/test.sty63
-rw-r--r--support/splint/examples/types/tree.sty190
-rw-r--r--support/splint/examples/xxpression/Makefile74
-rw-r--r--support/splint/examples/xxpression/xtoks.sty2
-rw-r--r--support/splint/examples/xxpression/xxpression.sty27
-rw-r--r--support/splint/examples/xxpression/xxpression.w365
-rw-r--r--support/splint/examples/xxpression/xymmap.sty155
30 files changed, 8768 insertions, 0 deletions
diff --git a/support/splint/examples/count/count.sty b/support/splint/examples/count/count.sty
new file mode 100644
index 0000000000..bb8998e64f
--- /dev/null
+++ b/support/splint/examples/count/count.sty
@@ -0,0 +1,552 @@
+% the sequences in this file have the eventual goal of implementing macros that count and compare token sequences
+% (as either parameters or contents of token registers) in expandable manner.
+% currently, a new sequence is prepared first, consisting of `markers'
+% that indicate whether the token in the coresponding position of the
+% original sequence is a potential blank space or brace (closing or
+% opening);
+% the macros then make the determination about the last possible blank
+% on whether this is a true space or not; the goal is to make this
+% macro independent of the value of \escapechar
+%
+% as of now the implementation is far from refined although an expandable conting macro
+% can be easily produced
+
+\catcode`\@=11
+\input ../../tex/yycommon.sty
+\input ../../tex/yymisc.sty
+
+%%%%%%%%%%%%% the material before this point should be included from appropriate files
+
+% #1 -- `call stack'
+% #2 -- remaining sequence
+% #3 -- `parsed' sequence
+
+\def\yypreparsetokensequenc@#1#2#3{%
+ \yystringempty{#2}{#1{#3}}{\yypreparsetokensequen@@{#1}{#2}{#3}}%
+}
+
+\def\yypreparsetokensequen@@#1#2#3{% remaining sequence is nonempty
+ \yystartsinbrace{#2}{\yydealwithbracedgroup{#1}{#2}{#3}}{\yypreparsetokensequ@n@@{#1}{#2}{#3}}%
+}
+
+\def\yydealwithbracedgroup#1#2#3{% the first token of the remaining sequence is a brace
+ \iffalse{\fi\yydealwithbracedgro@p#2}{#1}{#3}%
+}
+
+\def\yydealwithbracedgro@p#1{%
+ \yypreparsetokensequenc@{\yyrepackagesequence}{#1}{}%
+}
+
+% #1 -- parsed sequence
+% this is a sequence to `propagate expansion' into the next parameter.
+% the same can be achieved by packaging the whole sequence with a
+% \csname ... \endcsname pair and using a simple \expandafter
+
+\def\yyrepackagesequence#1{%
+ \yyrepackagesequenc@{}#1\end
+}
+
+% #1 -- `packaged' sequence (\expandafter\expandafter\expandafter ? ...)
+% #2 -- the next category 12 character or \end
+
+\def\yyrepackagesequenc@#1#2{%
+ \ifx#2\end
+ \yybreak{\yyrepackagesequ@nc@{#1\expandafter\expandafter\expandafter}}%
+ \else
+ \yybreak{\yyrepackagesequenc@{#1\expandafter\expandafter\expandafter#2}}%
+ \yycontinue
+}
+
+% #1 -- `packaged' sequence (\expandafter\expandafter\expandafter ? ...)
+% this macro is followed by the remainder of the original sequence with a so far
+% unmatched right brace, the `call stack' and the parsed sequence.
+
+\def\yyrepackagesequ@nc@#1{%
+ \expandafter\expandafter\expandafter\yyrepackagesequ@nc@swap#1{\expandafter\eatone\string}%
+}
+
+% #1 -- parsed sequence without packaging
+
+\def\yyrepackagesequ@nc@swap#1#{%
+ \yyrepackagesequ@nc@sw@p{#1}%
+}
+
+% #1 -- parsed `inner' sequence
+% #2 -- remainder of the original sequence
+% #3 -- `call stack'
+% #4 -- parsed sequence so far
+
+\def\yyrepackagesequ@nc@sw@p#1#2#3#4{%
+ \yypreparsetokensequenc@{#3}{#2}{#4[#1]}%
+}
+
+% `braced group' thread ends here
+
+% #1 -- `call stack'
+% #2 -- remaining sequence
+% #3 -- `parsed' sequence
+
+\def\yypreparsetokensequ@n@@#1#2#3{% the remaining group in #2 is nonempty and does not start with a brace
+ \yystartsinspace{#2}{\yyconsumetruespace{#1}{#2}{#3}}{\yypreparsetokenseq@@n@@{#1}{#2}{#3}}%
+}
+
+\def\yyconsumetruespace#1#2#3{%
+ \expandafter\yyconsumetruespac@swap\expandafter{\eatonespace#2}{#1}{#3.}%
+}
+
+\def\yyconsumetruespac@swap#1#2#3{%
+ \yypreparsetokensequenc@{#2}{#1}{#3}%
+}
+
+% `group starting with a true (character code 32, category code 10) space' thread ends here
+
+% #1 -- `call stack'
+% #2 -- remaining sequence
+% #3 -- `parsed' sequence
+
+\def\yypreparsetokenseq@@n@@#1#2#3{% a nonempty group, that does not start with a brace or a true space
+ \yymatchblankspace{#2}{\yyrescanblankspace{#2}{#1}{#3}}{\yypreparsetokens@q@@n@@{#1}{#2}{#3}}%
+}
+
+% #1 -- remaining sequence
+% #2 -- `call stack'
+% #3 -- `parsed' sequence
+
+\def\yyrescanblankspace#1#2#3{%
+ \expandafter\expandafter\expandafter
+ \yyrescanblankspac@swap
+ \expandafter\expandafter\expandafter{\expandafter\yynormalizeblankspac@\meaning#1}{#2}{#3*}%
+}
+
+\def\yyrescanblankspac@swap#1#2#3{%
+ \yystartsinspace{#1}{%
+ \expandafter\yyrescanblankspac@sw@p\expandafter{\eatonespace#1}{#2}{#3}%
+ }{%
+ \expandafter\yyrescanblankspac@sw@p\expandafter{\eatone#1}{#2}{#3}%
+ }%
+}
+
+\def\yyrescanblankspac@sw@p#1#2#3{%
+ \yypreparsetokensequenc@{#2}{#1}{#3}%
+}
+
+% `group starting with a blank space' ends here
+
+% #1 -- `call stack'
+% #2 -- remaining sequence
+% #3 -- `parsed' sequence
+
+\def\yypreparsetokens@q@@n@@#1#2#3{% nonempty group starting with a non blank, non brace token
+ \expandafter\yypreparsetokens@q@@n@@swap\expandafter{\eatone#2}{#1}{#30}%
+}
+
+\def\yypreparsetokens@q@@n@@swap#1#2#3{%
+ \yypreparsetokensequenc@{#2}{#1}{#3}%
+}
+
+% #1 -- `call stack'
+% #2 -- remaining sequence
+% #3 -- `parsed' sequence
+
+\def\yydebracesequence#1#2#3{%
+ \yybracesleft#3[\end{#1}{#2}%
+}
+
+% #1 -- tokens preceding the brace
+% #2 -- tokens following the brace
+% #3 -- `call stack'
+% #4 -- remaining sequence
+
+\def\yybracesleft#1[#2\end#3#4{%
+ \if9#29%
+ \yybreak{\yyfirstoftwo}%
+ \else
+ \yybreak{\yysecondoftwo}%
+ \yycontinue{#3{#4}}{\yydebracesequenc@swap{#4}{#3}{#1#2}}%
+}
+
+\def\yydebracesequenc@swap#1#2#3{%
+ \expandafter\expandafter\expandafter
+ \yydebracesequenc@sw@p
+ \expandafter\expandafter\expandafter{\yygrabprebrace#1}{#2}{#3}%
+}
+
+\def\yydebracesequenc@sw@p#1#2#3{%
+ \yydebracesequ@nc@sw@p#3\end{#1}{#2}%
+}
+
+\def\yydebracesequ@nc@sw@p#1[\end#2#3{%
+ \yydebracesequence{#3}{#2}{#1}%
+}
+\def\yygrabprebrace#1#{%
+ \yygrabprebrac@{#1}%
+}
+
+\def\yygrabprebrac@#1#2{#1#2}
+
+% the `debracing group' ends here
+
+% string comparison macros below are woefully inefficient and can be replaced by a much
+% shorter and faster version; they are easy to analyze, though;
+
+% #1 -- string of category code 12 or 10 characters
+% #2 -- string of category code 12 or 10 characters
+
+\def\yycomparesimplestrings#1#2{%
+ \yystringempty{#1}{%
+ \yystringempty{#2}{\yyfirstoftwo}{\yysecondoftwo}%
+ }{\yycomparesimplestrings@{#1}{#2}}%
+}
+
+\def\yycomparesimplestrings@#1#2{% the first string is nonempty
+ \yystringempty{#2}{\yysecondoftwo}{\yycomparesimplestrings@@{#1}{#2}}%
+}
+
+\def\yycomparesimplestrings@@#1#2{% both strings are nonempty
+ \yystartsinspace{#1}{%
+ \yystartsinspace{#2}{\yyabsorbfirstspace{#1}{#2}}{\yysecondoftwo}%
+ }{%
+ \yystartsinspace{#2}{\yysecondoftwo}{\yyabsorbfirstnonspace{#1}{#2}}%
+ }
+}
+
+\def\yyabsorbfirstspace#1#2{%
+ \expandafter\yyabsorbfirstspac@swap\expandafter{\eatonespace#1}{#2}%
+}
+
+\def\yyabsorbfirstspac@swap#1#2{%
+ \expandafter\yyabsorbfirst@swap\expandafter{\eatonespace#2}{#1}%
+}
+
+\def\yyabsorbfirstnonspace#1#2{%
+ \expandafter\yyabsorbfirstnonspac@swap\expandafter{\eatone#1}{#2}%
+}
+
+\def\yyabsorbfirstnonspac@swap#1#2{%
+ \expandafter\yyabsorbfirst@swap\expandafter{\eatone#2}{#1}%
+}
+
+\def\yyabsorbfirst@swap#1#2{%
+ \yycomparesimplestrings{#2}{#1}%
+}
+
+% `compare strings of category code 12' thread ends here
+
+% #1 -- a balanced sequence of tokens
+% #2 -- a `parsed version' of the same sequence
+%
+% #1 should be such that \eatone#1 does not lead to an immediate error
+
+\def\yycomparetailsignatures#1#2{%
+ \yypreparsetokensequenc@{\yycomparesimplestrings{#2}}{#1}{}%
+}
+
+% #1 -- `call stack'
+% #2 -- remaining sequence
+% #3 -- remaining parsed sequence
+% #4 -- resolved sequence
+
+\def\yyresolvespaces#1#2#3#4{%
+ \yystringempty{#2}{#1{#4}}{\yyresolveoneblank#3\end{#2}{#4}{#1}}%
+}
+
+\def\yyresolveoneblank#1{%
+ \if#1*%
+ \expandafter\yyfirstoftwo
+ \else
+ \expandafter\yysecondoftwo
+ \fi
+ {\yyresolveonebl@nk}{%
+ \ifx#1.%
+ \expandafter\yyfirstoftwo
+ \else
+ \expandafter\yysecondoftwo
+ \fi
+ {\yyresolveonebl@nk}%
+ {\yyconsumebothnonblanks}%
+ }%
+}
+
+% #1 -- the remainder of the parsed sequence
+% #2 -- remaining sequence
+% #3 -- resolved sequence
+
+\def\yyresolveonebl@nk#1\end#2#3{%
+ \expandafter\yycomparetailsignatures\expandafter{\eatone#2}{#1}%
+ {\expandafter\yyresolvespac@sswap\expandafter{\eatone#2}{#1}{#3+}}%
+ {\expandafter\yyresolveonebl@nklight\expandafter{\eatone#2}{#1}{#3-}}%
+}
+
+% #1 -- remaining sequence
+% #2 -- remaining parsed sequence
+% #3 -- resolved sequence
+% #4 -- `call stack'
+
+\def\yyresolvespac@sswap#1#2#3#4{%
+ \yyresolvespaces{#4}{#1}{#2}{#3}%
+}
+
+\def\yyconsumebothnonblanks#1\end#2#3{%
+ \expandafter\yyconsumebothnonblanksswap\expandafter{\eatone#2}{#1}{#30}%
+}
+
+\def\yyconsumebothnonblanksswap#1#2#3#4{%
+ \yyresolvespaces{#4}{#1}{#2}{#3}%
+}
+
+% #1 -- remaining sequence
+% #2 -- the remainder of the parsed sequence
+% #3 -- resolved sequence
+
+\def\yyresolveonebl@nklight#1#2#3{%
+ \yyresolveonebl@nklighttest#2\end{#1}{#3}%
+}
+
+\def\yyresolveonebl@nklighttest#1#2\end#3#4{%
+ \yycomparetailsignatures{#3}{#2}%
+ {%
+ \if#1*%
+ \expandafter\yyfirstoftwo
+ \else
+ \expandafter\yysecondoftwo
+ \fi
+ {\yyresolvespac@sswap{#3}{#2}{#4+}}%
+ {\yyresolvespac@sswap{#3}{#2}{#40}}%
+ }%
+ {\yyresolveonebl@nklight{#3}{#2}{#4-}}%
+}
+
+% `space resolution code' ends here
+
+% #1 -- remaining parsed sequence
+% #2 -- analysed sequence
+
+\def\yyanalysetokens@#1#2{%
+ \yystringempty{#1}{{#2}}%
+ {\yyanalysetok@ns@#1\end{#2}}%
+}
+
+\def\yyanalysetok@ns@#1#2\end{%
+ \ifx#1.%
+ \expandafter\yyfirstoftwo
+ \else
+ \expandafter\yysecondoftwo
+ \fi
+ {\yygrabablank{#2}}%
+ {%
+ \ifx#1[% not a space, an opening brace
+ \expandafter\yyfirstoftwo
+ \else
+ \expandafter\yysecondoftwo
+ \fi
+ {%
+ \yydisableobrace{#2}%
+ }{%
+ \ifx#1]% not a space, a closing brace
+ \expandafter\yyfirstoftwo
+ \else
+ \expandafter\yysecondoftwo
+ \fi
+ {%
+ \yydisablecbrace{#2}%
+ }{% neither space nor brace
+ \yygrabtokenraw{#2}%
+ }%
+ }%
+ }%
+}
+
+% #1 -- remaining parsed sequence
+% #2 -- analysed sequence
+% #3 -- next token
+
+\def\yygrabtokenraw#1#2#3{%
+ \expandafter\yyanalysetokens@swap\expandafter{\meaning#3}{#1}{#2}%
+}
+
+\def\yyanalysetokens@swap#1#2#3{%
+ \yyanalysetokens@{#2}{#3t#1e}%
+}
+
+\def\yygrabablank#1#2 {%
+ \yyanalysetokens@{#1}{#2s0e}%
+}
+
+% #1 -- remaining parsed sequence
+% #2 -- analysed sequence
+
+\def\yydisablecbrace#1#2{%
+ \yydisablecbrac@{}#1\relax#2\end
+}
+
+
+\def\yydisablecbrac@#1#2{%
+ \ifx#2\end
+ \yybreak{\yydisablecbrac@@{#1\expandafter\expandafter\expandafter}}%
+ \else
+ \yybreak{\yydisablecbrac@{#1\expandafter\expandafter\expandafter#2}}%
+ \yycontinue
+}
+
+\def\yydisablecbrac@@#1{%
+ \expandafter\expandafter\expandafter
+ \yydisablecbrace@@@#1\end
+ \expandafter\expandafter\expandafter
+ {\iffalse}\fi\string
+}
+
+\def\yydisablecbrace@@@#1\relax#2\end#3{%
+ \yystartsinspace{#3}%
+ {\expandafter\yyanalysetok@nsswap\expandafter{\eatonespace#3}{#1}{#2c1e}}%
+ {\expandafter\yyanalysetok@nsswap\expandafter{\eatone#3}{#1}{#2c2e}}%
+}
+
+\def\yyanalysetok@nsswap#1#2#3{%
+ \iffalse{\fi\yyanalysetokens@{#2}{#3}#1}%
+}
+
+% #1 -- remaining parsed sequence
+% #2 -- analysed sequence
+
+\def\yydisableobrace#1#2{%
+ \yydisableobrac@{}#1\relax#2\end
+}
+
+
+\def\yydisableobrac@#1#2{%
+ \ifx#2\end
+ \yybreak{\yydisableobrac@@{#1\expandafter\expandafter\expandafter}}%
+ \else
+ \yybreak{\yydisableobrac@{#1\expandafter\expandafter\expandafter#2}}%
+ \yycontinue
+}
+
+\def\yydisableobrac@@#1{%
+ \expandafter\expandafter\expandafter
+ \yydisableobrace@@@#1\end
+ \expandafter\expandafter\expandafter
+ {\iffalse}\fi\string
+}
+
+\def\yydisableobrace@@@#1\relax#2\end#3{%
+ \yystartsinspace{#3}%
+ {\expandafter\yyanalysetok@nsswap\expandafter{\eatonespace#3}{#1}{#2o1e}}%
+ {\expandafter\yyanalysetok@nsswap\expandafter{\eatone#3}{#1}{#2o2e}}%
+}
+
+% \ifx1\expandafter\eatone\string\11% check if \escapechar is nontrivial
+
+\uccode`\ =`\-
+
+\uppercase{\def\dotspace{ }}
+
+\toksa\expandafter\expandafter\expandafter{\expandafter\meaning\dotspace}
+
+\toksb{-}
+
+\toksc{#2}
+
+\toksd\toksa
+
+\yyreplacestring\toksb\in\toksa\with\toksc
+
+\toksc{}
+\yyreplacestring\toksb\in\toksd\with\toksc
+
+\expandafter\def\expandafter\yymatchblankspac@\expandafter#\expandafter1\the\toksd{%
+ \yystringempty{#1}{\expandafter\yysecondofthree\expandafter{\string}}%
+ {\expandafter\yythirdofthree\expandafter{\string}}%
+}
+
+\edef\yymatchblankspace#1{% is it \catcode 10 token?
+ \noexpand\iffalse{\noexpand\fi
+ \noexpand\expandafter
+ \noexpand\yymatchblankspac@
+ \noexpand\meaning#1\the\toksd}%
+}
+
+% the idea behind the sequence below is that a leading character of category code 10
+% is replaced either by a character of category code 10 and charachter code 32 or a character
+% of category code 12 and character code other than 32
+% note that while it is tempting to replace the definition below by something that ends in
+% ... blank space #2{ ... with the hope of absorbing the result of \meaning in one step,
+% this will not give the desired result in case of an active character,
+% say, `~' that had been \let to the normal blank space
+
+\expandafter\def\expandafter\yynormalizeblankspac@\expandafter#\expandafter1\the\toksd{}
+
+%% test code begins here
+
+\tracingmacros=3
+\tracingonline=3
+
+\catcode`\ =13\relax%
+\def\actspace{ }%
+\catcode`\ =10\relax%
+
+\catcode`\.=13\relax%
+\def\actdotspace{.}%
+\catcode`\.=12\relax%
+
+\edef\makefunkydotspace{\let\expandafter\noexpand\actdotspace= \dotspace}
+\edef\makefunkyspace{\let\expandafter\noexpand\actspace= \space}
+
+\makefunkyspace
+\makefunkydotspace
+
+\def\identity#1{#1}
+
+%\def\tempseq{\space\dotspace\space\space\dotspace\expandafter\noexpand\actspace\expandafter\noexpand\actdotspace
+% \end\noexpand\fi\noexpand\else\noexpand\iffalse}
+%\def\tempseq{\space\dotspace e}
+
+%\edef\mypars@{%
+% \noexpand\yypreparsetokensequenc@{\noexpand\identity}%
+% {\tempseq}%
+% {}%
+%}
+
+%\edef\myparse{\mypars@}
+
+%\toksa\expandafter{\myparse}
+
+%\showthe\toksa
+
+%\edef\myresolve{\noexpand\yyresolvespaces{\errmessage}%
+% {\tempseq}%
+% {\the\toksa}{}
+%}
+
+%\show\myresolve
+
+%\myresolve
+
+\catcode`\<=1
+\catcode`\>=2
+\uccode`\<=32
+\uccode`\>=32
+
+\uppercase{\edef\temptest{<> \space\space\dotspace\expandafter\noexpand\actspace\expandafter\noexpand\actdotspace{{} {{}{{ u o l k kk
+ \end\noexpand\fi\noexpand\else\noexpand\iffalse{}} }}}}}
+
+%\uppercase{\edef\temptest{\dotspace E <>}}
+
+\show\temptest
+
+\def\displaypreparse#1{%
+ \expandafter\errmessage\expandafter{\romannumeral-1\yypreparsetokensequenc@{\yyanalysetokens@}{#1}{}{}#1}%
+}
+
+%\def\displaydebraceparse#1{%
+% \yypreparsetokensequenc@{\yydebracesequence{\displayseq}{#1}}{#1}{}%
+%}
+
+%\def\displayseq#1{\toksa{#1}\showthe\toksa}
+
+\expandafter\displaypreparse\expandafter{\temptest}
+
+\errmessage{stop!}
+
+%\expandafter\displaydebraceparse\expandafter{\temptest}
+
+\end
diff --git a/support/splint/examples/expression/Makefile b/support/splint/examples/expression/Makefile
new file mode 100644
index 0000000000..0e2f33c2ba
--- /dev/null
+++ b/support/splint/examples/expression/Makefile
@@ -0,0 +1,59 @@
+# this Makefile uses a flat directory structure for demonstration
+# purposes; the main directory (../..) contains a slightly more
+# modular organization.
+
+SPLINT_ROOT = $(shell pwd)/../..
+
+include ${SPLINT_ROOT}/makefile.inc
+include ${SPLINT_ROOT}/makefile.loc
+
+# rules specific to this example
+
+PARSER = expp
+LEXER = expl
+
+all: expression.pdf ptab.tex ltab.tex
+
+step1: expp.y expl.l
+step2: ptabout ltabout
+step3: ltab.tex ptab.tex
+
+ptabout: ${SPLINT_ROOT}/cweb/mkeparser.c ${PARSER}.c
+ ${CC} -DPARSER_FILE=\"../examples/expression/$(lastword $^)\" -DYYPARSE_PARAMETERS= -o $@ $<
+
+ptab.tex: ptabout
+ $< --optimize-actions $@
+
+ltabout: ${SPLINT_ROOT}/cweb/mkscanner.c ${LEXER}.c
+ ${CC} -DLEXER_FILE=\"../examples/expression/$(lastword $^)\" -o $@ $<
+
+ltab.tex: ltabout
+ $< --optimize-actions $@
+
+${LEXER}.c: ${LEXER}.l
+ ${FLEX} -o $@ $<
+
+test.tex ${PARSER}.yy ${LEXER}.ll: expression.x
+ @${CTANGLE} $<
+ ${UNLINE} test.txx test.tex
+
+expression.tex: expression.x
+ @${CWEAVE} $<
+
+expression.pdf: expression.tex ${SPLINT_XPTABLES} ${SPLINT_XLTABLES} ${SPLINT_ROOT}/cweb/bo.tok etoks.sty
+ @${PDFTEX} $<
+
+test: test.tex ptab.tex ltab.tex
+ tex test.tex
+
+docs: expression.pdf
+
+mostlyclean: clean_temp
+ -rm -f ptabout ltabout expression.c *.txx
+
+clean: clean_core
+ -rm -f ptabout ltabout *.txx
+
+distclean: clean
+ cd ${SPLINT_ROOT} && ${MAKE} clean
+
diff --git a/support/splint/examples/expression/etoks.sty b/support/splint/examples/expression/etoks.sty
new file mode 100644
index 0000000000..7326245338
--- /dev/null
+++ b/support/splint/examples/expression/etoks.sty
@@ -0,0 +1,3 @@
+\prettywordpair{IDENTIFIER}{{$\langle$\rm identifier$\rangle$}}
+\prettywordpair{INTEGER}{{\bf int}}
+\prettywordpair{BOGUS}{{\tt Oh, @\%\$\&*!}}
diff --git a/support/splint/examples/expression/expression.sty b/support/splint/examples/expression/expression.sty
new file mode 100644
index 0000000000..9f9195aafb
--- /dev/null
+++ b/support/splint/examples/expression/expression.sty
@@ -0,0 +1,25 @@
+\def\optimization{5}
+
+\input yycommon.sty % general routines for stack and array access
+\input yymisc.sty % helper macros (stack manipulation, table processing, value stack pointers)
+\input yyinput.sty % input functions
+\input yyparse.sty % parser machinery
+\input flex.sty % lexer functions
+\input yyfaststack.sty % sped up stack access functions
+\input yyboth.sty % parser initializatio, optimization
+
+\let\yylexreturn\yylexreturnregular
+\let\setflexstates\relax
+\let\parsernamespace\empty
+
+\genericparser
+ name: main,
+ ptables: ptab.tex,
+ ltables: ltab.tex,
+ tokens: {},
+ asetup: {},
+ dsetup: {},
+ rsetup: {},
+ optimization: \optimizeall;%
+
+\tomainparser
diff --git a/support/splint/examples/expression/expression.w b/support/splint/examples/expression/expression.w
new file mode 100644
index 0000000000..c775741184
--- /dev/null
+++ b/support/splint/examples/expression/expression.w
@@ -0,0 +1,262 @@
+@q Copyright 2012-2014, Alexander Shibakov@>
+@q This file is part of SPLinT@>
+
+@q SPLinT is free software: you can redistribute it and/or modify@>
+@q it under the terms of the GNU General Public License as published by@>
+@q the Free Software Foundation, either version 3 of the License, or@>
+@q (at your option) any later version.@>
+
+@q SPLinT is distributed in the hope that it will be useful,@>
+@q but WITHOUT ANY WARRANTY; without even the implied warranty of@>
+@q MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the@>
+@q GNU General Public License for more details.@>
+
+@q You should have received a copy of the GNU General Public License@>
+@q along with SPLinT. If not, see <http://www.gnu.org/licenses/>.@>
+\input limbo.sty
+\def\optimization{5}
+\input yy.sty
+
+@** Parser file. This an example parser for expressions. It takes
+advantage of some of the features of \splint\ generated parsers,
+although anything that takes more than a straightforward setup is
+omitted.
+
+The top-level structure of the input file presents no surprises and is
+presented below.
+\let\currentparsernamespace\parsernamespace
+ \let\parsernamespace\smallnamespace
+ \let\hostparsernamespace\smallnamespace
+ \input etoks.sty
+\let\parsernamespace\currentparsernamespace
+\def\texnspace{[other]}
+@s TeX_ TeX
+
+@(expp.yy@>=
+@G Switch to generic mode.
+%{@> @<\.{expression} parser \Cee\ preamble@> @=%}
+ @> @<Bison options@> @=
+%union {@> @<Union of parser types@> @=}
+%{@> @<\.{expression} parser \Cee\ postamble@> @=%}
+ @> @<Token and types ...@> @=
+%%
+ @> @<Parser productions@> @=
+%%
+@g
+
+@ The \prodstyle{\%token-table} option is not merely a debugging help,
+as it is in the case of the `real' \bison\ parsers and cannot be
+omitted . The name table it is responsible for setting up is used as
+a set of keys for various associative arrays. Token declarations are
+parsed by a bootstrap parser during the \TeX\ processing stage to
+establish equivalences between the names kept in |yytname| and the
+macro names used internally by the parsers built by \bison. The reason
+this is necessary is not very complicated: either version of the token
+name can be used in the grammar while the `driver' program
+(\.{mkeparser.c}) only has access to the names in |yytname|. In
+general, this is important whenever the grammar uses a different set of
+token names from the lexer or when diagnostics messages are output. An
+important case is the symbolic name switch: before the rules can be
+listed to create the switch, the token numerical values must be
+known. If the parser is only aware of the |yytname| listed names and the
+grammar being parsed uses the `internal' names, the listing macros
+will fail. The array, |yytname| is used in a few functions inside the
+`driver', as well, so omitting this option would make building the
+parser impossible.
+@<Bison options@>=
+@G
+%token-table
+%debug
+%start value
+@g
+
+@ To continue the token name discussion, this parser uses internal
+names only so this is what will appear in the |yytname| array. No
+bootstrapping is necessary. The typesetting of the tokens can be
+adjusted using \.{\\prettywordpair} macros (see the included
+\.{etoks.sty} file for examples).
+@<Token and types declarations@>=
+@G
+%token IDENTIFIER
+%token INTEGER
+%token BOGUS
+@g
+
+@ Here is the whole grammar, simply additive expressions with two
+levels of precedence.
+@<Parser productions@>=
+@G
+value:
+ expression {@> TeX_( "/yy0{/the/yy(1)}" ); @=}
+;
+
+expression:
+ term {@> TeX_( "/yy0{/the/yy(1)}" ); @=}
+| expression '+' term {@> @<Add a term@> @=}
+;
+
+term:
+ atom {@> TeX_( "/yy0{/the/yy(1)}" ); @=}
+| term '*' atom {@> @<Multiply by an atom@> @=}
+;
+
+atom:
+ IDENTIFIER {@> @<Assign variable value to an atom@> @=}
+| INTEGER {@> @<Assign value to an atom@> @=}
+| '(' expression ')' {@> TeX_( "/yy0{/the/yy(2)}" ); @=}
+;
+@g
+
+@ @<Add a term@>=
+ @[TeX_( "/tempca/the/yy(1)/relax" );@]@;
+ @[TeX_( "/tempcb/the/yy(3)/relax" );@]@;
+ @[TeX_( "/advance/tempca by /tempcb" );@]@;
+ @[TeX_( "/yy0{/the/tempca}" );@]@;
+
+@ @<Multiply by an atom@>=
+ @[TeX_( "/tempca/the/yy(1)/relax" );@]@;
+ @[TeX_( "/tempcb/the/yy(3)/relax" );@]@;
+ @[TeX_( "/multiply/tempca by /tempcb" );@]@;
+ @[TeX_( "/yy0{/the/tempca}" );@]@;
+
+@ @<Assign variable value to an atom@>=
+ @[TeX_( "/getsecond{/yy(1)}/to/toksa" );@]@;
+ @[TeX_( "/toksb/expandafter/expandafter/expandafter{/expandafter" );@]@;
+ @[TeX_( " /number/csname/the/toksa/endcsname}" );@]@;
+ @[TeX_( "/yy0{/the/toksb}" );@]@;
+
+@ @<Assign value to an atom@>=
+ @[TeX_( "/getfirst{/yy(1)}/to/toksa" );@]@;
+ @[TeX_( "/yy0{/the/toksa}" );@]@;
+
+@ \Cee\ preamble. In this case, there are no `real' actions that our
+grammar performs, only \TeX\ output, so this section is empty.
+
+@<\.{expression} parser \Cee\ preamble@>=
+
+@ \Cee\ postamble. It is tricky to insert function definitions that use \bison's internal types,
+as they have to be inserted in a place that is aware of the internal definitions but before said
+definitions are used.
+
+@<\.{expression} parser \Cee\ postamble@>=
+#define YYPRINT(file, type, value) @[yyprint (file, type, value)@]
+ static void yyprint (FILE *file, int type, YYSTYPE value){}
+
+@ Union of types. Empty as well.
+
+@<Union of parser types@>=
+
+@** The lexer file. The scanner for the grammar above is even
+simpler. Identifiers are interpreted as variable names that expand to
+appropriate values.
+%\checktabletrue
+@(expl.ll@>=
+@G
+ @> @<Lexer definitions@> @=
+%{@> @<Lexer \Cee\ preamble@> @=%}
+ @> @<Lexer options@> @=
+%%
+ @> @<Regular expressions@> @=
+%%
+
+@ @<Lexer definitions@>=
+@G
+letter [_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ]
+id {letter}({letter}|[-0-9])*
+int [0-9]+
+@g
+
+@ @<Lexer \Cee\ preamble@>=
+
+#include <stdint.h>
+#include <stdbool.h>
+
+ void define_all_states( void ){}
+
+@ @<Lexer options@>=
+@G
+%option bison-bridge
+%option noyywrap nounput noinput reentrant
+%option noyy_top_state
+%option debug
+%option stack
+%option outfile="expl.c"
+@g
+
+@ @<Regular expressions@>=
+ @<Scan white space@>@;
+ @<Scan identifiers@>@;
+
+@ White space skipping.
+\traceparserstatestrue
+\tracestackstrue
+\tracerulestrue
+\traceactionstrue
+\tracelookaheadtrue
+\traceparseresultstrue
+\tracebadcharstrue
+\yyflexdebugtrue
+%
+\traceparserstatesfalse
+\tracestacksfalse
+\tracerulesfalse
+\traceactionsfalse
+\tracelookaheadfalse
+\traceparseresultsfalse
+\tracebadcharsfalse
+\yyflexdebugfalse
+@<Scan white space@>=
+@G
+[ \f\n\t\v] {@> @[TeX_( "/yylexnext" );@]@=}
+@g
+
+@ @<Scan identifiers@>=
+@G
+{id} {@> @[TeX_( "/yylexreturnval{IDENTIFIER}" );@]@=}
+{int} {@> @[TeX_( "/yylexreturnval{INTEGER}" );@]@=}
+[+*()] {@> @[TeX_( "/yylexreturnchar" );@]@=}
+. {@> @[@<React to a bad character@>@]@=}
+@g
+
+@ @<React to a bad character@>=
+ @[TeX_( "/iftracebadchars" );@]@;
+ @[TeX_( " /yycomplain{invalid character(s): /the/yytext}" );@]@;
+ @[TeX_( "/fi" );@]@;
+ @[TeX_( "/yylexreturn{$undefined}" );@]@;
+
+@*Test file. The test file includes a handy list of debugging options
+that can be activated to see the inner workings of the parser and
+scanner routines.
+@(test.txx@>=
+@G
+\input expression.sty
+
+\iffalse
+ \tracedfatrue
+ \traceparserstatestrue
+ \tracestackstrue
+ \tracerulestrue
+ \traceactionstrue
+ \tracelookaheadtrue
+ \traceparseresultstrue
+ \tracebadcharstrue
+ \yyflexdebugtrue
+ \yyinputdebugtrue
+\fi
+
+\def\varone{10}
+\def\expression{1 + 3 * ( 5 + 7 ) + varone}
+\basicparserinit\expandafter\yyparse \expression \yyeof\yyeof\endparseinput\endparse
+
+{
+ \newlinechar`^^J
+ \immediate\write16{^^Jexpression: \expression^^Jthe value: \the\yyval^^J^^J}
+}
+
+\bye
+@g
+
+@**Index.
+\immediate\closeout\exampletable
+\def\Tex{\TeX\ output}
+\def\TeXx{\TeX\ output}
diff --git a/support/splint/examples/ld/Makefile b/support/splint/examples/ld/Makefile
new file mode 100644
index 0000000000..a23f191b9c
--- /dev/null
+++ b/support/splint/examples/ld/Makefile
@@ -0,0 +1,118 @@
+# this Makefile uses a flat directory structure for demonstration
+# purposes; the main directory (../..) contains a slightly more
+# modular organization.
+
+SPLINT_ROOT = $(shell pwd)/../..
+
+PARSER = ldp
+LEXER = ldl
+MANUAL = ldman
+
+LD_CORE_PREREQS = ${SPLINT_XTEXSTYLES} ${SPLINT_XPTABLES} ${SPLINT_XLTABLES} ${SPLINT_ROOT}/cweb/bo.tok
+LD_DOC_PREREQS = %.tex %.sty ${PARSER}.tok ldunion.sty ldint.sty ldfrontmatter.sty ${LD_CORE_PREREQS} ptab.tex ltab.tex ld_small_tab.tex
+LD_DOC_PREREQS += ld_small_dfa.tex ltokenset.sty lstokenset.sty
+LD_DOC_PREREQS_XREF = ${LD_DOC_PREREQS} %.scn %.idx
+
+include ${SPLINT_ROOT}/makefile.inc
+include ${SPLINT_ROOT}/makefile.loc
+
+# rules specific to this example
+
+ptabout: ${SPLINT_ROOT}/cweb/mkeparser.c ${PARSER}.c
+ ${CC} -DPARSER_FILE=\"../examples/ld/$(lastword $^)\" -DYYPARSE_PARAMETERS= -o $@ $<
+
+ptab.tex: ptabout
+ $< --optimize-actions --optimize-tables $@
+
+ltabout: ${SPLINT_ROOT}/cweb/mkscanner.c ldl_states.h ${LEXER}.c
+ ${CC} -DLEXER_FILE=\"../examples/ld/$(lastword $^)\" -o $@ $<
+
+ltab.tex: ltabout
+ $< --optimize-actions --optimize-tables $@
+
+${LEXER}.c: ${LEXER}.l
+ ${FLEX} -o $@ $<
+
+${PARSER}.yy : ldgram.x
+ @${CTANGLE} $<
+
+${LEXER}.ll: ldlex.x
+ @${CTANGLE} $<
+
+${MANUAL}.stx: ${MANUAL}.x ldgram.x ldlex.x ldlexo.x ldgramo.x ldnp.x
+ @${CTANGLE} $<
+
+# term name parser for ld grammar
+
+ldsmallp_out: ${SPLINT_ROOT}/cweb/mkeparser.c ld_small_parser.c
+ ${CC} ${BISON_STATE} -DPARSER_FILE=\"../examples/ld/$(lastword $^)\" -DYYPARSE_PARAMETERS= -o $@ $<
+
+ldsmalll_out: ${SPLINT_ROOT}/cweb/mkscanner.c ld_small_lexer.c
+ ${CC} -DLEXER_FILE=\"../examples/ld/$(lastword $^)\" -o $@ $<
+
+ld_small_tab.tex: ldsmallp_out
+ $< --optimize-actions --optimize-tables $@
+
+ld_small_dfa.tex: ldsmalll_out
+ $< --optimize-actions --optimize-tables $@
+
+ld_small_parser.yy \
+ld_small_lexer.ll: ldnp.x
+ @${CTANGLE} $<
+
+# numeric parser for ld grammar
+
+ldnump_out: ${SPLINT_ROOT}/cweb/mkeparser.c ld_num_parser.c
+ ${CC} ${BISON_STATE} -DPARSER_FILE=\"../examples/ld/$(lastword $^)\" -DYYPARSE_PARAMETERS= -o $@ $<
+
+ldnuml_out: ${SPLINT_ROOT}/cweb/mkscanner.c ld_num_lexer.c
+ ${CC} -DLEXER_FILE=\"../examples/ld/$(lastword $^)\" -o $@ $<
+
+ld_num_tab.tex: ldnump_out
+ $< --optimize-actions --optimize-tables $@
+
+ld_num_dfa.tex: ldnuml_out
+ $< --optimize-actions --optimize-tables $@
+
+ld_num_parser.yy \
+ld_num_lexer.ll: ldnump.x
+ @${CTANGLE} $<
+
+${MANUAL}.tex: ${MANUAL}.x ldgram.x ldlex.x ldlexo.x ldgramo.x ldnp.x
+ ${CWEAVE} $<
+
+${MANUAL}.sty: ${MANUAL}.stx
+ ${UNLINE} $< $@
+
+${MANUAL}.gdx: %.gdx: ${LD_DOC_PREREQS_XREF} ${PARSER}.tok
+ @echo "Making the bison and TeX indices ..."
+ ${TEX} $*.tex
+
+${MANUAL}.pdf: %.pdf: ${LD_DOC_PREREQS_XREF} %.gdy
+ ${PDFTEX} $< && touch $*.gdy && touch $*.pdf
+
+#${PARSER}.tok \
+#ldl_states.h: ${MANUAL}.tex ${MANUAL}.sty ${LD_CORE_PREREQS}
+# ${TEX} ${MODEBOOTSTRAP} \\input $<
+
+${PARSER}.tok: ldgram.tex ${MANUAL}.sty ${LD_CORE_PREREQS}
+ ${TEX} ${MODEBOOTSTRAP} \\input $<
+
+ldl_states.h: ldlex.tex ${MANUAL}.sty ${LD_CORE_PREREQS}
+ ${TEX} ${MODEBOOTSTRAP} \\input $<
+
+ldgram.tex ldlex.tex: \
+%.tex: %.x
+ ${CWEAVE} -x $<
+
+docs: ${MANUAL}.pdf
+
+mostlyclean: clean_temp
+ -rm -f ptabout ltabout ldsmalll_out ldsmallp_out ldnump_out ldnuml_out ${MANUAL}.c
+
+clean: clean_core
+ -rm -f ptabout ltabout ldsmalll_out ldsmallp_out ldnump_out ldnuml_out *.stx ldman.sty
+
+distclean: clean
+ cd ${SPLINT_ROOT} && ${MAKE} clean
+
diff --git a/support/splint/examples/ld/ldfrontmatter.sty b/support/splint/examples/ld/ldfrontmatter.sty
new file mode 100644
index 0000000000..e4fd94bcf2
--- /dev/null
+++ b/support/splint/examples/ld/ldfrontmatter.sty
@@ -0,0 +1,2 @@
+% this file is left blank on purpose to avoid referencing non-free fonts
+% it would contain the \TeX\ macros that generate the cover page for \ld\ parser manual
diff --git a/support/splint/examples/ld/ldgram.w b/support/splint/examples/ld/ldgram.w
new file mode 100644
index 0000000000..4fb9a9a876
--- /dev/null
+++ b/support/splint/examples/ld/ldgram.w
@@ -0,0 +1,1083 @@
+@q Copyright 2012-2015 Alexander Shibakov@>
+@q Copyright 2002-2014 Free Software Foundation, Inc.@>
+@q This file is part of SPLinT@>
+
+@q SPLinT is free software: you can redistribute it and/or modify@>
+@q it under the terms of the GNU General Public License as published by@>
+@q the Free Software Foundation, either version 3 of the License, or@>
+@q (at your option) any later version.@>
+
+@q SPLinT is distributed in the hope that it will be useful,@>
+@q but WITHOUT ANY WARRANTY; without even the implied warranty of@>
+@q MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the@>
+@q GNU General Public License for more details.@>
+
+@q You should have received a copy of the GNU General Public License@>
+@q along with SPLinT. If not, see <http://www.gnu.org/licenses/>.@>
+
+@** The parser.
+\ifx\parsernamespace\UNDEFINED
+ \def\tokendeffile{ldp.tok}%
+ \input ldman.sty
+ \input limbo.sty
+ \input dcols.sty
+ \setupfootnotes
+ \def\MRI{}
+ \def\ld{}
+\fi
+\immediate\openout\exampletable=\jobname.exl\relax%
+The outline of the grammar file below does not reveal anything unusual
+in the general layout of \ld\ grammar. The first section lists all the
+token definitions, \prodstyle{\%union} styles, and some \Cee\
+code. The original comments that come with the grammar file of the
+linker have been mostly left intact. They are typeset in {\it
+italics\/} to make them easy to recognize.
+
+@s TeX_ TeX
+@s TeXa TeX
+@s TeXb TeX
+@s TeXf TeX
+@s TeXfo TeX
+@s TeXao TeX
+
+@(ldp.yy@>=
+@G Switch to generic mode.
+%{@> @<\ld\ parser \Cee\ preamble@> @=%}
+ @> @<\ld\ parser \bison\ options@> @=
+%union {@> @<Union of grammar parser types@> @=}
+%{@> @<\ld\ parser \Cee\ postamble@> @=%}
+ @> @<Token and type declarations@> @=
+%%
+ @> @<\ld\ parser productions@> @=
+%%
+@g
+
+@ Among the options listed in this section, \prodstyle{\%token-table}
+is the most critical for the proper operation of the parser and must be enabled
+to supply the token information to the lexer (the traditional way
+of passing this information along is to use a \Cee\ header file with
+the appropriate definitions). The start symbol does not have to be
+given explicitly and can be indicated by listing the appropriate rules
+at the beginning.
+
+Most other sections of the grammar file, with the exception of the
+rules are either empty or hold placeholder values. The functionality
+provided by the code in these sections in the case of a \Cee\ parser
+is supplied by the \TeX\ macros in \.{ldman.sty}.
+@<\ld\ parser \bison\ options@>=
+@G
+%token-table
+%debug
+%start script_file
+@g
+
+@ @<\ld\ parser \Cee\ preamble@>=
+
+@ @<Union of grammar parser types@>=
+
+@ @<\ld\ parser \Cee\ postamble@>=
+#define YYPRINT(file, type, value) yyprint (file, type, value)
+ static void yyprint (FILE *file, int type, YYSTYPE value){}
+
+@ @<\ld\ parser productions@>=
+ @<\GNU\ \ld\ script rules@>@;
+ @<Grammar rules@>@;
+
+@ The tokens are declared first. This section is also used to supply
+numerical token values to the lexer by the original parser, as well as
+the bootstrapping phase of the typesetting parser. Unlike the native (\Cee) parser for
+\ld\ the typesetting parser has no need for the type of each token
+(rather, the type consistency is based on the weak dynamic type system
+coded in \.{yyunion.sty} and \.{ldunion.sy}). Thus all the tokens used
+by the \ld\ parser are put in a single list.
+@<Token and type declarations@>=
+@G
+%token INT
+%token NAME LNAME
+%token END
+%token ALIGN_K BLOCK BIND QUAD SQUAD LONG SHORT BYTE
+%token SECTIONS PHDRS INSERT_K AFTER BEFORE
+%token DATA_SEGMENT_ALIGN DATA_SEGMENT_RELRO_END DATA_SEGMENT_END
+%token SORT_BY_NAME SORT_BY_ALIGNMENT SORT_NONE
+%token SORT_BY_INIT_PRIORITY
+%token '{' '}'
+%token SIZEOF_HEADERS OUTPUT_FORMAT FORCE_COMMON_ALLOCATION OUTPUT_ARCH
+%token INHIBIT_COMMON_ALLOCATION
+%token SEGMENT_START
+%token INCLUDE
+%token MEMORY
+%token REGION_ALIAS
+%token LD_FEATURE
+%token NOLOAD DSECT COPY INFO OVERLAY
+%token DEFINED TARGET_K SEARCH_DIR MAP ENTRY
+%token NEXT
+%token SIZEOF ALIGNOF ADDR LOADADDR MAX_K MIN_K
+%token STARTUP HLL SYSLIB FLOAT NOFLOAT NOCROSSREFS
+%token ORIGIN FILL
+%token LENGTH CREATE_OBJECT_SYMBOLS INPUT GROUP OUTPUT CONSTRUCTORS
+%token ALIGNMOD AT SUBALIGN HIDDEN PROVIDE PROVIDE_HIDDEN AS_NEEDED
+%token CHIP LIST SECT ABSOLUTE LOAD NEWLINE ENDWORD ORDER NAMEWORD ASSERT_K
+%token LOG2CEIL FORMAT PUBLIC DEFSYMEND BASE ALIAS TRUNCATE REL
+%token INPUT_SCRIPT INPUT_MRI_SCRIPT INPUT_DEFSYM CASE EXTERN START
+%token VERS_TAG VERS_IDENTIFIER
+%token GLOBAL LOCAL VERSIONK INPUT_VERSION_SCRIPT
+%token KEEP ONLY_IF_RO ONLY_IF_RW SPECIAL INPUT_SECTION_FLAGS ALIGN_WITH_INPUT
+%token EXCLUDE_FILE
+%token CONSTANT
+%token INPUT_DYNAMIC_LIST
+%right PLUSEQ MINUSEQ MULTEQ DIVEQ '=' LSHIFTEQ RSHIFTEQ ANDEQ OREQ '?' ':' UNARY
+%left OROR ANDAND '|' '^' '&' EQ NE '<' '>' LE GE LSHIFT RSHIFT '+' '-' '*' '/' '%' '('
+@g
+
+@*1 Grammar rules, an overview.
+The first natural step in transforming an existing parser into a
+`parser stack' for pretty printing is to understand the `anatomy' of
+the grammar. Not every grammar is suitable for such a transformation
+and in almost every case, some modifications are needed. The
+parser and lexer implementation for \ld\ is not terrible although it does
+have some idiosynchasies that could have been eliminated by a careful
+grammar redesign. Instead of invasive rewriting of significant
+portions of the grammar, the approach taken here merely omits some
+rules and partitions the grammar into several subsets, each of which
+is supposed to handle a well defined logical section of an \ld\ script
+file.
+
+One example of a trick used by the \ld\ parser that is not appropriate for a
+pretty printing grammar implements a way of handling the choice of the
+format of an input file. After a command line option that selects the
+input format has been read (or the format has been determined using
+some other method), the first token output by the lexer branches the
+parser to the appropriate portion of the full grammar.
+
+Since the token never appears as part of the input file there is no
+need to include this part of the main grammar for the purposes of
+typesetting.
+\traceparserstatestrue
+\tracestackstrue
+\tracerulestrue
+\traceactionstrue
+\tracelookaheadtrue
+\traceparseresultstrue
+\tracebadcharstrue
+\yyflexdebugtrue
+%\checktabletrue
+%
+\traceparserstatesfalse
+\tracestacksfalse
+\tracerulesfalse
+\traceactionsfalse
+\tracelookaheadfalse
+\traceparseresultsfalse
+\tracebadcharsfalse
+\yyflexdebugfalse
+\checktablefalse
+%
+\saveparseoutputfalse
+@<Ignored grammar rules@>=
+@G
+file:
+ INPUT_SCRIPT script_file
+ | INPUT_MRI_SCRIPT mri_script_file
+ | INPUT_VERSION_SCRIPT version_script_file
+ | INPUT_DYNAMIC_LIST dynamic_list_file
+ | INPUT_DEFSYM defsym_expr
+;
+@g
+
+@ @<Grammar rules@>=
+@G
+@t}\vb{\inline\flatten}{@>
+filename:
+ NAME {@>@[TeX_( "/yy0{/noexpand/ldfilename{/the/yy(1)}}" );@]@=}
+;
+@g
+
+@ The simplest parser subset is intended to parse symbol definitions
+given in the command line that invokes the linker. Creating a parser
+for it involves almost no extra effort so we leave it in.
+
+Note that the simpliciy is somewhat deceptive as the syntax of
+\prodstyle{exp} is rather complex. That part of the grammar is needed
+elsewhere, however, so symbol definitions parsing costs almost nothing
+on top of the already required effort. The only practical use for this
+part of the \ld\ grammar is presenting examples in text.
+
+The\namedspot{pingpong} \TeX\ macro \.{\\ldlex@@defsym} switches the lexer state to
+\.{DEFSYMEXP} (see \locallink{stateswitchers}all the state switching
+macros\endlink\ in the chapter about the lexer implementation
+below). Switching lexer states from the parser presents some
+difficulties which can be overcome by careful design. For example, the
+state switching macros can be invoked before the lexer is called and
+initialized (when the parser performs a {\it default action\/}).
+@<Inline symbol definitions@>=
+@G
+defsym_expr:
+ {@>@[TeX_( "/ldlex@@defsym" );@]@=}
+ NAME '=' exp {@>@[TeX_( "/ldlex@@popstate" );@]@=}
+ ;
+@g
+
+@ {\it Syntax within an \MRI\ script file}\footnote{As explained at the
+beginning of this chapter, the text in {\it italics\/} was taken from
+the original comments by \ld\ parser and lexer programmers.}. The parser for typesetting
+is only intended to process \GNU\ \ld\ scripts and does not concern
+itself with any additional compatibility modes. For this reason, all
+support for \MRI\ style scripts has been omitted. One use for the
+section below is a small demonstration of the formatting tools that
+change the output of the \bison\ parser.
+@<\MRI\ style script rules@>=
+@G
+@t}\vb{\inline\flatten}{@>
+mri_script_file:
+ {@>@[TeX_( "/ldlex@@mri@@script" );@]@=}
+ mri_script_lines {@>@[TeX_( "/ldlex@@popstate" );@]@=}
+ ;
+
+mri_script_lines:
+ mri_script_lines mri_script_command NEWLINE
+ |
+ ;
+@t}\vb{\resetf}{@>
+mri_script_command:
+ CHIP exp
+ | CHIP exp ',' exp
+ | NAME {}
+ | LIST {}
+ | ORDER ordernamelist {}
+ | ENDWORD {}
+@t}\vb{\flatten}{@>
+ | PUBLIC NAME '=' exp {}
+ | PUBLIC NAME ',' exp {}
+ | PUBLIC NAME exp
+@t}\vb{\resetf}{@>
+ {}
+ | FORMAT NAME {}
+@t}\vb{\flatten}{@>
+ | SECT NAME ',' exp {}
+ | SECT NAME exp {}
+ | SECT NAME '=' exp
+@t}\vb{\resetf}{@>
+ {}
+@t}\vb{\flatten}{@>
+ | ALIGN_K NAME '=' exp {}
+ | ALIGN_K NAME ',' exp
+@t}\vb{\resetf}{@>
+ {}
+@t}\vb{\flatten}{@>
+ | ALIGNMOD NAME '=' exp {}
+ | ALIGNMOD NAME ',' exp {}
+@t}\vb{\resetf}{@>
+ {}
+ | ABSOLUTE mri_abs_name_list
+ | LOAD mri_load_name_list
+ | NAMEWORD NAME {}
+@t}\vb{\flatten}{@>
+ | ALIAS NAME ',' NAME {}
+ | ALIAS NAME ',' INT {}
+@t}\vb{\resetf}{@>
+ {}
+ | BASE exp {}
+ | TRUNCATE INT {}
+ | CASE casesymlist
+ | EXTERN extern_name_list
+@t}\vb{\flatten}{@>
+ | INCLUDE filename {@>@<Peek at a file@>@=}
+ mri_script_lines END
+@t}\vb{\resetf}{@>
+ {@>@<Close the file@>@=}
+ | START NAME {}
+ |
+ ;
+@t}\vb{\inline\flatten}{@>
+ordernamelist:
+ ordernamelist ',' NAME {}
+ | ordernamelist NAME {}
+ |
+ ;
+
+mri_load_name_list:
+ NAME {}
+ | mri_load_name_list ',' NAME {}
+ ;
+
+mri_abs_name_list:
+ NAME {}
+ | mri_abs_name_list ',' NAME {}
+ ;
+
+casesymlist:
+ {}
+ | NAME
+ | casesymlist ',' NAME
+ ;
+@g
+
+@ {\it Parsed as expressions so that commas separate entries.} The
+core of the parser consists of productions describing \GNU\ \ld\ linker
+scripts. The first rule is common to both \MRI\ and \GNU\ formats.
+@<\GNU\ \ld\ script rules@>=
+@G
+extern_name_list:
+ {@>@[TeX_( "/ldlex@@expression" );@]@=}
+ extern_name_list_body {@>@[TeX_( "/ldlex@@popstate" );@]@=}
+ ;
+
+extern_name_list_body:
+ NAME {}
+ | extern_name_list_body NAME {}
+ | extern_name_list_body ',' NAME {}
+ ;
+
+@ The top level productions simply define a script file as a list of
+script commands.
+@<\GNU\ \ld\ script rules@>=
+@G
+script_file:
+ {@>@[TeX_( "/ldlex@@both" );@]@=}
+ ifile_list {@>@[TeX_( "/getsecond{/yy(2)}/to/ldcmds/ldlex@@popstate" );@]@=}
+ ;
+
+ifile_list:
+ ifile_list ifile_p1 {@>@<Add the next command@>@=}
+ | {@>@[TeX_( "/yy0{{}{}}" );@]@=}
+ ;
+@g
+
+@ @<Add the next command@>=
+ @[TeX_( "/getfirst{/yy(1)}/to/toksa/getsecond{/yy(1)}/to/toksb" );@]@;
+ @[TeX_( "/getfirst{/yy(2)}/to/toksc/getsecond{/yy(2)}/to/toksd" );@]@;
+ @[TeXb( "/yytoksempty{/toksb}{/yy0{/the/yy(2)}}" );@]@;
+ @[TeXao( "{/yy0{{/the/toksc}{/the/toksb/noexpand/ldcommandseparator{/the/toksa}{/the/toksc}/the/toksd}}}" );@]@;
+
+@*1 Script internals.
+There are a number of different commands. For typesetting purposes,
+the handling of most of these can be significantly
+simplified. In the \prodstyle{GROUP} command there is no need to
+perform any actions upon entering the group, for
+instance. \prodstyle{INCLUDE} presents a special challenge. In
+the original grammar this command is followed by a general list of script
+commands (the contents of the included file) terminated by
+\prodstyle{END}. The `magic' of opening the file and inserting its
+contents into the stream being parsed is performed by the lexer and
+the parser in the
+background. The typesetting parser, on the other hand, only has to
+typeset the \prodstyle{INCLUDE} command itself and has no need for
+opening and parsing the file being included. We can simply change the
+grammar rule to omit the follow up script commands but that would
+require altering the existing grammar. \namedspot{pretendbuffersw}Since the command list
+(\prodstyle{ifile\_list}) is allowed to be empty,
+we simply \locallink{pretendbufferswlex}fake\endlink\ the
+inclusion of the file in the lexer by immediately outputting
+\prodstyle{END} upon entering the appropriate lexer state. One
+advantage in using this approach is the ability, when desired, to
+examine the included file for possible cross-referencing information.
+
+Each command is packaged with a qualifier that records its type for
+the rule that adds the fragment to the script file.
+@<\GNU\ \ld\ script rules@>=
+@G
+ifile_p1:
+ memory {@>@[TeX_( "/yy0{{mem}{/the/yy(1)}}" );@]@=}
+ | sections {@>@[TeX_( "/yy0{{sect}{/the/yy(1)}}" );@]@=}
+ | phdrs
+ | startup
+ | high_level_library
+ | low_level_library
+ | floating_point_support
+ | statement_anywhere {@>@[TeX_( "/yy0{{stmt}{/noexpand/ldstatement{/the/yy(1)}}}" );@]@=}
+ | version
+ | ';' {@>@[TeX_( "/yy0{{none}{}}" );@]@=}
+ | TARGET_K '(' NAME ')' {}
+ | SEARCH_DIR '(' filename ')' {}
+ | OUTPUT '(' filename ')' {}
+ | OUTPUT_FORMAT '(' NAME ')' {}
+ | OUTPUT_FORMAT '(' NAME ','
+ NAME ',' NAME ')' {}
+ | OUTPUT_ARCH '(' NAME ')' {}
+ | FORCE_COMMON_ALLOCATION {}
+ | INHIBIT_COMMON_ALLOCATION {}
+ | INPUT '(' input_list ')'
+ | GROUP {}
+ '(' input_list ')' {}
+ | MAP '(' filename ')' {}
+ | INCLUDE filename {@>@<Peek at a file@>@=}
+ ifile_list END {@>@<Add an \prodstyle{INCLUDE} statement@>@=}
+ | NOCROSSREFS '('
+ nocrossref_list ')' {}
+ | EXTERN '(' extern_name_list ')'
+ | INSERT_K AFTER NAME {}
+ | INSERT_K BEFORE NAME {}
+ | REGION_ALIAS '(' NAME ',' NAME ')' {}
+ | LD_FEATURE '(' NAME ')' {}
+ ;
+
+input_list:
+ NAME {}
+ | input_list ',' NAME {}
+ | input_list NAME {}
+ | LNAME {}
+ | input_list ',' LNAME {}
+ | input_list LNAME {}
+ | AS_NEEDED '(' {}
+ input_list ')' {}
+ | input_list ',' AS_NEEDED '(' {}
+ input_list ')' {}
+ | input_list AS_NEEDED '(' {}
+ input_list ')' {}
+ ;
+
+sections:
+ SECTIONS '{' sec_or_group_p1 '}' {@>@[TeX_( "/yy0{/noexpand/ldsections{/the/yy(3)}}" );@]@=}
+ ;
+
+sec_or_group_p1:
+ sec_or_group_p1 section {@>@<Add the next section@>@=}
+ | sec_or_group_p1 statement_anywhere {@>@<Add the next statement@>@=}
+ | {@>@[TeX_( "/yy0{}" );@]@=}
+ ;
+
+statement_anywhere:
+ ENTRY '(' NAME ')' {}
+ | assignment end {@>@<Carry on@>@=}
+ | ASSERT_K {@>@[TeX_( "/ldlex@@expression" );@]@=}
+ '(' exp ',' NAME ')' {@>@[TeX_( "/ldlex@@popstate" );@]@=}
+ ;
+@g
+
+@ @<Add the next section@>=
+ @[TeXb( "/yytoksempty{/yy(1)}{/yy0{/the/yy(2)}}" );@]@;
+ @[TeXao( "{/yy0{/the/yy(1)/noexpand/ldsectionseparator/the/yy(2)}}" );@]@;
+
+@ @<Add the next statement@>=
+ @[TeXb( "/yytoksempty{/yy(1)}{/yy0{/the/yy(2)}}" );@]@;
+ @[TeXao( "{/yy0{/the/yy(1)/noexpand/ldsectionseparator/ldstatement{/the/yy(2)}}}" );@]@;
+
+@ This is the default action performed by the parser when the parser
+writer does not supply one. For a minor gain in efficiency, this
+definition can be made empty.
+@<Carry on@>=
+ @[TeX_( "/yy0{/the/yy(1)}" );@]@;
+
+@ @<Peek at a file@>=
+ @[TeX_( "/ldlex@@script" );@]@;
+ @[TeX_( "/ldfile@@open@@command@@file{/yy(2)}" );@]@;
+
+@ @<Close the file@>=
+ @[TeX_( "/yy0{/noexpand/ldinclude{/the/yy(2)}}/ldlex@@popstate" );@]@;
+
+@ @<Add an \prodstyle{INCLUDE} statement@>=
+ @[TeX_( "/yy0{{inc}{/noexpand/ldinclude{/the/yy(2)}}}/ldlex@@popstate" );@]@;
+
+@ \tracebadcharstrue
+{\it The \prodstyle{'*'} and \prodstyle{'?'} cases are there because the lexer returns them as
+separate tokens rather than as \prodstyle{NAME}.}
+\tracebadcharsfalse
+@<Grammar rules@>=
+@G
+wildcard_name:
+ NAME {@>@<Carry on@>@=}
+ | '*' {@>@[TeX_( "/yy0{{*}{*}}" );@]@=}
+ | '?' {@>@[TeX_( "/yy0{{?}{?}}" );@]@=}
+ ;
+@g
+
+@ @<Grammar rules@>=
+@G
+wildcard_spec:
+ wildcard_name {}
+ | EXCLUDE_FILE '(' exclude_name_list ')' wildcard_name
+ {}
+ | SORT_BY_NAME '(' wildcard_name ')' {}
+ | SORT_BY_ALIGNMENT '(' wildcard_name ')'
+ {}
+ | SORT_NONE '(' wildcard_name ')'
+ {}
+ | SORT_BY_NAME '(' SORT_BY_ALIGNMENT '(' wildcard_name ')' ')'
+ {}
+ | SORT_BY_NAME '(' SORT_BY_NAME '(' wildcard_name ')' ')'
+ {}
+ | SORT_BY_ALIGNMENT '(' SORT_BY_NAME '(' wildcard_name ')' ')'
+ {}
+ | SORT_BY_ALIGNMENT
+@t}\vb{\breakline}{@>
+ '(' SORT_BY_ALIGNMENT '(' wildcard_name ')' ')'
+ {}
+ | SORT_BY_NAME
+@t}\vb{\breakline}{@>
+ '(' EXCLUDE_FILE '(' exclude_name_list ')' wildcard_name ')'
+ {}
+ | SORT_BY_INIT_PRIORITY '(' wildcard_name ')'
+ {}
+ ;
+
+sect_flag_list:
+ NAME {}
+ | sect_flag_list '&' NAME {}
+ ;
+
+sect_flags:
+ INPUT_SECTION_FLAGS '(' sect_flag_list ')' {}
+ ;
+
+exclude_name_list:
+ exclude_name_list wildcard_name {}
+ | wildcard_name {}
+ ;
+
+file_NAME_list:
+ file_NAME_list opt_comma wildcard_spec {@>@[TeX_( "/yy0{/the/yy(1)/noexpand/ldspace/noexpand/ldregexp{/the/yy(2)}}" );@]@=}
+ | wildcard_spec {@>@[TeX_( "/yy0{/noexpand/ldregexp{/the/yy(1)}}" );@]@=}
+ ;
+
+input_section_spec_no_keep:
+ NAME {}
+ | sect_flags NAME {}
+ | '[' file_NAME_list ']' {}
+ | sect_flags '[' file_NAME_list ']' {}
+ | wildcard_spec '(' file_NAME_list ')' {@>@[TeX_( "/yy0{/noexpand/ldregexp{/the/yy(1)}(/the/yy(3))}" );@]@=}
+ | sect_flags wildcard_spec '(' file_NAME_list ')'
+ {}
+ ;
+@g
+
+@ @<Grammar rules@>=
+@G
+input_section_spec:
+ input_section_spec_no_keep {@>@<Carry on@>@=}
+ | KEEP '(' {}
+ input_section_spec_no_keep ')' {@>@[TeX_( "/yy0{/mathop{/hbox{/noexpand/ttl keep}(/the/yy(4))}}" );@]@=}
+ ;
+
+statement:
+ assignment end
+ | CREATE_OBJECT_SYMBOLS {}
+ | ';' {@>@[TeX_( "/yy0{}" );@]@=}
+ | CONSTRUCTORS {}
+ | SORT_BY_NAME '(' CONSTRUCTORS ')' {}
+ | input_section_spec
+ | length '(' mustbe_exp ')' {}
+ | FILL '(' fill_exp ')' {}
+ | ASSERT_K {@>@[TeX_( "/ldlex@@expression" );@]@=}
+ '(' exp ',' NAME ')' end {@>@[TeX_( "/ldlex@@popstate" );@]@=}
+ | INCLUDE filename {@>@<Peek at a file@>@=}
+ statement_list_opt END {@>@<Close the file@>@=}
+ ;
+
+statement_list:
+ statement_list statement {@>@<Attach a statement to a statement list@>@=}
+ | statement {@>@<Start a statement list with a statement@>@=}
+ ;
+
+statement_list_opt:
+ {@>@[TeX_( "/yy0{}" );@]@=}
+ | statement_list {@>@<Carry on@>@=}
+ ;
+@g
+
+@ @<Attach a statement to a statement list@>=
+ @[TeX_( "/yy0{/the/yy(1)/yytoksempty{/yy(2)}{}{/yytoksempty{/yy(1)}{}{/noexpand/ldor}{/the/yy(2)}}}" );@]
+
+@ @<Start a statement list with a statement@>=
+ @[TeX_( "/yy0{/yytoksempty{/yy(1)}{}{{/the/yy(1)}}}" );@]
+
+@ @<Grammar rules@>=
+@G
+@t}\vb{\inline\flatten}{@>
+length:
+ QUAD {}
+ | SQUAD {}
+ | LONG {}
+ | SHORT {}
+ | BYTE {}
+ ;
+
+fill_exp:
+ mustbe_exp {@>@<Carry on@>@=}
+ ;
+
+fill_opt:
+ '=' fill_exp {@>@[TeX_( "/yy0{/noexpand/ldfill{/the/yy(2)}}" );@]@=}
+ | {@>@[TeX_( "/yy0{}" );@]@=}
+ ;
+
+@t}\vb{\resetf}{@>
+assign_op:
+ PLUSEQ {@>@[TeX_( "/yy(0)={/MRL{+{/K}}}" );@]@=}
+ | MINUSEQ {@>@[TeX_( "/yy(0)={/MRL{-{/K}}}" );@]@=}
+@t}\vb{\inline\flatten}{@>
+ | MULTEQ {@>@[TeX_( "/yy(0)={/MRL*{/K}}" );@]@=}
+ | DIVEQ {@>@[TeX_( "/yy(0)={/MRL{{/div}{/K}}}" );@]@=}
+ | LSHIFTEQ {@>@[TeX_( "/yy(0)={/MRL{{/ll}{/K}}}" );@]@=}
+ | RSHIFTEQ {@>@[TeX_( "/yy(0)={/MRL{{/gg}{/K}}}" );@]@=}
+ | ANDEQ {@>@[TeX_( "/yy(0)={/Xandxeq}" );@]@=}
+ | OREQ {@>@[TeX_( "/yy(0)={/Xorxeq}" );@]@=}
+ ;
+
+end: ';' | ','
+ ;
+
+opt_comma: ',' |
+ ;
+@t}\vb{\resetf}{@>
+@g
+
+@ Assignments are not expressions as in \Cee.
+@<Grammar rules@>=
+@G
+assignment:
+ NAME '=' mustbe_exp {@>@<Process simple assignment@>@=}
+ | NAME assign_op mustbe_exp {@>@<Process compound assignment@>@=}
+ | HIDDEN '(' NAME '=' mustbe_exp ')' {}
+ | PROVIDE '(' NAME '=' mustbe_exp ')' {}
+ | PROVIDE_HIDDEN '(' NAME '=' mustbe_exp ')' {}
+ ;
+@g
+
+@ @<Process simple assignment@>=
+ @[TeX_( "/yy0{/noexpand/ldassignment{/noexpand/ldregexp{/the/yy(1)}}{/K}{/the/yy(3)}}" );@]
+
+@ @<Process compound assignment@>=
+ @[TeX_( "/yy0{/noexpand/ldassignment{/noexpand/ldregexp{/the/yy(1)}}{/the/yy(2)}{/the/yy(3)}}" );@]
+
+@ @<Grammar rules@>=
+@G
+memory:
+ MEMORY '{' memory_spec_list_opt '}' {@>@[TeX_( "/yy0{/noexpand/ldmemory{/the/yy(3)}}" );@]@=}
+ ;
+
+memory_spec_list_opt:
+ memory_spec_list {@>@<Carry on@>@=}
+ | {@>@[TeX_( "/yy0{}" );@]@=}
+ ;
+
+memory_spec_list:
+ memory_spec_list opt_comma memory_spec {@>@[TeX_( "/yy0{/the/yy(1)/the/yy(3)}" );@]@=}
+ | memory_spec {@>@[TeX_( "/yy0{/the/yy(1)}" );@]@=}
+ ;
+
+
+memory_spec:
+ NAME {}
+ attributes_opt ':'
+ origin_spec
+@t}\vb{\breakline}{@>
+ opt_comma length_spec {@>@[TeX_( "/yy0{/noexpand/ldmemoryspec{/the/yy(1)}{/the/yy(3)}{/the/yy(5)}{/the/yy(7)}}" );@]@=}
+ | INCLUDE filename {@>@<Peek at a file@>@=}
+ memory_spec_list_opt END {@>@<Close the file@>@=}
+ ;
+@g
+
+@ @<Grammar rules@>=
+@G
+origin_spec:
+ ORIGIN '=' mustbe_exp {@>@[TeX_( "/yy0{/noexpand/ldoriginspec{/the/yy(3)}}" );@]@=}
+ ;
+
+length_spec:
+ LENGTH '=' mustbe_exp {@>@[TeX_( "/yy0{/noexpand/ldlengthspec{/the/yy(3)}}" );@]@=}
+ ;
+
+attributes_opt:
+
+ {@>@[TeX_( "/yy0{}" );@]@=}
+ | '(' attributes_list ')' {@>@[TeX_( "/yy0{/the/yy(2)}" );@]@=}
+ ;
+
+attributes_list:
+ attributes_string {@>@[TeX_( "/yy0{/the/yy(1)}" );@]@=}
+ | attributes_list attributes_string {@>@[TeX_( "/yy0{/the/yy(1)/noexpand/ldspace/the/yy(2)}" );@]@=}
+ ;
+
+attributes_string:
+ NAME {@>@[TeX_( "/yy0{/noexpand/ldattributes{/the/yy(1)}}" );@]@=}
+ | '!' NAME {@>@[TeX_( "/yy0{/noexpand/ldattributesneg{/the/yy(2)}}" );@]@=}
+ ;
+
+startup:
+ STARTUP '(' filename ')' {}
+ ;
+
+high_level_library:
+ HLL '(' high_level_library_NAME_list ')'
+ | HLL '(' ')' {}
+ ;
+
+high_level_library_NAME_list:
+ high_level_library_NAME_list opt_comma filename
+ {}
+ | filename {}
+ ;
+
+low_level_library:
+ SYSLIB '(' low_level_library_NAME_list ')' {}
+ ;
+
+low_level_library_NAME_list:
+ low_level_library_NAME_list opt_comma filename
+ {}
+ | {}
+ ;
+
+floating_point_support:
+ FLOAT {}
+ | NOFLOAT {}
+ ;
+
+nocrossref_list:
+ {}
+ | NAME nocrossref_list {}
+ | NAME ',' nocrossref_list {}
+ ;
+
+mustbe_exp:
+ {@>@[TeX_( "/ldlex@@expression" );@]@=}
+ exp {@>@[TeX_( "/ldlex@@popstate/yy0{/the/yy(2)}" );@]@=}
+ ;
+@g
+
+@*1 {\ifheader\ninepoint\fi\prodstyle{SECTIONS}} and expressions.
+The linker supports an extensive range of expressions. The precedence
+mechanism provided by \bison\ is used to present the composition of
+expressions out of simpler chunks and basic building blocks tied
+together by algebraic operations.
+@<Grammar rules@>=
+@G
+exp :
+ '-' exp %prec UNARY {@>@[TeX_( "/yy0{{-/the/yy(2)}}" );@]@=}
+ | '(' exp ')' {@>@[TeX_( "/yy0{(/the/yy(2))}" );@]@=}
+ | NEXT '(' exp ')' %prec UNARY {@>@[TeX_( "/yy0{/hbox{/nx/ssf next}(/the/yy(3))}" );@]@=}
+ | '!' exp %prec UNARY {@>@[TeX_( "/yy0{{/noexpand/CM/the/yy(2)}}" );@]@=}
+ | '+' exp %prec UNARY {@>@[TeX_( "/yy0{{+/the/yy(2)}}" );@]@=}
+ | '~' exp %prec UNARY {@>@[TeX_( "/yy0{{/noexpand/R/the/yy(2)}}" );@]@=}
+ | exp '*' exp {@>@[TeX_( "/yy0{/the/yy(1)/noexpand/times/the/yy(3)}" );@]@=}
+ | exp '/' exp {@>@[TeX_( "/yy0{/the/yy(1)/noexpand///the/yy(3)}" );@]@=}
+ | exp '%' exp {@>@[TeX_( "/yy0{/the/yy(1)/noexpand/div/the/yy(3)}" );@]@=}
+ | exp '+' exp {@>@[TeX_( "/yy0{/the/yy(1)+/the/yy(3)}" );@]@=}
+ | exp '-' exp {@>@[TeX_( "/yy0{/the/yy(1)-/the/yy(3)}" );@]@=}
+ | exp LSHIFT exp {@>@[TeX_( "/yy0{/the/yy(1)/noexpand/ll/the/yy(3)}" );@]@=}
+ | exp RSHIFT exp {@>@[TeX_( "/yy0{/the/yy(1)/noexpand/gg/the/yy(3)}" );@]@=}
+ | exp EQ exp {@>@[TeX_( "/yy0{/the/yy(1)=/the/yy(3)}" );@]@=}
+ | exp NE exp {@>@[TeX_( "/yy0{/the/yy(1)/noexpand/not=/the/yy(3)}" );@]@=}
+ | exp LE exp {@>@[TeX_( "/yy0{/the/yy(1)/noexpand/leq/the/yy(3)}" );@]@=}
+ | exp GE exp {@>@[TeX_( "/yy0{/the/yy(1)/noexpand/geq/the/yy(3)}" );@]@=}
+ | exp '<' exp {@>@[TeX_( "/yy0{/the/yy(1)</the/yy(3)}" );@]@=}
+ | exp '>' exp {@>@[TeX_( "/yy0{/the/yy(1)>/the/yy(3)}" );@]@=}
+ | exp '&' exp {@>@[TeX_( "/yy0{/the/yy(1)/noexpand/AND/the/yy(3)}" );@]@=}
+ | exp '^' exp {@>@[TeX_( "/yy0{/the/yy(1)/noexpand/XOR/the/yy(3)}" );@]@=}
+ | exp '|' exp {@>@[TeX_( "/yy0{/the/yy(1)/noexpand/OR/the/yy(3)}" );@]@=}
+ | exp '?' exp ':' exp {@>@<Process a primitive conditional@>@=}
+ | exp ANDAND exp {@>@[TeX_( "/yy0{/the/yy(1)/noexpand/V/the/yy(3)}" );@]@=}
+ | exp OROR exp {@>@[TeX_( "/yy0{/the/yy(1)/noexpand/W/the/yy(3)}" );@]@=}
+@g
+
+@ More atomic expression types specific to the linker's function.
+@<Grammar rules@>=
+@G
+exp :
+ DEFINED '(' NAME ')' {}
+ | INT {}
+ | SIZEOF_HEADERS {}
+ | ALIGNOF '(' NAME ')' {}
+ | SIZEOF '(' NAME ')' {}
+ | ADDR '(' NAME ')' {}
+ | LOADADDR '(' NAME ')' {}
+ | CONSTANT '(' NAME ')' {}
+ | ABSOLUTE '(' exp ')' {}
+ | ALIGN_K '(' exp ')' {@>@[TeX_( "/yy0{/nx/mathop{/hbox{/nx/ssf align}}(/the/yy(3))}" );@]@=}
+ | ALIGN_K '(' exp ',' exp ')' {}
+ | DATA_SEGMENT_ALIGN '(' exp ',' exp ')' {}
+ | DATA_SEGMENT_RELRO_END '(' exp ',' exp ')' {}
+ | DATA_SEGMENT_END '(' exp ')' {}
+ | SEGMENT_START '(' NAME ',' exp ')' {}
+ | BLOCK '(' exp ')' {}
+ | NAME {@>@[TeX_( "/yy0{/noexpand/ldregexp{/the/yy(1)}}" );@]@=}
+ | MAX_K '(' exp ',' exp ')' {}
+ | MIN_K '(' exp ',' exp ')' {}
+ | ASSERT_K '(' exp ',' NAME ')' {}
+ | ORIGIN '(' NAME ')' {}
+ | LENGTH '(' NAME ')' {}
+ | LOG2CEIL '(' exp ')' {}
+ ;
+@g
+
+@ @<Process a primitive conditional@>=
+@q TeX_( "/yy0{/hbox{/nx/ttl let }/nx/xi(0)=/the/yy(5): /nx/xi(/nx/CM0)=/the/yy(3)/hbox{ /nx/ttl do }/xi(/the/yy(1))}" );@>
+@[TeX_( "/yy0{/hbox{/nx/ttl do }/xi(/the/yy(1))/hbox{ /nx/ttl where }" );@>
+@[TeX_( " {/let/nx/{/nx/bigbracedel/nx/xi(x)=/nx/cases{/the/yy(5)& if /inmath{x=0}/cr/the/yy(3)& if /inmath{x/nx/not=0}}}}" );@]
+
+@ @<Grammar rules@>=
+@G
+memspec_at_opt:
+ AT '>' NAME {@>@[TeX_( "/yy0{/the/yy(3)}" );@]@=}
+ | {@>@[TeX_( "/yy0{}" );@]@=}
+ ;
+
+opt_at:
+ AT '(' exp ')' {@>@[TeX_( "/yy0{/the/yy(3)}" );@]@=}
+ | {@>@[TeX_( "/yy0{}" );@]@=}
+ ;
+
+opt_align:
+ ALIGN_K '(' exp ')' {@>@[TeX_( "/yy0{/the/yy(3)}" );@]@=}
+ | {@>@[TeX_( "/yy0{}" );@]@=}
+ ;
+
+opt_align_with_input:
+ ALIGN_WITH_INPUT {@>@[TeX_( "/yy0{align with input}" );@]@=}
+ | {@>@[TeX_( "/yy0{}" );@]@=}
+ ;
+
+opt_subalign:
+ SUBALIGN '(' exp ')' {@>@[TeX_( "/yy0{/the/yy(3)}" );@]@=}
+ | {@>@[TeX_( "/yy0{}" );@]@=}
+ ;
+
+sect_constraint:
+ ONLY_IF_RO {@>@[TeX_( "/yy0{only/_if/_ro}" );@]@=}
+ | ONLY_IF_RW {@>@[TeX_( "/yy0{only/_if/_rw}" );@]@=}
+ | SPECIAL {@>@[TeX_( "/yy0{special}" );@]@=}
+ | {@>@[TeX_( "/yy0{}" );@]@=}
+ ;
+
+@g
+
+@ {\it The \prodstyle{GROUP} case is just enough to support the \gcc\
+|svr3.ifile| script. It is not intended to be full support. I'm
+not even sure what \prodstyle{GROUP} is supposed to mean.} A careful
+analysis of the productions below reveals some
+pitfalls in the parser/lexer interaction setup that uses the state switching
+macros (or functions in the case of the original parser). The switch
+to the \.{EXPRESSION} state at the end of the production for
+\prodstyle{section} is invoked before \prodstyle{opt\_comma} which can
+be empty. This means that the next (lookahead) token (which could be a
+\prodstyle{NAME} in a different context) might be read before the
+lexer is in the appropriate state. In practice, the names of the sections
+and other \prodstyle{NAME}s are usually pretty straightforward so this
+parser idiosynchrasy is unlikely to lead to a genuine problem. Since
+the goal was to keep the original grammar intact as much as possible,
+it was decided to leave this production unchanged.
+@<Grammar rules@>=
+@G
+section:
+ NAME {@>@[TeX_( "/ldlex@@expression" );@]@=}
+ opt_exp_with_type opt_at opt_align opt_align_with_input
+@t}\vb{\breakline}{@>
+ opt_subalign {@>@[TeX_( "/ldlex@@popstate/ldlex@@script" );@]@=}
+ sect_constraint
+ '{' {}
+ statement_list_opt
+ '}' {@>@[TeX_( "/ldlex@@popstate/ldlex@@expression" );@]@=}
+ memspec_opt memspec_at_opt phdr_opt fill_opt
+ {@>@[TeX_( "/ldlex@@popstate" );@]@=}
+ opt_comma {@>@<Record a named section@>@=}
+ | OVERLAY {@>@[TeX_( "/ldlex@@expression" );@]@=}
+ opt_exp_without_type opt_nocrossrefs opt_at opt_subalign
+ {@>@[TeX_( "/ldlex@@popstate/ldlex@@script" );@]@=}
+ '{' {}
+ overlay_section '}' {@>@[TeX_( "/ldlex@@popstate/ldlex@@expression" );@]@=}
+ memspec_opt memspec_at_opt phdr_opt fill_opt
+ {@>@[TeX_( "/ldlex@@popstate" );@]@=}
+ opt_comma {@>@<Record an overlay section@>@=}
+ | GROUP {@>@[TeX_( "/ldlex@@expression" );@]@=}
+ opt_exp_with_type {@>@[TeX_( "/ldlex@@popstate" );@]@=}
+ '{' sec_or_group_p1 '}'
+ | INCLUDE filename {@>@<Peek at a file@>@=}
+ sec_or_group_p1 END
+ {@>@<Close the file@>@=}
+ ;
+@g
+
+@ @<Record a named section@>=
+ @[TeXb( "/yy0{/nx/ldnamedsection{/the/yy(1)}{/the/yy(3)}{/the/yy(4)}" );@]@;
+ @[TeXf( " {{/the/yy(5)}{/the/yy(6)}{/the/yy(7)}}" );@]@;/* alignment */
+ @[TeXf( " {/the/yy(9)}{/the/yy(12)}" );@]@;
+ @[TeXfo( " {{/the/yy(15)}{/the/yy(16)}{/the/yy(17)}{/the/yy(18)}}}" );@]@; /*memory specifiers */
+
+@ @<Record an overlay section@>=
+
+@ @<Grammar rules@>=
+@G
+type:
+ NOLOAD {@>@[TeX_( "/yy0{noload}" );@]@=}
+ | DSECT {@>@[TeX_( "/yy0{dsect}" );@]@=}
+ | COPY {@>@[TeX_( "/yy0{copy}" );@]@=}
+ | INFO {@>@[TeX_( "/yy0{info}" );@]@=}
+ | OVERLAY {@>@[TeX_( "/yy0{overlay}" );@]@=}
+ ;
+
+atype:
+ '(' type ')' {@>@[TeX_( "/yy0{/noexpand/ldtype{/the/yy(2)}}" );@]@=}
+ | '(' ')' {@>@[TeX_( "/yy0{/noexpand/ldtype{}}" );@]@=}
+ | {@>@[TeX_( "/yy0{}" );@]@=}
+ ;
+@g
+
+@ {\it The \prodstyle{BIND} cases are to support the \gcc\ |svr3.ifile|
+script. They aren't intended to implement full support for the
+\prodstyle{BIND} keyword. I'm not even sure what \prodstyle{BIND}
+is supposed to mean.}
+@<Grammar rules@>=
+@G
+opt_exp_with_type:
+ exp atype ':' {@>@[TeX_( "/yy0{{}{/the/yy(1)}{}{}{/the/yy(2)}}" );@]@=}
+ | atype ':' {@>@[TeX_( "/yy0{{}{}{}{}{/the/yy(1)}}" );@]@=}
+ | BIND '(' exp ')' atype ':' {@>@[TeX_( "/yy0{{bind}{/the/yy(3)}{}{}{/the/yy(5)}}" );@]@=}
+ | BIND '(' exp ')' BLOCK '(' exp ')' atype ':'
+ {@>@[TeX_( "/yy0{{bind}{/the/yy(3)}{block}{/the/yy(7)}{/the/yy(9)}}" );@]@=}
+ ;
+
+opt_exp_without_type:
+ exp ':' {}
+ | ':' {}
+ ;
+
+opt_nocrossrefs:
+ {}
+ | NOCROSSREFS {}
+ ;
+
+memspec_opt:
+ '>' NAME {@>@[TeX_( "/yy0{/the/yy(2)}" );@]@=}
+ | {@>@[TeX_( "/yy0{}" );@]@=}
+ ;
+
+phdr_opt:
+ {@>@[TeX_( "/yy0{}" );@]@=}
+ | phdr_opt ':' NAME {@>@<Add another pheader@>@=}
+ ;
+
+overlay_section:
+
+ | overlay_section
+ NAME {@>@[TeX_( "/ldlex@@script" );@]@=}
+ '{' statement_list_opt '}' {@>@[TeX_( "/ldlex@@popstate/ldlex@@expression" );@]@=}
+ phdr_opt fill_opt {@>@[TeX_( "/ldlex@@popstate" );@]@=}
+ opt_comma
+ ;
+@g
+
+@ @<Add another pheader@>=
+ @[TeXb( "/yytoksempty{/yy(1)}{/yy0{{/the/yy(3)}}}" );@]@;
+ @[TeXao( "{/yy0{/the/yy(1)/noexpand/ldor{/the/yy(3)}}}" );@]@;
+
+@ @<Grammar rules@>=
+@G
+phdrs:
+ PHDRS '{' phdr_list '}'
+ ;
+
+phdr_list:
+
+ | phdr_list phdr
+ ;
+
+phdr:
+ NAME {@>@[TeX_( "/ldlex@@expression" );@]@=}
+ phdr_type phdr_qualifiers {@>@[TeX_( "/ldlex@@popstate" );@]@=}
+ ';' {}
+ ;
+
+phdr_type:
+ exp {}
+ ;
+
+phdr_qualifiers:
+ {}
+ | NAME phdr_val phdr_qualifiers {}
+ | AT '(' exp ')' phdr_qualifiers {}
+ ;
+
+phdr_val:
+ {}
+ | '(' exp ')' {}
+ ;
+@g
+
+@*1 Other types of script files. At present time other script types
+are ignored, although some of the rules are used in linker scripts
+that are processed by the parser.
+@<Dynamic list file rules@>=
+@G
+dynamic_list_file:
+ {@>@[TeX_( "/ldlex@@version@@file" );@]@=}
+ dynamic_list_nodes {@>@[TeX_( "/ldlex@@popstate" );@]@=}
+ ;
+
+dynamic_list_nodes:
+ dynamic_list_node
+ | dynamic_list_nodes dynamic_list_node
+ ;
+
+dynamic_list_node:
+ '{' dynamic_list_tag '}' ';'
+ ;
+
+dynamic_list_tag:
+ vers_defns ';' {}
+ ;
+@g
+
+@ {\it This syntax is used within an external version script file.}
+@<Version file rules@>=
+@G
+version_script_file:
+ {@>@[TeX_( "/ldlex@@version@@file" );@]@=}
+ vers_nodes {@>@[TeX_( "/ldlex@@popstate" );@]@=}
+ ;
+@g
+
+@ {\it This is used within a normal linker script file.}
+@<Grammar rules@>=
+@G
+version:
+ {@>@[TeX_( "/ldlex@@version@@script" );@]@=}
+ VERSIONK '{' vers_nodes '}' {@>@[TeX_( "/ldlex@@popstate" );@]@=}
+ ;
+
+vers_nodes:
+ vers_node
+ | vers_nodes vers_node
+ ;
+
+vers_node:
+ '{' vers_tag '}' ';' {}
+ | VERS_TAG '{' vers_tag '}' ';' {}
+ | VERS_TAG '{' vers_tag '}' verdep ';' {}
+ ;
+
+verdep:
+ VERS_TAG {}
+ | verdep VERS_TAG {}
+ ;
+
+vers_tag:
+ {}
+ | vers_defns ';' {}
+ | GLOBAL ':' vers_defns ';' {}
+ | LOCAL ':' vers_defns ';' {}
+ | GLOBAL ':' vers_defns ';' LOCAL ':' vers_defns ';'
+ {}
+ ;
+
+vers_defns:
+ VERS_IDENTIFIER {}
+ | NAME {}
+ | vers_defns ';' VERS_IDENTIFIER {}
+ | vers_defns ';' NAME {}
+ | vers_defns ';' EXTERN NAME '{' {}
+ vers_defns opt_semicolon '}' {}
+ | EXTERN NAME '{' {}
+ vers_defns opt_semicolon '}' {}
+ | GLOBAL {}
+ | vers_defns ';' GLOBAL {}
+ | LOCAL {}
+ | vers_defns ';' LOCAL {}
+ | EXTERN {}
+ | vers_defns ';' EXTERN {}
+ ;
+@t}\vb{\inline\flatten}{@>
+opt_semicolon:
+
+ | ';'
+ ;
+@g
diff --git a/support/splint/examples/ld/ldgramo.w b/support/splint/examples/ld/ldgramo.w
new file mode 100644
index 0000000000..3069bb71eb
--- /dev/null
+++ b/support/splint/examples/ld/ldgramo.w
@@ -0,0 +1,1645 @@
+@q Copyright 2015 Alexander Shibakov@>
+@q Copyright 2002-2015 Free Software Foundation, Inc.@>
+@q This file is part of SPLinT@>
+
+@q SPLinT is free software: you can redistribute it and/or modify@>
+@q it under the terms of the GNU General Public License as published by@>
+@q the Free Software Foundation, either version 3 of the License, or@>
+@q (at your option) any later version.@>
+
+@q SPLinT is distributed in the hope that it will be useful,@>
+@q but WITHOUT ANY WARRANTY; without even the implied warranty of@>
+@q MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the@>
+@q GNU General Public License for more details.@>
+
+@q You should have received a copy of the GNU General Public License@>
+@q along with SPLinT. If not, see <http://www.gnu.org/licenses/>.@>
+
+@*1 The original parser. {\it Here we present the full grammar of \ld, including some actions.
+The grammar is split into sections but otherwise is reproduced exactly.
+In addition to improving readability, such splitting allows \CWEB\ to process the code in
+manageable increments. An observant reader will notice the difficulty
+\CWEAVE\ is having with typesetting the structure tags that have the same
+name as the structure variables of the appropriate type. This is a well-known
+defect in \CWEAVE's design (see the requisite documentation) left
+uncorrected to discourage the poor programming practice.}
+
+@s bfd_boolean int
+@s bfd_vma int
+@s fill_type int
+@s lang_nocrossref int
+@s lang_output_section_phdr_list int
+@s bfd_elf_version_deps int
+@s bfd_elf_version_expr int
+@s bfd_elf_version_tree int
+@s etree_union int
+@s wildcard_spec int
+@s section_type int
+@s lang_memory_region_type int
+
+@<The original \ld\ parser@>=
+@G
+%{
+ @>@<\Cee\ setup for \ld\ grammar@>@;
+%}
+%union {
+@O
+ bfd_vma integer;
+ struct big_int
+ {
+ bfd_vma integer;
+ char *str;
+ } bigint;
+ fill_type *fill;
+ char *name;
+ const char *cname;
+ struct wildcard_spec wildcard;
+ struct wildcard_list *wildcard_list;
+ struct name_list *name_list;
+ struct flag_info_list *flag_info_list;
+ struct flag_info *flag_info;
+ int token;
+ union etree_union *etree;
+ struct phdr_info
+ {
+ bfd_boolean filehdr;
+ bfd_boolean phdrs;
+ union etree_union *at;
+ union etree_union *flags;
+ } phdr;
+ struct lang_nocrossref *nocrossref;
+ struct lang_output_section_phdr_list *section_phdr;
+ struct bfd_elf_version_deps *deflist;
+ struct bfd_elf_version_expr *versyms;
+ struct bfd_elf_version_tree *versnode;
+@o
+ }
+ @>@<Token definitions for the \ld\ grammar@>@;
+%%
+ @>@<Original \ld\ grammar rules@>@;
+%%
+@g
+
+@ {\it The \Cee\ code is left mostly intact (with the exception of a few
+comments) although it does not show up in the final output. The parts
+that {\it are\/} typeset represent the semantics that is reproduced in
+the typesetting parser. This includes all the state switching, as well
+as some other actions that affect the parser-lexer interaction (such
+as opening a new input buffer). The only exception to this rule is the
+code for the \MRI\ script section of the grammar. It is reproduced
+mostly as an example of a pretty printed grammar, since otherwise,
+\MRI\ scripts are completely ignored by the typeseting parser.}
+\def\initbootstrap{\restorecslist{parser-prototypes}\yyunion}%
+
+@<\Cee\ setup for \ld\ grammar@>=
+#define DONTDECLARE_MALLOC
+
+#include "sysdep.h"
+#include "bfd.h"
+#include "bfdlink.h"
+#include "ld.h"
+#include "ldexp.h"
+#include "ldver.h"
+#include "ldlang.h"
+#include "ldfile.h"
+#include "ldemul.h"
+#include "ldmisc.h"
+#include "ldmain.h"
+#include "mri.h"
+#include "ldctor.h"
+#include "ldlex.h"
+
+#ifndef YYDEBUG
+#define YYDEBUG 1
+#endif
+
+static enum section_type sectype;
+static lang_memory_region_type *region;
+
+bfd_boolean ldgram_had_keep = FALSE;
+char *ldgram_vers_current_lang = NULL;
+
+#define ERROR_NAME_MAX 20
+static char *error_names[ERROR_NAME_MAX];
+static int error_index;
+#define PUSH_ERROR(x) if (error_index < ERROR_NAME_MAX) error_names[error_index] = x; error_index++;
+#define POP_ERROR() @[error_index--;@]
+
+@ {\it The token definitions and the corresponding \prodstyle{\%union}
+styles are intermixed, which makes sense in the traditional style of a
+\bison\ script. When \CWEB\ is used, however, it helps to introduce the
+code in small, manageable sections and take advantage of \CWEB's crossreferencing
+facilities to provide cues on the relationships between various parts
+of the code.}
+@<Token definitions for the \ld\ grammar@>=
+@G
+%type <etree> exp opt_exp_with_type mustbe_exp opt_at phdr_type phdr_val
+%type <etree> opt_exp_without_type opt_subalign opt_align
+%type <fill> fill_opt fill_exp
+%type <name_list> exclude_name_list
+%type <wildcard_list> file_NAME_list
+%type <flag_info_list> sect_flag_list
+%type <flag_info> sect_flags
+%type <name> memspec_opt casesymlist
+%type <name> memspec_at_opt
+%type <cname> wildcard_name
+%type <wildcard> wildcard_spec
+%token <bigint> INT
+%token <name> NAME LNAME
+%type <integer> length
+%type <phdr> phdr_qualifiers
+%type <nocrossref> nocrossref_list
+%type <section_phdr> phdr_opt
+%type <integer> opt_nocrossrefs
+
+%right <token> PLUSEQ MINUSEQ MULTEQ DIVEQ '=' LSHIFTEQ RSHIFTEQ ANDEQ OREQ
+%right <token> '?' ':'
+%left <token> OROR
+%left <token> ANDAND
+%left <token> '|'
+%left <token> '^'
+%left <token> '&'
+%left <token> EQ NE
+%left <token> '<' '>' LE GE
+%left <token> LSHIFT RSHIFT
+
+%left <token> '+' '-'
+%left <token> '*' '/' '%'
+
+%right UNARY
+%token END
+%left <token> '('
+%token <token> ALIGN_K BLOCK BIND QUAD SQUAD LONG SHORT BYTE
+%token SECTIONS PHDRS INSERT_K AFTER BEFORE
+%token DATA_SEGMENT_ALIGN DATA_SEGMENT_RELRO_END DATA_SEGMENT_END
+%token SORT_BY_NAME SORT_BY_ALIGNMENT SORT_NONE
+%token SORT_BY_INIT_PRIORITY
+%token '{' '}'
+%token SIZEOF_HEADERS OUTPUT_FORMAT FORCE_COMMON_ALLOCATION OUTPUT_ARCH
+%token INHIBIT_COMMON_ALLOCATION
+%token SEGMENT_START
+%token INCLUDE
+%token MEMORY
+%token REGION_ALIAS
+%token LD_FEATURE
+%token NOLOAD DSECT COPY INFO OVERLAY
+%token DEFINED TARGET_K SEARCH_DIR MAP ENTRY
+%token <integer> NEXT
+%token SIZEOF ALIGNOF ADDR LOADADDR MAX_K MIN_K
+%token STARTUP HLL SYSLIB FLOAT NOFLOAT NOCROSSREFS
+%token ORIGIN FILL
+%token LENGTH CREATE_OBJECT_SYMBOLS INPUT GROUP OUTPUT CONSTRUCTORS
+%token ALIGNMOD AT SUBALIGN HIDDEN PROVIDE PROVIDE_HIDDEN AS_NEEDED
+%type <token> assign_op atype attributes_opt sect_constraint opt_align_with_input
+%type <name> filename
+%token CHIP LIST SECT ABSOLUTE LOAD NEWLINE ENDWORD ORDER NAMEWORD ASSERT_K
+%token LOG2CEIL FORMAT PUBLIC DEFSYMEND BASE ALIAS TRUNCATE REL
+%token INPUT_SCRIPT INPUT_MRI_SCRIPT INPUT_DEFSYM CASE EXTERN START
+%token <name> VERS_TAG VERS_IDENTIFIER
+%token GLOBAL LOCAL VERSIONK INPUT_VERSION_SCRIPT
+%token KEEP ONLY_IF_RO ONLY_IF_RW SPECIAL INPUT_SECTION_FLAGS ALIGN_WITH_INPUT
+%token EXCLUDE_FILE
+%token CONSTANT
+%type <versyms> vers_defns
+%type <versnode> vers_tag
+%type <deflist> verdep
+%token INPUT_DYNAMIC_LIST
+@g
+
+@ {\it The original \Cee\ code has been preserved and presented along with
+the grammar rules in the next two sections (the \Cee\ code has not
+been deleted in the subsequent sections either, it is just not
+typeset).}
+\saveparseoutputfalse
+@<Original \ld\ grammar rules@>=
+@G
+file:
+ INPUT_SCRIPT script_file
+ | INPUT_MRI_SCRIPT mri_script_file
+ | INPUT_VERSION_SCRIPT version_script_file
+ | INPUT_DYNAMIC_LIST dynamic_list_file
+ | INPUT_DEFSYM defsym_expr
+ ;
+
+
+filename: NAME;
+
+
+defsym_expr:
+ { @> ldlex_defsym(); @=}
+ NAME '=' exp
+ {
+@O
+ ldlex_popstate();
+@o
+ lang_add_assignment (exp_defsym ($2, $4));
+ }
+ ;
+
+@g
+
+@ Syntax within an \MRI\ script file.
+@<Original \ld\ grammar rules@>=
+@G
+mri_script_file:
+ {
+@O
+ @[ldlex_mri_script ();@]
+@o
+ PUSH_ERROR (_("MRI style script"));
+ }
+ mri_script_lines
+ {
+@O
+ ldlex_popstate ();
+@o
+ mri_draw_tree ();
+ POP_ERROR ();
+ }
+ ;
+
+mri_script_lines:
+ mri_script_lines mri_script_command NEWLINE
+ |
+ ;
+
+@g
+
+@ @<Original \ld\ grammar rules@>=
+@G
+mri_script_command:
+ CHIP exp
+ | CHIP exp ',' exp
+ | NAME { @> @<Flag an unrecognized keyword@> @=}
+ | LIST { @> config.map_filename = "-"; @=}
+ | ORDER ordernamelist
+ | ENDWORD
+ | PUBLIC NAME '=' exp
+ { @> mri_public($2, $4); @=}
+ | PUBLIC NAME ',' exp
+ { @> mri_public($2, $4); @=}
+ | PUBLIC NAME exp
+ { @> mri_public($2, $3); @=}
+ | FORMAT NAME
+ { @> mri_format($2); @=}
+ | SECT NAME ',' exp
+ { @> mri_output_section($2, $4); @=}
+ | SECT NAME exp
+ { @> mri_output_section($2, $3); @=}
+ | SECT NAME '=' exp
+ { @> mri_output_section($2, $4); @=}
+ | ALIGN_K NAME '=' exp
+ { @> mri_align($2,$4); @=}
+ | ALIGN_K NAME ',' exp
+ { @> mri_align($2,$4); @=}
+ | ALIGNMOD NAME '=' exp
+ { @> mri_alignmod($2,$4); @=}
+ | ALIGNMOD NAME ',' exp
+ { @> mri_alignmod($2,$4); @=}
+ | ABSOLUTE mri_abs_name_list
+ | LOAD mri_load_name_list
+ | NAMEWORD NAME
+ { @> mri_name($2); @=}
+ | ALIAS NAME ',' NAME
+ { @> mri_alias($2,$4,0); @=}
+ | ALIAS NAME ',' INT
+ { @> mri_alias ($2, 0, (int) $4.integer); @=}
+ | BASE exp
+ { @> mri_base($2); @=}
+ | TRUNCATE INT
+ { @> mri_truncate ((unsigned int) $2.integer); @=}
+ | CASE casesymlist
+ | EXTERN extern_name_list
+ | INCLUDE filename
+ { @> ldlex_script (); ldfile_open_command_file($2); @=}
+ mri_script_lines END
+ { @> ldlex_popstate (); @=}
+ | START NAME
+ { @> lang_add_entry ($2, FALSE); @=}
+ |
+ ;
+
+ordernamelist:
+ ordernamelist ',' NAME { @> mri_order($3); @=}
+ | ordernamelist NAME { @> mri_order($2); @=}
+ |
+ ;
+
+mri_load_name_list:
+ NAME { @> mri_load($1); @=}
+ | mri_load_name_list ',' NAME { @> mri_load($3); @=}
+ ;
+
+mri_abs_name_list:
+ NAME { @> mri_only_load($1); @=}
+ | mri_abs_name_list ',' NAME { @> mri_only_load($3); @=}
+ ;
+
+casesymlist:
+ { @> $$ = NULL; @=}
+ | NAME
+ | casesymlist ',' NAME
+ ;
+
+@g
+
+@ {\it Here is one way to deal with code that is too long to fit in an action.}
+@<Flag an unrecognized keyword@>=
+ einfo(_("%P%F: unrecognised keyword in MRI style script '%s'\n"),$1);
+
+@ Parsed as expressions so that commas separate entries.
+@<Original \ld\ grammar rules@>=
+@G
+extern_name_list:
+ {@> @[ldlex_expression ();@]@=}
+ extern_name_list_body
+ {@> @[ldlex_popstate ();@]@=}
+
+extern_name_list_body:
+ NAME
+ { ldlang_add_undef ($1, FALSE); }
+ | extern_name_list_body NAME
+ { ldlang_add_undef ($2, FALSE); }
+ | extern_name_list_body ',' NAME
+ { ldlang_add_undef ($3, FALSE); }
+ ;
+
+script_file:
+ {@> @[ldlex_both();@]@=}
+ ifile_list
+ {@> @[ldlex_popstate();@]@=}
+ ;
+
+ifile_list:
+ ifile_list ifile_p1
+ |
+ ;
+
+@g
+
+@ {\it All the commands that can appear in a standard linker script.}%
+@<Original \ld\ grammar rules@>=
+@G
+ifile_p1:
+ memory
+ | sections
+ | phdrs
+ | startup
+ | high_level_library
+ | low_level_library
+ | floating_point_support
+ | statement_anywhere
+ | version
+ | ';'
+ | TARGET_K '(' NAME ')'
+ { lang_add_target($3); }
+ | SEARCH_DIR '(' filename ')'
+ { ldfile_add_library_path ($3, FALSE); }
+ | OUTPUT '(' filename ')'
+ { lang_add_output($3, 1); }
+ | OUTPUT_FORMAT '(' NAME ')'
+ { lang_add_output_format ($3, (char *) NULL,
+ (char *) NULL, 1); }
+ | OUTPUT_FORMAT '(' NAME ',' NAME ',' NAME ')'
+ { lang_add_output_format ($3, $5, $7, 1); }
+ | OUTPUT_ARCH '(' NAME ')'
+ { ldfile_set_output_arch ($3, bfd_arch_unknown); }
+ | FORCE_COMMON_ALLOCATION
+ { command_line.force_common_definition = TRUE ; }
+ | INHIBIT_COMMON_ALLOCATION
+ { command_line.inhibit_common_definition = TRUE ; }
+ | INPUT '(' input_list ')'
+ | GROUP
+ { lang_enter_group (); }
+ '(' input_list ')'
+ { lang_leave_group (); }
+ | MAP '(' filename ')'
+ { lang_add_map($3); }
+ | INCLUDE filename
+ {
+@O
+ ldlex_script (); ldfile_open_command_file($2);
+@o
+ }
+ ifile_list END
+ {@> @[ldlex_popstate ();@]@=}
+ | NOCROSSREFS '(' nocrossref_list ')'
+ {
+ lang_add_nocrossref ($3);
+ }
+ | EXTERN '(' extern_name_list ')'
+ | INSERT_K AFTER NAME
+ { lang_add_insert ($3, 0); }
+ | INSERT_K BEFORE NAME
+ { lang_add_insert ($3, 1); }
+ | REGION_ALIAS '(' NAME ',' NAME ')'
+ { lang_memory_region_alias ($3, $5); }
+ | LD_FEATURE '(' NAME ')'
+ { lang_ld_feature ($3); }
+ ;
+
+@g
+
+@ @<Original \ld\ grammar rules@>=
+@G
+input_list:
+ NAME
+ { lang_add_input_file($1,lang_input_file_is_search_file_enum,
+ (char *)NULL); }
+ | input_list ',' NAME
+ { lang_add_input_file($3,lang_input_file_is_search_file_enum,
+ (char *)NULL); }
+ | input_list NAME
+ { lang_add_input_file($2,lang_input_file_is_search_file_enum,
+ (char *)NULL); }
+ | LNAME
+ { lang_add_input_file($1,lang_input_file_is_l_enum,
+ (char *)NULL); }
+ | input_list ',' LNAME
+ { lang_add_input_file($3,lang_input_file_is_l_enum,
+ (char *)NULL); }
+ | input_list LNAME
+ { lang_add_input_file($2,lang_input_file_is_l_enum,
+ (char *)NULL); }
+ | AS_NEEDED '('
+ { $<integer>$ = input_flags.add_DT_NEEDED_for_regular;
+ input_flags.add_DT_NEEDED_for_regular = TRUE; }
+ input_list ')'
+ { input_flags.add_DT_NEEDED_for_regular = $<integer>3; }
+ | input_list ',' AS_NEEDED '('
+ { $<integer>$ = input_flags.add_DT_NEEDED_for_regular;
+ input_flags.add_DT_NEEDED_for_regular = TRUE; }
+ input_list ')'
+ { input_flags.add_DT_NEEDED_for_regular = $<integer>5; }
+ | input_list AS_NEEDED '('
+ { $<integer>$ = input_flags.add_DT_NEEDED_for_regular;
+ input_flags.add_DT_NEEDED_for_regular = TRUE; }
+ input_list ')'
+ { input_flags.add_DT_NEEDED_for_regular = $<integer>4; }
+ ;
+
+sections:
+ SECTIONS '{' sec_or_group_p1 '}'
+ ;
+
+sec_or_group_p1:
+ sec_or_group_p1 section
+ | sec_or_group_p1 statement_anywhere
+ |
+ ;
+
+statement_anywhere:
+ ENTRY '(' NAME ')'
+ { lang_add_entry ($3, FALSE); }
+ | assignment end
+ | ASSERT_K {@>@[ldlex_expression ();@>@=} '(' exp ',' NAME ')'
+ {
+@O
+ ldlex_popstate ();
+@o
+ lang_add_assignment (exp_assert ($4, $6));
+ }
+ ;
+
+@g
+
+@ \tracebadcharstrue
+The \prodstyle{'*'} and \prodstyle{'?'} cases are there because the lexer returns them as
+separate tokens rather than as \prodstyle{NAME}.
+\tracebadcharsfalse
+@<Original \ld\ grammar rules@>=
+@G
+wildcard_name:
+ NAME
+ {
+ $$ = $1;
+ }
+ | '*'
+ {
+ $$ = "*";
+ }
+ | '?'
+ {
+ $$ = "?";
+ }
+ ;
+
+@g
+
+@ @<Original \ld\ grammar rules@>=
+@G
+wildcard_spec:
+ wildcard_name
+ {
+ $$.name = $1;
+ $$.sorted = none;
+ $$.exclude_name_list = NULL;
+ $$.section_flag_list = NULL;
+ }
+ | EXCLUDE_FILE '(' exclude_name_list ')' wildcard_name
+ {
+ $$.name = $5;
+ $$.sorted = none;
+ $$.exclude_name_list = $3;
+ $$.section_flag_list = NULL;
+ }
+ | SORT_BY_NAME '(' wildcard_name ')'
+ {
+ $$.name = $3;
+ $$.sorted = by_name;
+ $$.exclude_name_list = NULL;
+ $$.section_flag_list = NULL;
+ }
+ | SORT_BY_ALIGNMENT '(' wildcard_name ')'
+ {
+ $$.name = $3;
+ $$.sorted = by_alignment;
+ $$.exclude_name_list = NULL;
+ $$.section_flag_list = NULL;
+ }
+ | SORT_NONE '(' wildcard_name ')'
+ {
+ $$.name = $3;
+ $$.sorted = by_none;
+ $$.exclude_name_list = NULL;
+ $$.section_flag_list = NULL;
+ }
+ | SORT_BY_NAME '(' SORT_BY_ALIGNMENT '(' wildcard_name ')' ')'
+ {
+ $$.name = $5;
+ $$.sorted = by_name_alignment;
+ $$.exclude_name_list = NULL;
+ $$.section_flag_list = NULL;
+ }
+ | SORT_BY_NAME '(' SORT_BY_NAME '(' wildcard_name ')' ')'
+ {
+ $$.name = $5;
+ $$.sorted = by_name;
+ $$.exclude_name_list = NULL;
+ $$.section_flag_list = NULL;
+ }
+ | SORT_BY_ALIGNMENT '(' SORT_BY_NAME '(' wildcard_name ')' ')'
+ {
+ $$.name = $5;
+ $$.sorted = by_alignment_name;
+ $$.exclude_name_list = NULL;
+ $$.section_flag_list = NULL;
+ }
+ | SORT_BY_ALIGNMENT '(' SORT_BY_ALIGNMENT '(' wildcard_name ')' ')'
+ {
+ $$.name = $5;
+ $$.sorted = by_alignment;
+ $$.exclude_name_list = NULL;
+ $$.section_flag_list = NULL;
+ }
+ | SORT_BY_NAME '(' EXCLUDE_FILE '(' exclude_name_list ')' wildcard_name ')'
+ {
+ $$.name = $7;
+ $$.sorted = by_name;
+ $$.exclude_name_list = $5;
+ $$.section_flag_list = NULL;
+ }
+ | SORT_BY_INIT_PRIORITY '(' wildcard_name ')'
+ {
+ $$.name = $3;
+ $$.sorted = by_init_priority;
+ $$.exclude_name_list = NULL;
+ $$.section_flag_list = NULL;
+ }
+ ;
+
+sect_flag_list: NAME
+ {
+ struct flag_info_list *n;
+ n = ((struct flag_info_list *) xmalloc (sizeof *n));
+ if ($1[0] == '!')
+ {
+ n->with = without_flags;
+ n->name = &$1[1];
+ }
+ else
+ {
+ n->with = with_flags;
+ n->name = $1;
+ }
+ n->valid = FALSE;
+ n->next = NULL;
+ $$ = n;
+ }
+ | sect_flag_list '&' NAME
+ {
+ struct flag_info_list *n;
+ n = ((struct flag_info_list *) xmalloc (sizeof *n));
+ if ($3[0] == '!')
+ {
+ n->with = without_flags;
+ n->name = &$3[1];
+ }
+ else
+ {
+ n->with = with_flags;
+ n->name = $3;
+ }
+ n->valid = FALSE;
+ n->next = $1;
+ $$ = n;
+ }
+ ;
+
+sect_flags:
+ INPUT_SECTION_FLAGS '(' sect_flag_list ')'
+ {
+ struct flag_info *n;
+ n = ((struct flag_info *) xmalloc (sizeof *n));
+ n->flag_list = $3;
+ n->flags_initialized = FALSE;
+ n->not_with_flags = 0;
+ n->only_with_flags = 0;
+ $$ = n;
+ }
+ ;
+
+exclude_name_list:
+ exclude_name_list wildcard_name
+ {
+ struct name_list *tmp;
+ tmp = (struct name_list *) xmalloc (sizeof *tmp);
+ tmp->name = $2;
+ tmp->next = $1;
+ $$ = tmp;
+ }
+ |
+ wildcard_name
+ {
+ struct name_list *tmp;
+ tmp = (struct name_list *) xmalloc (sizeof *tmp);
+ tmp->name = $1;
+ tmp->next = NULL;
+ $$ = tmp;
+ }
+ ;
+
+file_NAME_list:
+ file_NAME_list opt_comma wildcard_spec
+ {
+ struct wildcard_list *tmp;
+ tmp = (struct wildcard_list *) xmalloc (sizeof *tmp);
+ tmp->next = $1;
+ tmp->spec = $3;
+ $$ = tmp;
+ }
+ |
+ wildcard_spec
+ {
+ struct wildcard_list *tmp;
+ tmp = (struct wildcard_list *) xmalloc (sizeof *tmp);
+ tmp->next = NULL;
+ tmp->spec = $1;
+ $$ = tmp;
+ }
+ ;
+
+input_section_spec_no_keep:
+ NAME
+ {
+ struct wildcard_spec tmp;
+ tmp.name = $1;
+ tmp.exclude_name_list = NULL;
+ tmp.sorted = none;
+ tmp.section_flag_list = NULL;
+ lang_add_wild (&tmp, NULL, ldgram_had_keep);
+ }
+ | sect_flags NAME
+ {
+ struct wildcard_spec tmp;
+ tmp.name = $2;
+ tmp.exclude_name_list = NULL;
+ tmp.sorted = none;
+ tmp.section_flag_list = $1;
+ lang_add_wild (&tmp, NULL, ldgram_had_keep);
+ }
+ | '[' file_NAME_list ']'
+ {
+ lang_add_wild (NULL, $2, ldgram_had_keep);
+ }
+ | sect_flags '[' file_NAME_list ']'
+ {
+ struct wildcard_spec tmp;
+ tmp.name = NULL;
+ tmp.exclude_name_list = NULL;
+ tmp.sorted = none;
+ tmp.section_flag_list = $1;
+ lang_add_wild (&tmp, $3, ldgram_had_keep);
+ }
+ | wildcard_spec '(' file_NAME_list ')'
+ {
+ lang_add_wild (&$1, $3, ldgram_had_keep);
+ }
+ | sect_flags wildcard_spec '(' file_NAME_list ')'
+ {
+ $2.section_flag_list = $1;
+ lang_add_wild (&$2, $4, ldgram_had_keep);
+ }
+ ;
+@g
+
+@ @<Original \ld\ grammar rules@>=
+@G
+input_section_spec:
+ input_section_spec_no_keep
+ | KEEP '('
+ { ldgram_had_keep = TRUE; }
+ input_section_spec_no_keep ')'
+ { ldgram_had_keep = FALSE; }
+ ;
+
+statement:
+ assignment end
+ | CREATE_OBJECT_SYMBOLS
+ {
+ lang_add_attribute(lang_object_symbols_statement_enum);
+ }
+ | ';'
+ | CONSTRUCTORS
+ {
+
+ lang_add_attribute(lang_constructors_statement_enum);
+ }
+ | SORT_BY_NAME '(' CONSTRUCTORS ')'
+ {
+ constructors_sorted = TRUE;
+ lang_add_attribute (lang_constructors_statement_enum);
+ }
+ | input_section_spec
+ | length '(' mustbe_exp ')'
+ {
+ lang_add_data ((int) $1, $3);
+ }
+
+ | FILL '(' fill_exp ')'
+ {
+ lang_add_fill ($3);
+ }
+ | ASSERT_K {@>@[ldlex_expression ();@]@=} '(' exp ',' NAME ')' end
+ {
+@O
+ ldlex_popstate ();
+@o
+ lang_add_assignment (exp_assert ($4, $6));
+ }
+ | INCLUDE filename
+ {@> @[ldlex_script (); ldfile_open_command_file($2);@]@=}
+ statement_list_opt END
+ {@> @[ldlex_popstate ();@]@=}
+ ;
+@t}\vb{\flatten\inline\squashtermstrue}{@>
+statement_list:
+ statement_list statement
+ | statement
+ ;
+
+statement_list_opt:
+
+ | statement_list
+ ;
+
+length:
+ QUAD
+ { $$ = $1; }
+ | SQUAD
+ { $$ = $1; }
+ | LONG
+ { $$ = $1; }
+ | SHORT
+ { $$ = $1; }
+ | BYTE
+ { $$ = $1; }
+ ;
+
+fill_exp:
+ mustbe_exp
+ {
+ $$ = exp_get_fill ($1, 0, "fill value");
+ }
+ ;
+
+fill_opt:
+ '=' fill_exp
+ { $$ = $2; }
+ | { $$ = (fill_type *) 0; }
+ ;
+
+assign_op:
+ PLUSEQ
+ { $$ = '+'; }
+ | MINUSEQ
+ { $$ = '-'; }
+ | MULTEQ
+ { $$ = '*'; }
+ | DIVEQ
+ { $$ = '/'; }
+ | LSHIFTEQ
+ { $$ = LSHIFT; }
+ | RSHIFTEQ
+ { $$ = RSHIFT; }
+ | ANDEQ
+ { $$ = '&'; }
+ | OREQ
+ { $$ = '|'; }
+
+ ;
+end: ';' | ','
+ ;
+@t}\vb{\resetf}{@>
+
+assignment:
+ NAME '=' mustbe_exp
+ {
+ lang_add_assignment (exp_assign ($1, $3, FALSE));
+ }
+ | NAME assign_op mustbe_exp
+ {
+ lang_add_assignment (exp_assign ($1,
+ exp_binop ($2,
+ exp_nameop (NAME,
+ $1),
+ $3), FALSE));
+ }
+ | HIDDEN '(' NAME '=' mustbe_exp ')'
+ {
+ lang_add_assignment (exp_assign ($3, $5, TRUE));
+ }
+ | PROVIDE '(' NAME '=' mustbe_exp ')'
+ {
+ lang_add_assignment (exp_provide ($3, $5, FALSE));
+ }
+ | PROVIDE_HIDDEN '(' NAME '=' mustbe_exp ')'
+ {
+ lang_add_assignment (exp_provide ($3, $5, TRUE));
+ }
+ ;
+
+@t}\vb{\inline\flatten}{@>
+opt_comma:
+ ',' | ;
+@t}\vb{\resetf}{@>
+memory:
+ MEMORY '{' memory_spec_list_opt '}'
+ ;
+
+memory_spec_list_opt: memory_spec_list | ;
+
+memory_spec_list:
+ memory_spec_list opt_comma memory_spec
+ | memory_spec
+ ;
+
+
+memory_spec: NAME
+ { region = lang_memory_region_lookup ($1, TRUE); }
+ attributes_opt ':'
+ origin_spec opt_comma length_spec
+ {}
+ | INCLUDE filename
+ {@> @[ldlex_script (); ldfile_open_command_file($2);@]@=}
+ memory_spec_list_opt END
+ {@> @[ldlex_popstate ();@]@=}
+ ;
+@g
+
+@ @<Original \ld\ grammar rules@>=
+@G
+origin_spec:
+ ORIGIN '=' mustbe_exp
+ {
+ region->origin = exp_get_vma ($3, 0, "origin");
+ region->current = region->origin;
+ }
+ ;
+
+length_spec:
+ LENGTH '=' mustbe_exp
+ {
+ region->length = exp_get_vma ($3, -1, "length");
+ }
+ ;
+
+attributes_opt:
+
+ { /* dummy action to avoid bison 1.25 error message */ }
+ | '(' attributes_list ')'
+ ;
+
+attributes_list:
+ attributes_string
+ | attributes_list attributes_string
+ ;
+
+attributes_string:
+ NAME
+ { lang_set_flags (region, $1, 0); }
+ | '!' NAME
+ { lang_set_flags (region, $2, 1); }
+ ;
+
+startup:
+ STARTUP '(' filename ')'
+ { lang_startup($3); }
+ ;
+
+high_level_library:
+ HLL '(' high_level_library_NAME_list ')'
+ | HLL '(' ')'
+ { ldemul_hll((char *)NULL); }
+ ;
+
+high_level_library_NAME_list:
+ high_level_library_NAME_list opt_comma filename
+ { ldemul_hll($3); }
+ | filename
+ { ldemul_hll($1); }
+
+ ;
+
+low_level_library:
+ SYSLIB '(' low_level_library_NAME_list ')'
+ ; low_level_library_NAME_list:
+ low_level_library_NAME_list opt_comma filename
+ { ldemul_syslib($3); }
+ |
+ ;
+
+floating_point_support:
+ FLOAT
+ { lang_float(TRUE); }
+ | NOFLOAT
+ { lang_float(FALSE); }
+ ;
+
+nocrossref_list:
+
+ {
+ $$ = NULL;
+ }
+ | NAME nocrossref_list
+ {
+ struct lang_nocrossref *n;
+
+ n = (struct lang_nocrossref *) xmalloc (sizeof *n);
+ n->name = $1;
+ n->next = $2;
+ $$ = n;
+ }
+ | NAME ',' nocrossref_list
+ {
+ struct lang_nocrossref *n;
+
+ n = (struct lang_nocrossref *) xmalloc (sizeof *n);
+ n->name = $1;
+ n->next = $3;
+ $$ = n;
+ }
+ ;
+
+mustbe_exp: {@> @[ldlex_expression ();@]@=}
+ exp
+ {@> @[ldlex_popstate ();@]@= $$=$2;}
+ ;
+
+@g
+
+@ {\it Rich expression syntax reproducing the one in \Cee.}
+@<Original \ld\ grammar rules@>=
+@G
+exp :
+ '-' exp %prec UNARY
+ { $$ = exp_unop ('-', $2); }
+ | '(' exp ')'
+ { $$ = $2; }
+ | NEXT '(' exp ')' %prec UNARY
+ { $$ = exp_unop ((int) $1,$3); }
+ | '!' exp %prec UNARY
+ { $$ = exp_unop ('!', $2); }
+ | '+' exp %prec UNARY
+ { $$ = $2; }
+ | '~' exp %prec UNARY
+ { $$ = exp_unop ('~', $2);}
+@t}\vb{\flatten\inline}{@>
+ | exp '*' exp
+ { $$ = exp_binop ('*', $1, $3); }
+ | exp '/' exp
+ { $$ = exp_binop ('/', $1, $3); }
+ | exp '%' exp
+ { $$ = exp_binop ('%', $1, $3); }
+ | exp '+' exp
+ { $$ = exp_binop ('+', $1, $3); }
+ | exp '-' exp
+@t}\vb{\resetf}{@>
+ { $$ = exp_binop ('-' , $1, $3); }
+@t}\vb{\flatten\inline}{@>
+ | exp LSHIFT exp
+ { $$ = exp_binop (LSHIFT , $1, $3); }
+ | exp RSHIFT exp
+ { $$ = exp_binop (RSHIFT , $1, $3); }
+ | exp EQ exp
+ { $$ = exp_binop (EQ , $1, $3); }
+ | exp NE exp
+ { $$ = exp_binop (NE , $1, $3); }
+ | exp LE exp
+@t}\vb{\resetf}{@>
+ { $$ = exp_binop (LE , $1, $3); }
+@t}\vb{\flatten\inline}{@>
+ | exp GE exp
+ { $$ = exp_binop (GE , $1, $3); }
+ | exp '<' exp
+ { $$ = exp_binop ('<' , $1, $3); }
+ | exp '>' exp
+ { $$ = exp_binop ('>' , $1, $3); }
+ | exp '&' exp
+ { $$ = exp_binop ('&' , $1, $3); }
+ | exp '^' exp
+@t}\vb{\resetf}{@>
+ { $$ = exp_binop ('^' , $1, $3); }
+@t}\vb{\flatten\inline}{@>
+ | exp '|' exp
+ { $$ = exp_binop ('|' , $1, $3); }
+ | exp '?' exp ':' exp
+ { $$ = exp_trinop ('?' , $1, $3, $5); }
+ | exp ANDAND exp
+ { $$ = exp_binop (ANDAND , $1, $3); }
+ | exp OROR exp
+@t}\vb{\resetf}{@>
+ { $$ = exp_binop (OROR , $1, $3); }
+@t}\vb{\flatten\inline}{@>
+ | DEFINED '(' NAME ')'
+ { $$ = exp_nameop (DEFINED, $3); }
+ | INT
+ { $$ = exp_bigintop ($1.integer, $1.str); }
+ | SIZEOF_HEADERS
+@t}\vb{\resetf}{@>
+ { $$ = exp_nameop (SIZEOF_HEADERS,0); }
+@t}\vb{\flatten\inline}{@>
+ | ALIGNOF '(' NAME ')'
+ { $$ = exp_nameop (ALIGNOF,$3); }
+ | SIZEOF '(' NAME ')'
+@t}\vb{\resetf}{@>
+ { $$ = exp_nameop (SIZEOF,$3); }
+@t}\vb{\flatten\inline}{@>
+ | ADDR '(' NAME ')'
+ { $$ = exp_nameop (ADDR,$3); }
+ | LOADADDR '(' NAME ')'
+@t}\vb{\resetf}{@>
+ { $$ = exp_nameop (LOADADDR,$3); }
+@t}\vb{\flatten\inline}{@>
+ | CONSTANT '(' NAME ')'
+ { $$ = exp_nameop (CONSTANT,$3); }
+ | ABSOLUTE '(' exp ')'
+ { $$ = exp_unop (ABSOLUTE, $3); }
+ | ALIGN_K '(' exp ')'
+@t}\vb{\resetf}{@>
+ { $$ = exp_unop (ALIGN_K,$3); }
+@t}\vb{\flatten\inline}{@>
+ | ALIGN_K '(' exp ',' exp ')'
+ { $$ = exp_binop (ALIGN_K,$3,$5); }
+ | DATA_SEGMENT_ALIGN '(' exp ',' exp ')'
+@t}\vb{\resetf}{@>
+ { $$ = exp_binop (DATA_SEGMENT_ALIGN, $3, $5); }
+ | DATA_SEGMENT_RELRO_END '(' exp ',' exp ')'
+ { $$ = exp_binop (DATA_SEGMENT_RELRO_END, $5, $3); }
+ | DATA_SEGMENT_END '(' exp ')'
+ { $$ = exp_unop (DATA_SEGMENT_END, $3); }
+ | SEGMENT_START '(' NAME ',' exp ')'
+ { $$ = exp_binop (SEGMENT_START,
+ $5,
+ exp_nameop (NAME, $3)); }
+ | BLOCK '(' exp ')'
+ { $$ = exp_unop (ALIGN_K,$3); }
+ | NAME
+ { $$ = exp_nameop (NAME,$1); }
+ | MAX_K '(' exp ',' exp ')'
+ { $$ = exp_binop (MAX_K, $3, $5 ); }
+ | MIN_K '(' exp ',' exp ')'
+ { $$ = exp_binop (MIN_K, $3, $5 ); }
+ | ASSERT_K '(' exp ',' NAME ')'
+ { $$ = exp_assert ($3, $5); }
+ | ORIGIN '(' NAME ')'
+ { $$ = exp_nameop (ORIGIN, $3); }
+ | LENGTH '(' NAME ')'
+ { $$ = exp_nameop (LENGTH, $3); }
+ | LOG2CEIL '(' exp ')'
+ { $$ = exp_unop (LOG2CEIL, $3); }
+ ;
+
+@g
+
+@ @<Original \ld\ grammar rules@>=
+@G
+memspec_at_opt:
+ AT '>' NAME { $$ = $3; }
+ | { $$ = 0; }
+ ;
+
+opt_at:
+ AT '(' exp ')' { $$ = $3; }
+ | { $$ = 0; }
+ ;
+
+opt_align:
+ ALIGN_K '(' exp ')' { $$ = $3; }
+ | { $$ = 0; }
+ ;
+
+opt_align_with_input:
+ ALIGN_WITH_INPUT { $$ = ALIGN_WITH_INPUT; }
+ | { $$ = 0; }
+ ;
+
+opt_subalign:
+ SUBALIGN '(' exp ')' { $$ = $3; }
+ | { $$ = 0; }
+ ;
+
+sect_constraint:
+ ONLY_IF_RO { $$ = ONLY_IF_RO; }
+ | ONLY_IF_RW { $$ = ONLY_IF_RW; }
+ | SPECIAL { $$ = SPECIAL; }
+ | { $$ = 0; }
+ ;
+
+@g
+
+@ The \prodstyle{GROUP} case is just enough to support the \gcc\
+|svr3.ifile| script. It is not intended to be full
+support. I'm not even sure what \prodstyle{GROUP} is supposed
+to mean.
+@<Original \ld\ grammar rules@>=
+@G
+section: NAME {@> @[ldlex_expression();@]@=}
+ opt_exp_with_type
+ opt_at
+ opt_align
+@t}\vb{\breakline}{@>
+ opt_align_with_input
+ opt_subalign {@> @[ldlex_popstate (); ldlex_script ();@]@=}
+ sect_constraint
+ '{'
+ {
+ lang_enter_output_section_statement($1, $3,
+ sectype,
+ $5, $7, $4, $9, $6);
+ }
+ statement_list_opt
+ '}' {@> @[ldlex_popstate (); ldlex_expression ();@]@=}
+ memspec_opt memspec_at_opt phdr_opt fill_opt
+ {
+@O
+ ldlex_popstate ();
+@o
+ lang_leave_output_section_statement ($18, $15, $17, $16);
+ }
+ opt_comma
+ {}
+ | OVERLAY
+ {@> @[ldlex_expression ();@]@=}
+ opt_exp_without_type opt_nocrossrefs
+@t}\vb{\breakline}{@>
+ opt_at opt_subalign
+ {@> @[ldlex_popstate (); ldlex_script ();@]@=}
+ '{'
+ {
+ lang_enter_overlay ($3, $6);
+ }
+ overlay_section
+ '}'
+ {@> @[ldlex_popstate (); ldlex_expression ();@]@=}
+ memspec_opt memspec_at_opt phdr_opt fill_opt
+ {
+@O
+ ldlex_popstate ();
+@o
+ lang_leave_overlay ($5, (int) $4,
+ $16, $13, $15, $14);
+ }
+ opt_comma
+ | GROUP {@> @[ldlex_expression ();@]@=}
+ opt_exp_with_type
+ {
+@O
+ ldlex_popstate ();
+@o
+ lang_add_assignment (exp_assign (".", $3, FALSE));
+ }
+ '{' sec_or_group_p1 '}'
+ | INCLUDE filename
+ {@> @[ldlex_script (); ldfile_open_command_file($2);@]@=}
+ sec_or_group_p1 END
+ {@> @[ldlex_popstate ();@]@=}
+ ;
+@t}\vb{\flatten\inline}{@>
+type:
+ NOLOAD { sectype = noload_section; }
+ | DSECT { sectype = noalloc_section; }
+ | COPY { sectype = noalloc_section; }
+ | INFO { sectype = noalloc_section; }
+ | OVERLAY { sectype = noalloc_section; }
+ ;
+
+atype:
+ '(' type ')'
+ | { sectype = normal_section; }
+ | '(' ')' { sectype = normal_section; }
+ ;
+
+@g
+
+@ The \prodstyle{BIND} cases are to support the \gcc\ |svr3.ifile|
+script. They aren't intended to implement full
+support for the \prodstyle{BIND} keyword. I'm not even sure
+what \prodstyle{BIND} is supposed to mean.
+@<Original \ld\ grammar rules@>=
+@G
+
+opt_exp_with_type:
+ exp atype ':' { $$ = $1; }
+ | atype ':' { $$ = (etree_type *)NULL; }
+ | BIND '(' exp ')' atype ':' { $$ = $3; }
+ | BIND '(' exp ')' BLOCK '(' exp ')' atype ':'
+ { $$ = $3; }
+ ;
+
+opt_exp_without_type:
+ exp ':' { $$ = $1; }
+ | ':' { $$ = (etree_type *) NULL; }
+ ;
+
+opt_nocrossrefs:
+
+ { $$ = 0; }
+ | NOCROSSREFS
+ { $$ = 1; }
+ ;
+
+memspec_opt:
+ '>' NAME
+ { $$ = $2; }
+ | { $$ = DEFAULT_MEMORY_REGION; }
+ ;
+
+phdr_opt:
+
+ {
+ $$ = NULL;
+ }
+ | phdr_opt ':' NAME
+ {
+ struct lang_output_section_phdr_list *n;
+
+ n = ((struct lang_output_section_phdr_list *)
+ xmalloc (sizeof *n));
+ n->name = $3;
+ n->used = FALSE;
+ n->next = $1;
+ $$ = n;
+ }
+ ;
+
+overlay_section:
+
+ | overlay_section
+ NAME
+ {
+@O
+ ldlex_script ();
+@o
+ lang_enter_overlay_section ($2);
+ }
+ '{' statement_list_opt '}'
+ {@> @[ldlex_popstate (); ldlex_expression ();@]@=}
+ phdr_opt fill_opt
+ {
+@O
+ ldlex_popstate ();
+@o
+ lang_leave_overlay_section ($9, $8);
+ }
+ opt_comma
+ ;
+@g
+
+@ @<Original \ld\ grammar rules@>=
+@G
+phdrs:
+ PHDRS '{' phdr_list '}'
+ ;
+
+phdr_list:
+
+ | phdr_list phdr
+ ;
+
+phdr:
+ NAME {@> @[ldlex_expression ();@]@=}
+ phdr_type phdr_qualifiers {@> @[ldlex_popstate ();@]@=}
+ ';'
+ {
+ lang_new_phdr ($1, $3, $4.filehdr, $4.phdrs, $4.at,
+ $4.flags);
+ }
+ ;
+
+phdr_type:
+ exp
+ {
+ $$ = $1;
+
+ if ($1->type.node_class == etree_name
+ && $1->type.node_code == NAME)
+ {
+ const char *s;
+ unsigned int i;
+ static const char * const phdr_types[] =
+ {
+ "PT_NULL", "PT_LOAD", "PT_DYNAMIC",
+ "PT_INTERP", "PT_NOTE", "PT_SHLIB",
+ "PT_PHDR", "PT_TLS"
+ };
+
+ s = $1->name.name;
+ for (i = 0;
+ i < sizeof phdr_types / sizeof phdr_types[0];
+ i++)
+ if (strcmp (s, phdr_types[i]) == 0)
+ {
+ $$ = exp_intop (i);
+ break;
+ }
+ if (i == sizeof phdr_types / sizeof phdr_types[0])
+ {
+ if (strcmp (s, "PT_GNU_EH_FRAME") == 0)
+ $$ = exp_intop (0x6474e550);
+ else if (strcmp (s, "PT_GNU_STACK") == 0)
+ $$ = exp_intop (0x6474e551);
+ else
+ {
+ einfo (_("\
+%X%P:%S: unknown phdr type `%s' (try integer literal)\n"),
+ NULL, s);
+ $$ = exp_intop (0);
+ }
+ }
+ }
+ }
+ ;
+
+phdr_qualifiers:
+
+ {
+ memset (&$$, 0, sizeof (struct phdr_info));
+ }
+ | NAME phdr_val phdr_qualifiers
+ {
+ $$ = $3;
+ if (strcmp ($1, "FILEHDR") == 0 && $2 == NULL)
+ $$.filehdr = TRUE;
+ else if (strcmp ($1, "PHDRS") == 0 && $2 == NULL)
+ $$.phdrs = TRUE;
+ else if (strcmp ($1, "FLAGS") == 0 && $2 != NULL)
+ $$.flags = $2;
+ else
+ einfo (_("%X%P:%S: PHDRS syntax error at `%s'\n"),
+ NULL, $1);
+ }
+ | AT '(' exp ')' phdr_qualifiers
+ {
+ $$ = $5;
+ $$.at = $3;
+ }
+ ;
+
+phdr_val:
+
+ {
+ $$ = NULL;
+ }
+ | '(' exp ')'
+ {
+ $$ = $2;
+ }
+ ;
+
+dynamic_list_file:
+ {
+@O
+ ldlex_version_file ();
+@o
+ PUSH_ERROR (_("dynamic list"));
+ }
+ dynamic_list_nodes
+ {
+@O
+ ldlex_popstate ();
+@o
+ POP_ERROR ();
+ }
+ ;
+
+dynamic_list_nodes:
+ dynamic_list_node
+ | dynamic_list_nodes dynamic_list_node
+ ;
+
+dynamic_list_node:
+ '{' dynamic_list_tag '}' ';'
+ ;
+
+dynamic_list_tag:
+ vers_defns ';'
+ {
+ lang_append_dynamic_list ($1);
+ }
+ ;
+
+@g
+
+@ This syntax is used within an external version script file.
+@<Original \ld\ grammar rules@>=
+@G
+
+version_script_file:
+ {
+@O
+ ldlex_version_file ();
+@o
+ PUSH_ERROR (_("VERSION script"));
+ }
+ vers_nodes
+ {
+@O
+ ldlex_popstate ();
+@o
+ POP_ERROR ();
+ }
+ ;
+@g
+
+@ This is used within a normal linker script file.
+@<Original \ld\ grammar rules@>=
+@G
+version:
+ {
+@O
+ ldlex_version_script ();
+@o
+ }
+ VERSIONK '{' vers_nodes '}'
+ {
+@O
+ ldlex_popstate ();
+@o
+ }
+ ;
+
+vers_nodes:
+ vers_node
+ | vers_nodes vers_node
+ ;
+
+vers_node:
+ '{' vers_tag '}' ';'
+ {
+ lang_register_vers_node (NULL, $2, NULL);
+ }
+ | VERS_TAG '{' vers_tag '}' ';'
+ {
+ lang_register_vers_node ($1, $3, NULL);
+ }
+ | VERS_TAG '{' vers_tag '}' verdep ';'
+ {
+ lang_register_vers_node ($1, $3, $5);
+ }
+ ;
+
+verdep:
+ VERS_TAG
+ {
+ $$ = lang_add_vers_depend (NULL, $1);
+ }
+ | verdep VERS_TAG
+ {
+ $$ = lang_add_vers_depend ($1, $2);
+ }
+ ;
+
+vers_tag:
+
+ {
+ $$ = lang_new_vers_node (NULL, NULL);
+ }
+ | vers_defns ';'
+ {
+ $$ = lang_new_vers_node ($1, NULL);
+ }
+ | GLOBAL ':' vers_defns ';'
+ {
+ $$ = lang_new_vers_node ($3, NULL);
+ }
+ | LOCAL ':' vers_defns ';'
+ {
+ $$ = lang_new_vers_node (NULL, $3);
+ }
+ | GLOBAL ':' vers_defns ';' LOCAL ':' vers_defns ';'
+ {
+ $$ = lang_new_vers_node ($3, $7);
+ }
+ ;
+
+vers_defns:
+ VERS_IDENTIFIER
+ {
+ $$ = lang_new_vers_pattern (NULL, $1, ldgram_vers_current_lang, FALSE);
+ }
+ | NAME
+ {
+ $$ = lang_new_vers_pattern (NULL, $1, ldgram_vers_current_lang, TRUE);
+ }
+ | vers_defns ';' VERS_IDENTIFIER
+ {
+ $$ = lang_new_vers_pattern ($1, $3, ldgram_vers_current_lang, FALSE);
+ }
+ | vers_defns ';' NAME
+ {
+ $$ = lang_new_vers_pattern ($1, $3, ldgram_vers_current_lang, TRUE);
+ }
+ | vers_defns ';' EXTERN NAME '{'
+ {
+ $<name>$ = ldgram_vers_current_lang;
+ ldgram_vers_current_lang = $4;
+ }
+ vers_defns opt_semicolon '}'
+ {
+ struct bfd_elf_version_expr *pat;
+ for (pat = $7; pat->next != NULL; pat = pat->next);
+ pat->next = $1;
+ $$ = $7;
+ ldgram_vers_current_lang = $<name>6;
+ }
+ | EXTERN NAME '{'
+ {
+ $<name>$ = ldgram_vers_current_lang;
+ ldgram_vers_current_lang = $2;
+ }
+ vers_defns opt_semicolon '}'
+ {
+ $$ = $5;
+ ldgram_vers_current_lang = $<name>4;
+ }
+ | GLOBAL
+ {
+ $$ = lang_new_vers_pattern (NULL, "global", ldgram_vers_current_lang, FALSE);
+ }
+ | vers_defns ';' GLOBAL
+ {
+ $$ = lang_new_vers_pattern ($1, "global", ldgram_vers_current_lang, FALSE);
+ }
+ | LOCAL
+ {
+ $$ = lang_new_vers_pattern (NULL, "local", ldgram_vers_current_lang, FALSE);
+ }
+ | vers_defns ';' LOCAL
+ {
+ $$ = lang_new_vers_pattern ($1, "local", ldgram_vers_current_lang, FALSE);
+ }
+ | EXTERN
+ {
+ $$ = lang_new_vers_pattern (NULL, "extern", ldgram_vers_current_lang, FALSE);
+ }
+ | vers_defns ';' EXTERN
+ {
+ $$ = lang_new_vers_pattern ($1, "extern", ldgram_vers_current_lang, FALSE);
+ }
+ ;
+@t}\vb{\inline\flatten}{@>
+opt_semicolon:
+
+ | ';'
+ ;
+
+@g
+
+@q%%@>
+
+@ \Cee\ sugar.
+@c
+void
+yyerror(arg)
+ const char *arg;
+{
+ if (ldfile_assumed_script)
+ einfo (_("%P:%s: file format not recognized; treating as linker script\n"),
+ ldlex_filename ());
+ if (error_index > 0 && error_index < ERROR_NAME_MAX)
+ einfo ("%P%F:%S: %s in %s\n", NULL, arg, error_names[error_index - 1]);
+ else
+ einfo ("%P%F:%S: %s\n", NULL, arg);
+}
+
diff --git a/support/splint/examples/ld/ldint.sty b/support/splint/examples/ld/ldint.sty
new file mode 100644
index 0000000000..478bdef17d
--- /dev/null
+++ b/support/splint/examples/ld/ldint.sty
@@ -0,0 +1,259 @@
+% Copyright 2012-2015, Alexander Shibakov
+% This file is part of SPLinT
+%
+% SPLinT is free software: you can redistribute it and/or modify
+% it under the terms of the GNU General Public License as published by
+% the Free Software Foundation, either version 3 of the License, or
+% (at your option) any later version.
+%
+% SPLinT 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 SPLinT. If not, see <http://www.gnu.org/licenses/>.
+
+% Simple integer parsing macros to display various styles of integers
+% used in ld scripts. Instead of creating a dedicated parser for this
+% task, it was decided to implement it as a set of expandable
+% macros. The degree of complexity of both implementations would
+% probably be about the same, and a true parser approach will be more
+% flexible. The choice was made in favor of a macro implementation to
+% ensure expandability and speed.
+
+\def\ldintiterator#1#2#3#4#5#6#7#8{%
+ % #1 a control sequence to insert at the end
+ % #2 first divisor
+ % #3 second divisor
+ % #4 first remainder
+ % #5 second remainder
+ % #6 read digits
+ % #7 last read digit
+ % #8 current digit
+ \ifcat\noexpand#8\relax
+ \yybreak{#1{#2}{#3}{#4}{#5}{#6}{#7}}%
+ \else
+ \yybreak{\expandafter\lditeratormodone\expandafter{\number\incrementmod{#4}{#2}}{#5}{#3}{#1}{#2}{#3}{#6#7}{#8}}%
+ \yycontinue
+}
+
+\def\incrementmod#1#2{%
+ \expandafter\incr@mentmod\expandafter{\number\xincrement{#1}}{#2}%
+}
+
+\def\incr@mentmod#1#2{%
+ \ifnum#1=#2
+ \yybreak{0}%
+ \else
+ \yybreak{#1}%
+ \yycontinue
+}
+
+\def\decrementmod#1#2{%
+ \ifnum#1=\z@
+ \yybreak{\xdecrement{#2}}%
+ \else
+ \yybreak{\xdecrement{#1}}%
+ \yycontinue
+}
+
+\def\lditeratormodone#1#2#3{%
+ \expandafter\lditeratormodtwo\expandafter{\number\incrementmod{#2}{#3}}{#1}%
+}
+
+\def\lditeratormodtwo#1#2#3#4#5{%
+ \ldintiterator{#3}{#4}{#5}{#2}{#1}%
+}
+
+\def\ldintegerspacingmodone#1#2#3#4#5#6#7#8#9{%
+ % #1 control sequence to insert at the end
+ % #2 first divisor
+ % #3 second divisor
+ % #4 number of digits mod #2
+ % #5 number of digits mod #3
+ % #6 digits read
+ % #7 separator
+ % #8 last digit
+ % #9 current digit
+ \ifcat\noexpand#9\relax
+ \yybreak{#1{#2}{#3}{#4}{#5}{#6}{#8}}%
+ \else
+ \yybreak{\ldintegerspacingmodon@{#1}{#2}{#3}{#4}{#5}{#6}{#7}{#8}{#9}}%
+ \yycontinue
+}
+
+\def\ldintegerspacingmodon@#1#2#3#4#5#6#7#8#9{%
+ \ifnum#4=\z@
+ \yybreak{%
+ \yystringempty{#8}{%
+ \expandafter\ldintegerspacingmod@n@\expandafter{\number\decrementmod{#4}{#2}}{#1}{#2}{#3}{#5}{}{#7}{#9}%
+ }{%
+ \expandafter\ldintegerspacingmod@n@\expandafter{\number\decrementmod{#4}{#2}}{#1}{#2}{#3}{#5}{#6#8#7}{#7}{#9}%
+ }%
+ }%
+ \else
+ \yybreak{%
+ \expandafter\ldintegerspacingmod@n@\expandafter{\number\decrementmod{#4}{#2}}{#1}{#2}{#3}{#5}{#6#8}{#7}{#9}%
+ }%
+ \yycontinue
+}
+
+\def\ldintegerspacingmod@n@#1#2#3#4#5#6#7#8{%
+ \ldintegerspacingmodone{#2}{#3}{#4}{#1}{#5}{#6}{#7}{#8}%
+}
+
+\def\showiteratorresults#1#2#3#4#5#6{%
+ \errmessage{mod #1: #3, mod #2: #4, digits: #5, last digit: #6}%
+}
+
+\def\showseparatorresults#1#2#3#4#5#6#7{%
+ \errmessage{digits after separation: \yystringempty{#1}{}{[#1]}#6.#7}%
+}
+
+\def\ldseparatemodone#1#2#3#4#5#6#7{%
+ \expandafter\yystringempty\expandafter{\romannumeral-"0#7}{%
+ \ldintegerspacingmodone{#1{}}{#2}{#3}{#4}{#5}{}{\ldintsep}{}#6#7\end
+ }{%
+ \ldseparatewithsuffix{#1}{#2}{#3}{#4}{#5}{#6}{#7}%
+ }%
+}
+
+\def\ldseparatewithsuffix#1#2#3#4#5#6#7{%
+ \ifcase\csname ldsuffix#7\endcsname\space
+ \expandafter\ldseparatewiths@ffix\expandafter{\number\decrementmod{#4}{#2}}{#1}{#2}{#3}{#5}{#6}{#7}%
+ \or
+ \expandafter\ldseparatewiths@ffix\expandafter{\number\decrementmod{#5}{#3}}{#1}{#3}{#2}{#4}{#6}{#7}%
+ \else
+ \fi
+}
+
+\def\ldseparatewiths@ffix#1#2#3#4#5#6#7{%
+ \ldintegerspacingmodone{#2{#7}}{#3}{#4}{#1}{#5}{}{\ldintsep}{}#6\end
+}
+
+\def\ldsuffixD{0}
+\def\ldsuffixO{0}
+\def\ldsuffixB{1}
+\def\ldsuffixH{1}
+\def\ldsuffixX{1}
+%
+\def\ldradixD{}
+\def\ldradixO{8}
+\def\ldradixB{01}
+\def\ldradixH{16}
+\def\ldradixX{16}
+%
+\def\ldsuffixK{0}
+\def\ldsuffixM{0}
+\def\ldsuffixG{0}
+
+\let\ldintsep\relax
+
+\def\intprefix#1{% analyzing the prefix of an integer
+ \intpr@fix#1..\end
+}
+
+\def\intpr@fix#1#2#3\end{%
+ \if#10%
+ \if#2X% prefix 0X
+ 1% hex number
+ \else
+ \if#2.%
+ 4% zero
+ \else
+ 3% octal number
+ \fi
+ \fi
+ \else
+ \if#1$%
+ 2% hex number
+ \else
+ 0% decimal number (no prefix)
+ \fi
+ \fi
+}
+
+\def\ldsciinteger#1{%
+ \ifcase\intprefix{#1}
+ % decimal number (no prefix)
+ \lddecsplitws{#1}{}%
+ \or % hex number (0X)
+ \expandafter\ldhexsplitws\expandafter{\eattwo#1}{16}%
+ \or % hex number ($)
+ \expandafter\ldhexsplitws\expandafter{\eatone#1}{16}%
+ \or % octal number
+ \lddecsplitws{#1}{8}%
+ \or % zero
+ 0%
+ \else
+ \fi
+}
+
+\def\ldhexsplitws#1#2{%
+ \ldintiterator{\ldseparatemodone{\displayinteger{#2}}}{4}{4}{0}{0}{}{}#1\end
+}
+
+\def\lddecsplitws#1#2{%
+ \ldintiterator{\ldseparatemodone{\displayinteger{#2}}}{3}{3}{0}{0}{}{}#1\end
+}
+
+\def\ldbasedinteger#1{%
+ \ldintiterator{\ldseparatewithsuffix{\displayintegerws}}{3}{4}{0}{0}{}{}#1\end
+}
+
+\def\displayinteger#1#2#3#4#5#6#7#8{%
+ {\def\ldintsep{$\,$}\hbox{\tt#7#8${}_{#1}\yystringempty{#2}{}{\,\hbox{\tt#2}}$}}%
+}
+
+\def\displayintegerws#1#2#3#4#5#6#7{%
+ {\def\ldintsep{$\,$}\hbox{\tt#6#7${}_{\yystringempty{#1}{}{\csname ldradix#1\endcsname}}$}}%
+}
+
+% typeseting examples in text
+
+\def\beginldprod{%
+% \par
+ \begingroup
+ \b@ginldprod
+}
+
+\long\def\b@ginldprod#1\endprod{%
+ \setldproduction{#1}%
+ \endgroup
+% \par
+}
+
+\long\def\setldproduction#1{%
+ \def\termidxrank{5}%
+ \def\headeridxrank{4}%
+ \def\defidxrank{3}%
+ \def\texcsidxrank{5}%
+ \ninepoint
+ \let\returnexplicitspace\splitexplicitspace
+ \let\acharswitch\texcharadjust
+ \let\onecharswitch\texcsadjust
+ \let\yyinputgroup\yyinputldgroup
+ \toldparser
+ \ldparserinit
+ \yyparse#1\yyeof\yyeof\endparseinput\endparse
+ \ifyyparsefail % revert to generic macros if parsing failed
+ \yybreak{\toks0{#1}\errmessage{failed to parse: \the\toks0}}%
+ \else % Stage three, process the parsed table
+ \yybreak{%
+ {%
+ \restorecslist{ld-display}\ldunion
+ \the\ldcmds
+% \par
+ \the\lddisplay
+ }%
+ }%
+ \yycontinue
+}
+
+% to make it possible to write {...} without changes
+
+\def\yyinputldgroup#1{%
+ \yyinput\{#1\}%
+}
+
diff --git a/support/splint/examples/ld/ldlex.w b/support/splint/examples/ld/ldlex.w
new file mode 100644
index 0000000000..9d1c256e62
--- /dev/null
+++ b/support/splint/examples/ld/ldlex.w
@@ -0,0 +1,550 @@
+@q Copyright 2012-2015 Alexander Shibakov@>
+@q Copyright 2002-2014 Free Software Foundation, Inc.@>
+@q This file is part of SPLinT@>
+
+@q SPLinT is free software: you can redistribute it and/or modify@>
+@q it under the terms of the GNU General Public License as published by@>
+@q the Free Software Foundation, either version 3 of the License, or@>
+@q (at your option) any later version.@>
+
+@q SPLinT is distributed in the hope that it will be useful,@>
+@q but WITHOUT ANY WARRANTY; without even the implied warranty of@>
+@q MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the@>
+@q GNU General Public License for more details.@>
+
+@q You should have received a copy of the GNU General Public License@>
+@q along with SPLinT. If not, see <http://www.gnu.org/licenses/>.@>
+
+@** The lexer.
+\ifx\parsernamespace\UNDEFINED
+ \input ldman.sty
+ \input limbo.sty
+ \input dcols.sty
+ \setupfootnotes
+ \def\MRI{}
+ \def\ld{}
+\fi
+The lexer used by \ld\ is almost straightforward. There are a few
+facilities (\Cee\ header files, some output functions) needed by the
+lexer that are conviniently coded into the \Cee\ code run by the
+driver routines that make the lexer more complex than it should have
+been but the function of each such facility can be easily clarified
+using this documentation and occasionally referring to the manual for
+the \bison\ parser which is part of this distribution.
+@(ldl.ll@>=
+@G
+ @> @<\ld\ lexer definitions@> @=
+%{@> @<\ld\ lexer \Cee\ preamble@> @=%}
+ @> @<\ld\ lexer options@> @=
+%%
+ @> @<\ld\ token regular expressions@> @=
+%%
+@O
+void define_all_states( void ) {
+ @<Collect state definitions for the \ld\ lexer@>@;
+}
+@o
+@g
+
+@ @<\ld\ lexer options@>=
+@G
+%option bison-bridge
+%option noyywrap nounput noinput reentrant
+%option noyy_top_state
+%option debug
+%option stack
+%option outfile="ldl.c"
+@g
+
+@ @<\ld\ lexer \Cee\ preamble@>=
+#include <stdint.h>
+#include <stdbool.h>
+
+@ @<Collect state definitions for the \ld\ lexer@>=
+#define _register_name( name ) @[Define_State( #name, name )@]
+#include "ldl_states.h"
+#undef _register_name
+
+@ \yyskipparsetrue The character classes used by the scanner as well as
+lexer state declarations have been put in the definitions section of
+the input file. No attempt has been made to clean up the definitions
+of the character classes.
+@<\ld\ lexer definitions@>=
+@<\ld\ lexer states@>@;
+@G
+CMDFILENAMECHAR [_a-zA-Z0-9\/\.\\_\+\$\:\[\]\\\,\=\&\!\<\>\-\~]
+CMDFILENAMECHAR1 [_a-zA-Z0-9\/\.\\_\+\$\:\[\]\\\,\=\&\!\<\>\~]
+FILENAMECHAR1 [_a-zA-Z\/\.\\\$\_\~]
+SYMBOLCHARN [_a-zA-Z\/\.\\\$\_\~0-9]
+FILENAMECHAR [_a-zA-Z0-9\/\.\-\_\+\=\$\:\[\]\\\,\~]
+WILDCHAR [_a-zA-Z0-9\/\.\-\_\+\=\$\:\[\]\\\,\~\?\*\^\!]
+WHITE [ \t\n\r]+
+NOCFILENAMECHAR [_a-zA-Z0-9\/\.\-\_\+\$\:\[\]\\\~]
+V_TAG [.$_a-zA-Z][._a-zA-Z0-9]*
+V_IDENTIFIER [*?.$_a-zA-Z\[\]\-\!\^\\]([*?.$_a-zA-Z0-9\[\]\-\!\^\\]|::)*
+@g
+
+@ The lexer uses different sets of rules depending on the context and the current state.
+These can be changed from the lexer itself or externally by the parser
+(as is the case in \ld\
+implementation). \locallink{stateswitchers}Later\endlink, a number of
+helper macros implement state switching so that the state names are
+very rarely used explicitly. Keeping all the state declarations in the
+same section simplifies the job of the
+\locallink{bootstrapstates}bootstrap parser\endlink, as well.
+\ifbootstrapmode\immediate\openout\stlist=ldl_states.h\fi
+\yyskipparsefalse
+@<\ld\ lexer states@>=
+@G
+%s SCRIPT
+%s EXPRESSION
+%s BOTH
+%s DEFSYMEXP
+%s MRI
+%s VERS_START
+%s VERS_SCRIPT
+%s VERS_NODE
+@g
+
+@*1 Macros for lexer functions.
+The \locallink{pingpong}state switching\endlink\ `ping-pong' between the lexer and the parser aside,
+the \ld\ lexer is very traditional. One implementation choice
+deserving some attenion is the treatment of comments by the lexer. The
+difficulty of implementing \Cee\ style comment lexing using regular
+expressions is well-known so an often used alternative is a
+special function that simply skips to the end of the comment. This is
+exactly what the \ld\ lexer does with an aptly named |comment()|
+function. The typesetting parser uses the \.{\\ldcomment} macro for
+the same purpose. For the curious, here is a \flex\ style regular
+expression defining \Cee\ comments\footnote{Taken from W.~McKeeman's site
+at
+\url{http://www.cs.dartmouth.edu/~mckeeman/cs118/assignments/comment.html}
+and adopted to \flex\ syntax.}:
+$$
+\hbox{\.{"/*" ("/"\yl[\^*/]\yl"*"+[\^*/])* "*"+ "/"}}
+$$
+This expression does not handle {\it every\/} practical situation,
+however, since it assumes that the end of line character can be
+matched like any other. Neither does it detect some often made
+mistakes such as attempting to nest comments. A few minor
+modifications can fix this deficiency, as well as add some error
+handling, however, for the sake of consistency, the approach taken
+here mirrors the one in the original \ld.
+
+The top level of the \.{\\ldcomment} macro simply bypasses the state
+setup of the lexer and enters a `|while| loop' in the input
+routine. This macro is a reasonable approximation of the functionality
+provided by |comment()|.
+@<Additional macros for the \ld\ lexer/parser@>=
+@G
+\def\ldcomment{%
+ \let\oldyyreturn\yyreturn
+ \let\oldyylextail\yylextail
+ \let\yylextail\yymatch %/* start inputting characters until {\tt *}{\tt /} is seen */
+ \let\yyreturn\ldcommentskipchars
+}
+@g
+
+@ The rest of the |while| loop merely waits for the \.{*/} combination.
+@<Additional macros for the \ld\ lexer/parser@>=
+@G
+\def\ldcommentskipchars{%
+ \ifnum\yycp@@=`*
+ \yybreak{\let\yyreturn\ldcommentseekslash\yyinput}%
+ %/* {\tt *} found, look for {\tt /} */
+ \else
+ \yybreak{\yyinput}% %/* keep skipping characters */
+ \yycontinue
+}%
+
+\def\ldcommentseekslash{%
+ \ifnum\yycp@@=`/
+ \yybreak{\ldcommentfinish}%/* {\tt /} found, exit */
+ \else
+ \ifnum\yycp@@=`*
+ \yybreak@@{\yyinput}% %/* keep skipping {\tt *}'s looking for a {\tt /} */
+ \else
+ \yybreak@@{\let\yyreturn\ldcommentskipchars\yyinput}%
+ %/* found a character other than {\tt *} or {\tt /} */
+ \fi
+ \yycontinue
+}%
+@g
+
+@ Once the end of the comment has been found, resume lexing the input
+stream.
+@<Additional macros for the \ld\ lexer/parser@>=
+@G
+\def\ldcommentfinish{%
+ \let\yyreturn\oldyyreturn
+ \let\yylextail\oldyylextail
+ \yylextail
+}
+@g
+
+@ The semantics of the macros defined above do not quite match that
+of the |comment()| function. The most significant difference is that
+the portion of the action following \.{\\ldcomment} expands {\it
+before\/} the comment characters are skipped. In most applications,
+|comment()| is the last function called so this would not limit the use
+of \.{\\ldcomment} too dramatically.
+
+A more intuitive and easier to use version of \.{\\ldcomment} is
+possible, however, if \.{\\yylextail} is not used inside actions (in the case of
+an `optimized' lexer the restriction is even weaker, namely,
+\.{\\yylextail} merely has to be absent in the portion of the action
+following \.{\\ldcomment}).
+@<Additional macros for the \ld\ lexer/parser@>=
+@G
+\def\ldcomment#1\yylextail{%
+ \let\oldyyreturn\yyreturn
+ \def\yylexcontinuation{#1\yylextail}%
+ \let\yyreturn\ldcommentskipchars %/* start inputting characters until {\tt *}{\tt /} is seen */
+ \yymatch
+}
+
+\def\ldcommentfinish{%
+ \let\yyreturn\oldyyreturn
+ \yylexcontinuation
+}
+@g
+
+@ \namedspot{pretendbufferswlex}The same idea can be applied to
+`\locallink{pretendbuffersw}pretend buffer switching\endlink'. Whenever
+the `real' \ld\ parser encounters an \prodstyle{INCLUDE} command, it
+switches the input buffer for the lexer and waits for the lexer to
+return the tokens from the file it just opened. When the lexer scans
+the end of the included file, it returns a special token, \prodstyle{END} that
+completes the appropriate production and lets the parser continue with
+its job.
+
+We would like to simulate the file inclusion by inserting the
+appropriate end of file marker for the lexer (a double
+\.{\\yyeof}). After the relevant production completes, the marker
+has to be cleaned up from the input stream (the lexer is designed to
+leave it intact). The macros below are designed to handle this assignment.
+@<Additional macros for the \ld\ lexer/parser@>=
+@G
+\def\ldcleanyyeof#1\yylextail{%
+ \let\oldyyinput\yyinput
+ \def\yyinput\yyeof\yyeof{\let\yyinput\oldyyinput#1\yylextail}%
+ \yymatch
+}
+@g
+
+@*1 Regular expressions.
+The `heart' of any lexer is the collection of regular expressions that
+describe the {\it tokens\/} of the appropriate language. The variey of
+tokens recognized by \ld\ is quite extensive and is described in the
+sections that follow.
+
+Variable names and algebraic operations come first.
+@<\ld\ token regular expressions@>=
+@G
+<BOTH,SCRIPT,EXPRESSION,VERS_START,VERS_NODE,VERS_SCRIPT>"/*" {@> @[TeX_( "/ldcomment/yylexnext" );@]@=}
+<DEFSYMEXP>"-" {@> @[TeX_( "/yylexreturnchar" );@]@=}
+<DEFSYMEXP>"+" {@> @[TeX_( "/yylexreturnchar" );@]@=}
+<DEFSYMEXP>{FILENAMECHAR1}{SYMBOLCHARN}* {@> @[TeX_( "/yylexreturnval{NAME}" );@]@=}
+<DEFSYMEXP>"=" {@> @[TeX_( "/yylexreturnchar" );@]@=}
+<MRI,EXPRESSION>"$"([0-9A-Fa-f])+ {@> @<Return an absolute hex constant@> @=}
+<MRI,EXPRESSION>([0-9A-Fa-f])+(H|h|X|x|B|b|O|o|D|d) {@> @<Return a constant in a specific radix@>@=}
+<SCRIPT,DEFSYMEXP,MRI,BOTH,EXPRESSION>((("$"|0[xX])([0-9A-Fa-f])+)|(([0-9])+))(M|K|m|k)? {
+ @> @<Return a constant with a multiplier@>@=}
+<BOTH,SCRIPT,EXPRESSION,MRI>"]" {@> @[TeX_( "/yylexreturnchar" );@]@=}
+<BOTH,SCRIPT,EXPRESSION,MRI>"[" {@> @[TeX_( "/yylexreturnchar" );@]@=}
+<BOTH,SCRIPT,EXPRESSION,MRI>"<<=" {@> @[TeX_( "/yylexreturnptr{LSHIFTEQ}" );@]@=}
+<BOTH,SCRIPT,EXPRESSION,MRI>">>=" {@> @[TeX_( "/yylexreturnptr{RSHIFTEQ}" );@]@=}
+<BOTH,SCRIPT,EXPRESSION,MRI>"||" {@> @[TeX_( "/yylexreturnptr{OROR}" );@]@=}
+<BOTH,SCRIPT,EXPRESSION,MRI>"==" {@> @[TeX_( "/yylexreturnptr{EQ}" );@]@=}
+<BOTH,SCRIPT,EXPRESSION,MRI>"!=" {@> @[TeX_( "/yylexreturnptr{NE}" );@]@=}
+<BOTH,SCRIPT,EXPRESSION,MRI>">=" {@> @[TeX_( "/yylexreturnptr{GE}" );@]@=}
+<BOTH,SCRIPT,EXPRESSION,MRI>"<=" {@> @[TeX_( "/yylexreturnptr{LE}" );@]@=}
+<BOTH,SCRIPT,EXPRESSION,MRI>"<<" {@> @[TeX_( "/yylexreturnptr{LSHIFT}" );@]@=}
+<BOTH,SCRIPT,EXPRESSION,MRI>">>" {@> @[TeX_( "/yylexreturnptr{RSHIFT}" );@]@=}
+<BOTH,SCRIPT,EXPRESSION,MRI>"+=" {@> @[TeX_( "/yylexreturnptr{PLUSEQ}" );@]@=}
+<BOTH,SCRIPT,EXPRESSION,MRI>"-=" {@> @[TeX_( "/yylexreturnptr{MINUSEQ}" );@]@=}
+<BOTH,SCRIPT,EXPRESSION,MRI>"*=" {@> @[TeX_( "/yylexreturnptr{MULTEQ}" );@]@=}
+<BOTH,SCRIPT,EXPRESSION,MRI>"/=" {@> @[TeX_( "/yylexreturnptr{DIVEQ}" );@]@=}
+<BOTH,SCRIPT,EXPRESSION,MRI>"&=" {@> @[TeX_( "/yylexreturnptr{ANDEQ}" );@]@=}
+<BOTH,SCRIPT,EXPRESSION,MRI>"|=" {@> @[TeX_( "/yylexreturnptr{OREQ}" );@]@=}
+<BOTH,SCRIPT,EXPRESSION,MRI>"&&" {@> @[TeX_( "/yylexreturnptr{ANDAND}" );@]@=}
+<BOTH,SCRIPT,EXPRESSION,MRI>">" {@> @[TeX_( "/yylexreturnchar" );@]@=}
+<BOTH,SCRIPT,EXPRESSION,MRI>"," {@> @[TeX_( "/yylexreturnchar" );@]@=}
+<BOTH,SCRIPT,EXPRESSION,MRI>"&" {@> @[TeX_( "/yylexreturnchar" );@]@=}
+<BOTH,SCRIPT,EXPRESSION,MRI>"|" {@> @[TeX_( "/yylexreturnchar" );@]@=}
+<BOTH,SCRIPT,EXPRESSION,MRI>"~" {@> @[TeX_( "/yylexreturnchar" );@]@=}
+<BOTH,SCRIPT,EXPRESSION,MRI>"!" {@> @[TeX_( "/yylexreturnchar" );@]@=}
+<BOTH,SCRIPT,EXPRESSION,MRI>"?" {@> @[TeX_( "/yylexreturnchar" );@]@=}
+<BOTH,SCRIPT,EXPRESSION,MRI>"*" {@> @[TeX_( "/yylexreturnchar" );@]@=}
+<BOTH,SCRIPT,EXPRESSION,MRI>"+" {@> @[TeX_( "/yylexreturnchar" );@]@=}
+<BOTH,SCRIPT,EXPRESSION,MRI>"-" {@> @[TeX_( "/yylexreturnchar" );@]@=}
+<BOTH,SCRIPT,EXPRESSION,MRI>"/" {@> @[TeX_( "/yylexreturnchar" );@]@=}
+<BOTH,SCRIPT,EXPRESSION,MRI>"%" {@> @[TeX_( "/yylexreturnchar" );@]@=}
+<BOTH,SCRIPT,EXPRESSION,MRI>"<" {@> @[TeX_( "/yylexreturnchar" );@]@=}
+<BOTH,SCRIPT,EXPRESSION,MRI>"=" {@> @[TeX_( "/yylexreturnchar" );@]@=}
+<BOTH,SCRIPT,EXPRESSION,MRI>"}" {@> @[TeX_( "/yylexreturnchar" );@]@=}
+<BOTH,SCRIPT,EXPRESSION,MRI>"{" {@> @[TeX_( "/yylexreturnchar" );@]@=}
+<BOTH,SCRIPT,EXPRESSION,MRI>")" {@> @[TeX_( "/yylexreturnchar" );@]@=}
+<BOTH,SCRIPT,EXPRESSION,MRI>"(" {@> @[TeX_( "/yylexreturnchar" );@]@=}
+<BOTH,SCRIPT,EXPRESSION,MRI>":" {@> @[TeX_( "/yylexreturnchar" );@]@=}
+<BOTH,SCRIPT,EXPRESSION,MRI>";" {@> @[TeX_( "/yylexreturnchar" );@]@=}
+@g
+
+@ The bulk of tokens produced by the lexer are the keywords used
+inside script files. File name syntax is listed as well, along with
+miscellanea such as whitespace and version symbols.
+@<\ld\ token regular expressions@>=
+@G
+<BOTH,SCRIPT>"MEMORY" {@> @[TeX_( "/yylexreturnptr{MEMORY}" );@]@=}
+<BOTH,SCRIPT>"REGION_ALIAS" {@> @[TeX_( "/yylexreturnptr{REGION_ALIAS}" );@]@=}
+<BOTH,SCRIPT>"LD_FEATURE" {@> @[TeX_( "/yylexreturnptr{LD_FEATURE}" );@]@=}
+<BOTH,SCRIPT,EXPRESSION>"ORIGIN" {@> @[TeX_( "/yylexreturnptr{ORIGIN}" );@]@=}
+<BOTH,SCRIPT>"VERSION" {@> @[TeX_( "/yylexreturnptr{VERSIONK}" );@]@=}
+<EXPRESSION,BOTH,SCRIPT>"BLOCK" {@> @[TeX_( "/yylexreturnptr{BLOCK}" );@]@=}
+<EXPRESSION,BOTH,SCRIPT>"BIND" {@> @[TeX_( "/yylexreturnptr{BIND}" );@]@=}
+<BOTH,SCRIPT,EXPRESSION>"LENGTH" {@> @[TeX_( "/yylexreturnptr{LENGTH}" );@]@=}
+<EXPRESSION,BOTH,SCRIPT>"ALIGN" {@> @[TeX_( "/yylexreturnptr{ALIGN_K}" );@]@=}
+<EXPRESSION,BOTH,SCRIPT>"DATA_SEGMENT_ALIGN" {@> @[TeX_( "/yylexreturnptr{DATA_SEGMENT_ALIGN}" );@]@=}
+<EXPRESSION,BOTH,SCRIPT>"DATA_SEGMENT_RELRO_END" {@> @[TeX_( "/yylexreturnptr{DATA_SEGMENT_RELRO_END}" );@]@=}
+<EXPRESSION,BOTH,SCRIPT>"DATA_SEGMENT_END" {@> @[TeX_( "/yylexreturnptr{DATA_SEGMENT_END}" );@]@=}
+<EXPRESSION,BOTH,SCRIPT>"ADDR" {@> @[TeX_( "/yylexreturnptr{ADDR}" );@]@=}
+<EXPRESSION,BOTH,SCRIPT>"LOADADDR" {@> @[TeX_( "/yylexreturnptr{LOADADDR}" );@]@=}
+<EXPRESSION,BOTH,SCRIPT>"ALIGNOF" {@> @[TeX_( "/yylexreturnptr{ALIGNOF}" );@]@=}
+<EXPRESSION,BOTH>"MAX" {@> @[TeX_( "/yylexreturnptr{MAX_K}" );@]@=}
+<EXPRESSION,BOTH>"MIN" {@> @[TeX_( "/yylexreturnptr{MIN_K}" );@]@=}
+<EXPRESSION,BOTH>"LOG2CEIL" {@> @[TeX_( "/yylexreturnptr{LOG2CEIL}" );@]@=}
+<EXPRESSION,BOTH,SCRIPT>"ASSERT" {@> @[TeX_( "/yylexreturnptr{ASSERT_K}" );@]@=}
+<BOTH,SCRIPT>"ENTRY" {@> @[TeX_( "/yylexreturnptr{ENTRY}" );@]@=}
+<BOTH,SCRIPT,MRI>"EXTERN" {@> @[TeX_( "/yylexreturnptr{EXTERN}" );@]@=}
+<EXPRESSION,BOTH,SCRIPT>"NEXT" {@> @[TeX_( "/yylexreturnptr{NEXT}" );@]@=}
+<EXPRESSION,BOTH,SCRIPT>"sizeof_headers" {@> @[TeX_( "/yylexreturnptr{SIZEOF_HEADERS}" );@]@=}
+<EXPRESSION,BOTH,SCRIPT>"SIZEOF_HEADERS" {@> @[TeX_( "/yylexreturnptr{SIZEOF_HEADERS}" );@]@=}
+<EXPRESSION,BOTH,SCRIPT>"SEGMENT_START" {@> @[TeX_( "/yylexreturnptr{SEGMENT_START}" );@]@=}
+<BOTH,SCRIPT>"MAP" {@> @[TeX_( "/yylexreturnptr{MAP}" );@]@=}
+<EXPRESSION,BOTH,SCRIPT>"SIZEOF" {@> @[TeX_( "/yylexreturnptr{SIZEOF}" );@]@=}
+<BOTH,SCRIPT>"TARGET" {@> @[TeX_( "/yylexreturnptr{TARGET_K}" );@]@=}
+<BOTH,SCRIPT>"SEARCH_DIR" {@> @[TeX_( "/yylexreturnptr{SEARCH_DIR}" );@]@=}
+<BOTH,SCRIPT>"OUTPUT" {@> @[TeX_( "/yylexreturnptr{OUTPUT}" );@]@=}
+<BOTH,SCRIPT>"INPUT" {@> @[TeX_( "/yylexreturnptr{INPUT}" );@]@=}
+<EXPRESSION,BOTH,SCRIPT>"GROUP" {@> @[TeX_( "/yylexreturnptr{GROUP}" );@]@=}
+<EXPRESSION,BOTH,SCRIPT>"AS_NEEDED" {@> @[TeX_( "/yylexreturnptr{AS_NEEDED}" );@]@=}
+<EXPRESSION,BOTH,SCRIPT>"DEFINED" {@> @[TeX_( "/yylexreturnptr{DEFINED}" );@]@=}
+<BOTH,SCRIPT>"CREATE_OBJECT_SYMBOLS" {@> @[TeX_( "/yylexreturnptr{CREATE_OBJECT_SYMBOLS}" );@]@=}
+<BOTH,SCRIPT>"CONSTRUCTORS" {@> @[TeX_( "/yylexreturnptr{CONSTRUCTORS}" );@]@=}
+<BOTH,SCRIPT>"FORCE_COMMON_ALLOCATION" {@> @[TeX_( "/yylexreturnptr{FORCE_COMMON_ALLOCATION}" );@]@=}
+<BOTH,SCRIPT>"INHIBIT_COMMON_ALLOCATION" {@> @[TeX_( "/yylexreturnptr{INHIBIT_COMMON_ALLOCATION}" );@]@=}
+<BOTH,SCRIPT>"SECTIONS" {@> @[TeX_( "/yylexreturnptr{SECTIONS}" );@]@=}
+<BOTH,SCRIPT>"INSERT" {@> @[TeX_( "/yylexreturnptr{INSERT_K}" );@]@=}
+<BOTH,SCRIPT>"AFTER" {@> @[TeX_( "/yylexreturnptr{AFTER}" );@]@=}
+<BOTH,SCRIPT>"BEFORE" {@> @[TeX_( "/yylexreturnptr{BEFORE}" );@]@=}
+<BOTH,SCRIPT>"FILL" {@> @[TeX_( "/yylexreturnptr{FILL}" );@]@=}
+<BOTH,SCRIPT>"STARTUP" {@> @[TeX_( "/yylexreturnptr{STARTUP}" );@]@=}
+<BOTH,SCRIPT>"OUTPUT_FORMAT" {@> @[TeX_( "/yylexreturnptr{OUTPUT_FORMAT}" );@]@=}
+<BOTH,SCRIPT>"OUTPUT_ARCH" {@> @[TeX_( "/yylexreturnptr{OUTPUT_ARCH}" );@]@=}
+<BOTH,SCRIPT>"HLL" {@> @[TeX_( "/yylexreturnptr{HLL}" );@]@=}
+<BOTH,SCRIPT>"SYSLIB" {@> @[TeX_( "/yylexreturnptr{SYSLIB}" );@]@=}
+<BOTH,SCRIPT>"FLOAT" {@> @[TeX_( "/yylexreturnptr{FLOAT}" );@]@=}
+<BOTH,SCRIPT>"QUAD" {@> @[TeX_( "/yylexreturnptr{QUAD}" );@]@=}
+<BOTH,SCRIPT>"SQUAD" {@> @[TeX_( "/yylexreturnptr{SQUAD}" );@]@=}
+<BOTH,SCRIPT>"LONG" {@> @[TeX_( "/yylexreturnptr{LONG}" );@]@=}
+<BOTH,SCRIPT>"SHORT" {@> @[TeX_( "/yylexreturnptr{SHORT}" );@]@=}
+<BOTH,SCRIPT>"BYTE" {@> @[TeX_( "/yylexreturnptr{BYTE}" );@]@=}
+<BOTH,SCRIPT>"NOFLOAT" {@> @[TeX_( "/yylexreturnptr{NOFLOAT}" );@]@=}
+<EXPRESSION,BOTH,SCRIPT>"NOCROSSREFS" {@> @[TeX_( "/yylexreturnptr{NOCROSSREFS}" );@]@=}
+<BOTH,SCRIPT>"OVERLAY" {@> @[TeX_( "/yylexreturnptr{OVERLAY}" );@]@=}
+<BOTH,SCRIPT>"SORT_BY_NAME" {@> @[TeX_( "/yylexreturnptr{SORT_BY_NAME}" );@]@=}
+<BOTH,SCRIPT>"SORT_BY_ALIGNMENT" {@> @[TeX_( "/yylexreturnptr{SORT_BY_ALIGNMENT}" );@]@=}
+<BOTH,SCRIPT>"SORT" {@> @[TeX_( "/yylexreturnptr{SORT_BY_NAME}" );@]@=}
+<BOTH,SCRIPT>"SORT_BY_INIT_PRIORITY" {@> @[TeX_( "/yylexreturnptr{SORT_BY_INIT_PRIORITY}" );@]@=}
+<BOTH,SCRIPT>"SORT_NONE" {@> @[TeX_( "/yylexreturnptr{SORT_NONE}" );@]@=}
+<EXPRESSION,BOTH,SCRIPT>"NOLOAD" {@> @[TeX_( "/yylexreturnptr{NOLOAD}" );@]@=}
+<EXPRESSION,BOTH,SCRIPT>"DSECT" {@> @[TeX_( "/yylexreturnptr{DSECT}" );@]@=}
+<EXPRESSION,BOTH,SCRIPT>"COPY" {@> @[TeX_( "/yylexreturnptr{COPY}" );@]@=}
+<EXPRESSION,BOTH,SCRIPT>"INFO" {@> @[TeX_( "/yylexreturnptr{INFO}" );@]@=}
+<EXPRESSION,BOTH,SCRIPT>"OVERLAY" {@> @[TeX_( "/yylexreturnptr{OVERLAY}" );@]@=}
+<EXPRESSION,BOTH,SCRIPT>"ONLY_IF_RO" {@> @[TeX_( "/yylexreturnptr{ONLY_IF_RO}" );@]@=}
+<EXPRESSION,BOTH,SCRIPT>"ONLY_IF_RW" {@> @[TeX_( "/yylexreturnptr{ONLY_IF_RW}" );@]@=}
+<EXPRESSION,BOTH,SCRIPT>"SPECIAL" {@> @[TeX_( "/yylexreturnptr{SPECIAL}" );@]@=}
+<BOTH,SCRIPT>"o" {@> @[TeX_( "/yylexreturnptr{ORIGIN}" );@]@=}
+<BOTH,SCRIPT>"org" {@> @[TeX_( "/yylexreturnptr{ORIGIN}" );@]@=}
+<BOTH,SCRIPT>"l" {@> @[TeX_( "/yylexreturnptr{LENGTH}" );@]@=}
+<BOTH,SCRIPT>"len" {@> @[TeX_( "/yylexreturnptr{LENGTH}" );@]@=}
+<EXPRESSION,BOTH,SCRIPT>"INPUT_SECTION_FLAGS" {@> @[TeX_( "/yylexreturnptr{INPUT_SECTION_FLAGS}" );@]@=}
+<EXPRESSION,BOTH,SCRIPT>"INCLUDE" {@> @[TeX_( "/yylexreturnptr{INCLUDE}" );@]@=}
+<BOTH,SCRIPT>"PHDRS" {@> @[TeX_( "/yylexreturnptr{PHDRS}" );@]@=}
+<EXPRESSION,BOTH,SCRIPT>"AT" {@> @[TeX_( "/yylexreturnptr{AT}" );@]@=}
+<EXPRESSION,BOTH,SCRIPT>"ALIGN_WITH_INPUT" {@> @[TeX_( "/yylexreturnptr{ALIGN_WITH_INPUT}" );@]@=}
+<EXPRESSION,BOTH,SCRIPT>"SUBALIGN" {@> @[TeX_( "/yylexreturnptr{SUBALIGN}" );@]@=}
+<EXPRESSION,BOTH,SCRIPT>"HIDDEN" {@> @[TeX_( "/yylexreturnptr{HIDDEN}" );@]@=}
+<EXPRESSION,BOTH,SCRIPT>"PROVIDE" {@> @[TeX_( "/yylexreturnptr{PROVIDE}" );@]@=}
+<EXPRESSION,BOTH,SCRIPT>"PROVIDE_HIDDEN" {@> @[TeX_( "/yylexreturnptr{PROVIDE_HIDDEN}" );@]@=}
+<EXPRESSION,BOTH,SCRIPT>"KEEP" {@> @[TeX_( "/yylexreturnptr{KEEP}" );@]@=}
+<EXPRESSION,BOTH,SCRIPT>"EXCLUDE_FILE" {@> @[TeX_( "/yylexreturnptr{EXCLUDE_FILE}" );@]@=}
+<EXPRESSION,BOTH,SCRIPT>"CONSTANT" {@> @[TeX_( "/yylexreturnptr{CONSTANT}" );@]@=}
+<MRI>"#".*\n? {@> @[TeX_( "/yylexnext" );@]@=}
+<MRI>"\n" {@> @[TeX_( "/yylexreturnptr{NEWLINE}" );@]@=}
+<MRI>"*".* {@> @[TeX_( "/yylexnext" );@]@=}
+<MRI>";".* {@> @[TeX_( "/yylexnext" );@]@=}
+<MRI>"END" {@> @[TeX_( "/yylexreturnptr{ENDWORD}" );@]@=}
+<MRI>"ALIGNMOD" {@> @[TeX_( "/yylexreturnptr{ALIGNMOD}" );@]@=}
+<MRI>"ALIGN" {@> @[TeX_( "/yylexreturnptr{ALIGN_K}" );@]@=}
+<MRI>"CHIP" {@> @[TeX_( "/yylexreturnptr{CHIP}" );@]@=}
+<MRI>"BASE" {@> @[TeX_( "/yylexreturnptr{BASE}" );@]@=}
+<MRI>"ALIAS" {@> @[TeX_( "/yylexreturnptr{ALIAS}" );@]@=}
+<MRI>"TRUNCATE" {@> @[TeX_( "/yylexreturnptr{TRUNCATE}" );@]@=}
+<MRI>"LOAD" {@> @[TeX_( "/yylexreturnptr{LOAD}" );@]@=}
+<MRI>"PUBLIC" {@> @[TeX_( "/yylexreturnptr{PUBLIC}" );@]@=}
+<MRI>"ORDER" {@> @[TeX_( "/yylexreturnptr{ORDER}" );@]@=}
+<MRI>"NAME" {@> @[TeX_( "/yylexreturnptr{NAMEWORD}" );@]@=}
+<MRI>"FORMAT" {@> @[TeX_( "/yylexreturnptr{FORMAT}" );@]@=}
+<MRI>"CASE" {@> @[TeX_( "/yylexreturnptr{CASE}" );@]@=}
+<MRI>"START" {@> @[TeX_( "/yylexreturnptr{START}" );@]@=}
+<MRI>"LIST".* {@> @[TeX_( "/yylexreturnptr{LIST}" );@]@=}
+<MRI>"SECT" {@> @[TeX_( "/yylexreturnptr{SECT}" );@]@=}
+<EXPRESSION,BOTH,SCRIPT,MRI>"ABSOLUTE" {@> @[TeX_( "/yylexreturnptr{ABSOLUTE}" );@]@=}
+<MRI>"end" {@> @[TeX_( "/yylexreturnptr{ENDWORD}" );@]@=}
+<MRI>"alignmod" {@> @[TeX_( "/yylexreturnptr{ALIGNMOD}" );@]@=}
+<MRI>"align" {@> @[TeX_( "/yylexreturnptr{ALIGN_K}" );@]@=}
+<MRI>"chip" {@> @[TeX_( "/yylexreturnptr{CHIP}" );@]@=}
+<MRI>"base" {@> @[TeX_( "/yylexreturnptr{BASE}" );@]@=}
+<MRI>"alias" {@> @[TeX_( "/yylexreturnptr{ALIAS}" );@]@=}
+<MRI>"truncate" {@> @[TeX_( "/yylexreturnptr{TRUNCATE}" );@]@=}
+<MRI>"load" {@> @[TeX_( "/yylexreturnptr{LOAD}" );@]@=}
+<MRI>"public" {@> @[TeX_( "/yylexreturnptr{PUBLIC}" );@]@=}
+<MRI>"order" {@> @[TeX_( "/yylexreturnptr{ORDER}" );@]@=}
+<MRI>"name" {@> @[TeX_( "/yylexreturnptr{NAMEWORD}" );@]@=}
+<MRI>"format" {@> @[TeX_( "/yylexreturnptr{FORMAT}" );@]@=}
+<MRI>"case" {@> @[TeX_( "/yylexreturnptr{CASE}" );@]@=}
+<MRI>"extern" {@> @[TeX_( "/yylexreturnptr{EXTERN}" );@]@=}
+<MRI>"start" {@> @[TeX_( "/yylexreturnptr{START}" );@]@=}
+<MRI>"list".* {@> @[TeX_( "/yylexreturnptr{LIST}" );@]@=}
+<MRI>"sect" {@> @[TeX_( "/yylexreturnptr{SECT}" );@]@=}
+<EXPRESSION,BOTH,SCRIPT,MRI>"absolute" {@> @[TeX_( "/yylexreturnptr{ABSOLUTE}" );@]@=}
+<MRI>{FILENAMECHAR1}{NOCFILENAMECHAR}* {@> @[TeX_( "/yylexreturnval{NAME}" );@]@=}
+<BOTH>{FILENAMECHAR1}{FILENAMECHAR}* {@> @[TeX_( "/yylexreturnval{NAME}" );@]@=}
+<BOTH>"-l"{FILENAMECHAR}+ {@> @[TeX_( "/yylexreturnval{NAME}" );@]@=}
+<EXPRESSION>{FILENAMECHAR1}{NOCFILENAMECHAR}* {@> @[TeX_( "/yylexreturnval{NAME}" );@]@=}
+<EXPRESSION>"-l"{NOCFILENAMECHAR}+ {@> @[TeX_( "/yylexreturnval{NAME}" );@]@=}
+<SCRIPT>{WILDCHAR}* {@> @[@<Skip a possible comment and return a \prodstyle{NAME}@>@]@=}
+<EXPRESSION,BOTH,SCRIPT,VERS_NODE>"\""[^\"]*"\"" {@> @[@<Return the \prodstyle{NAME} inside quotes@>@]@=}
+<BOTH,SCRIPT,EXPRESSION>"\n" {@> @[TeX_( "/yylexnext" );@]@=}
+<MRI,BOTH,SCRIPT,EXPRESSION>[ \t\r]+ {@> @[TeX_( "/yylexnext" );@]@=}
+<VERS_NODE,VERS_SCRIPT>[:,;] {@> @[TeX_( "/yylexreturnchar" );@]@=}
+<VERS_NODE>global {@> @[TeX_( "/yylexreturnptr{GLOBAL}" );@]@=}
+<VERS_NODE>local {@> @[TeX_( "/yylexreturnptr{LOCAL}" );@]@=}
+<VERS_NODE>extern {@> @[TeX_( "/yylexreturnptr{EXTERN}" );@]@=}
+<VERS_NODE>{V_IDENTIFIER} {@> @[TeX_( "/yylexreturnval{VERS_IDENTIFIER}" );@]@=}
+<VERS_SCRIPT>{V_TAG} {@> @[TeX_( "/yylexreturnval{VERS_TAG}" );@]@=}
+<VERS_START>"{" {@> @[TeX_( "/yyBEGIN{VERS_SCRIPT}/yylexreturnchar" );@]@=}
+@g
+
+@ There is a bit of a trick to returning an absolute hex value. The
+macros are looking for a \.{\$} suffix while the contents of
+\.{\\yytext} start with \.{\\\$}.
+@<Return an absolute hex constant@>=
+@[TeX_( "/edef/next{/yylval{/nx/hexint{$/expandafter/eatone/the/yytext}" );@]@;
+@[TeX_( "{/the/yyfmark}{/the/yysmark}}}/next" );@]@;
+@[TeX_( "/yylexreturn{INT}" );@]@;
+
+@ @<Return a constant in a specific radix@>=
+@[TeX_( "/edef/next{/yylval{/nx/bint{/the/yytext}" );@]@;
+@[TeX_( "{/the/yyfmark}{/the/yysmark}}}/next" );@]@;
+@[TeX_( "/yylexreturn{INT}" );@]@;
+
+@ @<Return a constant with a multiplier@>=
+@[TeX_( "/edef/next{/yylval{/nx/anint{/the/yytext}" );@]@;
+@[TeX_( "{/the/yyfmark}{/the/yysmark}}}/next" );@]@;
+@[TeX_( "/yylexreturn{INT}" );@]@;
+
+@ @<Additional macros for the \ld\ lexer/parser@>=
+@G
+@=\def\matchcomment@@#1/*#2\yyeof#3#4{%@>@;
+ \yystringempty{#1}{#3}{#4}%
+}
+\def\matchcomment#1{%
+@= \expandafter\matchcomment@@\the#1/*\yyeof@>@;
+}
+\def\ldstripquotes@@"#1"\yyeof{#1}
+\def\ldstripquotes#1{%
+ \yytext\expandafter\expandafter\expandafter
+ {\expandafter\ldstripquotes@@\the\yytext\yyeof}%
+ \yytextpure\expandafter\expandafter\expandafter
+ {\expandafter\ldstripquotes@@\the\yytextpure\yyeof}%
+}
+@g
+
+@ {\it Annoyingly, this pattern can match comments, and we have
+longest match issues to consider. So if the first two
+characters are a comment opening, put the input back and
+try again.}
+@<Skip a possible comment and return a \prodstyle{NAME}@>=
+ @[TeX_( "/matchcomment/yytextpure" );@]@;
+ @[TeX_( " {/yyless/tw@@/ldcomment}" );@]/*matched the beginning of a comment*/@;
+ @[TeX_( " {/yylexreturnval{NAME}}" );@]@;
+
+@ {\it No matter the state, quotes give what's inside.}
+@<Return the \prodstyle{NAME} inside quotes@>=
+ @[TeX_( "/ldstripquotes/yylexreturnval{NAME}" );@]@;
+
+@ @<Additional macros for the \ld\ lexer/parser@>=
+@G
+\newcount\versnodenesting
+\newcount\includestackptr
+@g
+
+@ Some syntax specific to version scripts.
+@<\ld\ token regular expressions@>=
+@G
+<VERS_SCRIPT>"{" {@> @[TeX_( "/yyBEGIN{VERS_NODE}/versnodenesting=/z@@/yylexreturnchar" );@]@=}
+<VERS_SCRIPT>"}" {@> @[TeX_( "/yylexreturnchar" );@]@=}
+<VERS_NODE>"{" {@> @[TeX_( "/advance/versnodenesting/@@ne /yylexreturnchar" );@]@=}
+<VERS_NODE>"}" {@> @[TeX_( "/advance/versnodenesting/m@@ne" );@]@;
+ @> @[TeX_( "/ifnum/versnodenesting</z@@" );@]@;
+ @> @[TeX_( " /yyBEGIN{VERS_SCRIPT}" );@]@;
+ @> @[TeX_( "/fi" );@]@;
+ @> @[TeX_( "/yylexreturnchar" );@]@=}
+<VERS_START,VERS_NODE,VERS_SCRIPT>[\n] {@> @[TeX_( "/yylexnext" );@]@=}
+<VERS_START,VERS_NODE,VERS_SCRIPT>#.* {@> @[TeX_( "/yylexnext" );@]@=}
+<VERS_START,VERS_NODE,VERS_SCRIPT>[ \t\r]+ {@> @[TeX_( "/yylexnext" );@]@=}
+
+<<EOF>> {@> @[@<Process the end of (possibly included) file@>@]@=}
+
+<SCRIPT,MRI,VERS_START,VERS_SCRIPT,VERS_NODE>. {@> @[TeX_( "/yycomplain{bad character `/the/yytext'" );@]
+ @> @[TeX_( " in script}" );@]
+ @> @[TeX_( "/yyerrterminate" );@]@=}
+<EXPRESSION,DEFSYMEXP,BOTH>. {@> @[TeX_( "/yycomplain{bad character `/the/yytext'" );@]
+ @> @[TeX_( " in expression}" );@]@=
+ @> @[TeX_( "/yyerrterminate" );@]@=}
+@g
+
+@ @<Process the end of (possibly included) file@>=
+ @[TeX_( "/advance/includestackptr/m@@ne" );@]@;
+ @[TeX_( "/ifnum/includestackptr=/z@@" );@]@;
+ @[TeX_( " /yybreak{/yyterminate}" );@]@;
+ @[TeX_( "/else" );@]@;
+ @[TeX_( " /yybreak{/ldcleanyyeof/yylexreturn{END}}" );@]@;
+ @[TeX_( "/yycontinue" );@]@;
+
+@*1 Parser-lexer interaction support.
+\namedspot{stateswitchers}Here are the long promised auxiliary
+macros for switching lexer states and handling file input.
+@<Additional macros for the \ld\ lexer/parser@>=
+@G
+\def\ldlex@@script{\yypushstate{SCRIPT}}
+\def\ldlex@@mri@@script{\yypushstate{MRI}}
+\def\ldlex@@version@@script{\yypushstate{VERS_START}}
+\def\ldlex@@version@@file{\yypushstate{VERS_SCRIPT}}
+\def\ldlex@@defsym{\yypushstate{DEFSYMEXP}}
+\def\ldlex@@expression{\yypushstate{EXPRESSION}}
+\def\ldlex@@both{\yypushstate{BOTH}}
+\let\ldlex@@popstate\yypopstate
+
+\def\ldfile@@open@@command@@file#1{%
+ \advance\includestackptr\@@ne
+ \appendl\yytextseen{\noexpand\yyeof\noexpand\yyeof}%
+ \yytextbackuptrue
+}
+
+\def\ldlex@@filename{}
+@g
+
diff --git a/support/splint/examples/ld/ldlexo.w b/support/splint/examples/ld/ldlexo.w
new file mode 100644
index 0000000000..6b62d2fd77
--- /dev/null
+++ b/support/splint/examples/ld/ldlexo.w
@@ -0,0 +1,763 @@
+@q Copyright 2015 Alexander Shibakov@>
+@q Copyright 2002-2015 Free Software Foundation, Inc.@>
+@q This file is part of SPLinT@>
+
+@q SPLinT is free software: you can redistribute it and/or modify@>
+@q it under the terms of the GNU General Public License as published by@>
+@q the Free Software Foundation, either version 3 of the License, or@>
+@q (at your option) any later version.@>
+
+@q SPLinT is distributed in the hope that it will be useful,@>
+@q but WITHOUT ANY WARRANTY; without even the implied warranty of@>
+@q MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the@>
+@q GNU General Public License for more details.@>
+
+@q You should have received a copy of the GNU General Public License@>
+@q along with SPLinT. If not, see <http://www.gnu.org/licenses/>.@>
+
+@*1 The original lexer. {\it Note that the \ld\ lexer was designed to accomodate
+the syntax of various \flex\ flavors, such as the original \lex. The
+options \prodstyle{\%a} and \prodstyle{\%o} are ignored by \flex\ and
+are a leftover from the archaic days of the original scanner generator.}
+
+@s input_type int
+
+@<Original \ld\ lexer@>=
+@G
+ @> @<Original \ld\ macros@> @=
+%{@>@<Original \ld\ preamble@> @=%}
+%option nounput
+ @> @<Ignored options@> @=
+%%
+ @> @<Original \ld\ regular expressions@> @=
+%%
+@g
+
+@ @<Original \ld\ preamble@>=
+#include "bfd.h"
+#include "safe-ctype.h"
+#include "bfdlink.h"
+#include "ld.h"
+#include "ldmisc.h"
+#include "ldexp.h"
+#include "ldlang.h"
+#include <ldgram.h>
+#include "ldfile.h"
+#include "ldlex.h"
+#include "ldmain.h"
+#include "libiberty.h"
+
+input_type parser_input;/* The type of top-level parser input.
+ |yylex| and |yyparse| (indirectly) both check this. */
+
+unsigned int lineno = 1;/* Line number in the current input file. */
+
+const char *lex_string = NULL;/* The string we are currently lexing, or |NULL| if we are reading a
+ file. */
+
+#undef YY_INPUT
+#define YY_INPUT(buf,result,max_size) result = yy_input (buf, max_size)
+/* Support for \flex\ reading from more than one input file (stream).
+ |include_stack| is \flex's input state for each open file;
+ |file_name_stack| is the file names. |lineno_stack| is the current
+ line numbers.
+
+ If |include_stack_ptr| is 0, we haven't started reading anything yet.
+ Otherwise, stack elements 0 through |include_stack_ptr - 1| are valid. */
+
+
+#ifndef YY_NO_UNPUT
+#define YY_NO_UNPUT
+#endif
+
+#define MAX_INCLUDE_DEPTH 10
+static YY_BUFFER_STATE@, @[include_stack[MAX_INCLUDE_DEPTH]@];
+static const char *file_name_stack[MAX_INCLUDE_DEPTH];
+static unsigned int lineno_stack[MAX_INCLUDE_DEPTH];
+static unsigned int sysrooted_stack[MAX_INCLUDE_DEPTH];
+static unsigned int include_stack_ptr = 0;
+static int vers_node_nesting = 0;
+
+static int yy_input (char *, int);
+static void comment (void);
+static void lex_warn_invalid (char *where, char *what);
+
+#define RTOKEN(x) { yylval.token = x; return x; }
+
+#ifndef yywrap
+int yywrap (void) { return 1; }/* Some versions of \flex\ want this. */
+#endif
+
+@ @<Ignored options@>=
+@G
+%a 4000
+%o 5000
+@g
+
+@ {\it Some convenient abbreviations for regular expressions.}%
+\ifbootstrapmode\else\yyskipparsetrue\fi@<Original \ld\ macros@>=
+@G
+CMDFILENAMECHAR [_a-zA-Z0-9\/\.\\_\+\$\:\[\]\\\,\=\&\!\<\>\-\~]
+CMDFILENAMECHAR1 [_a-zA-Z0-9\/\.\\_\+\$\:\[\]\\\,\=\&\!\<\>\~]
+FILENAMECHAR1 [_a-zA-Z\/\.\\\$\_\~]
+SYMBOLCHARN [_a-zA-Z\/\.\\\$\_\~0-9]
+FILENAMECHAR [_a-zA-Z0-9\/\.\-\_\+\=\$\:\[\]\\\,\~]
+WILDCHAR [_a-zA-Z0-9\/\.\-\_\+\=\$\:\[\]\\\,\~\?\*\^\!]
+WHITE [ \t\n\r]+
+NOCFILENAMECHAR [_a-zA-Z0-9\/\.\-\_\+\$\:\[\]\\\~]
+V_TAG [.$_a-zA-Z][._a-zA-Z0-9]*
+V_IDENTIFIER [*?.$_a-zA-Z\[\]\-\!\^\\]([*?.$_a-zA-Z0-9\[\]\-\!\^\\]|::)*
+@g
+
+@ {%
+\def\aterm{\item{\sqbullet}\ignorespaces}%
+\setbox0=\hbox{\sqbullet\enspace}%
+\parindent=0pt
+\advance\parindent by \wd0
+States:
+\aterm |EXPRESSION| definitely in an expression
+
+\aterm |SCRIPT| definitely in a script
+
+\aterm |BOTH| either |EXPRESSION| or |SCRIPT|
+
+\aterm |DEFSYMEXP| in an argument to \.{--defsym}
+
+\aterm |MRI| in an \MRI\ script
+
+\aterm |VERS_START| starting a Sun style mapfile
+
+\aterm |VERS_SCRIPT| a Sun style mapfile
+
+\aterm |VERS_NODE| a node within a Sun style mapfile
+
+}%
+\ifbootstrapmode\else\yyskipparsefalse\fi
+@<\ld\ states@>=
+@G
+%s SCRIPT
+%s EXPRESSION
+%s BOTH
+%s DEFSYMEXP
+%s MRI
+%s VERS_START
+%s VERS_SCRIPT
+%s VERS_NODE
+@g
+
+@ @<\ld\ postamble@>=
+ if (parser_input != input_selected)
+ {
+ /* The first token of the input determines the initial parser state. */
+ input_type t = parser_input;
+ parser_input = input_selected;
+ switch (t)
+ {
+ case input_script: return INPUT_SCRIPT; break;
+ case input_mri_script: return INPUT_MRI_SCRIPT; break;
+ case input_version_script: return INPUT_VERSION_SCRIPT; break;
+ case input_dynamic_list: return INPUT_DYNAMIC_LIST; break;
+ case input_defsym: return INPUT_DEFSYM; break;
+ default: abort ();
+ }
+}
+
+@ @<Original \ld\ regular expressions@>=
+@=<BOTH,SCRIPT,EXPRESSION,VERS_START,VERS_NODE,VERS_SCRIPT>"/*" {@> comment ();@+@=}@>@;
+@G
+<DEFSYMEXP>"-" {@>@[RTOKEN('-');@]@=}
+<DEFSYMEXP>"+" {@>@[RTOKEN('+');@]@=}
+<DEFSYMEXP>{FILENAMECHAR1}{SYMBOLCHARN}* {@>@[yylval.name = xstrdup (yytext);@+return NAME;@]@=}
+<DEFSYMEXP>"=" {@>@[RTOKEN('=');@]@=}
+
+<MRI,EXPRESSION>"$"([0-9A-Fa-f])+ {
+@O
+ yylval.integer = bfd_scan_vma (yytext + 1, 0, 16);
+ yylval.bigint.str = NULL;
+ return INT;
+@o
+}
+
+<MRI,EXPRESSION>([0-9A-Fa-f])+(H|h|X|x|B|b|O|o|D|d) {
+@O
+ int ibase ;
+ switch (yytext[yyleng - 1]) {
+ case 'X':
+ case 'x':
+ case 'H':
+ case 'h':
+ ibase = 16;
+ break;
+ case 'O':
+ case 'o':
+ ibase = 8;
+ break;
+ case 'B':
+ case 'b':
+ ibase = 2;
+ break;
+ default:
+ ibase = 10;
+ }
+ yylval.integer = bfd_scan_vma (yytext, 0,
+ ibase);
+ yylval.bigint.str = NULL;
+ return INT;
+@o
+}
+
+<SCRIPT,DEFSYMEXP,MRI,BOTH,EXPRESSION>((("$"|0[xX])([0-9A-Fa-f])+)|(([0-9])+))(M|K|m|k)? {
+@O
+ char *s = yytext;
+ int ibase = 0;
+
+ if (*s == '$')
+ {
+ ++s;
+ ibase = 16;
+ }
+ yylval.integer = bfd_scan_vma (s, 0, ibase);
+ yylval.bigint.str = NULL;
+ if (yytext[yyleng - 1] == 'M'
+ || yytext[yyleng - 1] == 'm')
+ {
+ yylval.integer *= 1024 * 1024;
+ }
+ else if (yytext[yyleng - 1] == 'K'
+ || yytext[yyleng - 1]=='k')
+ {
+ yylval.integer *= 1024;
+ }
+ else if (yytext[0] == '0'
+ && (yytext[1] == 'x'
+ || yytext[1] == 'X'))
+ {
+ yylval.bigint.str = xstrdup (yytext + 2);
+ }
+ return INT;
+@o
+}
+
+<BOTH,SCRIPT,EXPRESSION,MRI>"]" {@>@[RTOKEN(']');@]@=}
+<BOTH,SCRIPT,EXPRESSION,MRI>"[" {@>@[RTOKEN('[');@]@=}
+<BOTH,SCRIPT,EXPRESSION,MRI>"<<=" {@>@[RTOKEN(LSHIFTEQ);@]@=}
+<BOTH,SCRIPT,EXPRESSION,MRI>">>=" {@>@[RTOKEN(RSHIFTEQ);@]@=}
+<BOTH,SCRIPT,EXPRESSION,MRI>"||" {@>@[RTOKEN(OROR);@]@=}
+<BOTH,SCRIPT,EXPRESSION,MRI>"==" {@>@[RTOKEN(EQ);@]@=}
+<BOTH,SCRIPT,EXPRESSION,MRI>"!=" {@>@[RTOKEN(NE);@]@=}
+<BOTH,SCRIPT,EXPRESSION,MRI>">=" {@>@[RTOKEN(GE);@]@=}
+<BOTH,SCRIPT,EXPRESSION,MRI>"<=" {@>@[RTOKEN(LE);@]@=}
+<BOTH,SCRIPT,EXPRESSION,MRI>"<<" {@>@[RTOKEN(LSHIFT);@]@=}
+<BOTH,SCRIPT,EXPRESSION,MRI>">>" {@>@[RTOKEN(RSHIFT);@]@=}
+<BOTH,SCRIPT,EXPRESSION,MRI>"+=" {@>@[RTOKEN(PLUSEQ);@]@=}
+<BOTH,SCRIPT,EXPRESSION,MRI>"-=" {@>@[RTOKEN(MINUSEQ);@]@=}
+<BOTH,SCRIPT,EXPRESSION,MRI>"*=" {@>@[RTOKEN(MULTEQ);@]@=}
+<BOTH,SCRIPT,EXPRESSION,MRI>"/=" {@>@[RTOKEN(DIVEQ);@]@=}
+<BOTH,SCRIPT,EXPRESSION,MRI>"&=" {@>@[RTOKEN(ANDEQ);@]@=}
+<BOTH,SCRIPT,EXPRESSION,MRI>"|=" {@>@[RTOKEN(OREQ);@]@=}
+<BOTH,SCRIPT,EXPRESSION,MRI>"&&" {@>@[RTOKEN(ANDAND);@]@=}
+<BOTH,SCRIPT,EXPRESSION,MRI>">" {@>@[RTOKEN('>');@]@=}
+<BOTH,SCRIPT,EXPRESSION,MRI>"," {@>@[RTOKEN(',');@]@=}
+<BOTH,SCRIPT,EXPRESSION,MRI>"&" {@>@[RTOKEN('&');@]@=}
+<BOTH,SCRIPT,EXPRESSION,MRI>"|" {@>@[RTOKEN('|');@]@=}
+<BOTH,SCRIPT,EXPRESSION,MRI>"~" {@>@[RTOKEN('~');@]@=}
+<BOTH,SCRIPT,EXPRESSION,MRI>"!" {@>@[RTOKEN('!');@]@=}
+<BOTH,SCRIPT,EXPRESSION,MRI>"?" {@>@[RTOKEN('?');@]@=}
+<BOTH,SCRIPT,EXPRESSION,MRI>"*" {@>@[RTOKEN('*');@]@=}
+<BOTH,SCRIPT,EXPRESSION,MRI>"+" {@>@[RTOKEN('+');@]@=}
+<BOTH,SCRIPT,EXPRESSION,MRI>"-" {@>@[RTOKEN('-');@]@=}
+<BOTH,SCRIPT,EXPRESSION,MRI>"/" {@>@[RTOKEN('/');@]@=}
+<BOTH,SCRIPT,EXPRESSION,MRI>"%" {@>@[RTOKEN('%');@]@=}
+<BOTH,SCRIPT,EXPRESSION,MRI>"<" {@>@[RTOKEN('<');@]@=}
+<BOTH,SCRIPT,EXPRESSION,MRI>"=" {@>@[RTOKEN('=');@]@=}
+<BOTH,SCRIPT,EXPRESSION,MRI>"}" {@>@[RTOKEN('}') ; @]@=}
+<BOTH,SCRIPT,EXPRESSION,MRI>"{" {@>@[RTOKEN('{'); @]@=}
+<BOTH,SCRIPT,EXPRESSION,MRI>")" {@>@[RTOKEN(')');@]@=}
+<BOTH,SCRIPT,EXPRESSION,MRI>"(" {@>@[RTOKEN('(');@]@=}
+<BOTH,SCRIPT,EXPRESSION,MRI>":" {@>@[RTOKEN(':'); @]@=}
+<BOTH,SCRIPT,EXPRESSION,MRI>";" {@>@[RTOKEN(';');@]@=}
+<BOTH,SCRIPT>"MEMORY" {@>@[RTOKEN(MEMORY);@]@=}
+<BOTH,SCRIPT>"REGION_ALIAS" {@>@[RTOKEN(REGION_ALIAS);@]@=}
+<BOTH,SCRIPT>"LD_FEATURE" {@>@[RTOKEN(LD_FEATURE);@]@=}
+<BOTH,SCRIPT,EXPRESSION>"ORIGIN" {@>@[RTOKEN(ORIGIN);@]@=}
+<BOTH,SCRIPT>"VERSION" {@>@[RTOKEN(VERSIONK);@]@=}
+<EXPRESSION,BOTH,SCRIPT>"BLOCK" {@>@[RTOKEN(BLOCK);@]@=}
+<EXPRESSION,BOTH,SCRIPT>"BIND" {@>@[RTOKEN(BIND);@]@=}
+<BOTH,SCRIPT,EXPRESSION>"LENGTH" {@>@[RTOKEN(LENGTH);@]@=}
+<EXPRESSION,BOTH,SCRIPT>"ALIGN" {@>@[RTOKEN(ALIGN_K);@]@=}
+<EXPRESSION,BOTH,SCRIPT>"DATA_SEGMENT_ALIGN" {@>@[RTOKEN(DATA_SEGMENT_ALIGN);@]@=}
+<EXPRESSION,BOTH,SCRIPT>"DATA_SEGMENT_RELRO_END" {@>@[RTOKEN(DATA_SEGMENT_RELRO_END);@]@=}
+<EXPRESSION,BOTH,SCRIPT>"DATA_SEGMENT_END" {@>@[RTOKEN(DATA_SEGMENT_END);@]@=}
+<EXPRESSION,BOTH,SCRIPT>"ADDR" {@>@[RTOKEN(ADDR);@]@=}
+<EXPRESSION,BOTH,SCRIPT>"LOADADDR" {@>@[RTOKEN(LOADADDR);@]@=}
+<EXPRESSION,BOTH,SCRIPT>"ALIGNOF" {@>@[RTOKEN(ALIGNOF); @]@=}
+<EXPRESSION,BOTH>"MAX" {@>@[RTOKEN(MAX_K); @]@=}
+<EXPRESSION,BOTH>"MIN" {@>@[RTOKEN(MIN_K); @]@=}
+<EXPRESSION,BOTH>"LOG2CEIL" {@>@[RTOKEN(LOG2CEIL); @]@=}
+<EXPRESSION,BOTH,SCRIPT>"ASSERT" {@>@[RTOKEN(ASSERT_K); @]@=}
+<BOTH,SCRIPT>"ENTRY" {@>@[RTOKEN(ENTRY);@]@=}
+<BOTH,SCRIPT,MRI>"EXTERN" {@>@[RTOKEN(EXTERN);@]@=}
+<EXPRESSION,BOTH,SCRIPT>"NEXT" {@>@[RTOKEN(NEXT);@]@=}
+<EXPRESSION,BOTH,SCRIPT>"sizeof_headers" {@>@[RTOKEN(SIZEOF_HEADERS);@]@=}
+<EXPRESSION,BOTH,SCRIPT>"SIZEOF_HEADERS" {@>@[RTOKEN(SIZEOF_HEADERS);@]@=}
+<EXPRESSION,BOTH,SCRIPT>"SEGMENT_START" {@>@[RTOKEN(SEGMENT_START);@]@=}
+<BOTH,SCRIPT>"MAP" {@>@[RTOKEN(MAP);@]@=}
+<EXPRESSION,BOTH,SCRIPT>"SIZEOF" {@>@[RTOKEN(SIZEOF);@]@=}
+<BOTH,SCRIPT>"TARGET" {@>@[RTOKEN(TARGET_K);@]@=}
+<BOTH,SCRIPT>"SEARCH_DIR" {@>@[RTOKEN(SEARCH_DIR);@]@=}
+<BOTH,SCRIPT>"OUTPUT" {@>@[RTOKEN(OUTPUT);@]@=}
+<BOTH,SCRIPT>"INPUT" {@>@[RTOKEN(INPUT);@]@=}
+<EXPRESSION,BOTH,SCRIPT>"GROUP" {@>@[RTOKEN(GROUP);@]@=}
+<EXPRESSION,BOTH,SCRIPT>"AS_NEEDED" {@>@[RTOKEN(AS_NEEDED);@]@=}
+<EXPRESSION,BOTH,SCRIPT>"DEFINED" {@>@[RTOKEN(DEFINED);@]@=}
+<BOTH,SCRIPT>"CREATE_OBJECT_SYMBOLS" {@>@[RTOKEN(CREATE_OBJECT_SYMBOLS);@]@=}
+<BOTH,SCRIPT>"CONSTRUCTORS" {@>@[RTOKEN( CONSTRUCTORS);@]@=}
+<BOTH,SCRIPT>"FORCE_COMMON_ALLOCATION" {@>@[RTOKEN(FORCE_COMMON_ALLOCATION);@]@=}
+<BOTH,SCRIPT>"INHIBIT_COMMON_ALLOCATION" {@>@[RTOKEN(INHIBIT_COMMON_ALLOCATION);@]@=}
+<BOTH,SCRIPT>"SECTIONS" {@>@[RTOKEN(SECTIONS);@]@=}
+<BOTH,SCRIPT>"INSERT" {@>@[RTOKEN(INSERT_K);@]@=}
+<BOTH,SCRIPT>"AFTER" {@>@[RTOKEN(AFTER);@]@=}
+<BOTH,SCRIPT>"BEFORE" {@>@[RTOKEN(BEFORE);@]@=}
+<BOTH,SCRIPT>"FILL" {@>@[RTOKEN(FILL);@]@=}
+<BOTH,SCRIPT>"STARTUP" {@>@[RTOKEN(STARTUP);@]@=}
+<BOTH,SCRIPT>"OUTPUT_FORMAT" {@>@[RTOKEN(OUTPUT_FORMAT);@]@=}
+<BOTH,SCRIPT>"OUTPUT_ARCH" {@>@[RTOKEN( OUTPUT_ARCH);@]@=}
+<BOTH,SCRIPT>"HLL" {@>@[RTOKEN(HLL);@]@=}
+<BOTH,SCRIPT>"SYSLIB" {@>@[RTOKEN(SYSLIB);@]@=}
+<BOTH,SCRIPT>"FLOAT" {@>@[RTOKEN(FLOAT);@]@=}
+<BOTH,SCRIPT>"QUAD" {@>@[RTOKEN( QUAD);@]@=}
+<BOTH,SCRIPT>"SQUAD" {@>@[RTOKEN( SQUAD);@]@=}
+<BOTH,SCRIPT>"LONG" {@>@[RTOKEN( LONG);@]@=}
+<BOTH,SCRIPT>"SHORT" {@>@[RTOKEN( SHORT);@]@=}
+<BOTH,SCRIPT>"BYTE" {@>@[RTOKEN( BYTE);@]@=}
+<BOTH,SCRIPT>"NOFLOAT" {@>@[RTOKEN(NOFLOAT);@]@=}
+<EXPRESSION,BOTH,SCRIPT>"NOCROSSREFS" {@>@[RTOKEN(NOCROSSREFS);@]@=}
+<BOTH,SCRIPT>"OVERLAY" {@>@[RTOKEN(OVERLAY); @]@=}
+<BOTH,SCRIPT>"SORT_BY_NAME" {@>@[RTOKEN(SORT_BY_NAME); @]@=}
+<BOTH,SCRIPT>"SORT_BY_ALIGNMENT" {@>@[RTOKEN(SORT_BY_ALIGNMENT); @]@=}
+<BOTH,SCRIPT>"SORT" {@>@[RTOKEN(SORT_BY_NAME); @]@=}
+<BOTH,SCRIPT>"SORT_BY_INIT_PRIORITY" {@>@[RTOKEN(SORT_BY_INIT_PRIORITY); @]@=}
+<BOTH,SCRIPT>"SORT_NONE" {@>@[RTOKEN(SORT_NONE); @]@=}
+<EXPRESSION,BOTH,SCRIPT>"NOLOAD" {@>@[RTOKEN(NOLOAD);@]@=}
+<EXPRESSION,BOTH,SCRIPT>"DSECT" {@>@[RTOKEN(DSECT);@]@=}
+<EXPRESSION,BOTH,SCRIPT>"COPY" {@>@[RTOKEN(COPY);@]@=}
+<EXPRESSION,BOTH,SCRIPT>"INFO" {@>@[RTOKEN(INFO);@]@=}
+<EXPRESSION,BOTH,SCRIPT>"OVERLAY" {@>@[RTOKEN(OVERLAY);@]@=}
+<EXPRESSION,BOTH,SCRIPT>"ONLY_IF_RO" {@>@[RTOKEN(ONLY_IF_RO); @]@=}
+<EXPRESSION,BOTH,SCRIPT>"ONLY_IF_RW" {@>@[RTOKEN(ONLY_IF_RW); @]@=}
+<EXPRESSION,BOTH,SCRIPT>"SPECIAL" {@>@[RTOKEN(SPECIAL); @]@=}
+<BOTH,SCRIPT>"o" {@>@[RTOKEN(ORIGIN);@]@=}
+<BOTH,SCRIPT>"org" {@>@[RTOKEN(ORIGIN);@]@=}
+<BOTH,SCRIPT>"l" {@>@[RTOKEN( LENGTH);@]@=}
+<BOTH,SCRIPT>"len" {@>@[RTOKEN( LENGTH);@]@=}
+<EXPRESSION,BOTH,SCRIPT>"INPUT_SECTION_FLAGS" {@>@[RTOKEN(INPUT_SECTION_FLAGS); @]@=}
+<EXPRESSION,BOTH,SCRIPT>"INCLUDE" {@>@[RTOKEN(INCLUDE);@]@=}
+<BOTH,SCRIPT>"PHDRS" {@>@[RTOKEN (PHDRS); @]@=}
+<EXPRESSION,BOTH,SCRIPT>"AT" {@>@[RTOKEN(AT);@]@=}
+<EXPRESSION,BOTH,SCRIPT>"ALIGN_WITH_INPUT" {@>@[RTOKEN(ALIGN_WITH_INPUT);@]@=}
+<EXPRESSION,BOTH,SCRIPT>"SUBALIGN" {@>@[RTOKEN(SUBALIGN);@]@=}
+<EXPRESSION,BOTH,SCRIPT>"HIDDEN" {@>@[RTOKEN(HIDDEN); @]@=}
+<EXPRESSION,BOTH,SCRIPT>"PROVIDE" {@>@[RTOKEN(PROVIDE); @]@=}
+<EXPRESSION,BOTH,SCRIPT>"PROVIDE_HIDDEN" {@>@[RTOKEN(PROVIDE_HIDDEN); @]@=}
+<EXPRESSION,BOTH,SCRIPT>"KEEP" {@>@[RTOKEN(KEEP); @]@=}
+<EXPRESSION,BOTH,SCRIPT>"EXCLUDE_FILE" {@>@[RTOKEN(EXCLUDE_FILE); @]@=}
+<EXPRESSION,BOTH,SCRIPT>"CONSTANT" {@>@[RTOKEN(CONSTANT);@]@=}
+<MRI>"#".*\n? {@>@[++ lineno; @]@=}
+<MRI>"\n" {@> @[++lineno;@+RTOKEN(NEWLINE);@]@=}
+<MRI>"*".* {}/* \MRI\ comment line */
+<MRI>";".* {}/* \MRI\ comment line */
+<MRI>"END" {@>@[RTOKEN(ENDWORD); @]@=}
+<MRI>"ALIGNMOD" {@>@[RTOKEN(ALIGNMOD);@]@=}
+<MRI>"ALIGN" {@>@[RTOKEN(ALIGN_K);@]@=}
+<MRI>"CHIP" {@>@[RTOKEN(CHIP); @]@=}
+<MRI>"BASE" {@>@[RTOKEN(BASE); @]@=}
+<MRI>"ALIAS" {@>@[RTOKEN(ALIAS); @]@=}
+<MRI>"TRUNCATE" {@>@[RTOKEN(TRUNCATE); @]@=}
+<MRI>"LOAD" {@>@[RTOKEN(LOAD); @]@=}
+<MRI>"PUBLIC" {@>@[RTOKEN(PUBLIC); @]@=}
+<MRI>"ORDER" {@>@[RTOKEN(ORDER); @]@=}
+<MRI>"NAME" {@>@[RTOKEN(NAMEWORD); @]@=}
+<MRI>"FORMAT" {@>@[RTOKEN(FORMAT); @]@=}
+<MRI>"CASE" {@>@[RTOKEN(CASE); @]@=}
+<MRI>"START" {@>@[RTOKEN(START); @]@=}
+<MRI>"LIST".* {@>@[RTOKEN(LIST); @]@=}/* \prodstyle{LIST} and ignore to end of line */
+<MRI>"SECT" {@>@[RTOKEN(SECT); @]@=}
+<EXPRESSION,BOTH,SCRIPT,MRI>"ABSOLUTE" {@>@[RTOKEN(ABSOLUTE); @]@=}
+<MRI>"end" {@>@[RTOKEN(ENDWORD); @]@=}
+<MRI>"alignmod" {@>@[RTOKEN(ALIGNMOD);@]@=}
+<MRI>"align" {@>@[RTOKEN(ALIGN_K);@]@=}
+<MRI>"chip" {@>@[RTOKEN(CHIP); @]@=}
+<MRI>"base" {@>@[RTOKEN(BASE); @]@=}
+<MRI>"alias" {@>@[RTOKEN(ALIAS); @]@=}
+<MRI>"truncate" {@>@[RTOKEN(TRUNCATE); @]@=}
+<MRI>"load" {@>@[RTOKEN(LOAD); @]@=}
+<MRI>"public" {@>@[RTOKEN(PUBLIC); @]@=}
+<MRI>"order" {@>@[RTOKEN(ORDER); @]@=}
+<MRI>"name" {@>@[RTOKEN(NAMEWORD); @]@=}
+<MRI>"format" {@>@[RTOKEN(FORMAT); @]@=}
+<MRI>"case" {@>@[RTOKEN(CASE); @]@=}
+<MRI>"extern" {@>@[RTOKEN(EXTERN); @]@=}
+<MRI>"start" {@>@[RTOKEN(START); @]@=}
+<MRI>"list".* {@>@[RTOKEN(LIST); @]@=}/* \prodstyle{LIST} and ignore to end of line */
+<MRI>"sect" {@>@[RTOKEN(SECT); @]@=}
+<EXPRESSION,BOTH,SCRIPT,MRI>"absolute" {@>@[RTOKEN(ABSOLUTE); @]@=}
+
+<MRI>{FILENAMECHAR1}{NOCFILENAMECHAR}* {
+@O
+/* Filename without commas, needed to parse \MRI\ stuff */
+ yylval.name = xstrdup (yytext);
+ return NAME;
+@o
+}
+<BOTH>{FILENAMECHAR1}{FILENAMECHAR}* {
+@O
+ yylval.name = xstrdup (yytext);
+ return NAME;
+@o
+}
+<BOTH>"-l"{FILENAMECHAR}+ {
+@O
+ yylval.name = xstrdup (yytext + 2);
+ return LNAME;
+@o
+}
+<EXPRESSION>{FILENAMECHAR1}{NOCFILENAMECHAR}* {
+@O
+ yylval.name = xstrdup (yytext);
+ return NAME;
+@o
+}
+<EXPRESSION>"-l"{NOCFILENAMECHAR}+ {
+@O
+ yylval.name = xstrdup (yytext + 2);
+ return LNAME;
+@o
+}
+<SCRIPT>{WILDCHAR}* {
+@O
+ /* Annoyingly, this pattern can match comments, and we have
+ longest match issues to consider. So if the first two
+ characters are a comment opening, put the input back and
+ try again. */
+ if (yytext[0] == '/' && yytext[1] == '*')
+ {
+ yyless (2);
+ comment ();
+ }
+ else
+ {
+ yylval.name = xstrdup (yytext);
+ return NAME;
+ }
+@o
+}
+
+<EXPRESSION,BOTH,SCRIPT,VERS_NODE>"\""[^\"]*"\"" {
+@O
+ /* No matter the state, quotes
+ give what's inside */
+ yylval.name = xstrdup (yytext + 1);
+ yylval.name[yyleng - 2] = 0;
+ return NAME;
+@o
+}
+
+<BOTH,SCRIPT,EXPRESSION>"\n" {@>@[lineno++;@]@=}
+<MRI,BOTH,SCRIPT,EXPRESSION>[ \t\r]+ {}
+
+<VERS_NODE,VERS_SCRIPT>[:,;] {@>@[return *yytext; @]@=}
+<VERS_NODE>global {@>@[RTOKEN(GLOBAL); @]@=}
+<VERS_NODE>local {@>@[RTOKEN(LOCAL); @]@=}
+<VERS_NODE>extern {@>@[RTOKEN(EXTERN); @]@=}
+
+<VERS_NODE>{V_IDENTIFIER} {
+@O
+ yylval.name = xstrdup (yytext);
+ return VERS_IDENTIFIER;
+@o
+}
+
+<VERS_SCRIPT>{V_TAG} {
+@O
+ yylval.name = xstrdup (yytext);
+ return VERS_TAG;
+@o
+}
+
+<VERS_START>"{" {@>@[BEGIN(VERS_SCRIPT);@+return *yytext;@]@=}
+
+<VERS_SCRIPT>"{" {
+@O
+ BEGIN(VERS_NODE);
+ vers_node_nesting = 0;
+ return *yytext;
+@o
+}
+
+<VERS_SCRIPT>"}" {@>@[return *yytext;@]@=}
+<VERS_NODE>"{" {@>@[vers_node_nesting++;@+return *yytext;@]@=}
+
+<VERS_NODE>"}" {
+@O
+ if (--vers_node_nesting < 0)
+ BEGIN(VERS_SCRIPT);
+ return *yytext;
+@o
+}
+
+<VERS_START,VERS_NODE,VERS_SCRIPT>[\n] {@>@[lineno++;@]@=}
+<VERS_START,VERS_NODE,VERS_SCRIPT>#.* {}/* Eat up comments */
+<VERS_START,VERS_NODE,VERS_SCRIPT>[ \t\r]+ {}/* Eat up whitespace */
+
+<<EOF>> {
+@O
+ include_stack_ptr--;
+ if (include_stack_ptr == 0)
+ yyterminate ();
+ else
+ yy_switch_to_buffer (include_stack[include_stack_ptr]);
+
+ lineno = lineno_stack[include_stack_ptr];
+ input_flags.sysrooted = sysrooted_stack[include_stack_ptr];
+
+ return END;
+@o
+}
+
+<SCRIPT,MRI,VERS_START,VERS_SCRIPT,VERS_NODE>. @>@[lex_warn_invalid (" in script", yytext);@]
+<EXPRESSION,DEFSYMEXP,BOTH>. @>@[lex_warn_invalid (" in expression", yytext);@]
+@g
+
+@ Switch \flex\ to reading script file |name|, open on |file|,
+saving the current input info on the include stack.
+@<Supporting \Cee\ code@>=
+void
+lex_push_file (FILE *file, const char *name, unsigned int sysrooted)
+{
+ if (include_stack_ptr >= MAX_INCLUDE_DEPTH)
+ {
+ einfo ("%F:includes nested too deeply\n");
+ }
+ file_name_stack[include_stack_ptr] = name;
+ lineno_stack[include_stack_ptr] = lineno;
+ sysrooted_stack[include_stack_ptr] = input_flags.sysrooted;
+ include_stack[include_stack_ptr] = YY_CURRENT_BUFFER;
+
+ include_stack_ptr++;
+ lineno = 1;
+ input_flags.sysrooted = sysrooted;
+ yyin = file;
+ yy_switch_to_buffer (yy_create_buffer (yyin, YY_BUF_SIZE));
+}
+
+@ Return a newly created \flex\ input buffer containing |string|,
+which is |size| bytes long.
+@<Supporting \Cee\ code@>=
+static YY_BUFFER_STATE
+yy_create_string_buffer (const char *string, size_t size)
+{
+ YY_BUFFER_STATE b;
+
+ b = malloc (sizeof (struct yy_buffer_state));/* Calls to |malloc| get turned by sed into |xmalloc|. */
+ b->yy_input_file = 0;
+ b->yy_buf_size = size;
+
+ b->yy_ch_buf = malloc ((unsigned) (b->yy_buf_size + 3));
+ /* |yy_ch_buf| has to be 2 characters longer than the size given because
+ we need to put in 2 end-of-buffer characters. */
+
+ b->yy_ch_buf[0] = '\n';
+ strcpy (b->yy_ch_buf+1, string);
+ b->yy_ch_buf[size+1] = YY_END_OF_BUFFER_CHAR;
+ b->yy_ch_buf[size+2] = YY_END_OF_BUFFER_CHAR;
+ b->yy_n_chars = size+1;
+ b->yy_buf_pos = &b->yy_ch_buf[1];
+
+ b->yy_is_our_buffer = 1;
+ b->yy_is_interactive = 0;
+ b->yy_at_bol = 1;
+ b->yy_fill_buffer = 0;
+
+#ifdef YY_BUFFER_NEW
+ b->yy_buffer_status = YY_BUFFER_NEW;
+#else
+ b->yy_eof_status = EOF_NOT_SEEN;
+#endif
+
+ return b;
+}
+
+@ Switch \flex\ to reading from |string|, saving the current input info
+on the include stack.
+@<Supporting \Cee\ code@>=
+void
+lex_redirect (const char *string, const char *fake_filename, unsigned int count)
+{
+ YY_BUFFER_STATE tmp;
+
+ yy_init = 0;
+ if (include_stack_ptr >= MAX_INCLUDE_DEPTH)
+ {
+ einfo("%F: macros nested too deeply\n");
+ }
+ file_name_stack[include_stack_ptr] = fake_filename;
+ lineno_stack[include_stack_ptr] = lineno;
+ include_stack[include_stack_ptr] = YY_CURRENT_BUFFER;
+ include_stack_ptr++;
+ lineno = count;
+ tmp = yy_create_string_buffer (string, strlen (string));
+ yy_switch_to_buffer (tmp);
+}
+
+@ Functions to switch to a different \flex\ start condition,
+saving the current start condition on |state_stack|.
+@<Supporting \Cee\ code@>=
+static int state_stack[MAX_INCLUDE_DEPTH * 2];
+static int *state_stack_p = state_stack;
+
+void
+ldlex_script (void)
+{
+ *(state_stack_p)++ = yy_start;
+ BEGIN (SCRIPT);
+}
+
+void
+ldlex_mri_script (void)
+{
+ *(state_stack_p)++ = yy_start;
+ BEGIN (MRI);
+}
+
+void
+ldlex_version_script (void)
+{
+ *(state_stack_p)++ = yy_start;
+ BEGIN (VERS_START);
+}
+
+void
+ldlex_version_file (void)
+{
+ *(state_stack_p)++ = yy_start;
+ BEGIN (VERS_SCRIPT);
+}
+
+void
+ldlex_defsym (void)
+{
+ *(state_stack_p)++ = yy_start;
+ BEGIN (DEFSYMEXP);
+}
+
+void
+ldlex_expression (void)
+{
+ *(state_stack_p)++ = yy_start;
+ BEGIN (EXPRESSION);
+}
+
+void
+ldlex_both (void)
+{
+ *(state_stack_p)++ = yy_start;
+ BEGIN (BOTH);
+}
+
+void
+ldlex_popstate (void)
+{
+ yy_start = *(--state_stack_p);
+}
+
+@ Return the current file name, or the previous file if no file is
+current.
+@<Supporting \Cee\ code@>=
+const char*
+ldlex_filename (void)
+{
+ return file_name_stack[include_stack_ptr - (include_stack_ptr != 0)];
+}
+
+@ Place up to |max_size| characters in |buf| and return
+either the number of characters read, or 0 to indicate |EOF|.
+@<Supporting \Cee\ code@>=
+static int
+yy_input (char *buf, int max_size)
+{
+ int result = 0;
+ if (YY_CURRENT_BUFFER->yy_input_file)
+ {
+ if (yyin)
+ {
+ result = fread (buf, 1, max_size, yyin);
+ if (result < max_size && ferror (yyin))
+ einfo ("%F%P: read in flex scanner failed\n");
+ }
+ }
+ return result;
+}
+
+@ Eat the rest of a \Cee-style comment.
+@<Supporting \Cee\ code@>=
+static void
+comment (void)
+{
+ int c;
+
+ while (1)
+ {
+ c = input();
+ while (c != '*' && c != EOF)
+ {
+ if (c == '\n')
+ lineno++;
+ c = input();
+ }
+
+ if (c == '*')
+ {
+ c = input();
+ while (c == '*')
+ c = input();
+ if (c == '/')
+ break; /* found the end */
+ }
+
+ if (c == '\n')
+ lineno++;
+
+ if (c == EOF)
+ {
+ einfo( "%F%P: EOF in comment\n");
+ break;
+ }
+ }
+}
+
+@ Warn the user about a garbage character |what| in the input
+in context |where|.
+@<Supporting \Cee\ code@>=
+static void
+lex_warn_invalid (char *where, char *what)
+{
+ char buf[5];
+
+ if (ldfile_assumed_script)
+ { /* If we have found an input file whose format we do not recognize,
+ and we are therefore treating it as a linker script, and we find
+ an invalid character, then most likely this is a real object file
+ of some different format. Treat it as such. */
+
+ bfd_set_error (bfd_error_file_not_recognized);
+ einfo ("%F%s: file not recognized: %E\n", ldlex_filename ());
+ }
+
+ if (! ISPRINT (*what))
+ {
+ sprintf (buf, "\\%03o", *(unsigned char *) what);
+ what = buf;
+ }
+
+ einfo ("%P:%S: ignoring invalid character `%s'%s\n", NULL, what, where);
+}
diff --git a/support/splint/examples/ld/ldman.w b/support/splint/examples/ld/ldman.w
new file mode 100644
index 0000000000..c9551d1b3e
--- /dev/null
+++ b/support/splint/examples/ld/ldman.w
@@ -0,0 +1,572 @@
+% Copyright 2012-2015, Alexander Shibakov
+% Copyright 2002-2014 Free Software Foundation, Inc.
+% This file is part of SPLinT
+%
+% SPLinT is free software: you can redistribute it and/or modify
+% it under the terms of the GNU General Public License as published by
+% the Free Software Foundation, either version 3 of the License, or
+% (at your option) any later version.
+%
+% SPLinT 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 SPLinT. If not, see <http://www.gnu.org/licenses/>.
+@s TeX_ TeX
+\input limbo.sty
+\input ldfrontmatter.sty
+\def\MRI{{\sc MRI}}
+\def\optimization{5}
+\input ldman.sty
+% multi-column output
+\input dcols.sty
+
+\let\oldN\N
+\let\N\textN
+\let\M\textM
+\def\ld{\.{ld}}
+
+\showlastactiontrue
+\immediate\openout\gindex=\jobname.gdx
+@** Introduction.
+\setupfootnotes
+This is a manual documenting the development of a parser that can be
+used to typeset \ld\ files (linker scripts) with or without the help
+of \CWEB. An existing parser for \ld\ has been adopted as a base, with
+appropriately designed actions specific to the task of
+typesetting. The appendix to this manual contains the full source code
+(including the parts written in \Cee) of both the scanner and the parser for \ld,
+used in the original program. Some very minor modifications have been
+made to make the programs more `presentable' in \CWEB\ (in particular, the
+file had to be split into smaller chunks to satisfy \CWEAVE's
+limitations).
+
+Nearly every aspect of the design is discussed, including the
+supporting \TeX\ macros that make both the parser and this
+documentation possible. The \TeX\ macros presented here are collected
+in \.{ldman.sty} which is later included in the \TeX\ file produced by \CWEAVE.
+@<Set up the generic parser machinery@>=
+@G
+\ifx\optimization\UNDEFINED %/* this trick is based on the premise that \.{\\UNDEFINED} */
+ \def\optimization{0} %/* is never defined nor created with \.{\\csname$\ldots$\\endcsname} */
+\fi
+
+\let\nx\noexpand %/* convenient */
+
+\input yycommon.sty %/* general routines for stack and array access */
+\input yymisc.sty %/* helper macros (stack manipulation, table processing, value stack pointers) */
+\input yyinput.sty %/* input functions */
+\input yyparse.sty %/* parser machinery */
+\input flex.sty %/* lexer functions */
+\input yyboth.sty %/* parser initialization, optimization */
+
+\ifnum\optimization>\tw@
+ \input yyfaststack.sty
+\fi
+
+\input yystype.sty %/* scanner auxiliary types and functions */
+\input yyunion.sty %/* parser data structures */
+\input yxunion.sty %/* extended parser data structures */
+@=\input ldunion.sty %@>/* \ld\ parser data structures */@+
+@g
+
+@*1 Bootstrapping.
+To produce a usable parser/scanner duo, several pieces of code must
+be generated. The most important of these are the {\it table files\/}
+(\.{ptab.tex} and \.{ltab.tex}) for the parser and the scanner. These
+consist of the integer tables defining the operation of the parser and
+scanner automata, the values of some constants, and the `action switch'.
+
+Just like in the case of `real' parsers and scanners, in order to
+make the parser and the scanner interact seamlessly, some amount of `glue'
+is required. As an example, a file containing the (numerical)
+definitions of the token values is generated by \bison\ to be used by
+a \flex\ generated scanner. Unfortunately, this file has too little
+structure for our purposes (it contains definitions of token values
+mixed in with other constants making it hard to distinguish one kind of
+definition from another). Therefore, the `glue' is generated by
+parsing our grammar once again, this time with a \bison\ grammar
+designed for typesetting \bison\ files. A special {\it
+bootstrapping\/} mode is used to extract the appropriate
+information. The name `bootstrapping' notwithstanding, the parser and
+lexer used in the bootstrapping phase are not the minimized versions
+used in bootstrapping the \bison\ parser.
+
+The first component generated during the bootstrapping pass is a list
+of `token equivalences' (or `aliases') to be used by the lexer. Every
+token (to be precise, every {\it named token type}) used in
+a \bison\ grammar is declared using one of the
+\prodstyle{\%token}, \prodstyle{\%left}, \prodstyle{\%right},
+\prodstyle{\%precedence}, or \prodstyle{\%nonassoc} declarations. If
+no {\it alias\/} (see below) has been declared using a
+\prodstyle{\%token} declaration, this name ends up in the |yytname|
+array output by \bison\ and can be used by the lexer after associating
+the token names with their numerical values (accomplished by
+\.{\\settokens}). If all tokens are named tokens, no token equivalence
+list is necessary to set up the interaction between the lexer and the
+parser. In this case (the present \ld\ parser is a typical
+example), the token list serves a secondary role: it provides hints
+for the macros that typeset the grammar terms, after the \.{\\tokeneq}
+macro is redefined to serve this purpose.
+
+On the other hand, after a declaration such as `\prodstyle{\%token}
+\.{CHAR} \.{"char"}' the string \.{"char"} becomes an alias
+for the named token \.{CHAR}. Only the string version gets recorded in
+the |yytname| array. Establishing the equivalence between the two
+token forms can now only be accomplished by examining the grammar
+source file and is delegated to the bootstrapping phase parser.
+
+\leavevmode\namedspot{bootstrapstates}The other responsibility of the bootstrapping parser is to extract
+the information about \flex\ {\it states\/} used by the lexer from the
+appropriate source file. As is the case with token names, this
+information is output in a rather chaotic fashion by the scanner
+generator and is all but useless for our purposes. The original
+bootstrapping macros were designed to handle \flex's \prodstyle{\%x}
+and \prodstyle{\%s} state declarations and produce a \Cee\ file with the
+appropriate definitions. This file can later be included by the
+`driver' routine to produce the appropriate table file for the lexer.
+To round off the bootstrapping mode we only need to establish the
+output streams for the tokens and the states, supply the appropriate file
+names for the two lists, flag the bootstrapping mode for the
+bootstrapping macros and inline typesetting (\.{\\prodstyle} macros)
+and input the appropriate machinery.
+
+This is done by the macros
+below. The bootstrap lexer setup (\.{\\bootstraplexersetup}) consists
+of inputting the token equivalence table for the \bison\ parser
+(i.e.~the parser that processes the \bison\ grammar file) and defining
+a robust token output function which simply ignores the token values
+the lexer is not aware of (it should not be necessary in our case
+since we are using full featured lexer and parser).
+@<Define the bootstrapping mode@>=
+@G
+\newwrite\tokendefs %/* token list */
+\newwrite\stlist %/* \flex\ state list */
+\newwrite\gindex %/* index entries */
+
+\def\modebootstrap{%
+ \edef\bstrapparser{dyytab.tex}%
+ \bootstrapmodetrue
+ \def\bootstraplexersetup{%
+ \input bo.tok%
+ \let\yylexreturn\yylexreturnbootstrap /* only return tokens whose value is known */
+ %\let\yylexreturn\yylexreturnregular /* should also work */
+ }%
+ \input yybootstrap.sty%
+}
+@g
+
+@*1 Namespaces and modes.
+Every parser/lexer pair (as well as some other macros) operates
+within a dedicated {\it namespace\/}. This simply means that the macros
+that output token values, switch lexer states and access various
+tables `tack on' the string of characters representing the current
+namespace to the `low level' control sequence name that performs the
+actual output or access. Say, \.{\\yytname} becomes an alias of
+\.{\\yytname[main]} while in the \.{[main]} namespace. When a parser
+or lexer is initialized, the appropriate tables are aliased with a
+generic name in the case of an `unoptimized' parser or lexer. The
+optimized parser or lexer handles the namespace referencing internally.
+
+The mode setup macros for this manual define several separate
+namespaces. The \.{[main]} namespace is established for the parser
+that does the typesetting of the grammar. Every time a term name is
+processed, the token names are looked up in the \.{[ld]}
+namespace. The same namespace is used by the parser that typesets \ld\
+script examples in the manual (i.e.~the parser described here). This
+is done to provide visual consistency between the description of the
+parser and its output. The \.{[small]} namespace is used by the term
+name parser itself. Since we use a customized version of the name parser, we
+dedicate a separate namespace for this purpose, \.{[ldsmall]}.
+The parser based on a subset of the full \bison\
+grammar describing prologue declarations uses the \.{[prologue]}
+namespace. The \.{[index]} namespace is used for typesetting the
+index entries and is not necessarily associated with any parser or
+lexer.
+@<Begin namespace setup@>=
+@G
+\def\indexpseudonamespace{[index]}
+\let\parsernamespace\empty
+@g
+
+@ After all the appropriate tables and `glue' have been generated, the
+typesetting of this manual can be handled by the {\tt normal} mode. Note
+that this requires the \ld\ parser, as well as the \bison\ parser,
+including all the appropriate machinery.
+
+The normal mode is started by including the tables and lists and
+initializing the \bison\ parser (accomplished by inputting
+\.{yyinit.sty}), followed by handling the token typesetting for the
+\ld\ grammar.
+@<Define the normal mode@>=
+@G
+\newtoks\ldcmds
+
+\def\modenormal{%
+ \def\drvname{bo}%
+ \def\appendr##1##2{\edef\appnext{##1{\the##1##2}}\appnext}%
+ \def\appendl##1##2{\edef\appnext{##1{##2\the##1}}\appnext}%
+ \input yyinit.sty%
+ \let\hostparsernamespace\ldnamespace /* the namespace where tokens are looked up for typesetting purposes */
+}
+@g
+
+@ The \ld\ parser initialization requires setting a few global
+variables, as well as entering the \.{INITIAL} state for the \ld\
+lexer. The latter is somewhat counterintuitive and is necessitated by
+the ability of the parser to switch lexer states. Thus, the parser can
+switch the lexer state before the lexer is invoked for the first time
+wreaking havoc on the lexer state stack.
+@<Define the normal mode@>=
+@G
+\def\ldparserinit{%
+ \basicparserinit
+ \includestackptr=\@@ne
+ \versnodenesting=\z@@
+ \ldcmds{}%
+ \yyBEGIN{INITIAL}%
+}
+@g
+
+@ This is the \ld\ parser invocation routine. It is coded according to
+a straightforward sequence initialize-invoke-execute-or-fall back.
+@<Define the normal mode@>=
+@G
+\expandafter\def\csname parserstack[l]\endcsname#1#2{%
+ \toldparser\ldparserinit\yyparse#1\yyeof\yyeof\endparseinput\endparse
+ \ifyyparsefail % /* revert to generic macros if parsing failed */
+ \yybreak{\message{parsing failed ...}#2}%
+ \else % /* stage three, process the parsed table */
+ \yybreak{%
+ \message{commands: \the\ldcmds}%
+ {%
+ \restorecslist{ld-display}\ldunion
+ \the\ldcmds
+ \par
+ \vskip-\baselineskip
+ \the\lddisplay
+ }%
+ }%
+ \yycontinue
+}
+@g
+
+@ @<Initialize the active mode@>=
+@G
+\ifx\modeactive\UNDEFINED
+ \def\modeactive{\modenormal}
+\fi
+
+\modeactive
+
+\ifbootstrapmode\else
+ @>@[@<Initialize \ld\ parsers@>@]@;
+ @>@[@<Modified name parser for \ld\ grammar@>@]@;
+\fi
+@g
+
+@ Unless they are being bootstrapped, the \ld\ parser and its
+term parser are initialized by the normal mode. The token typesetting
+of \ld\ grammar tokens is adjusted at the same time (see the remarks
+above about the mechanism that is responsible for this). Most nonterminals
+(such as keywords, etc.) may be displayed unchanged (provided the
+names used by the lexer agree with their appearance in the script file,
+see below), while the typeseting of others is modified in
+\.{ltokenset.sty}.
+
+In the original \bison-\flex\ interface, token names are
+defined as straightforward macros (a poor choice as will be seen
+shortly) which can sometimes clash with the standard \Cee\ macros.
+This is why \ld\ lexer returns \prodstyle{ASSERT} as
+\prodstyle{ASSERT_K}. The name parser treats \.{K} as a suffix to
+supply a visual reminder of this flaw. Note that the `suffixless' part
+of these tokens (such as \prodstyle{ASSERT}) is never declared and
+thus has to be entered in \.{ltokenset.sty} by hand.
+
+The tokens that never appear as part of the input (such as
+\prodstyle{END} and \prodstyle{UNARY}) or those that do but have no
+fixed appearance (for example, \prodstyle{NAME}) are typeset in a
+style that indicates their origin. The details can be found by
+examining \.{ltokenset.sty}.
+@<Initialize \ld\ parsers@>=
+@G
+\genericparser
+ name: ld,
+ ptables: ptab.tex,
+ ltables: ltab.tex,
+ tokens: {},
+ asetup: {},
+ dsetup: {},
+ rsetup: {},
+ optimization: {};%
+\genericprettytokens
+ namespace: ld,
+ tokens: ldp.tok,
+ correction: ltokenset.sty,
+ host: ld;%
+@g
+
+@ The macros are collected in a single file included at the beginning
+of this documentation.
+@(ldman.stx@>=
+@<Set up the generic parser machinery@>@;
+@<Begin namespace setup@>@;
+@<Define the bootstrapping mode@>@;
+@<Define the normal mode@>@;
+@<Additional macros for the \ld\ lexer/parser@>@;
+@<Initialize the active mode@>@;
+
+@i ldgram.x
+@i ldlex.x
+
+@** Example output. Here is an example output of the \ld\ parser designed in this
+document. The original linker script is presented in the section that
+follows. The same parser can be used to present examples of \ld\ scripts
+in text similar to the one below.
+\beginldprod
+MEMORY
+{
+ RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 20K
+ FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 128K
+ ASH (rx) : ORIGIN = 8000000, LENGTH = 128K
+ CLASH (rx) : ORIGIN = 700000, LENGTH = 128K
+ ASH (rx) : ORIGIN = $8000000, LENGTH = 128K
+ CLASH (rx) : ORIGIN = 700000B, LENGTH = 128K
+ INCLUDE file.mem
+}
+\endprod
+\noindent The syntax of \ld\ is modular enough so there does not seem to be a
+need for a `parser stack' as in the case of the \bison\
+parser. If one must be able to display still smaller segments of \ld\
+code, using `hidden context' tricks (discussed elsewhere) seems to be
+a better approach.
+\iffalse
+\traceparserstatestrue
+\tracestackstrue
+\tracerulestrue
+\traceactionstrue
+\tracelookaheadtrue
+\traceparseresultstrue
+\tracebadcharstrue
+\yyflexdebugtrue
+\tracestatestrue
+\fi
+%
+@<Example \ld\ script@>=
+@G(l)
+INCLUDE file.ld
+
+MEMORY
+{
+ RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 20K
+ FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 128K
+ ASH (rx) : ORIGIN = 8000000, LENGTH = 128K
+ CLASH (rx) : ORIGIN = 700000, LENGTH = 128K
+ ASH (rx) : ORIGIN = $8000000, LENGTH = 128K
+ CLASH (rx) : ORIGIN = 700000B, LENGTH = 128K
+ INCLUDE file.mem
+}
+
+_estack = 0x20005000;
+_bstack = a > 0 ? NEXT(11) : 0x19;
+
+SECTIONS
+{
+ .isr_vector ALIGN(8) (NOLOAD): AT(.) ALIGN(.) ALIGN_WITH_INPUT SUBALIGN(8) SPECIAL
+ {
+ . = ALIGN(4);
+ KEEP(*(.isr_vector))
+ . = ALIGN(4);
+ } > FLASH AT > RAM : FLASH : RAM : OTHER = . + 8
+
+ .text :
+ {
+ /* skip this comment */;
+ . = ALIGN(4);
+ *(.text)
+ *(.text.*)
+ *(.rodata)
+ *(.rodata*)
+ *(.glue_7)
+ *(.glue_7t)
+ . = ALIGN(4);
+ _etext = . + 8;
+ _sidata = _etext;
+ } >FLASH AT > RAM
+
+ .data : AT ( _sidata )
+ {
+ . = ALIGN(4);
+ _sdata = . ;
+ *(.data)
+ *(.data.*)
+ . = ALIGN(4);
+ _edata = . ;
+ } >RAM
+
+ .bss :
+ {
+ . = ALIGN(4);
+ _sbss = .;
+ *(.bss)
+ *(COMMON)
+ . = ALIGN(4);
+ _ebss = . ;
+ } >RAM
+}
+@g
+
+@ @<The same example of an \ld\ script@>=
+@G(b)
+INCLUDE file.ld
+
+MEMORY
+{
+ RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 20K
+ FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 128K
+ ASH (rx) : ORIGIN = 8000000, LENGTH = 128K
+ CLASH (rx) : ORIGIN = 700000, LENGTH = 128K
+ ASH (rx) : ORIGIN = $8000000, LENGTH = 128K
+ CLASH (rx) : ORIGIN = 700000B, LENGTH = 128K
+ INCLUDE file.mem
+}
+
+_estack = 0x20005000;
+_bstack = a > 0 ? NEXT(11) : 0x19;
+
+SECTIONS
+{
+ .isr_vector ALIGN(8) (NOLOAD): AT(.) ALIGN(.) ALIGN_WITH_INPUT SUBALIGN(8) SPECIAL
+ {
+ . = ALIGN(4);
+ KEEP(*(.isr_vector))
+ . = ALIGN(4);
+ } > FLASH AT > RAM : FLASH : RAM : OTHER = . + 8
+
+ .text :
+ {
+ /* skip this comment */;
+ . = ALIGN(4);
+ *(.text)
+ *(.text.*)
+ *(.rodata)
+ *(.rodata*)
+ *(.glue_7)
+ *(.glue_7t)
+ . = ALIGN(4);
+ _etext = . + 8;
+ _sidata = _etext;
+ } >FLASH AT > RAM
+
+ .data : AT ( _sidata )
+ {
+ . = ALIGN(4);
+ _sdata = . ;
+ *(.data)
+ *(.data.*)
+ . = ALIGN(4);
+ _edata = . ;
+ } >RAM
+
+ .bss :
+ {
+ . = ALIGN(4);
+ _sbss = .;
+ *(.bss)
+ *(COMMON)
+ . = ALIGN(4);
+ _ebss = . ;
+ } >RAM
+}
+@g
+
+@
+\traceparserstatesfalse
+\tracestacksfalse
+\tracerulesfalse
+\traceactionsfalse
+\tracelookaheadfalse
+\traceparseresultsfalse
+\tracebadcharsfalse
+\yyflexdebugfalse
+\tracestatesfalse
+
+@i ldnp.x
+
+@** Appendix. The original code of the \ld\ parser and lexer is reproduced below. It
+is mostly left intact and is typeset by the pretty printing parser for
+\bison\ input. The lexer (\flex) input is reproduced verbatim and is
+left mostly unformatted with the exception of spacing and the embedded
+\Cee\ code.
+
+The treatment of comments is a bit more invasive. \CWEB\ silently
+assumes that the comment refers to the preceding statement or a group
+of statements which is reflected in the way the comment is
+typeset. The comments in \ld\ source files use the
+opposite convention. For the sake of consistency, such comments have
+been moved so as to make them fit the \CWEB\ style. The comments meant to refer to a
+sizable portion of the program (such as a whole function or a group
+of functions) are put at the beginning of a \CWEB\ section containing
+the appropriate part of the program.
+
+\CWEB\ treats comments as ordinary \TeX\ so the comments are changed
+to take advantage of \TeX\ formatting and introduce some visual
+cues. The convention of using {\it italics\/} for the original
+comments has been reversed: the italicized comments are the ones
+introduced by the author, {\it not\/} the original
+creators of \ld.
+
+@i ldgramo.x
+@i ldlexo.x
+
+@** Index. This section lists the variable names and (in some cases)
+the keywords used inside the `language sections' of the \CWEB\
+source. It takes advantage of the built-in facility of \CWEB\ to supply
+references for both definitions (set in {\it
+italic}) as well as uses for each \Cee\ identifier in the text.
+
+Special facilities have been added to extend indexing to
+\bison\ grammar terms, \TeX\ control sequences encountered in
+\bison\ actions, and file and section names encountered in \ld\
+scripts. For a detailed description of the various conventions adhered
+to by the index entries the reader is encouraged to consult the
+remarks preceding the index of the document describing the core of
+the \splint\ suite. We will only mention here that (consistent with
+the way \bison\ references are treated) a script example:
+$$
+\vbox{
+\beginldprod
+MEMORY
+{
+ MEMORY1 (xrw) : ORIGIN = 0x20000000, LENGTH = 20K
+ MEMORY2 (rx) : ORIGIN = 0x8000000, LENGTH = 128K
+}
+_var_1 = 0x20005000;
+\endprod
+}%
+$$
+\noindent inside the \TeX\ part of a \CWEB\ section will generate several
+index entries, as well, mimicking \CWEB's behavior for the
+{\it inline \Cee\/} (\.{\yl}$\ldots$\.{\yl}). Such entries are labeled
+with $^\circ$, to provide a reminder of their origin.
+\def\otherlangindexseparator{%
+ \par
+ \vskip.5\baselineskip
+ \centerline{B{\sc ISON}, LD, {\sc AND} \TeX\ {\sc INDICES}}%
+ \vskip.5\baselineskip
+ \par
+}
+\let\currentparsernamespace\parsernamespace
+ \let\parsernamespace\indexpseudonamespace
+ \prettywordpair{emptyrhs}{$\circ$ {\rm(empty rhs)}}%
+ \prettywordpair{inline_action}{$\diamond$ {\rm(inline action)}}%
+\let\parsernamespace\currentparsernamespace
+\closeout\gindex
+\let\inx\inxmod
+\let\fin\finmod
+\let\oldMRL\MRL
+\def\MRL#1{\smash{\oldMRL{#1}}} % a more sophisticated way to handle it woud be to add a \smash whenever we are
+ % in the [index] namespace but this is simpler and works as well
+\def\topofcontents{\null\vskip-3\baselineskip\centerline{C{\sc ONTENTS} (\sc\uppercase\expandafter{\title})}\medskip}
diff --git a/support/splint/examples/ld/ldnp.w b/support/splint/examples/ld/ldnp.w
new file mode 100644
index 0000000000..f92d0dfc8c
--- /dev/null
+++ b/support/splint/examples/ld/ldnp.w
@@ -0,0 +1,362 @@
+@q Copyright 2012-2015, Alexander Shibakov@>
+@q This file is part of SPLinT@>
+
+@q SPLinT is free software: you can redistribute it and/or modify@>
+@q it under the terms of the GNU General Public License as published by@>
+@q the Free Software Foundation, either version 3 of the License, or@>
+@q (at your option) any later version.@>
+
+@q SPLinT is distributed in the hope that it will be useful,@>
+@q but WITHOUT ANY WARRANTY; without even the implied warranty of@>
+@q MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the@>
+@q GNU General Public License for more details.@>
+
+@q You should have received a copy of the GNU General Public License@>
+@q along with SPLinT. If not, see <http://www.gnu.org/licenses/>.@>
+
+@** The name parser for \ld\ term names.
+We take a lazy approach to the typeseting of term names for the \ld\
+grammar by creating a dedicated parser for name processing. This way
+any pattern we notice can be quickly incorporated into our typesetting scheme.
+% We include the macros here since this file is intended to be
+% included by the documentation `aggregator' so putting bare \TeX\
+% at the beginning of the file runs the risk of producing an error
+% of having \TeX\ material inside a \Cee\ section.
+\genericprettytokens namespace: ldsmall, tokens: {}, correction: lstokenset.sty, host: ldsmall;
+@(ld_small_parser.yy@>=
+@G Switch to generic mode.
+%{@> @<Name parser \Cee\ preamble@> @=%}
+ @> @<Bison options@> @=
+%union {@> @<Union of parser types@> @=}
+%{@> @<Name parser \Cee\ postamble@> @=%}
+ @> @<Token and types ...@> @=
+%%
+ @> @<Parser productions@> @=
+%%
+@g
+
+@ To put the new name parser to work, we need to initialize it. The
+initialization is done by the macros below. After the initialization
+has been completed, the switch command is replaced by the one that
+activates the new name parser.
+@<Modified name parser for \ld\ grammar@>=
+@G
+\genericparser
+ name: ldsmall,
+ ptables: ld_small_tab.tex,
+ ltables: ld_small_dfa.tex,
+ tokens: {},
+ asetup: {},
+ dsetup: {},
+ rsetup: {\noexpand\savefullstateextra},
+ optimization: {};%
+\let\otosmallparser\tosmallparser % /* save the old name parser */
+\let\tosmallparser\toldsmallparser
+@g
+
+@ @<Bison options@>=
+@G
+%token-table
+%debug
+%start full_name
+@g
+
+@ @<Token and types declarations@>=
+@G
+%token PERCENT_IDENTIFIER
+%token IDENTIFIER
+%token OPTIONAL
+%token K_SUFFIX
+%token INTEGER
+%token EXTENDED
+%token WILDCARD
+@g
+
+@*1 The name parser productions. These macros do a bit more than we
+need to typeset the term names. Their core is designed to treat
+suffixes and prefixes of a certain form in a special way. In addition,
+some productions were left in place from the original name parser in
+order to be able to refer to, say, \flex\ options in text. The inline
+action in one of the rules for \prodstyle{identifier\_string} was
+added to adjust the number and the position of the terms so that the
+appropriate action can be reused later for
+\prodstyle{qualified\_identifier\_string}.
+@<Parser productions@>=
+@G
+full_name:
+ identifier_string suffixes.opt {@> @<Compose the full name@> @=}
+| qualifier '_' identifier_string suffixes.opt {@> @<Compose a qualified name@> @=}
+;
+
+identifier_string:
+ PERCENT_IDENTIFIER {@> @<Attach option name@> @=}
+| IDENTIFIER {@> @<Start with an identifier@> @=}
+| '\'' WILDCARD '\'' {@> @<Start with a quoted string@> @=}
+| '\'' '.' '\'' {@> @<Start with a \prodstyle{'.'} string@> @=}
+| '\'' '_' '\'' {@> @<Start with an \prodstyle{'\_'} string@> @=}
+@t}\vb{\flatten}{@>
+| incomplete_identifier_string {} IDENTIFIER {@> @<Attach an identifier@> @=}
+;
+@t}\vb{\resetf}{@>
+incomplete_identifier_string:
+ identifier_string '_' {@> TeX_( "/yy0{/the/yy(1)}" ); @=}
+| qualified_identifier_string '_' {@> TeX_( "/yy0{/the/yy(1)}" ); @=}
+;
+
+qualified_identifier_string:
+ identifier_string '_' qualifier {@> @<Attach qualifier to a name@> @=}
+| qualified_identifier_string '_' qualifier {@> @<Attach qualifier to a name@> @=}
+;
+
+suffixes.opt:
+ {@> TeX_( "/yy0{}" ); @=}
+| '.' {@> TeX_( "/yy0{/nx/dotsp/nx/sfxnone}" ); @=}
+| '.' suffixes {@> @<Attach suffixes@> @=}
+| '.' qualified_suffixes {@> @<Attach qualified suffixes@> @=}
+| INTEGER {@> @<Attach an integer@> @=}
+| '_' INTEGER {@> @<Attach a subscripted integer@> @=}
+| '_' qualifier {@> @<Attach a subscripted qualifier@> @=}
+;
+
+suffixes:
+ IDENTIFIER {@> @<Start with a named suffix@> @=}
+| INTEGER {@> @<Start with a numeric suffix@> @=}
+| suffixes '.' {@> @<Add a dot separator@> @=}
+| suffixes IDENTIFIER {@> @<Attach a named suffix@> @=}
+| suffixes INTEGER {@> @<Attach integer suffix@> @=}
+| qualifier '.' {@> TeX_( "/yy0{/nx/sfxn/the/yy(1)/nx/dotsp}" ); @=}
+| suffixes qualifier '.' {@> TeX_( "/yy0{/the/yy(1)/nx/sfxn/the/yy(2)/nx/dotsp}" ); @=}
+;
+
+qualified_suffixes:
+ suffixes qualifier {@> @<Attach a qualifier@> @=}
+| qualifier {@> @<Start suffixes with a qualifier@> @=}
+;
+
+qualifier:
+ OPTIONAL {@> TeX_( "/yy0{/the/yy(1)}" ); @=}
+| K_SUFFIX {@> TeX_( "/yy0{/the/yy(1)}" ); @=}
+| EXTENDED {@> TeX_( "/yy0{/the/yy(1)}" ); @=}
+;
+@g
+
+@ @<Compose the full name@>=
+ @[TeX_( "/yy0{/the/yy(1)/the/yy(2)}/namechars/yyval" );@]@;
+
+@ @<Compose a qualified name@>=
+ @[TeX_( "/yy0{/the/yy(3)/the/yy(4)/nx/dotsp/nx/qual/the/yy(1)}/namechars/yyval" );@]@;
+
+@ @<Attach option name@>=
+ @[TeX_( "/getfirst{/yy(1)}/to/toksa" );@]@;
+ @[TeX_( "/getsecond{/yy(1)}/to/toksb" );@]@;
+ @[TeX_( "/yy0{/nx/optstr{/the/toksa}{/the/toksb}}" );@]@;
+
+@ @<Start with an identifier@>=
+ @[TeX_( "/getfirst{/yy(1)}/to/toksa" );@]@;
+ @[TeX_( "/getsecond{/yy(1)}/to/toksb" );@]@;
+ @[TeX_( "/yy0{/nx/idstr{/the/toksa}{/the/toksb}}" );@]@;
+
+@ @<Start with a tag@>=
+ @[TeX_( "/getfirst{/yy(2)}/to/toksa" );@]@;
+ @[TeX_( "/getsecond{/yy(2)}/to/toksb" );@]@;
+ @[TeX_( "/yy0{/nx/idstr{</the/toksa>}{</the/toksb>}}" );@]@;
+
+@ @<Start with a quoted string@>=
+ @[TeX_( "/getfirst{/yy(2)}/to/toksa" );@]@;
+ @[TeX_( "/getsecond{/yy(2)}/to/toksb" );@]@;
+ @[TeX_( "/yy0{/nx/chstr{/the/toksa}{/the/toksb}}" );@]@;
+
+@ @<Start with a \prodstyle{'.'} string@>=
+ @[TeX_( "/yy0{/nx/chstr{.}{.}}" );@]@;
+
+@ @<Start with an \prodstyle{'\_'} string@>=
+ @[TeX_( "/yy0{/nx/chstr{/uscoreletter}{/uscoreletter}}" );@]@;
+
+@ @<Turn a qualifier into an identifier@>=
+ @<Start with an identifier@>@;
+
+@ @<Attach an identifier@>=
+ @[TeX_( "/getsecond{/yy(1)}/to/toksa" );@]@;
+ @[TeX_( "/appendr/toksa{/noexpand/_}" );@]@;
+ @[TeX_( "/getfirst{/yy(3)}/to/toksb" );@]@;
+ @[TeX_( "/concat/toksa/toksb" );@]@;
+ @[TeX_( "/getthird{/yy(1)}/to/toksb" );@]@;
+ @[TeX_( "/appendr/toksb{/uscoreletter}" );@]@;
+ @[TeX_( "/getsecond{/yy(3)}/to/toksc" );@]@;
+ @[TeX_( "/concat/toksb/toksc" );@]@;
+ @[TeX_( "/yy0{/nx/idstr{/the/toksa}{/the/toksb}}" );@]@;
+
+@ @<Attach qualifier to a name@>=
+
+
+@ @<Attach an integer@>=
+ @[TeX_( "/yy0{/nx/dotsp/nx/sfxi/the/yy(1)}" );@]@;
+
+@ @<Attach a subscripted integer@>=
+ @[TeX_( "/yy0{/nx/dotsp/nx/sfxi/the/yy(2)}" );@]@;
+
+@ @<Attach a subscripted qualifier@>=
+ @[TeX_( "/yy0{/nx/dotsp/nx/qual/the/yy(2)}" );@]@;
+
+@ @<Attach suffixes@>=
+ @[TeX_( "/yy0{/nx/dotsp/the/yy(2)}" );@]@;
+
+@ @<Attach qualified suffixes@>=
+ @<Attach suffixes@>@;
+
+@ @<Start with a named suffix@>=
+ @[TeX_( "/yy0{/nx/sfxn/the/yy(1)}" );@]@;
+
+@ @<Start with a numeric suffix@>=
+ @[TeX_( "/yy0{/nx/sfxi/the/yy(1)}" );@]@;
+
+@ @<Add a dot separator@>=
+ @[TeX_( "/yy0{/the/yy(1)/nx/dotsp}" );@]@;
+
+@ @<Attach integer suffix@>=
+ @[TeX_( "/yy0{/the/yy(1)/nx/sfxi/the/yy(2)}" );@]@;
+
+@ @<Attach a named suffix@>=
+ @[TeX_( "/yy0{/the/yy(1)/nx/sfxn/the/yy(2)}" );@]@;
+
+@ @<Attach a qualifier@>=
+ @[TeX_( "/yy0{/the/yy(1)/nx/qual/the/yy(2)}" );@]@;
+
+@ @<Start suffixes with a qualifier@>=
+ @[TeX_( "/yy0{/nx/qual/the/yy(1)}" );@]@;
+
+@ \Cee\ preamble. In this case, there are no `real' actions that our
+grammar performs, only \TeX\ output, so this section is empty.
+
+@<Name parser \Cee\ preamble@>=
+
+@ \Cee\ postamble. It is tricky to insert function definitions that use \bison's internal types,
+as they have to be inserted in a place that is aware of the internal definitions but before said
+definitions are used.
+
+@<Name parser \Cee\ postamble@>=
+#define YYPRINT(file, type, value) @[yyprint (file, type, value)@]
+ static void yyprint (FILE *file, int type, YYSTYPE value){}
+
+@ Union of types.
+
+@<Union of parser types@>=
+
+@*1 The name scanner.
+%\checktabletrue
+@(ld_small_lexer.ll@>=
+@G
+ @> @<Lexer definitions@> @=
+%{@> @<Lexer \Cee\ preamble@> @=%}
+ @> @<Lexer options@> @=
+%%
+ @> @<Regular expressions@> @=
+%%
+@O
+void define_all_states( void ) {
+ @<Collect all state definitions@>@;
+}
+@o
+@g
+@t}\ifbootstrapmode\yyskipparsetrue\fi{@>
+
+@ @<Lexer definitions@>=
+ @<Lexer states@>@;
+@G
+aletter [a-zA-Z]
+wc ([^\\\']{-}[a-zA-Z0-9]|\\.)
+id ({aletter}|{aletter}({aletter}|[0-9])*{aletter})
+int [0-9]+
+@g
+
+@ @<Collect all state definitions@>=
+#define _register_name( name ) @[Define_State( #name, name )@]
+/* nothing for now */
+#undef _register_name
+
+@ Strings and characters in directives/rules.
+@<Lexer states@>=
+@G
+%x SC_ESCAPED_STRING SC_ESCAPED_CHARACTER
+@g
+
+@ @<Lexer \Cee\ preamble@>=
+
+#include <stdint.h>
+#include <stdbool.h>
+
+@t}\yyskipparsefalse{@>
+@ @<Lexer options@>=
+@G
+%option bison-bridge
+%option noyywrap nounput noinput reentrant
+%option noyy_top_state
+%option debug
+%option stack
+%option outfile="ld_small_lexer.c"
+@g
+
+@ @<Regular expressions@>=
+ @<Scan white space@>@;
+ @<Scan identifiers@>@;
+
+@ White space skipping.
+\traceparserstatestrue
+\tracestackstrue
+\tracerulestrue
+\traceactionstrue
+\tracelookaheadtrue
+\traceparseresultstrue
+\tracebadcharstrue
+\yyflexdebugtrue
+%
+%\prodstyle{abc123}
+%
+\traceparserstatesfalse
+\tracestacksfalse
+\tracerulesfalse
+\traceactionsfalse
+\tracelookaheadfalse
+\traceparseresultsfalse
+\tracebadcharsfalse
+\yyflexdebugfalse
+%
+\yyskipparsetrue
+@<Scan white space@>=
+@G
+[ \f\n\t\v] {@> @[TeX_( "/yylexnext" );@]@=}
+@g
+
+@ This collection of regular expressions might seem redundant, and in
+its present state, it certainly is. However, if later on the
+typesetting style for some of the keywords would need to be adjusted,
+such changes would be easy to implement, since the template is already
+here.
+@<Scan identifiers@>=
+@G
+"%"({aletter}|[0-9]|[-_]|"%"|[<>])+ {@> @[TeX_( "/yylexreturnval{PERCENT_IDENTIFIER}" );@]@=}
+
+"opt" {@> @[TeX_( "/yylexreturnval{OPTIONAL}" );@]@=}
+"K" {@> @[TeX_( "/yylexreturnval{K_SUFFIX}" );@]@=}
+"ext" {@> @[TeX_( "/yylexreturnval{EXTENDED}" );@]@=}
+
+[\'._] {@> @[TeX_( "/yylexreturnchar" );@]@=}
+{wc} {@> @[TeX_( "/yylexreturnval{WILDCARD}" );@]@=}
+
+{id} {@> @[@<Prepare to process an identifier@>@]@=}
+{int} {@> @[TeX_( "/yylexreturnval{INTEGER}" );@]@=}
+
+"\"" {@> @[TeX_( "/yylexnext" );@]@=}
+. {@> @[@<React to a bad character@>@]@=}
+@g
+
+@ @<Prepare to process an identifier@>=
+ @[TeX_( "/yylexreturnval{IDENTIFIER}" );@]@;
+
+@ \let\hostparsernamespace\ldnamespace\yyskipparsefalse A simple routine to detect
+trivial scanning problems.
+@<React to a bad character@>=
+ @[TeX_( "/iftracebadchars" );@]@;
+ @[TeX_( " /yycomplain{invalid character(s): /the/yytext}" );@]@;
+ @[TeX_( "/fi" );@]@;
+ @[TeX_( "/yylexreturn{$undefined}" );@]@;
diff --git a/support/splint/examples/ld/ldnump.w b/support/splint/examples/ld/ldnump.w
new file mode 100644
index 0000000000..5d4d45f724
--- /dev/null
+++ b/support/splint/examples/ld/ldnump.w
@@ -0,0 +1,306 @@
+@q Copyright 2012-2015, Alexander Shibakov@>
+@q This file is part of SPLinT@>
+
+@q SPLinT is free software: you can redistribute it and/or modify@>
+@q it under the terms of the GNU General Public License as published by@>
+@q the Free Software Foundation, either version 3 of the License, or@>
+@q (at your option) any later version.@>
+
+@q SPLinT is distributed in the hope that it will be useful,@>
+@q but WITHOUT ANY WARRANTY; without even the implied warranty of@>
+@q MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the@>
+@q GNU General Public License for more details.@>
+
+@q You should have received a copy of the GNU General Public License@>
+@q along with SPLinT. If not, see <http://www.gnu.org/licenses/>.@>
+
+@** The name parser for \ld\ term names.
+We take a lazy approach to the typeseting of term names for the \ld\
+grammar by creating a dedicated parser for name processing. This way
+any pattern we notice can be quickly incorporated into our typesetting scheme.
+% We include the macros here since this file is intended to be
+% included by the documentation `aggregator' so putting bare \TeX\
+% at the beginning of the file runs the risk of producing an error
+% of having \TeX\ material inside a \Cee\ section.
+\genericprettytokens namespace: ldsmall, tokens: {}, correction: lstokenset.sty, host: ldsmall;
+\iffalse
+\let\currentparsernamespace\parsernamespace
+ \let\parsernamespace\ldsmallnamespace
+ \let\hostparsernamespace\ldsmallnamespace
+ \input lstokenset.sty
+\let\parsernamespace\currentparsernamespace
+\fi
+@(ld_num_parser.yy@>=
+@G Switch to generic mode.
+%{@> @<Name parser \Cee\ preamble@> @=%}
+ @> @<Bison options@> @=
+%union {@> @<Union of parser types@> @=}
+%{@> @<Name parser \Cee\ postamble@> @=%}
+ @> @<Token and types ...@> @=
+%%
+ @> @<Parser productions@> @=
+%%
+@g
+
+@ To put the new name parser to work, we need to initialize it. The
+initialization is done by the macros below. After the initialization
+has been completed, the switch command is replaced by the one that
+activates the new name parser.
+@<Modified name parser for \ld\ grammar@>=
+@G
+\genericparser name: ldnum,
+ ptables: ld_num_tab.tex,
+ ltables: ld_num_dfa.tex,
+ tokens: {},
+ asetup: {},
+ dsetup: {},
+ rsetup: {\noexpand\savefullstateextra},
+ optimization: {};%
+@g
+
+@ @<Bison options@>=
+@G
+%token-table
+%debug
+%start hex_number
+@g
+
+@ @<Token and types declarations@>=
+@G
+%token DIGIT NYBBLE
+@g
+
+@*1 The name parser productions. These macros do a bit more than we
+need to typeset the term names. Their core is designed to treat
+suffixes and prefixes of a certain form in a special way. In addition,
+some productions were left in place from the original name parser in
+order to be able to refer to, say, \flex\ options in text. The inline
+action in one of the rules for \prodstyle{identifier\_string} was
+added to adjust the number and the position of the terms so that the
+appropriate action can be reused later for
+\prodstyle{qualified\_identifier\_string}.
+@<Parser productions@>=
+@G
+hex_number:
+ DIGIT {}
+ | DIGIT DIGIT {}
+ | DIGIT DIGIT DIGIT {}
+ | hex_number nybble {}
+ ;
+
+nybble:
+ DIGIT DIGIT DIGIT DIGIT {}
+ ;
+@g
+
+@ @<Compose the full name@>=
+ @[TeX_( "/yy0{/the/yy(1)/the/yy(2)}/namechars/yyval" );@]@;
+
+@ @<Compose a qualified name@>=
+ @[TeX_( "/yy0{/the/yy(3)/the/yy(4)/nx/dotsp/nx/qual/the/yy(1)}/namechars/yyval" );@]@;
+
+@ @<Attach option name@>=
+ @[TeX_( "/getfirst{/yy(1)}/to/toksa" );@]@;
+ @[TeX_( "/getsecond{/yy(1)}/to/toksb" );@]@;
+ @[TeX_( "/yy0{/nx/optstr{/the/toksa}{/the/toksb}}" );@]@;
+
+@ @<Start with an identifier@>=
+ @[TeX_( "/getfirst{/yy(1)}/to/toksa" );@]@;
+ @[TeX_( "/getsecond{/yy(1)}/to/toksb" );@]@;
+ @[TeX_( "/yy0{/nx/idstr{/the/toksa}{/the/toksb}}" );@]@;
+
+@ @<Start with a tag@>=
+ @[TeX_( "/getfirst{/yy(2)}/to/toksa" );@]@;
+ @[TeX_( "/getsecond{/yy(2)}/to/toksb" );@]@;
+ @[TeX_( "/yy0{/nx/idstr{</the/toksa>}{</the/toksb>}}" );@]@;
+
+@ @<Start with a quoted string@>=
+ @[TeX_( "/getfirst{/yy(2)}/to/toksa" );@]@;
+ @[TeX_( "/getsecond{/yy(2)}/to/toksb" );@]@;
+ @[TeX_( "/yy0{/nx/chstr{/the/toksa}{/the/toksb}}" );@]@;
+
+@ @<Turn a qualifier into an identifier@>=
+ @<Start with an identifier@>@;
+
+@ @<Attach an identifier@>=
+ @[TeX_( "/getsecond{/yy(1)}/to/toksa" );@]@;
+ @[TeX_( "/appendr/toksa{/noexpand/_}" );@]@;
+ @[TeX_( "/getfirst{/yy(3)}/to/toksb" );@]@;
+ @[TeX_( "/concat/toksa/toksb" );@]@;
+ @[TeX_( "/getthird{/yy(1)}/to/toksb" );@]@;
+ @[TeX_( "/appendr/toksb{/uscoreletter}" );@]@;
+ @[TeX_( "/getsecond{/yy(3)}/to/toksc" );@]@;
+ @[TeX_( "/concat/toksb/toksc" );@]@;
+ @[TeX_( "/yy0{/nx/idstr{/the/toksa}{/the/toksb}}" );@]@;
+
+@ @<Attach qualifier to a name@>=
+
+
+@ @<Attach an integer@>=
+ @[TeX_( "/yy0{/nx/dotsp/nx/sfxi/the/yy(1)}" );@]@;
+
+@ @<Attach a subscripted integer@>=
+ @[TeX_( "/yy0{/nx/dotsp/nx/sfxi/the/yy(2)}" );@]@;
+
+@ @<Attach a subscripted qualifier@>=
+ @[TeX_( "/yy0{/nx/dotsp/nx/qual/the/yy(2)}" );@]@;
+
+@ @<Attach suffixes@>=
+ @[TeX_( "/yy0{/nx/dotsp/the/yy(2)}" );@]@;
+
+@ @<Attach qualified suffixes@>=
+ @<Attach suffixes@>@;
+
+@ @<Start with a named suffix@>=
+ @[TeX_( "/yy0{/nx/sfxn/the/yy(1)}" );@]@;
+
+@ @<Start with a numeric suffix@>=
+ @[TeX_( "/yy0{/nx/sfxi/the/yy(1)}" );@]@;
+
+@ @<Add a dot separator@>=
+ @[TeX_( "/yy0{/the/yy(1)/nx/dotsp}" );@]@;
+
+@ @<Attach integer suffix@>=
+ @[TeX_( "/yy0{/the/yy(1)/nx/sfxi/the/yy(2)}" );@]@;
+
+@ @<Attach a named suffix@>=
+ @[TeX_( "/yy0{/the/yy(1)/nx/sfxn/the/yy(2)}" );@]@;
+
+@ @<Attach a qualifier@>=
+ @[TeX_( "/yy0{/the/yy(1)/nx/qual/the/yy(2)}" );@]@;
+
+@ @<Start suffixes with a qualifier@>=
+ @[TeX_( "/yy0{/nx/qual/the/yy(1)}" );@]@;
+
+@ \Cee\ preamble. In this case, there are no `real' actions that our
+grammar performs, only \TeX\ output, so this section is empty.
+
+@<Name parser \Cee\ preamble@>=
+
+@ \Cee\ postamble. It is tricky to insert function definitions that use \bison's internal types,
+as they have to be inserted in a place that is aware of the internal definitions but before said
+definitions are used.
+
+@<Name parser \Cee\ postamble@>=
+#define YYPRINT(file, type, value) @[yyprint (file, type, value)@]
+ static void yyprint (FILE *file, int type, YYSTYPE value){}
+
+@ Union of types.
+
+@<Union of parser types@>=
+
+@*1 The name scanner.
+%\checktabletrue
+@(ld_num_lexer.ll@>=
+@G
+ @> @<Lexer definitions@> @=
+%{@> @<Lexer \Cee\ preamble@> @=%}
+ @> @<Lexer options@> @=
+%%
+ @> @<Regular expressions@> @=
+%%
+@O
+void define_all_states( void ) {
+ @<Collect all state definitions@>@;
+}
+@o
+@g
+
+@ \ifbotstrapmode\yyskipparsetrue\fi@<Lexer definitions@>=
+ @<Lexer states@>@;
+@G
+aletter [a-zA-Z]
+wc ([^\\\'\"-]{-}[_a-zA-Z0-9]|\\.)
+id ({aletter}|{aletter}({aletter}|[0-9])*{aletter})
+int [0-9]+
+@g
+
+@ @<Collect all state definitions@>=
+#define _register_name( name ) @[Define_State( #name, name )@]
+/* nothing for now */
+#undef _register_name
+
+@ Strings and characters in directives/rules.
+@<Lexer states@>=
+@G
+%x SC_ESCAPED_STRING SC_ESCAPED_CHARACTER
+@g
+
+@ @<Lexer \Cee\ preamble@>=
+
+#include <stdint.h>
+#include <stdbool.h>
+
+@ \yyskipparsefalse@<Lexer options@>=
+@G
+%option bison-bridge
+%option noyywrap nounput noinput reentrant
+%option noyy_top_state
+%option debug
+%option stack
+%option outfile="ld_num_lexer.c"
+@g
+
+@ @<Regular expressions@>=
+ @<Scan white space@>@;
+ @<Scan identifiers@>@;
+
+@ White space skipping.
+\traceparserstatestrue
+\tracestackstrue
+\tracerulestrue
+\traceactionstrue
+\tracelookaheadtrue
+\traceparseresultstrue
+\tracebadcharstrue
+\yyflexdebugtrue
+%
+%\prodstyle{abc123}
+%
+\traceparserstatesfalse
+\tracestacksfalse
+\tracerulesfalse
+\traceactionsfalse
+\tracelookaheadfalse
+\traceparseresultsfalse
+\tracebadcharsfalse
+\yyflexdebugfalse
+%
+%\yyskipparsetrue
+@<Scan white space@>=
+@G
+[ \f\n\t\v] {@> @[TeX_( "/yylexnext" );@]@=}
+@g
+
+@ This collection of regular expressions might seem redundant, and in
+its present state, it certainly is. However, if later on the
+typesetting style for some of the keywords would need to be adjusted,
+such changes would be easy to implement, since the template is already
+here.
+%\yyskipparsefalse % this is not necessary
+@<Scan identifiers@>=
+@G
+"%"({aletter}|[0-9]|[-_]|"%"|[<>])+ {@> @[TeX_( "/yylexreturnval{PERCENT_IDENTIFIER}" );@]@=}
+
+"opt" {@> @[TeX_( "/yylexreturnval{OPTIONAL}" );@]@=}
+"na" {@> @[TeX_( "/yylexreturnval{NO_ATTR}" );@]@=}
+"ext" {@> @[TeX_( "/yylexreturnval{EXTENDED}" );@]@=}
+
+[<>._\'] {@> @[TeX_( "/yylexreturnchar" );@]@=}
+{wc} {@> @[TeX_( "/yylexreturnval{WILDCARD}" );@]@=}
+
+{id} {@> @[@<Prepare to process an identifier@>@]@=}
+{int} {@> @[TeX_( "/yylexreturnval{INTEGER}" );@]@=}
+
+"\"" {@> @[TeX_( "/yylexnext" );@]@=}
+. {@> @[@<React to a bad character@>@]@=}
+@g
+
+@ @<Prepare to process an identifier@>=
+ @[TeX_( "/yylexreturnval{IDENTIFIER}" );@]@;
+
+@ \let\hostparsernamespace\ldnamespace @<React to a bad character@>=
+ @[TeX_( "/iftracebadchars" );@]@;
+ @[TeX_( " /yycomplain{invalid character(s): /the/yytext}" );@]@;
+ @[TeX_( "/fi" );@]@;
+ @[TeX_( "/yylexreturn{$undefined}" );@]@;
diff --git a/support/splint/examples/ld/ldunion.sty b/support/splint/examples/ld/ldunion.sty
new file mode 100644
index 0000000000..b2c3837e57
--- /dev/null
+++ b/support/splint/examples/ld/ldunion.sty
@@ -0,0 +1,351 @@
+% Copyright 2012-2015, Alexander Shibakov
+% This file is part of SPLinT
+%
+% SPLinT is free software: you can redistribute it and/or modify
+% it under the terms of the GNU General Public License as published by
+% the Free Software Foundation, either version 3 of the License, or
+% (at your option) any later version.
+%
+% SPLinT 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 SPLinT. If not, see <http://www.gnu.org/licenses/>.
+
+% prototypes of all the macros produced by the ld parser
+% we will follow the convention: 12string is a string of category 12 characters and spaces, tex_string: a string
+% of TeX tokens; sptr is a pointer to the stash stream, fptr is a pointer to the format stream
+
+\def\yyuniontag{\ldunion}
+\def\parserstrictnamespace{ld-parser-strict}
+\def\parserprototypesnamespace{ld-parser-strict:headers}
+
+\def\ldunion{\currentyyunionnamespace}
+\def\currentyyunionnamespace{ld-generic}
+
+% types returned by the lexer (* marks the types that get removed by the parser in some cases)
+
+\defp\anint#1#2#3{} % integer :: \anint{integer}{fptr}{sptr}
+\defp\bint#1#2#3{} % integer in a specifix radix :: \bint{integer}{fptr}{sptr}
+\defp\hexint#1#2#3{} % hex integer :: \hexint{integer}{fptr}{sptr}
+
+% ld commands
+
+\defp\ldregexp#1{} % name pattern :: \ldregexp{name}
+\defp\ldspace{} % space separator :: \ldspace
+\defp\ldattributes#1{} % attributes :: \ldattributes{name}
+\defp\ldattributesneg#1{} % complemented attributes :: \ldattributesneg{name}
+\defp\ldfilename#1{} % file name :: \ldfilename{name}
+\defp\ldcommandseparator#1#2{} % command separator
+\defp\ldassignment#1#2#3{} % assignment :: \ldassignment{lhs}{op}{rhs}
+\defp\ldinclude#1{} % file inclusion :: \ldinclude{file name}
+\defp\ldmemory#1{} % memory specification :: \ldmemory{memory spcification}
+\defp\ldfill#1{} % fill expression :: \ldfill{expression}
+\defp\ldmemoryspec#1#2#3#4{} % memory item :: \ldmemoryspec{name}{attributes}{origin}{length}
+\defp\ldoriginspec#1{} % origin :: \ldoriginspec{expression}
+\defp\ldlengthspec#1{} % length :: \ldlengthspec{expression}
+\defp\ldsections#1{} % ld sections :: \ldsections{sections}
+\defp\ldsectionseparator{} % section separator
+\defp\ldtype#1{} % section type :: \ldtype{type}
+\defp\ldstatement#1{} % stray statement :: \ldstatement{statement}
+\defp\ldnamedsection#1#2#3#4#5#6#7{} % named section :: \ldnamedsection{name}
+ % {{expression}{type}}{at}
+ % {{}{}{}:alignment}
+ % {constraint}{statements}
+ % {{}{}{}{}:placement}
+
+\savecslist{ld-parser-prototypes}\ldunion
+
+\input ldint.sty
+
+\def\bigbracedel{\delimiter"4266308}
+
+\newtoks\lddisplay
+
+\defc\ldinclude{%
+ \toksa={&##\cr\ttl include\ &}#1%
+ \concat\toksa\toksc
+ \toksc{\cr}
+ \concat\toksa\toksc
+ \edef\next{\lddisplay{\the\lddisplay\halign{\the\toksa}}}\next
+}
+
+\defc\ldmemory{%
+ \savecslist{local-namespace}{\ldunion}%
+ \restorecslist{ld-parser:memory-spec}\ldunion
+ \toksa{}#1%
+ \toksc{%
+ \hfil##\qquad&##\hfil&\qquad##\hfil\quad&\hfil##&\quad\hfil##\cr
+ \ttl memory&\hfil&\ttl attributes&\ttl origin&\ttl length\cr
+ \noalign{\smallskip}%
+ }%
+ \edef\next{\lddisplay{\the\lddisplay\halign{\the\toksc\the\toksa}}}\next
+ \restorecslist{local-namespace}{\ldunion}%
+}
+
+\defc\ldsections{%
+ \savecslist{local-namespace}{\ldunion}%
+ \restorecslist{ld-parser:sections}\ldunion
+ \toksa{}\def\sections@header{\ttl sections}%
+ #1%
+ \toksc{%
+ &##\hfil\quad\cr
+ }%
+ \edef\next{\lddisplay{\the\lddisplay\halign{\the\toksc\the\toksa}}}\next
+ \restorecslist{local-namespace}{\ldunion}%
+}
+
+\def\ldextractname#1#2{%
+ \edef\next{\toksc{\gidxentry{\termttstring}{#2}{\ntt #2}}}\next
+}
+
+% the grammar of ld scripts is very uniform so the separator form
+% below is more than adequate; if a more sophisticated spacing
+% strategy is required, one may consult the design of
+% \separatorswitcheq and \separatorswitchneq in yyunion.sty
+
+\defc\ldcommandseparator{\yyifsamestring{#1}{#2}{}{\appendr\lddisplay{\noexpand\medskip}}}
+
+\defc\ldstatement{\toksc{\hbox{$#1$}}\concat\lddisplay\toksc}
+
+\defc\ldassignment{%
+ #1#2#3%
+}
+
+\defc\anint{%
+ \uppercase{\ldsciinteger{#1}}%
+}
+
+\defc\hexint{%
+ \ldsciinteger{#1}%
+}
+
+\defc\bint{%
+ \uppercase{\ldbasedinteger{#1}}%
+}
+
+\defc\ldregexp{%
+ \ldreg@xp#1%
+}
+
+\def\ldreg@xp#1#2{%
+ \hbox{\let\termindex\writeidxentry\edef\next{\toksc{\gidxentry{\termttstring}{#2}}}\next\the\toksc\ntt@#2}%
+}
+
+\defc\ldfill{%
+ #1%
+}
+
+\defc\ldfilename{\ldextractname#1}
+
+\savecslist{ld-display}\ldunion
+
+% memory specifications
+
+\restorecslist{ld-parser-strict}\ldunion
+
+\defc\ldmemoryspec{%
+ \toksb{\hfil&}%
+ \let\termindex\writeidxhentry
+ \ldextractname#1\concat\toksb\toksc
+ \let\termindex\eatone
+ \appendr\toksb{&}%
+ \toksc{}#2\concat\toksb\toksc
+ \toksc{}#3\concat\toksb\toksc
+ \toksc{}#4\concat\toksb\toksc
+ \concat\toksa\toksb
+ \toksb{\cr}\concat\toksa\toksb
+}
+
+\defc\ldattributes{%
+ \ldextractname#1\appendr\toksc{&}%
+}
+
+\defc\ldlengthspec{%
+ \toksc{#1}%
+}
+
+\defc\ldoriginspec{%
+ \toksc{#1&}%
+}
+
+\defc\ldinclude{%
+ \toksc={\hfil&\ttl include }%
+ \concat\toksa\toksc#1%
+ \concat\toksa\toksc
+ \toksc{&\hfil&\hfil&\hfil\cr}%
+ \concat\toksa\toksc
+}
+
+\restorecs{ld-display}{\anint\ldfilename}
+\toyyunion{ld-parser:memory-spec}
+
+% sections commands
+
+\restorecslist{ld-parser-strict}\ldunion
+
+\newif\ifplacementpushed
+\newif\ifsectioncomplete
+\newif\iffillextracted
+
+\defc\ldnamedsection{ % named section :: \ldnamedsection{name}
+ % {{bind?}{expression}{block?}{expression}{type}}{at}
+ % {{}{}{}:alignment}
+ % {constraint}{statements}
+ % {{}{}{}{}:placement}
+ \tempca=\z@ % line counter
+ \tempcb=\z@ % alignment line counter
+ \placementpushedfalse
+ \sectioncompletefalse
+ \fillextractedfalse
+ \bloop
+ \toksb{}%
+ \ifnum\tempca=\z@
+ \toksb\expandafter{\sections@header&}% section header
+ \ldextractname#1% section name
+ \concat\toksb\toksc
+ \appendr\toksb{&}%
+ \ldexpwithtype#2% location and type
+ \concat\toksb\toksc
+ \appendr\toksb{&}%
+ \yystringempty{#3}{\ldpushalignment#4}{\toksc{{\ttl at }$#3$}}% alignment
+ \concat\toksb\toksc
+ \appendr\toksb{&}%
+ \yystringempty{#5}{\ldpushplacement#7}{\toksc{{\ttl #5}}}% constraint
+ \concat\toksb\toksc
+ \appendr\toksb{&}%
+ \ldstartpheaders#7% possible pheaders
+ \concat\toksb\toksc
+ \appendr\toksb{\cr}%
+ \def\sections@header{}%
+ \else
+ \toksb\expandafter{&}% section header
+ \advance\tempca\m@ne
+ \ldextractitem\tempca{#6}% expression
+ \advance\tempca\@ne
+ \yytoksempty\toksc{%
+ \ldextractfill#7%
+ \iffillextracted
+ \ifnum\tempcb<\tw@
+ \else
+ \sectioncompletetrue
+ \fi
+ \fi
+ \fillextractedtrue
+ }{%
+ \toksc\expandafter{\expandafter\qquad\expandafter$\the\toksc{}$}%
+ }%
+ \concat\toksb\toksc
+ \appendr\toksb{&}%
+% \ldexpwithtype#2% location and type
+% \concat\toksa\toksc
+ \appendr\toksb{&}%
+ \ldpushalignment#4% alignment
+ \concat\toksb\toksc
+ \appendr\toksb{&}%
+ \ldpushplacement#7% placement
+ \concat\toksb\toksc
+ \appendr\toksb{&}%
+ \ldpushpheaders#7% possible pheaders
+ \concat\toksb\toksc
+ \appendr\toksb{\cr}%
+ \def\sections@header{}%
+ \fi
+ \ifsectioncomplete
+ \else
+ \concat\toksa\toksb
+ \advance\tempca\@ne
+ \repeat
+}
+
+\def\ldextractitem#1#2{%
+ \yystringempty{#2}{%
+ \toksc{}%
+ }{%
+ \let\ldor\or
+ \toksc=\ifcase#1#2\else{}\fi
+ \let\ldor\relax
+ }%
+}
+
+\def\ldpushalignment#1#2#3{%
+ \toksd=\ifcase\tempcb{#1}\or{#2}\or{#3}\else{}\fi
+ \yytoksempty\toksd{%
+ \advance\tempcb\@ne
+ \ifnum\tempcb<\tw@
+ \yybreak{\ldpushalignment{#1}{#2}{#3}}%
+ \else
+ \yybreak{\toksc{}}%
+ \yycontinue
+ }{%
+ \toksc=\ifcase\tempcb{{\ttl align }}\concat\toksc\toksd\or
+ {{\ttl align\_with\_input}}\or
+ {{\ttl subalign }}\concat\toksc\toksd\fi
+ \advance\tempcb\@ne
+ }%
+}
+
+\def\ldpushplacement#1#2#3#4{%
+ \ifplacementpushed
+ \toksc{}%
+ \else
+ \yystringempty{#1}{% any > ?
+ \toksc{}%
+ }{%
+ \ldextractname#1%
+ \toksd{{\ttl in }}%
+ \appendl\toksc{\the\toksd}%
+ }%
+ \yystringempty{#2}{% any AT > ?
+ }{%
+ \yytoksempty\toksc{\toksc{{\ttl as }}}{\appendr\toksc{ {\noexpand\ttl as }}}%
+ \toksd=\toksc
+ \ldextractname#2%
+ \concat\toksd\toksc
+ \toksc=\toksd
+ }%
+ \placementpushedtrue
+ \fi
+}
+
+\def\ldstartpheaders#1#2#3#4{%
+ \tempcc=\z@
+ \yystringempty{#3}{\toksc{}}{\toksc{{\ttl phdrs}}}%
+}
+
+\def\ldextractfill#1#2#3#4{%
+ \yystringempty{#4}{%
+ \toksc{}%
+ \fillextractedtrue
+ }{%
+ \iffillextracted
+ \toksc{}%
+ \else
+ \toksc={\qquad{\ttl fill }$#4$}%
+ \fi
+ }%
+}
+
+\def\ldpushpheaders#1#2#3#4{%
+ \ldextractitem\tempcc{#3}%
+ \advance\tempcc\@ne
+ \yytoksempty\toksc{}{\expandafter\ldextractname\the\toksc}%
+}
+
+\def\ldexpwithtype#1#2#3#4#5{% TODO
+ \yystringempty{#2}{\toksc{$}}{\toksc{$#2}}%$
+ \yystringempty{#5}{\toksd{{}$}}{#5\appendr\toksd{]$}\appendl\toksd{[}}%
+ \concat\toksc\toksd
+}
+
+\defc\ldtype{%
+ \toksd{\hbox{\ttl #1}}%
+}
+
+\defc\ldstatement{}
+\defc\ldsectionseparator{\toksc{&\multispan5\cdotfill\quad\cr}\concat\toksa\toksc}
+
+\restorecs{ld-display}{\anint\ldregexp\ldassignment\ldfill}
+\toyyunion{ld-parser:sections}
diff --git a/support/splint/examples/ld/lstokenset.sty b/support/splint/examples/ld/lstokenset.sty
new file mode 100644
index 0000000000..3ab3ae2d16
--- /dev/null
+++ b/support/splint/examples/ld/lstokenset.sty
@@ -0,0 +1,23 @@
+% Copyright 2012-2015, Alexander Shibakov
+% This file is part of SPLinT
+%
+% SPLinT is free software: you can redistribute it and/or modify
+% it under the terms of the GNU General Public License as published by
+% the Free Software Foundation, either version 3 of the License, or
+% (at your option) any later version.
+%
+% SPLinT 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 SPLinT. If not, see <http://www.gnu.org/licenses/>.
+
+\prettywordpair{OPTIONAL}{{\tt opt}}%
+\prettywordpair{SUFFIX}{{\tt suffix}}%
+\prettywordpair{EXTENDED}{{\tt ext}}%
+\prettywordpair{INTEGER}{{$[\,0\ldots9\,]\ast$}}%
+\prettywordpair{IDENTIFIER}{{$[\,\hbox{\tt a}\ldots\hbox{\tt Z}\,0\ldots9\,]\ast$}}%
+\prettywordpair{WILDCARD}{{{\tt *} {\rm or} {\tt ?}}}%
+\prettywordpair{PERCENT_IDENTIFIER}{{\tt\%$[\,\hbox{\tt a}\ldots\hbox{\tt Z}\,0\ldots9\,]\ast$}}%
diff --git a/support/splint/examples/ld/ltokenset.sty b/support/splint/examples/ld/ltokenset.sty
new file mode 100644
index 0000000000..d5d0d9b1ee
--- /dev/null
+++ b/support/splint/examples/ld/ltokenset.sty
@@ -0,0 +1,91 @@
+% Copyright 2012-2015, Alexander Shibakov
+% This file is part of SPLinT
+%
+% SPLinT is free software: you can redistribute it and/or modify
+% it under the terms of the GNU General Public License as published by
+% the Free Software Foundation, either version 3 of the License, or
+% (at your option) any later version.
+%
+% SPLinT 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 SPLinT. If not, see <http://www.gnu.org/licenses/>.
+
+\prettywordpair{comma}{{\tt,}}
+\prettywordpair{semicolon}{{\tt;}}
+\prettywordpair@@{file\_NAME\_list}{\ifinheader\itbold\else\it\fi file\_{\rm name}\_list}
+\prettywordpair@@{high\_level\_library\_NAME\_list}{\ifinheader\itbold\else\it\fi high\_level\_library\_{\rm name}\_list}
+\prettywordpair@@{low\_level\_library\_NAME\_list}{\ifinheader\itbold\else\it\fi low\_level\_library\_{\rm name}\_list}
+\prettywordpair@@{NAME}{{\rm name}}
+\prettywordpair@@{LNAME}{{\rm name$_{\rm L}$}}
+\prettywordpair@@{END}{{\rm end}}
+\prettywordpair@@{UNARY}{{\rm unary}}
+\prettywordpair@@{VERSIONK}{{\tt VERSION}$_{\rm K}$}
+\prettytoken{ALIGN}
+\prettytoken{MIN}
+\prettytoken{MAX}
+\prettytoken{TARGET}
+\prettytoken{ASSERT}
+\prettytoken{INSERT}
+\prettywordpair@@{PLUSEQ}{{}$\MRL{+{\K}}${}}
+\prettywordpair@@{MINUSEQ}{{}$\MRL{-{\K}}${}}
+\prettywordpair@@{MULTEQ}{{}$\MRL{\times{\K}}${}}
+\prettywordpair@@{DIVEQ}{{}$\MRL{{\div}{\K}}${}}
+\prettywordpair@@{ANDEQ}{{}$\Xandxeq${}}
+\prettywordpair@@{OREQ}{{}$\Xorxeq${}}
+\prettywordpair@@{LSHIFTEQ}{{}$\MRL{\ll{\K}}${}}
+\prettywordpair@@{RSHIFTEQ}{{}$\MRL{\gg{\K}}${}}
+\prettywordpair@@{NE}{{}$\not=${}}
+\prettywordpair@@{LE}{{}$\leq${}}
+\prettywordpair@@{GE}{{}$\geq${}}
+\prettywordpair@@{EQ}{{}$=${}}
+\prettywordpair@@{OROR}{{}$\V${}}
+\prettywordpair@@{ANDAND}{{}$\W${}}
+\prettywordpair@@{LSHIFT}{{}$\ll${}}
+\prettywordpair@@{RSHIFT}{{}$\gg${}}
+\prettywordpair@@{=}{{}$\K${}}
+\prettywordpair@@{+}{{}$+${}}
+\prettywordpair@@{-}{{}$-${}}
+\prettywordpair@@{!}{{}$\CM${}}
+\prettywordpair@@{~}{{}$\R${}}
+\prettywordpair@@{^}{{}$\XOR${}}
+\prettywordpair@@{|}{{}$\OR${}}
+\prettywordpair@@{&}{{}$\AND${}}
+
+\def\gtsymswitch{%
+ \raw exp *left *right\raw {%
+ {}$>${}%
+ }
+}
+
+\def\gtsymswitchdefault{{\tt >}}
+
+\def\ltsymswitch{%
+ \raw exp *left *right\raw {%
+ {}$<${}%
+ }
+}
+
+\def\ltsymswitchdefault{{\tt <}}
+
+\setspecialcharsfrom\gtsymswitch
+\setspecialcharsfrom\ltsymswitch
+
+\prettywordpair@@{>}{{%
+ \let\default\gtsymswitchdefault
+ \switchon{#1}\in\gtsymswitch
+}}
+
+\prettywordpair@@{<}{{%
+ \let\default\ltsymswitchdefault
+ \switchon{#1}\in\ltsymswitch
+}}
+
+\prettywordpair@@{*}{\yyifsamestring{exp}{#1}{{}$\times${}}{{\tt *}}}
+
+\prettywordpair@@{/}{{}$/${}}
+
+\expandafter\prettywordpair@@\expandafter{\harmlesscomment}{{}$\div${}}
diff --git a/support/splint/examples/symbols/Makefile b/support/splint/examples/symbols/Makefile
new file mode 100644
index 0000000000..d22110baaf
--- /dev/null
+++ b/support/splint/examples/symbols/Makefile
@@ -0,0 +1,37 @@
+# this Makefile uses a flat directory structure for demonstration
+# purposes; the main directory (../..) follows a slightly more
+# modular organization scheme.
+
+SPLINT_ROOT = $(shell pwd)/../..
+SYMBOLS_PREREQS = %.tex %.idx ${SPLINT_XTEXSTYLES} ${SPLINT_ROOT}/cweb/bo.tok symtoks.sty
+SYMBOLS_PREREQS += ${SPLINT_XPTABLES} ${SPLINT_XLTABLES} symmap.sty ${SPLINT_ROOT}/cweb/bg.y
+
+
+include ${SPLINT_ROOT}/makefile.inc
+
+# rules specific to this example
+
+%.tex: %.w
+
+%.tex %.idx: %.w
+ ${CWEAVE} $<
+
+%.gdx: ${SYMBOLS_PREREQS}
+ ${TEX} $*.tex
+
+%.pdf %.sns: ${SYMBOLS_PREREQS} %.gdy
+ ${PDFTEX} $*.tex && touch $*.gdy && touch $*.pdf
+
+docs: symbols.pdf
+
+clean: clean_core
+ rm -f symbols.tex
+
+mostlyclean: clean_temp
+
+distclean: clean
+ cd ${SPLINT_ROOT} && ${MAKE} clean
+
+.PRECIOUS: symbols.gdy
+
+.INTERMEDIATE: symbols.gdx
diff --git a/support/splint/examples/symbols/symbols.w b/support/splint/examples/symbols/symbols.w
new file mode 100644
index 0000000000..47c210e4f8
--- /dev/null
+++ b/support/splint/examples/symbols/symbols.w
@@ -0,0 +1,193 @@
+% Copyright 2012-2014, Alexander Shibakov
+% This file is part of SPLinT
+%
+% SPLinT is free software: you can redistribute it and/or modify
+% it under the terms of the GNU General Public License as published by
+% the Free Software Foundation, either version 3 of the License, or
+% (at your option) any later version.
+%
+% SPLinT 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 SPLinT. If not, see <http://www.gnu.org/licenses/>.
+\newwrite\gindex
+
+\input limbo.sty
+\def\optimization{5}
+\input yy.sty
+\input dcols.sty
+\input symmap.sty
+
+\def\symnamespace{[symbols]}
+
+\let\currentnamespace\parsernamespace
+\let\parsernamespace\symnamespace
+ \input symtoks.sty %
+\let\parsernamespace\currentnamespace
+\let\hostparsernamespace\symnamespace % the namespace where tokens are looked up
+ % for typesetting purposes
+
+\immediate\openout\exampletable=\jobname.exl
+
+\def\cite[#1]{%
+ \def\next{#1}\setbox0=\hbox{l}
+ [\ifx\next\empty$\,$\hbox{\vrule width\wd0 height\ht0 depth\dp0}$\,$\else #1\fi]%
+}
+
+\let\oldN\N
+\let\N\textN
+\let\M\textM
+
+\defreserved{Y}{\.{Y}}
+
+@** Introduction. \setupfootnotes
+The same parser and lexer (with a slightly different input routine)
+are used to typeset examples of productions in text.
+Some of the features of this parser
+are collected below for future reference. One might keep this section
+handy when typesetting his own examples (for example, it is probably
+unintuitive that `\.{`}' produces `\.{\yl}' but there is simply no
+way to use `\.{\yl}' as a character inside the \TeX\ section of \CWEB).
+The first, rather eclectic and lengthy example demonstrates various
+typesetting features of the \bison\ parser. The parsing output as well
+as the resulting table are saved in {\tt \jobname.exl}. All the \Cee\
+typesetting is performed by \CWEB, using its \.{\yl}$\ldots$\.{\yl}
+facility.
+\saveparseoutputtrue
+\expandafter\def\csname lexspecial[^^D^^D]\endcsname{}
+\medskip
+\beginprod
+\inline
+example:
+ term.1 term.2 \{\} term.3 \stashed{\relax} \{\stashed{\relax}\}
+` term.more \{\} "nonterminal"[sym_name.1] term_other[sym_name.2] \{\}
+` \
+` \%empty \
+` terms terms ',' terms \%? \{ \stashed{|a = b = c = d = e;|} \} \%dprec 7
+` terms terms ',' terms \%? \{ \stashed{|a = b = c;|} \}
+;
+%
+another:
+ term.8 \%merge <some_tag> term.one \%dprec 3 term.two \{\stashed{\rm|int a, b, c;|}\}
+` term.17 \%merge <other_tag> \{\stashed{|f(a,b)==c;|}\}
+` term.78 \{\stashed{|h(b)=g(c);|}\} \%merge <tag.2> \%dprec 0x17
+` term.77 \{\stashed{|h(b)=g(c);|}\} \%prec new_term
+;
+%
+\resetf
+and_another:
+ term.8 \%merge <some_tag> term.one \%dprec 3 term.two \{\stashed{\rm|int a, b, c;|}\}
+` term.17 \%merge <other_tag> \{\stashed{|f(a,b)==c;|}\}
+` term.78 \{\stashed{|h(b)=g(c);|}\} \%merge <tag.2> \%dprec 0x17
+` term.77 \{\stashed{|h(b)=g(c);|}\} \%prec new_term
+;
+%
+\%token ANOTHER NONEXISTENT GENERIC TOKEN 7 "token" ANOTHER 0x77 "more" TOKEN TOKEN ;
+\%token bogey1 bogey2 ;
+\%type <some> TOKEN ANOTHER ;
+\%start inputer;
+\stashed{\rm Example 1 of flushed code}\sflush{F}{flush this}
+\%default-prec;
+\%no-default-prec;
+\stashed{\rm Example 2 of flushed code}
+\%destructor \{ \stashed{\rm |func(int a, char b); a = b + c;|}\^^D\^^D % ignored because anything is accepted inside braces
+ \stashed{\6\rm |func2(int a, char b);|} \} \^^D\^^D
+ "token" TOKEN NONEXISTENT "none" BOGEY "more" A_TOKEN IDENTIFIER;
+\%printer \{ \stashed{\rm |func(int a, char b); a = b + c;|}
+ \stashed{\6\rm |func2(int a, char b);|} \} \^^D\^^D
+ "token" TOKEN NAME NONEXISTENT "none" ANOTHER BOGEY "more" A_TOKEN identifier.1 identifier.2;
+\%code token.3 \{ \stashed{\rm |func(int a, char b); a = b + c;|}
+ \stashed{\6\rm |func2(int a, char b);|} \};
+\%code \{ \stashed{\rm |new_function(int x, char y); |} \};
+\%left <whoops> "one" 1 "two" 2 three.137 0x7;
+\%precedence five six seven;
+\%nonassoc two;\^^D\^^D
+\%code \{ \stashed{\rm |other_function(int x, char y); |} \};
+\endprod
+\medskip
+%\checktabletrue
+\beginprod
+\%expect 0x137;
+\%expect-rr 17;
+\%lex-param \{\stashed{|int number;|}\};
+\%define var.1 \{ \stashed{ |func3(8, "string"){n = m++;};| } \}
+\%union var.2 \{ \stashed{\rm |int a, b, c;|\6 |char a_char;|} \}
+\%\{ \stashed{\rm |int a, b, c;|\6 |char a_char;|} \%\}
+\endprod
+%
+\medskip
+\noindent The next example is a demonstration of the hidden context
+added to an incomplete language fragment and local typesetting
+variations enabled by such context.
+\def\cset#1{%
+ \nx\colorset{darkwood}%
+ {#1}%
+ \nx\restorecolor
+}%
+\def\dset#1{%
+ $\nx\underbrace{\hbox{#1}}_{{\nx\rm identifier:\ \the\toksc}}$%
+}%
+\def\esets#1{%
+ \nx\beginub#1%
+}%
+\def\esete#1{%
+ #1\nx\endub
+}%
+\def\beginub#1\endub{%
+ $\underbrace{\hbox{#1}}_{\rm a\ group}$%
+}
+\smallskip
+\beginprod
+\skipheader
+ghost:
+ headerless_term.1 \formatlocal{\let\termmetastyle\cset} headerless_term.2 \{\stashed{\colorset{link}\rm|color(x,y,z);|\restorecolor}\}
+` \formatlocal{\let\termmetastyle\dset}more.of.the.same.0\formatlocal{\restorecs{table-render}\termmetastyle} but.not.here
+ \{\stashed{\rm|color(a, b, c);|}\}
+` \formatlocal{\let\termmetastyle\esets}three.more.terms\formatlocal{\restorecs{table-render}\termmetastyle}follow
+ \formatlocal{\let\termmetastyle\esete}this\formatlocal{\restorecs{table-render}\termmetastyle}one\{\stashed{\rm|assign(x, y, z);|}\}
+;
+\endprod
+\medskip
+\noindent Finally, an incomplete listing of the characters that can be
+typeset, as well as the way to typeset them. The use of `\.{`}' to
+typeset `\.{\yl}' deserves a special note---\CWEB's rules make it
+nearly impossible to use `\.{\yl}' in the \TeX\ portion of the program.
+\medskip
+\tomainparser
+\prettywordpair{GENERIC}{\_Generic}
+\prettywordpair{ss}{$^{\rm C99[}\,$\aftergroup\aftergroup\aftergroup\ignorespaces}
+\prettywordpair{es}{\unskip$\,{}^{\rm ]C99}$}% there is still a problem when this appears in headers
+\beginprod
+line_breaking_and_symbols:
+ GENERIC '(' expression',' \ ss another es')' \
+ ` inline_c \{ \stashed{\X{$\infty$}:See this example to deduce $\ldots$\X\6}\stashed{|b == a - c|} \}
+ ` more_inline_c \{ \stashed{|func(int a, char b);|} \}
+%
+\endprod
+\medskip
+\beginprod
+\format{\inline\flatten}
+symbol_tricks:
+ '\&' \
+ ` '*' \
+ ` '+' \
+ ` '-' \
+ ` '\~' \
+ ` '!' \
+ ` '\{' \
+ ` '`' \
+ ` '\`' \
+ ` '\'' \
+ ` '\\' \
+ ` ' ' \
+ ;
+\endprod
+
+\closeout\gindex
+@** Index. Totally superfluous in this case.
+\let\inx\inxmod
+\let\fin\finmod
+\def\topofcontents{\null\vskip-3\baselineskip\centerline{C{\sc ONTENTS} (\sc\uppercase\expandafter{\title})}\medskip}
diff --git a/support/splint/examples/symbols/symmap.sty b/support/splint/examples/symbols/symmap.sty
new file mode 100644
index 0000000000..12261be656
--- /dev/null
+++ b/support/splint/examples/symbols/symmap.sty
@@ -0,0 +1,164 @@
+% Copyright 2012-2014, Alexander Shibakov
+% This file is part of SPLinT
+%
+% SPLinT is free software: you can redistribute it and/or modify
+% it under the terms of the GNU General Public License as published by
+% the Free Software Foundation, either version 3 of the License, or
+% (at your option) any later version.
+%
+% SPLinT 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 SPLinT. If not, see <http://www.gnu.org/licenses/>.
+
+% assigning symbolic names to production terms (this is only a demonstration)
+% no attempt is made to make this code modular or namespace safe;
+% the approach is not very elegant and can stand a lot of improvement;
+% it was decided against such optimization to present a more explicit demonstration
+% of the procedures
+
+\def\makesymbols{%
+ \ifsymdemo
+ \restorecslist{symbols}\yyunion
+ \toksa{}\toksb{}\toksc{}\toksd{}%
+ %\showthe\newsymswitch
+ \the\symstream
+ \global\newsymswitch\newsymswitch
+ \else
+ \newsymswitch{}% otherwise \yysymswitch is trying to expand the wrong names (\namepair is not present to do \csname ... )
+ \fi
+}
+
+% symbolic reference name parser
+
+\newtoks\newsymswitch
+\newread\symnames
+
+\newwrite\symbolicswitch
+\newif\ifsymdemo
+
+\symdemotrue
+
+\ifbootstrapmode
+ \symdemofalse
+\fi
+
+\ifsymdemo
+ \def\inamespace{[intermediate]}%
+ \let\parsernamespace\inamespace
+ \let\hostparsernamespace\mainnamespace % purely for testing reasons
+ \pinittoks{}%
+ \input cweb/gyytab.tex % this should be the parser that will be used later
+ % in this case it is just an example
+ \edef\tointermediateparser{%
+ \noexpand\savefullstate % unnecessary
+ \noexpand\savefullstateextra % unnecessary
+ \let\noexpand\parsernamespace\noexpand\inamespace % switch to the new namespace
+ \the\pinittoks % restore all the tables, tokens and constants, and stacks
+ \let\noexpand\getcurrentparser\noexpand\tointermediateparser
+ }%
+ \settokens % this simply assign values to tokens where the name of each token is taken out of yytname ...
+ \input \drvname.tok % this will set up token equivalences in the namespace above ...
+ % those are the values gleaned during the bootstrapping stage.
+ % in the general case, one needs to run a bootsrapping (or similar)
+ % parser to extract the token information.
+ \optimizeall % this is necessary for correct rule listing in the output stage:
+ % otherwise \fgetelemof will use the current value of the \yy... token registers which
+ % will hold the values of the full parser that is loaded next
+ \newsymswitch{}%
+ \listrules % ... to be used while listing the rules
+ % note that we do not bother to set up a lexer for this parser (even though we already have one and the
+ % \optimizeall macro above will create a set of associative tables for it---this is merely an unwanted
+ % sideffect); after the rules have been listed, the intemediate parser in no longer needed.
+ %\showthe\newsymswitch
+ \def\fullnamespace{[full]}% this is the parser that parses the bison grammar from a raw
+ % bison file; it can play a role of the bootstrap parser for
+ % the grammar above, as well, since its input is a complete
+ % bison file; note that it cannot be a bootstrap parser for itself
+ % because it will reject any input that does not form a complete
+ % bison file; this is why a special grammar was created that includes
+ % only a small subset of the full set of productions (%token rules only) to
+ % serve as a bootstrap grammar.
+ %\tomainparser % this will set the value of \setflexstates, so that, if the lexer initialization
+ % below is omitted, the \setflexstates macro can still be used to correctly set the
+ % lexer states
+ \let\parsernamespace\fullnamespace
+ \pinittoks{}% %%
+ \input cweb/fyytab.tex
+ \input cweb/ltab.tex % we reinitialize the lexer out of necessity:
+ % \collecttokennames needs to know how to switch
+ % between two lexer/parser environments so both states
+ % have to be preserved; if one is sure that
+ % grammar_declarations will not used in the productions
+ % part of the file, this can simply be disabled
+ \settokens
+ \setflexstates % the main lexer can be reused in this case; the states still need to be set up
+ \input \drvname.tok % set up the tokens for the bison grammar parser
+ \newparserstate
+ \newlexerstate
+ \newlexerstateextra
+ %
+ \setnulstack{yyirulestack}%
+ %
+ \edef\tofullparser{%
+ \noexpand\savefullstate
+ \noexpand\savefullstateextra
+ \let\noexpand\parsernamespace\noexpand\fullnamespace % switch to the new namespace
+ \the\pinittoks % restore all the tables, tokens and constants, and stacks
+ \let\noexpand\getcurrentparser\noexpand\tofullparser
+ }%
+ \optimizeall
+ \toksa{\input bg.y}% start building the parsing command
+ % this has to be done carefully, since all the characters input
+ % from the parser file have to be `harmless', so their categories
+ % have to be reset; in order for the parser to be able to stop,
+ % appropriate command sequences would have to be inserted at the end
+ \toksb{\yyeof\yyeof\endparseinput\endparse
+ \let\yyinput\yyinputold
+ \undoascii
+ \ifyyparsefail
+ \errmessage{could not process symbols}%
+ \else
+ \symstream\table
+ \tointermediateparser % the parsing is finished, so we have two very long strings:
+ % o the rules of the hosted parser ([intermediate])
+ % o the rules of the same parser just parsed
+ % these two strings are used to associate the symbolic names
+ % (which only exist in the second list) to the rule numbers and
+ % the relevant terms;
+ % switching the parse namespace above is done so that the term
+ % indices are looked up in the appropriate table
+ %\showthe\table
+ \makesymbols % list all the rules deriving explicit non-terminals
+ %\showthe\newsymswitch
+ \setexplicitinlinerules\newsymswitch % process implicit non-terminals resulting from inline actions
+ %\showthe\newsymswitch
+ \makesymrefs\newsymswitch % create the switch to be used by the parser (\yyparse)
+ \fi
+ }%
+ % build the command to create the symbolic name switch
+ \toksc{\tofullparser\parserinit
+ \let\yyinputold\yyinput
+ \let\yyinput\yyinputtrivial % a demo of a stripped down, slightly faster input routine
+ \doascii{11}\expandafter\yyparse}%
+ \edef\next{\the\toksc\the\toksa\relax\the\toksb}\next % \relax is to stop \TeX\ from trying to expand the file name further
+ % it is not flagged as a bad character because it is part of the epilogue
+ \immediate\openout\symbolicswitch=\jobname.sns
+ %
+ \edef\next{\setsncommands{\def\noexpand\symswitch\hashletter1{\harmlesscomment^^J\noexpand\ifcase\hashletter1\relax
+ \harmlesscomment^^J\the\setsncommands
+ \noexpand\else\harmlesscomment^^J%
+ \noexpand\fi\harmlesscomment^^J%
+ }\harmlesscomment^^J^^J}}\next
+ \edef\next{\unsetsncommands{\def\noexpand\symswitchoff\hashletter1{\harmlesscomment^^J\noexpand\ifcase\hashletter1\relax
+ \harmlesscomment^^J\the\unsetsncommands
+ \noexpand\else\harmlesscomment^^J%
+ \noexpand\fi\harmlesscomment^^J%
+ }\harmlesscomment^^J^^J}}\next
+ {\newlinechar=`\^^J \immediate\write\symbolicswitch{\the\setsncommands\the\unsetsncommands}}%
+ \immediate\closeout\symbolicswitch
+ \tomainparser % go back to the main parser
+\fi
diff --git a/support/splint/examples/symbols/symtoks.sty b/support/splint/examples/symbols/symtoks.sty
new file mode 100644
index 0000000000..8d6cdc5596
--- /dev/null
+++ b/support/splint/examples/symbols/symtoks.sty
@@ -0,0 +1,8 @@
+\prettywordpair{ANOTHER}{{\rm(}another\rm{)}}
+\prettywordpair{TOKEN}{$\langle${\it token}$\rangle$}
+\prettywordpair{GENERIC}{{\tt \_Generic}}
+\prettywordpair{IDENTIFIER}{{\tt Identifier}}
+\prettywordpair{BOGEY}{{\tt \_Bogey}}
+\prettywordpair{NAME}{{\tt NAME}}
+\prettywordpair{A_TOKEN}{{a\_token.}}
+\prettywordpair{NONEXISTENT}{$\hbox{\tt Non}^{\rm existent}$}
diff --git a/support/splint/examples/types/basic.sty b/support/splint/examples/types/basic.sty
new file mode 100644
index 0000000000..856faf2374
--- /dev/null
+++ b/support/splint/examples/types/basic.sty
@@ -0,0 +1,464 @@
+% Copyright 2012-2014, Alexander Shibakov
+% This file is part of SPLinT
+%
+% SPLinT is free software: you can redistribute it and/or modify
+% it under the terms of the GNU General Public License as published by
+% the Free Software Foundation, either version 3 of the License, or
+% (at your option) any later version.
+%
+% SPLinT 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 SPLinT. If not, see <http://www.gnu.org/licenses/>.
+
+% various macros that implement `expandable arithmetic' that can be
+% used with the tree evaluator macros;
+% these are here as an example only; a much more complete version of
+% big integer arithmetic (including division and exponentiation) is
+% implemented in the `bigintcalc' package by Heiko Oberdiek; I was
+% unaware of the existence of `bigintcalc' when these macros were written;
+% note that the tree evaluator macros perform recursive expansion of
+% their arguments; `bigintcalc' uses \number for the same purpose
+% (since \number will keep expanding tokens until a non digit is
+% encountered)
+
+% macros that expand into a sequence of given length
+
+% #1 is the 1-radix of the number read so far
+% #2 is the `digit'
+% #3 is the next 10-radix digit to be processed or `S'
+
+\def\unroll#1#2#3{\csname unroll#3\endcsname{#1}{#2}}
+\expandafter\def\csname unroll0\endcsname#1#2{\unroll{#1#1#1#1#1#1#1#1#1#1}{#2}}
+\expandafter\def\csname unroll1\endcsname#1#2{\unroll{#2#1#1#1#1#1#1#1#1#1#1}{#2}}
+\expandafter\def\csname unroll2\endcsname#1#2{\unroll{#2#2#1#1#1#1#1#1#1#1#1#1}{#2}}
+\expandafter\def\csname unroll3\endcsname#1#2{\unroll{#2#2#2#1#1#1#1#1#1#1#1#1#1}{#2}}
+\expandafter\def\csname unroll4\endcsname#1#2{\unroll{#2#2#2#2#1#1#1#1#1#1#1#1#1#1}{#2}}
+\expandafter\def\csname unroll5\endcsname#1#2{\unroll{#2#2#2#2#2#1#1#1#1#1#1#1#1#1#1}{#2}}
+\expandafter\def\csname unroll6\endcsname#1#2{\unroll{#2#2#2#2#2#2#1#1#1#1#1#1#1#1#1#1}{#2}}
+\expandafter\def\csname unroll7\endcsname#1#2{\unroll{#2#2#2#2#2#2#2#1#1#1#1#1#1#1#1#1#1}{#2}}
+\expandafter\def\csname unroll8\endcsname#1#2{\unroll{#2#2#2#2#2#2#2#2#1#1#1#1#1#1#1#1#1#1}{#2}}
+\expandafter\def\csname unroll9\endcsname#1#2{\unroll{#2#2#2#2#2#2#2#2#2#1#1#1#1#1#1#1#1#1#1}{#2}}
+
+\def\unrollS#1#2#3{%
+ \ifx#3F%
+ \xskiptofi{#1S}%
+ \else
+ \xskiptofi{G{#1}}%
+ \fi
+}
+
+\def\sequence#1#2{\expandafter\s@quence\expandafter{\number#1}{#2}}
+\def\s@quence#1#2{\unrollbegin{}{#2}{}#1}
+
+\def\unrollbegin#1#2#3#4#5{%
+ \ifx#5S%
+ \ifx#40%
+ \yybreak@{S}%
+ \else
+ \yybreak@{\unroll{#1}{#2}{#3}#4#5}%
+ \fi
+ \else
+ \yybreak{\unroll{#1}{#2}{#3}#4#5}%
+ \yycontinue
+}
+
+% macros that count the number of non-S in a sequence
+
+\def\startconversion#1{%
+ \ifx#1S%
+ \xskiptofi{0}%
+ \else
+ \xskiptofi{\convertone{}{}}%
+ \fi
+}
+
+\def\convertzer@#1#2#3{%
+ \ifx#3S%
+ \xskiptofi{#1}%
+ \else
+ \xskiptofi{\convertone{0#1}{#2}}%
+ \fi
+}
+
+\def\convertzero#1#2#3{%
+ \ifx#3S%
+ \xskiptofi{\convertzer@{#1}{}#2S}%
+ \else
+ \xskiptofi{\convertone{#1}{#2}}%
+ \fi
+}
+
+\def\convertone#1#2#3{%
+ \ifx#3S%
+ \xskiptofi{\convertzero{1#1}{}#2S}%
+ \else
+ \xskiptofi{\converttwo{#1}{#2}}%
+ \fi
+}
+
+\def\converttwo#1#2#3{%
+ \ifx#3S%
+ \xskiptofi{\convertzero{2#1}{}#2S}%
+ \else
+ \xskiptofi{\convertthree{#1}{#2}}%
+ \fi
+}
+
+\def\convertthree#1#2#3{%
+ \ifx#3S%
+ \xskiptofi{\convertzero{3#1}{}#2S}%
+ \else
+ \xskiptofi{\convertfour{#1}{#2}}%
+ \fi
+}
+
+\def\convertfour#1#2#3{%
+ \ifx#3S%
+ \xskiptofi{\convertzero{4#1}{}#2S}%
+ \else
+ \xskiptofi{\convertfive{#1}{#2}}%
+ \fi
+}
+
+\def\convertfive#1#2#3{%
+ \ifx#3S%
+ \xskiptofi{\convertzero{5#1}{}#2S}%
+ \else
+ \xskiptofi{\convertsix{#1}{#2}}%
+ \fi
+}
+
+\def\convertsix#1#2#3{%
+ \ifx#3S%
+ \xskiptofi{\convertzero{6#1}{}#2S}%
+ \else
+ \xskiptofi{\convertseven{#1}{#2}}%
+ \fi
+}
+
+\def\convertseven#1#2#3{%
+ \ifx#3S%
+ \xskiptofi{\convertzero{7#1}{}#2S}%
+ \else
+ \xskiptofi{\converteight{#1}{#2}}%
+ \fi
+}
+
+\def\converteight#1#2#3{%
+ \ifx#3S%
+ \xskiptofi{\convertzero{8#1}{}#2S}%
+ \else
+ \xskiptofi{\convertnine{#1}{#2}}%
+ \fi
+}
+
+\def\convertnine#1#2#3{%
+ \ifx#3S%
+ \xskiptofi{\convertzero{9#1}{}#2S}%
+ \else
+ \xskiptofi{\convertzero{#1}{#2#3}}%
+ \fi
+}
+
+% list evaluator
+
+\def\expander#1#2{%
+ \ifcat\noexpand#2\relax
+ \xskiptofi{\@xp@nder#1}%
+ \else
+ \ifx#2G%
+ \grabexpanderpostfix{#1}%
+ \else
+ \xskiptofifi{#1}%
+ \fi
+ \fi
+ #2%
+}
+
+\def\@xpander#1#2{%
+ \ifcat\noexpand#2\relax
+ \xskiptofi{\expandafter\expander\expandafter{\expandafter#1\expandafter}#2}%
+ \else
+ \xskiptofi{\@xpander{#1\expandafter#2}}%
+ \fi
+}
+
+\def\@xp@nder#1{%
+ \ifcat\noexpand#1\relax
+ \xskiptofi{\expandafter\expander\expandafter{\expandafter}}%
+ \else
+ \xskiptofi
+ \@xpander%
+ \fi
+ #1%
+}
+
+
+\def\grabexpanderpostfix#1\else#2\fi\fi G#3{%
+ \fi\fi\expander{#1#3}%
+}
+
+% the next two macros set up the multiplication and addition tables in the form of
+% \xdigit a b c which expands to the two digits of a\times b + c
+% and
+% \sdigit a b c which expands to the two digits of a + b + c
+% where c \in \{0, 1\}.
+% altogether there are 1200 sequences in use. this number can be
+% reduced to under 500 at the expence of more sophisticated
+% conditionals:
+% o in the case of \xdigit, a == 1 or b == 1 reduces \xdigit a b c to
+% \sdigit a c 0 (for b == 1), whereas a == 0 or b == 0 makes
+% \xdigit a b c {c}{0}, finally for a == 2 or b == 2, \xdigit a b c is
+% the same as \sdigit a a c (if b == 2); in addition, \xdigit a b 0
+% and \xdigit a b 1 are the same for all pairs (a,b) other than (3,3)
+% and (7,7); thus, the number of \xdigit sequences can be reduced to
+% 261 (by also requiring that a < b)
+% o similar techniques can be used to reduce the number of \sdigit
+% sequences necessary to under 60
+
+\def\setxdigitmachine{%
+ \tempca=0
+ \loop
+ \ifnum10>\tempca
+ \expandafter\setxdcs\expandafter0\expandafter0\the\tempca
+ \else
+ \ifnum100>\tempca
+ \expandafter\setxdcs\expandafter0\the\tempca
+ \else
+ \expandafter\setxdcs\the\tempca
+ \fi
+ \fi
+ \advance\tempca\@ne
+ \ifnum1000>\tempca
+ \repeat
+}
+
+\def\setsdigitmachine{%
+ \tempca=0
+ \loop
+ \ifnum10>\tempca
+ \expandafter\setsdcs\expandafter0\expandafter0\the\tempca
+ \else
+ \ifnum100>\tempca
+ \expandafter\setsdcs\expandafter0\the\tempca
+ \else
+ \expandafter\setsdcs\the\tempca
+ \fi
+ \fi
+ \advance\tempca\@ne
+ \ifnum200>\tempca
+ \repeat
+}
+
+% #1: carry
+% #2: the first summand
+% #3: the second summand
+
+% the result:
+% {sum digit}{new carry}
+
+\def\setsdcs#1#2#3{%
+ \tempcb=#2
+ \advance\tempcb#3
+ \advance\tempcb#1
+ \ifnum10>\tempcb
+ \expandafter\edef\csname sdigit#2#3#1\endcsname{\expandafter\parenthesize\expandafter0\the\tempcb}%
+ \else
+ \expandafter\edef\csname sdigit#2#3#1\endcsname{\expandafter\parenthesize\the\tempcb}%
+ \fi
+}
+
+% #1: the first multiplier
+% #2: the second multiplier
+% #3: carry
+
+% the result:
+% {product digit}{new carry}
+
+\def\setxdcs#1#2#3{%
+ \tempcb=#1
+ \multiply\tempcb#2
+ \advance\tempcb#3
+ \ifnum10>\tempcb
+ \expandafter\edef\csname xdigit#1#2#3\endcsname{\expandafter\parenthesize\expandafter0\the\tempcb}%
+ \else
+ \expandafter\edef\csname xdigit#1#2#3\endcsname{\expandafter\parenthesize\the\tempcb}%
+ \fi
+}
+
+\def\parenthesize#1#2{{#2}{#1}}
+
+\setxdigitmachine
+\setsdigitmachine
+
+% #1: carryover
+% #2: shift
+% #3: multiplier
+% #4: carry
+% #5: digits so far
+% #6: next digit
+
+\def\smallmultiply#1#2#3#4#5#6{%
+ \ifx#6F%
+ \ifx#40%
+ \yybreak@{\attachnxtnumber#1{#2#5}}%
+ \else
+ \yybreak@{\attachnxtnumber#1{#2#5#4}}%
+ \fi
+ \else
+ \yybreak{\expandafter\expandafter\expandafter
+ \sm@llmultiply\csname xdigit#3#6#4\endcsname{#1}{#2}{#3}{#5}}%
+ \yycontinue
+}
+
+\def\sm@llmultiply#1#2#3#4#5#6{%
+ \smallmultiply{#3}{#4}{#5}{#2}{#6#1}%
+}
+
+% carryover:
+% {number1}{number2}{shift}{product so far}
+
+% #1: number1
+% #2: number2
+% #3: shift
+% #4: product so far
+% #5; new number
+
+\def\attachnxtnumber#1#2#3#4#5{%
+ \startnxtproduct{#1}{#2}{#30}{#4#5F}#1%
+}
+
+% #1: number1
+% #2: number2
+% #3: shift
+% #4: product so far
+% #5; next digit
+
+\def\startnxtproduct#1#2#3#4#5{%
+ \ifx#5F%
+ \xskiptofi{\addmultiples#4G}%
+ \else
+ \xskiptofi{\expandafter\sm@llm@ltiply\expandafter{\expandafter{\eatone#1}{#2}{#3}{#4}}{#3}{#5}{0}{#2}}%
+ \fi
+}
+
+% #1: carryover
+% #2: shift
+% #3: multiplier
+% #4: carry
+% #5: number2
+% #6: remainder of the number
+
+\def\sm@llm@ltiply#1#2#3#4#5#6F{%
+ \smallmultiply{#1}{#2}{#3}{#4}{}#5%
+}
+
+\def\addmultiples#1F#2{%
+ \ifx#2G%
+ \xskiptofi{\postprocesssum{#1}}%
+ \else
+ \xskiptofi{\startnxtsum{#1}#2}%
+ \fi
+}
+
+\def\postprocesssum#1#2{%
+ #2{#1}%
+}
+
+% the summation macro below can be used for subtraction, as well,
+% using a well known 9-complement + 1 technique (compare two numbers,
+% take the complement of the smaller, add 1, add the results, remove
+% the first nonzero digit of the sum; the result of the comparison
+% determines the sign of the sum;
+
+\def\startnxtsum#1#2F{%
+ \startnxts@m{}{0}{#1}{#2}%
+}
+
+% #1: sum so far
+% #2: carry
+% #3: first number
+% #4: second number
+
+\def\startnxts@m#1#2#3#4{%
+ \ifx F#3F% the first number is exhausted
+ \ifx F#4F% both numbers are exhausted: finished
+ \yybreak@{\addmultiples#1#2F}%
+ \else % the second number is still non empty
+ \yybreak@{\makesimples@m{#1}{#2}0F#4F}%
+ \fi
+ \else
+ \ifx F#4F% the second number is exhausted
+ \yybreak@{\makesimples@m{#1}{#2}#3F0F}%
+ \else % both numbers are non empty
+ \yybreak@{\makesimples@m{#1}{#2}#3F#4F}%
+ \fi
+ \yycontinue
+}
+
+% #1: sum so far
+% #2: carry
+% #3: first digit
+% #4: rest of first number
+% #5: second digit
+% #6: rest of second number
+
+\def\makesimples@m#1#2#3#4F#5#6F{%
+ \expandafter\expandafter\expandafter\makesimpl@s@m\csname sdigit#3#5#2\endcsname{#1}{#4}{#6}%
+}
+
+% #1: digit
+% #2: carry
+% #3: sum so far
+% #4: first number
+% #5: second mumber
+
+\def\makesimpl@s@m#1#2#3#4#5{%
+ \startnxts@m{#3#1}{#2}{#4}{#5}%
+}
+
+% #1: prefix
+% #2: postfix
+% #3: digits
+
+\def\reversepp#1#2#3{%
+ \r@versepp{#1}{#2}{}#3R%
+}
+
+\def\r@versepp#1#2#3#4{%
+ \ifx#4R%
+ \xskiptofi{#1#3#2}%
+ \else
+ \xskiptofi{\r@versepp{#1}{#2}{#4#3}}%
+ \fi
+}
+
+\def\xmul#1#2{%
+ \reversepp{\xm@l}{F}{#2F#1}%
+}
+
+\def\xm@l#1F#2F{%
+ \startnxtproduct{#1F}{#2F}{}{}#1F{\reversepp{\eatzeros}{F}}%
+}
+
+\def\xsum#1#2{%
+ \reversepp{\addmultiples}{FG{\reversepp{\eatzeros}{F}}}{#2F#1}%
+}
+
+\def\eatzeros#1{% to remove zero carry digits
+ \ifx#10%
+ \yybreak\eatzeros
+ \else
+ \ifx#1F%
+ \yybreak@0%
+ \else
+ \yybreak@{\removepostfix#1}%
+ \fi
+ \yycontinue
+}
+
+\def\removepostfix#1F{#1}
diff --git a/support/splint/examples/types/test.sty b/support/splint/examples/types/test.sty
new file mode 100644
index 0000000000..8a7859d3d6
--- /dev/null
+++ b/support/splint/examples/types/test.sty
@@ -0,0 +1,63 @@
+% Copyright 2012-2014, Alexander Shibakov
+% This file is part of SPLinT
+%
+% SPLinT is free software: you can redistribute it and/or modify
+% it under the terms of the GNU General Public License as published by
+% the Free Software Foundation, either version 3 of the License, or
+% (at your option) any later version.
+%
+% SPLinT 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 SPLinT. If not, see <http://www.gnu.org/licenses/>.
+
+% some examples of the `tree evaluator' and the `expandable arithmetic' macros
+
+\input ../../yycommon.sty
+\input ../../yymisc.sty
+\input basic.sty
+\input tree.sty
+
+% defining the node arities for the tree evaluator
+
+\nodesetup{xmul}{2}
+\nodesetup{xsum}{2}
+\nodesetup{xxttop}{0}
+\nodesetup{the}{0}
+\nodesetup{number}{0}
+
+%\tracingmacros=3
+%\tracingonline=3
+
+\tempca=77
+
+\edef\asum{\xsum{0}{21809808}}
+\edef\aproduct{\xmul{118768770987098709870987098787979}{69876987698769824320980}}
+
+\message{product: \aproduct, sum: \asum}
+
+\def\anexpression{\treeeval{\xmul{\xsum{\xsum{1}{\xmul{2764567}{74674}}}{3}}{\xsum{\the\tempca}{\xsum{\number\tempcb}{\xmul{5764567}{7}}}}}}
+
+\message{value of the expression: \anexpression}
+
+% `symbolic definitions' of the nodes for the tree evaluator
+
+\def\xsum#1#2{(#1 + #2)}
+\def\xmul#1#2{#1 * #2}
+
+\message{expression: \anexpression}
+
+%\tracingmacros=0
+%\tracingonline=0
+
+%\tempca=17
+
+%\edef\seq{\noexpand\startconversion\expander{}\sequence\tempca{*}SS\sequence\tempca{.}SS\sequence\tempca{.}SF}
+%\show\seq
+%\edef\cseq{\seq}
+%\show\cseq
+
+\end
diff --git a/support/splint/examples/types/tree.sty b/support/splint/examples/types/tree.sty
new file mode 100644
index 0000000000..46a4c94a97
--- /dev/null
+++ b/support/splint/examples/types/tree.sty
@@ -0,0 +1,190 @@
+% Copyright 2012-2014, Alexander Shibakov
+% This file is part of SPLinT
+%
+% SPLinT is free software: you can redistribute it and/or modify
+% it under the terms of the GNU General Public License as published by
+% the Free Software Foundation, either version 3 of the License, or
+% (at your option) any later version.
+%
+% SPLinT 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 SPLinT. If not, see <http://www.gnu.org/licenses/>.
+
+% tree evaluator macros.
+
+% #1: first token of a leaf
+
+\def\leafexpand#1{%
+ \ifcat\noexpand#1\relax % the leaf starts with an expandable token or control sequence
+ \xskiptofi{\expandafter\leafexpand}%
+ \else
+ \xskiptofi{\leafattach}%
+ \fi
+ #1%
+}
+
+% #1: the leaf
+% #2: {{pruned tree}{last pruned branch}}
+
+\def\leafattach#1\endleaf#2{%
+ \leafatt@ch{#1}#2%
+}
+
+% #1: the leaf
+% #2: pruned tree
+% #3: last pruned branch
+
+\def\leafatt@ch#1#2#3{%
+ \leaf@tt@ch{#1}{#2}#3%
+}
+
+\def\xname{\expandafter\eatone\string}
+
+% #1: the leaf
+% #2: pruned tree
+% #3: treenode type
+
+\def\leaf@tt@ch#1#2#3{%
+ \csname\xname#3.ifargdone\endcsname
+ % all leaves of the last pruned node have been evaluated, evaluate the node
+ \xskiptofi{\csname leafprune\csname\xname#3.arity\endcsname\endcsname{#2}#3{#1}}%
+ \else
+ % look at the next argument
+ \xskiptofi{\csname nextargument\csname\xname#3.arity\endcsname\endcsname{#2}#3{#1}}% rest of the arguments follow
+ \fi
+}
+
+% #1: pruned tree
+% #2: treenode type
+% #3: argument
+
+\expandafter\def\csname leafprune0\endcsname#1#2#3{%
+ #3%
+}
+
+% #1: pruned tree
+% #2: treenode type
+% #3: argument
+
+\expandafter\def\csname leafprune1\endcsname#1#2#3{%
+ \leafexpand#2{#3}\endleaf{#1}%
+}
+
+% #1: pruned tree
+% #2: treenode type
+% #3: argument1
+% #4: argument2
+
+\expandafter\def\csname leafprune2\endcsname#1#2#3#4{%
+ \leafexpand#2{#3}{#4}\endleaf{#1}%
+}
+
+% #1: pruned tree
+% #2: treenode type
+% #3: argument1
+
+\expandafter\def\csname nextargument1\endcsname#1#2#3{%
+ \expandafter\expandafter\expandafter
+ \treedesc@nd#3\endleaf{{#1}{#2}}%
+}
+
+% #1: pruned tree
+% #2: treenode type
+% #3: argument1
+% #4: argument2
+
+\expandafter\def\csname nextargument2\endcsname#1#2#3#4{%
+ \expandafter\expandafter\expandafter
+ \treedescend\csname\xname#2.argshift\endcsname{#4}{{#3}}{#1}%
+}
+
+% #1: treenode type
+% #2: last argument
+% #3: rest of arguments
+% #4: pruned tree
+
+\def\treedescend#1#2#3#4{%
+ \treedesc@nd#2\endleaf{{#4}{#1#3}}%
+}
+
+% #1: treenode type or leaf
+
+\def\treedesc@nd#1{%
+ \ifcat\noexpand#1\noexpand\relax % in case someone redefined \relax
+ % this is an argument that has to be expanded
+ \xskiptofi{\csname treed@sc@nd\csname\xname#1.arity\endcsname\endcsname}%
+ \else
+ % this is a leaf
+ \xskiptofi{\leafattach}%
+ \fi
+ #1%
+}
+
+% data type, expand it
+
+\expandafter\def\csname treed@sc@nd0\endcsname{%
+ \expandafter\leafattach % \leafattach will consume \endleaf
+}
+
+% unary operation
+% #1: treenode type
+% #2: argument1
+% #3: pruned tree
+
+\expandafter\def\csname treed@sc@nd1\endcsname#1#2\endleaf#3{%
+ \csname nextargument1\endcsname{#3}#1{#2}%
+}
+
+% binary operation
+% #1: treenode type
+% #2: argument1
+% #3: argument2
+% #4: pruned tree
+
+\expandafter\def\csname treed@sc@nd2\endcsname#1#2#3\endleaf#4{%
+ \csname nextargument2\endcsname{#4}#1{#2}{#3}%
+}
+
+\def\treeeval#1{%
+ \treeev@l#1%
+}
+
+\def\treeev@l#1{%
+ \csname nextargument\csname\xname#1.arity\endcsname\endcsname{{}\xxttop}#1%
+}
+
+% #1: node name
+% #2: arity
+
+\def\nodesetup#1#2{%
+ \expandafter\let\csname #1.ifargdone\endcsname\iftrue
+ \ifnum#2>0
+ \expandafter\edef\csname #1.argshift\endcsname{%
+ \expandafter\noexpand\csname #11\endcsname
+ }%
+ \fi
+ \expandafter\edef\csname #1.arity\endcsname{#2}%
+ \tempca\@ne
+ \loop
+ \ifnum\tempca<#2
+ \expandafter\def\csname #1\the\tempca.arity\endcsname{#2}%
+ \makeargdonefalse{#1}%
+ \tempcb\tempca
+ \advance\tempca\@ne
+ \ifnum\tempca<#2
+ \expandafter\edef\csname #1\the\tempcb.argshift\endcsname{%
+ \expandafter\noexpand\csname #1\the\tempca\endcsname
+ }%
+ \else
+ \expandafter\edef\csname #1\the\tempcb.argshift\endcsname{%
+ \expandafter\noexpand\csname #1\endcsname
+ }%
+ \fi
+ \repeat
+}
+
+\def\makeargdonefalse#1{\expandafter\let\csname #1\the\tempca.ifargdone\endcsname\iffalse}
diff --git a/support/splint/examples/xxpression/Makefile b/support/splint/examples/xxpression/Makefile
new file mode 100644
index 0000000000..4450e3126d
--- /dev/null
+++ b/support/splint/examples/xxpression/Makefile
@@ -0,0 +1,74 @@
+# this Makefile uses a flat directory structure for demonstration
+# purposes; the main directory (../..) contains a slightly more
+# modular organization.
+
+SPLINT_ROOT = $(shell pwd)/../..
+XXPRESSION_PREREQS = %.tex %.scn %.idx %.tok ${SPLINT_XPTABLES} ${SPLINT_XLTABLES} ${SPLINT_ROOT}/cweb/bo.tok xymmap.sty xtoks.sty
+
+include ${SPLINT_ROOT}/makefile.inc
+include ${SPLINT_ROOT}/makefile.loc
+
+# rules specific to this example
+
+PARSER = xxpp
+LEXER = xxpl
+
+all: xxpression.pdf ptab.tex ltab.tex
+
+step1: ${PARSER}.y ${LEXER}.l
+step2: ptabout ltabout
+step3: ltab.tex ptab.tex
+step4: xymbols.sns
+
+ptabout: ${SPLINT_ROOT}/cweb/mkeparser.c ${PARSER}.c
+ ${CC} -DPARSER_FILE=\"../examples/xxpression/$(lastword $^)\" -DYYPARSE_PARAMETERS= -o $@ $<
+
+ptab.tex: ptabout
+ $< --optimize-actions $@
+
+ltabout: ${SPLINT_ROOT}/cweb/mkscanner.c ${LEXER}.c
+ ${CC} -DLEXER_FILE=\"../examples/xxpression/$(lastword $^)\" -o $@ $<
+
+ltab.tex: ltabout
+ $< --optimize-actions $@
+
+${LEXER}.c: ${LEXER}.l
+ ${FLEX} -o $@ $<
+
+test.tex xymbols.tex \
+${PARSER}.yy ${LEXER}.ll: xxpression.x
+ @${CTANGLE} $<
+ ${UNLINE} test.txx test.tex
+ ${UNLINE} xymbols.txx xymbols.tex
+
+xymbols.sns: xymbols.tex xxpression.tok ${SPLINT_ROOT}/cweb/bo.tok ${SPLINT_XPTABLES} ${SPLINT_XLTABLES} ptab.tex
+ ${PDFTEX} $<
+
+xxpression.tex: xxpression.x
+ ${CWEAVE} $<
+
+xxpression.gdx: %.gdx: ${XXPRESSION_PREREQS}
+ ${TEX} $*.tex
+
+xxpression.pdf: %.pdf: ${XXPRESSION_PREREQS} %.gdy
+ ${PDFTEX} $* && touch $*.gdy && touch $*.pdf
+# if [ -f $*.gdx ] ; then ${BINDX} $*.gdx $*.gdy; fi
+
+xxpression.tok: xxpression.tex ${SPLINT_XPTABLES} ${SPLINT_XLTABLES} ${SPLINT_ROOT}/cweb/bo.tok
+ ${PDFTEX} $< && touch xxpression.tok
+
+test: test.tex xymbols.sns xxpression.tok ptab.tex ltab.tex
+ tex test.tex
+
+docs: xxpression.pdf
+
+clean: clean_core
+ -rm -f ptabout ltabout *.txx
+
+mostlyclean: clean_temp
+ -rm -f ptabout ltabout xxpression.c *.txx
+
+distclean: clean
+ cd ${SPLINT_ROOT} && ${MAKE} clean
+
+.INTERMEDIATE: xxpression.gdx
diff --git a/support/splint/examples/xxpression/xtoks.sty b/support/splint/examples/xxpression/xtoks.sty
new file mode 100644
index 0000000000..2dc5abafb4
--- /dev/null
+++ b/support/splint/examples/xxpression/xtoks.sty
@@ -0,0 +1,2 @@
+\prettywordpair{IDENTIFIER}{{$\langle$\rm identifier$\rangle$}}
+\prettywordpair{INTEGER}{{\bf int}}
diff --git a/support/splint/examples/xxpression/xxpression.sty b/support/splint/examples/xxpression/xxpression.sty
new file mode 100644
index 0000000000..422901f6da
--- /dev/null
+++ b/support/splint/examples/xxpression/xxpression.sty
@@ -0,0 +1,27 @@
+\def\optimization{5}
+
+\input yycommon.sty % general routines for stack and array access
+\input yymisc.sty % helper macros (stack manipulation, table processing, value stack pointers)
+\input yyinput.sty % input functions
+\input yyparse.sty % parser machinery
+\input flex.sty % lexer functions
+\input yyfaststack.sty % sped up stack access functions
+\input yyboth.sty % parser initializatio, optimization
+
+\def\yycomplain#1{\immediate\write16{#1}} % lexer errors
+
+\let\yylexreturn\yylexreturnregular
+\let\setflexstates\relax
+\let\parsernamespace\empty
+
+\genericparser
+ name: main,
+ ptables: ptab.tex,
+ ltables: ltab.tex,
+ tokens: xxpression.tok,
+ asetup: {},
+ dsetup: {},
+ rsetup: {},
+ optimization: \optimizeall;%
+
+\tomainparser
diff --git a/support/splint/examples/xxpression/xxpression.w b/support/splint/examples/xxpression/xxpression.w
new file mode 100644
index 0000000000..00834b4436
--- /dev/null
+++ b/support/splint/examples/xxpression/xxpression.w
@@ -0,0 +1,365 @@
+@q Copyright 2012-2014, Alexander Shibakov@>
+@q This file is part of SPLinT@>
+
+@q SPLinT is free software: you can redistribute it and/or modify@>
+@q it under the terms of the GNU General Public License as published by@>
+@q the Free Software Foundation, either version 3 of the License, or@>
+@q (at your option) any later version.@>
+
+@q SPLinT is distributed in the hope that it will be useful,@>
+@q but WITHOUT ANY WARRANTY; without even the implied warranty of@>
+@q MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the@>
+@q GNU General Public License for more details.@>
+
+@q You should have received a copy of the GNU General Public License@>
+@q along with SPLinT. If not, see <http://www.gnu.org/licenses/>.@>
+
+% The scheme for extracting token equivalences below does not use a
+% bootstrap parser, which would be easier.
+% To use a different parser (the `prologue' parser, \.{dyytab.tex} in
+% this case), some extra steps have to be inserted in
+% \.{yybootstrap.sty}. First, the token equivalence table for the `main'
+% parser (rather, for the `main' scanner) had to be loaded
+% (\.{yybootstrap.sty} usually relies on the tokens that are
+% `hard-coded' with the bootstrap parser). Second, it was necessary to
+% define \.{\\let\\yylexreturn\\yylexregular} to use the scanner. One
+% advantage of using a different parser is the ability to intermix token
+% definitions with grammar productions (the bootstrap mode macros in
+% \.{\\yyunion} will simply ignore the extra definitions).
+% Note also, that the `grammar rule' parser cannot be used in this
+% case since the token definitions as they are used in this file fit
+% the `prologue' parser syntax only (there are no semicolons at the
+% end of the definitions). A more elaborate scheme (similar to how the
+% typesetting of rules is set up) using several parsers can be used
+% instead.
+\newwrite\gindex
+\input limbo.sty
+\input dcols.sty
+\def\optimization{5}
+\newread\testeof
+\immediate\openin\testeof=\jobname.tok
+\ifeof\testeof % make the local token equivalence table
+ \def\drvname{bo}
+ \csname newwrite\endcsname\tokendefs
+ \let\nx\noexpand
+ \edef\tokendeffile{\jobname.tok} % where to put the token equivalence table
+ \edef\bstrapparser{dyytab.tex}
+ \def\bootstraplexersetup{%
+ \let\yylexreturn\yylexreturnregular
+ \bootstrapmodetrue
+ \input \drvname.tok % use token equivalence table to set the values of non-string tokens
+ % this has to be added if a non-bootstrap parser is used to
+ % extract token information (see the comments above)
+ }
+ \toks0{%
+ \input yycommon.sty % general routines for stack and array access
+ \input yymisc.sty % helper macros (stack manipulation, table processing, value stack pointers)
+ \input yyinput.sty % input functions
+ \input yyparse.sty % parser machinery
+ \input flex.sty % lexer functions
+ \input yyboth.sty % parser initialization, optimization
+ \input yyfaststack.sty
+ \input yystype.sty % scanner auxiliary types and functions
+ \input yyunion.sty % parser data structures
+ % the main parser
+ \let\parsernamespace\empty
+ % create token equivalence table (making, say, \tokenID the same as \csname token"identifier"\endcsname)
+ \input yybootstrap.sty
+ }
+\else
+ \toks0{%
+ \input yy.sty
+ \let\currentparsernamespace\parsernamespace
+ \let\parsernamespace\smallnamespace
+ \let\hostparsernamespace\smallnamespace
+ \input xtoks.sty
+ \let\parsernamespace\currentparsernamespace
+ }
+\fi
+\immediate\closein\testeof
+\the\toks0
+
+@**Parser file. \setupfootnotes
+This an enhanced parser for expressions. It takes
+advantage of the `symbolic term name' mechanism and extends the basic
+expression syntax.
+
+The top-level structure of the input file is an exact copy of the one
+for the expression parser.
+@s TeX_ TeX
+
+@(xxpp.yy@>=
+@G Switch to generic mode.
+%{@> @<Extended \.{expression} parser \Cee\ preamble@> @=%}
+ @> @<Bison options@> @=
+%union {@> @<Union of parser types@> @=}
+%{@> @<Extended \.{expression} parser \Cee\ postamble@> @=%}
+ @> @<Token and types ...@> @=
+%%
+ @> @<Parser productions@> @=
+%%
+@g
+
+@ The following is reproduced from the simple expression example.
+
+The \prodstyle{\%token-table} option is not merely a debugging help,
+as it is in the case of the `real' \bison\ parsers and cannot be
+omitted . The name table it is responsible for setting up is used as
+a set of keys for various associative arrays. Token declarations are
+parsed by a bootstrap parser during the \TeX\ processing stage to
+establish equivalences between the names kept in |yytname| and the
+macro names used internally by the parsers built by \bison. The reason
+this is necessary is not very complicated: either version of the token
+name can be used in the grammar while the `driver' program
+(\.{mkeparser.c}) only has access to the names in |yytname|. In
+general, this is important whenever the grammar uses a different set of
+token names from the lexer or when diagnostics messages are output. An
+important case is the symbolic name switch: before the rules can be
+listed to create the switch, the token numerical values must be
+known. If the parser is only aware of the |yytname| listed names and the
+grammar being parsed uses the `internal' names, the listing macros
+will fail. The array, |yytname| is used in a few functions inside the
+`driver', as well, so omitting this option would make building the
+parser impossible.
+@<Bison options@>=
+@G
+%token-table
+%debug
+%start value
+@g
+
+@ To continue the token name discussion, this parser uses internal
+names only but the |yytname| array contains a string equivalent of
+\prodstyle{IDENTIFIER}. Thus, bootstrapping is necessary. The beginning
+of this file contains a simple scheme for producing a token
+equivalence table.
+The typesetting of the tokens can be adjusted using \.{\\prettywordpair}
+macros (see the included \.{xtoks.sty} file for examples and the way
+\prodstyle{IDENTIFIER} is typeset).
+@<Token and types declarations@>=
+@G
+%token IDENTIFIER "identifier"
+%token INTEGER
+@g
+
+@ Here is the whole grammar, simply additive expressions with two
+levels of precedence. We have added `divide' and `subtract' operations.
+The use of \prodstyle{IDENTIFIER} instead of \.{"identifier"} below
+necessitates `harvesting' of token equivalences in \.{xxpression.tok}
+at the beginning of this file.
+\showlastactiontrue
+\input yynested.sty
+@<Parser productions@>=
+@G
+value:
+ expression[exp] {@> TeX_( "/yy0{/the/yy]exp[}" ); @=}
+;
+
+expression:
+ term {@> TeX_( "/yy0{/the/yy]term[}" ); @=}
+| expression[exp] add_op term {@> @<Add a term@> @=}
+;
+
+term:
+ atom {@> TeX_( "/yy0{/the/yy]atom[}" ); @=}
+| term mult_op atom {@> @<Make a term@> @=}
+;
+@t}\vb{\inline\flatten}{@>
+mult_op:
+ '*' {@> TeX_( "/yy0{/multiply}" ); @=}
+| '/' {@> TeX_( "/yy0{/divide}" ); @=}
+;
+
+add_op:
+ '+' {@> TeX_( "/yy0{}" ); @=}
+| '-' {@> TeX_( "/yy0{-}" ); @=}
+;
+@t}\vb{\resetf}{@>
+atom:
+@t}\vb{\inputboundary{\boundarylower}}{@>
+ IDENTIFIER[id] {@> @<Assign variable value to an atom@> @=}
+| INTEGER[int] {@> @<Assign value to an atom@> @=}
+| '(' expression[exp] ')' {@> TeX_( "/yy0{/the/yy]exp[}" ); @=}
+;
+@t}\vb{\inputboundary{\boundaryupper}}{@>
+@g
+
+@ @<Add a term@>=
+ @[TeX_( "/tempca/the/yy]exp[/relax" );@]@;
+ @[TeX_( "/tempcb/the/yy]term[/relax" );@]@;
+ @[TeX_( "/advance/tempca by /the/yy]add_op[/tempcb" );@]@;
+ @[TeX_( "/yy0{/the/tempca}" );@]@;
+
+@ @<Make a term@>=
+ @[TeX_( "/tempca/the/yy]term[/relax" );@]@;
+ @[TeX_( "/tempcb/the/yy]atom[/relax" );@]@;
+ @[TeX_( "/the/yy]mult_op[/tempca by /tempcb" );@]@;
+ @[TeX_( "/yy0{/the/tempca}" );@]@;
+
+@ @<Assign variable value to an atom@>=
+ @[TeX_( "/getsecond{/yy]id[}/to/toksa" );@]@;
+ @[TeX_( "/toksb/expandafter/expandafter/expandafter{/expandafter" );@]@;
+ @[TeX_( " /number/csname/the/toksa/endcsname}" );@]@;
+ @[TeX_( "/yy0{/the/toksb}" );@]@;
+
+@ @<Assign value to an atom@>=
+ @[TeX_( "/getfirst{/yy]int[}/to/toksa" );@]@;
+ @[TeX_( "/yy0{/the/toksa}" );@]@;
+
+@ \Cee\ preamble. In this case, there are no `real' actions that our
+grammar performs, only \TeX\ output, so this section is empty.
+
+@<Extended \.{expression} parser \Cee\ preamble@>=
+
+@ \Cee\ postamble. It is tricky to insert function definitions that use \bison's internal types,
+as they have to be inserted in a place that is aware of the internal definitions but before said
+definitions are used.
+
+@<Extended \.{expression} parser \Cee\ postamble@>=
+#define YYPRINT(file, type, value) @[yyprint (file, type, value)@]
+ static void yyprint (FILE *file, int type, YYSTYPE value){}
+
+@ Union of types. Empty as well.
+
+@<Union of parser types@>=
+
+@**The lexer file. The scanner for the grammar above is the same as
+for a regular expression parser. Identifiers are interpreted as
+variable names that expand to appropriate values.
+%\checktabletrue
+@(xxpl.ll@>=
+@G
+ @> @<Lexer definitions@>@=
+%{@> @<Lexer \Cee\ preamble@> @=%}
+ @> @<Lexer options@> @=
+%%
+ @> @<Regular expressions@> @=
+%%
+@g
+
+@ @<Lexer definitions@>=
+@G
+letter [_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ]
+id {letter}({letter}|[-0-9])*
+int [0-9]+
+@g
+
+@ @<Lexer \Cee\ preamble@>=
+
+#include <stdint.h>
+#include <stdbool.h>
+
+ void define_all_states( void ){}
+
+@ @<Lexer options@>=
+@G
+%option bison-bridge
+%option noyywrap nounput noinput reentrant
+%option noyy_top_state
+%option debug
+%option stack
+%option outfile="xxpl.c"
+@g
+
+@ @<Regular expressions@>=
+ @<Scan white space@>@;
+ @<Scan identifiers@>@;
+
+@ White space skipping.
+\traceparserstatestrue
+\tracestackstrue
+\tracerulestrue
+\traceactionstrue
+\tracelookaheadtrue
+\traceparseresultstrue
+\tracebadcharstrue
+\yyflexdebugtrue
+%
+\traceparserstatesfalse
+\tracestacksfalse
+\tracerulesfalse
+\traceactionsfalse
+\tracelookaheadfalse
+\traceparseresultsfalse
+\tracebadcharsfalse
+\yyflexdebugfalse
+@<Scan white space@>=
+@G
+[ \f\n\t\v] {@> @[TeX_( "/yylexnext" );@]@=}
+@g
+
+@ @<Scan identifiers@>=
+@G
+{id} {@> @[TeX_( "/yylexreturnval{IDENTIFIER}" );@]@=}
+{int} {@> @[TeX_( "/yylexreturnval{INTEGER}" );@]@=}
+[-+*/()] {@> @[TeX_( "/yylexreturnchar" );@]@=}
+. {@> @[@<React to a bad character@>@]@=}
+@g
+
+@ @<React to a bad character@>=
+ @[TeX_( "/iftracebadchars" );@]@;
+ @[TeX_( " /yycomplain{invalid character(s): /the/yytext}" );@]@;
+ @[TeX_( "/fi" );@]@;
+ @[TeX_( "/yylexreturn{$undefined}" );@]@;
+
+@**Generating symbols. This is the routine that creates symbolic name
+assignments for the grammar. The internal mechanics of creating such
+assignments is inside \.{xymmap.sty} which should be consulted if
+any adjustments are needed.
+@(xymbols.txx@>=
+@G
+\def\optimization{5} % this can be omitted
+\input yy.sty
+\input xymmap.sty
+\end
+@g
+
+@**Test file. The test file includes a handy list of debugging options
+that can be activated to see the inner workings of the parser and
+scanner routines.
+@(test.txx@>=
+@G
+\input xxpression.sty
+
+\iftrue
+ \tracedfatrue
+ \traceparserstatestrue
+ \tracestackstrue
+ \tracerulestrue
+ \traceactionstrue
+ \tracelookaheadtrue
+ \traceparseresultstrue
+ \tracebadcharstrue
+ \yyflexdebugtrue
+ \yyinputdebugtrue
+\fi
+
+\newread\ssw
+\immediate\openin\ssw = xymbols.sns
+\ifeof\ssw
+\else
+ \immediate\closein\ssw
+ \input xymbols.sns
+ \let\yysymswitch\symswitch
+ \let\yysymcleanup\symswitchoff
+\fi
+
+\def\varone{10}
+\def\expression{1 + 3 * ( 5 + 7 ) + varone - 10}
+
+\basicparserinit\expandafter\yyparse \expression \yyeof\yyeof\endparseinput\endparse
+
+{
+ \newlinechar`^^J
+ \immediate\write16{^^Jexpression: \expression^^Jthe value: \the\yyval^^J^^J}
+}
+
+\bye
+@g
+
+@**Index.
+\let\inx\inxmod
+\let\fin\finmod
+\immediate\closeout\exampletable
+\def\Tex{\TeX\ output}
+\def\TeXx{\TeX\ output}
diff --git a/support/splint/examples/xxpression/xymmap.sty b/support/splint/examples/xxpression/xymmap.sty
new file mode 100644
index 0000000000..3d36bae920
--- /dev/null
+++ b/support/splint/examples/xxpression/xymmap.sty
@@ -0,0 +1,155 @@
+% Copyright 2012-2015, Alexander Shibakov
+% This file is part of SPLinT
+%
+% SPLinT is free software: you can redistribute it and/or modify
+% it under the terms of the GNU General Public License as published by
+% the Free Software Foundation, either version 3 of the License, or
+% (at your option) any later version.
+%
+% SPLinT 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 SPLinT. If not, see <http://www.gnu.org/licenses/>.
+
+% assigning symbolic names to production terms (this is only a demonstration)
+
+\def\makesymbols{%
+ \restorecslist{symbols}\yyunion
+ \toksa{}\toksb{}\toksc{}\toksd{}%
+ \the\symstream
+ \global\newsymswitch\newsymswitch
+}
+
+% symbolic reference name parser
+
+\newtoks\newsymswitch
+\newread\symnames
+
+\newwrite\symbolicswitch
+
+\def\inamespace{[intermediate]}%
+\let\parsernamespace\inamespace
+\let\hostparsernamespace\mainnamespace % purely for testing reasons
+\pinittoks{}%
+\input ptab.tex % this is the enhanced expression parser
+\edef\tointermediateparser{%
+ \noexpand\savefullstate % unnecessary
+ \noexpand\savefullstateextra % unnecessary
+ \let\noexpand\parsernamespace\noexpand\inamespace % switch to the new namespace
+ \the\pinittoks % restore all the tables, tokens and constants, and stacks
+ \let\noexpand\getcurrentparser\noexpand\tointermediateparser
+}%
+\settokens % this simply assigns values to tokens where the name of each token is taken out of yytname ...
+\input xxpression.tok % this will set up token equivalences in the namespace above ...
+ % those are the values gleaned during the bootstrapping stage.
+ % in the general case, one needs to run a bootsrapping (or similar)
+ % parser to extract the token information.
+ % this is only needed if the bison file contains a definition that
+ % lists both the idenitifier and a string as names for a token but the grammar
+ % uses the identifier version at least once:
+ % (say, %token IDENTIFIER "identifier"; is used as well as
+ % ...
+ % token:
+ % IDENTIFIER { ... }
+ % ...
+ % see the included xxpression.w)
+\optimizeall % this is necessary for correct rule listing in the output stage:
+ % otherwise \fgetelemof will use the current value of the \yy... token registers which
+ % will hold the values of the full parser that is loaded next
+\newsymswitch{}%
+\listrules % ... to be used while listing the rules
+% note that we do not bother to set up a lexer for this parser (even though we already have one and the
+% \optimizeall macro above will create a set of associative tables for it---this is merely an unwanted
+% sideffect); after the rules have been listed, the intemediate parser in no longer needed.
+%\showthe\newsymswitch
+\def\fullnamespace{[full]}% this is the parser that parses the bison grammar from a raw
+ % bison file; it can play a role of the bootstrap parser for
+ % the grammar above, as well, since its input is a complete
+ % bison file; note that it cannot be a bootstrap parser for itself
+ % because it will reject any input that does not form a complete
+ % bison file; this is why a special grammar was created that includes
+ % only a small subset of the full set of productions (%token rules only) to
+ % serve as a bootstrap grammar.
+%\tomainparser % this will set the value of \setflexstates, so that, if the lexer initialization
+ % below is omitted, the \setflexstates macro can still be used to correctly set the
+ % lexer states
+\let\parsernamespace\fullnamespace
+\pinittoks{}% %%
+\input cweb/fyytab.tex
+\input cweb/ltab.tex % we reinitialize the lexer out of necessity:
+ % \collecttokennames needs to know how to switch
+ % between two lexer/parser environments so both states
+ % have to be preserved; if one is sure that
+ % grammar_declarations will not used in the productions
+ % part of the file, this can simply be disabled
+\settokens
+\setflexstates % the main lexer can be reused in this case; the states still need to be set up
+\input \drvname.tok % set up the tokens for the bison grammar parser
+\newparserstate
+\newlexerstate
+\newlexerstateextra
+%
+\setnulstack{yyirulestack}%
+%
+\edef\tofullparser{%
+ \noexpand\savefullstate
+ \noexpand\savefullstateextra
+ \let\noexpand\parsernamespace\noexpand\fullnamespace % switch to the new namespace
+ \the\pinittoks % restore all the tables, tokens and constants, and stacks
+ \let\noexpand\getcurrentparser\noexpand\tofullparser
+}%
+\optimizeall
+\toksa{\input xxpp.y}% start building the parsing command
+ % this has to be done carefully, since all the characters input
+ % from the parser file have to be `harmless', so their categories
+ % have to be reset; in order for the parser to be able to stop,
+ % appropriate command sequences would have to be inserted at the end
+\toksb{\yyeof\yyeof\endparseinput\endparse
+ \let\yyinput\yyinputold
+ \undoascii
+ \ifyyparsefail
+ \errmessage{could not process symbols}%
+ \else
+ \symstream\table
+ \tointermediateparser % the parsing is finished, so we have two very long strings:
+ % o the rules of the hosted parser ([intermediate])
+ % o the rules of the same parser just parsed
+ % these two strings are used to associate the symbolic names
+ % (which only exist in the second list) to the rule numbers and
+ % the relevant terms;
+ % switching the parse namespace above is done so that the term
+ % indices are looked up in the appropriate table
+ %\showthe\table
+ \makesymbols % list all the rules deriving explicit non-terminals
+ %\showthe\newsymswitch
+ \setexplicitinlinerules\newsymswitch % process implicit non-terminals resulting from inline actions
+ %\showthe\newsymswitch
+ \makesymrefs\newsymswitch % create the switch to be used by the parser (\yyparse)
+ \fi
+}%
+% build the command to create the symbolic name switch
+\toksc{\tofullparser\parserinit
+ \let\yyinputold\yyinput
+ \let\yyinput\yyinputtrivial % a demo of a stripped down, slightly faster input routine
+ \doascii{11}\expandafter\yyparse}%
+\edef\next{\the\toksc\the\toksa\relax\the\toksb}\next % \relax is to stop \TeX\ from trying to expand the file name further
+ % it is not flagged as a bad character because it is part of the epilogue
+\immediate\openout\symbolicswitch=\jobname.sns
+%
+\edef\next{\setsncommands{\def\noexpand\symswitch\hashletter1{\harmlesscomment^^J\noexpand\ifcase\hashletter1\relax
+ \harmlesscomment^^J\the\setsncommands
+ \noexpand\else\harmlesscomment^^J%
+ \noexpand\fi\harmlesscomment^^J%
+ }\harmlesscomment^^J^^J}}\next
+\edef\next{\unsetsncommands{\def\noexpand\symswitchoff\hashletter1{\harmlesscomment^^J\noexpand\ifcase\hashletter1\relax
+ \harmlesscomment^^J\the\unsetsncommands
+ \noexpand\else\harmlesscomment^^J%
+ \noexpand\fi\harmlesscomment^^J%
+ }\harmlesscomment^^J^^J}}\next
+{\newlinechar=`\^^J \immediate\write\symbolicswitch{\the\setsncommands\the\unsetsncommands}}%
+\immediate\closeout\symbolicswitch
+\tomainparser % go back to the main parser
+