diff options
author | Norbert Preining <norbert@preining.info> | 2019-09-02 13:46:59 +0900 |
---|---|---|
committer | Norbert Preining <norbert@preining.info> | 2019-09-02 13:46:59 +0900 |
commit | e0c6872cf40896c7be36b11dcc744620f10adf1d (patch) | |
tree | 60335e10d2f4354b0674ec22d7b53f0f8abee672 /support/splint/examples |
Initial commit
Diffstat (limited to 'support/splint/examples')
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 + |