% Copyright 2012-2024, 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 . % finish parser initialization \let\yylexreturn\yylexreturnregular \genericparser name: main, ptables: cweb/gyytab.tex, ltables: cweb/ltab.tex, tokens: bo.tok, asetup: {}, dsetup: \newlexerstateextra\newparserstateextra, rsetup: {}, optimization: \optimizeall;% % prologue parser \genericparser name: prologue, ptables: cweb/dyytab.tex, ltables: cweb/ltab.tex, tokens: bo.tok, asetup: {}, dsetup: \newlexerstateextra\newparserstateextra, rsetup: {}, optimization: \optimizeall;% % flex parser \genericparser name: flex, ptables: cweb/fiptab.tex, ltables: cweb/filtab.tex, tokens: fo.tok, asetup: {}, dsetup: {}, rsetup: {}, optimization: {};% optimized by the driver (--optimize-tables, --optimize-actions) % flex regex parser \genericparser name: flexre, ptables: cweb/reptab.tex, ltables: cweb/filtab.tex, tokens: fo.tok, asetup: {}, dsetup: {}, rsetup: {}, optimization: {};% optimized by the driver (--optimize-tables, --optimize-actions) % flex section 2 parser \genericparser name: flextwo, ptables: cweb/raptab.tex, ltables: cweb/filtab.tex, tokens: fo.tok, asetup: {}, dsetup: \newparserstateextra, rsetup: {}, optimization: {};% optimized by the driver (--optimize-tables, --optimize-actions) % flex section 1 parser \genericparser name: flexone, ptables: cweb/ddptab.tex, ltables: cweb/filtab.tex, tokens: fo.tok, asetup: {}, dsetup: {}, rsetup: {}, optimization: {};% optimized by the driver (--optimize-tables, --optimize-actions) \let\flexpseudonamespace\flexnamespace \let\flexpseudorenamespace\flexrenamespace % parser for term names: this is not really a great idea in itself but rather an % illustration of what is possible \genericparser name: small, ptables: cweb/small_tab.tex, ltables: cweb/small_dfa.tex, tokens: {}, asetup: {}, dsetup: {}, rsetup: \let\returnexplicitspace\ignoreexplicitspace, % ignore spaces in names optimization: \optimizeall;% \tomainparser % stage two macros: parsing % \flex parser stack % section 1 parser \def\flexoneparserinit{% \yylessusedtrue \floption@sensetrue } \def\flexoneparserdatainit{% \table{}% } % regular expression parser \def\flexreparserinit{% \yyBEGIN{SECT2}% \flin@ruletrue \yylessusedtrue } \def\flexreparserdatainit{% \table{}% } % section 2 parser \def\flexparserinit{% \yyBEGIN{SECT2}% \def\flbracelevel{0}% \yylessusedtrue } \def\flexparserdatainit{% \table{}% \let\secttwoprefix\empty } % output parsed tables to a file \long\def\saveoutputcode#1#2#3{% #1 is the output code (will be expanded by \write) % #2 is the output stream % #3 is the preamble (will be expanded by \write) \newlinechar=`^^J% \immediate\write#2{% \harmlesscomment \parsernamespace::parsed table #3:^^J#1^^J^^J% \harmlesscomment \parsernamespace::stashed stream:^^J\yystash^^J^^J% TODO: this just displays the name for now; \harmlesscomment \parsernamespace::format stream:^^J\yyformat^^J^^J% TODO: this just displays the name for now; }% } % display parsed tables and streams \def\displayparsedoutput#1{% \ifchecktable \ferrmessage{parsed table: \the#1^^J^^J% stashed stream: \yystash^^J^^J% TODO: this just displays the name for now; format stream: \yyformat}% TODO: this just displays the name for now; \fi } % display raw input \def\displayrawtable{% \ifsaveparseoutput {\newlinechar=`^^J\immediate\write\exampletable{^^J\harmlesscomment table before parsing:^^J\the\Binputtoks}}% \fi \ifchecktable \ferrmessage{table before parsing: \the\Binputtoks}% \fi } \def\displayorsavefulloutput#1#2{% \ifchecktable \ferrmessage{table after processing: \the#1}% \fi \ifsaveparseoutput {\newlinechar=`^^J\immediate\write#2{^^J\harmlesscomment processed table:^^J\the#1}}% \fi } % the macros below make sure that (almost) none of the command sequences produced by the parser are % expandable; this makes debugging easier \def\saveflextable#1{{% \hidecslist\cwebstreamchars \restorecslist{flexparser-debug}\yyflunion \expandafter\saveoutputcode\expandafter{\the\table}\exampletable{#1}% }} \def\savebisontable#1{{% \hidecslist\cwebstreamchars \restorecslist{parser-debug}\yyunion \expandafter\saveoutputcode\expandafter{\the\table}\exampletable{#1}% }} % stage two parsing macros \def\preparsebisongrammar{% \let\postparse\postparsebisongrammar \tomainparser \displayrawtable % do this after the parse namespaces are setup \basicparserinit \bisonparserinit \bisonparserdatainit \yyparse } \def\preparsebisonprologue{% \let\postparse\postparsebisonprologue \toprologueparser \displayrawtable % do this after the namespaces are setup \basicparserinit \bisonparserinit \bisonparserdatainit \yyparse } \def\preparseflexone{% \let\postparse\postparseflexone \toflexoneparser \displayrawtable % do this after the namespaces are setup \basicparserinit \flexoneparserinit \flexoneparserdatainit \yyparse } \def\preparseflextwo{% \let\postparse\postparseflextwo \toflextwoparser \displayrawtable % do this after the namespaces are setup \basicparserinit \flexparserinit \flexparserdatainit \yyparse } \def\preparsefallback#1{% \let\postparse\relax \message{#1}% } % stage three, postprocessing and typesetting \newif\ifparseverbose \def\postparsegeneric#1{% \ifyyparsefail \yybreak{% \ifparseverbose\ferrmessage{#1 parsing failed.}\fi \parserreset }% \else \yybreak{% \ifparseverbose\ferrmessage{#1 parsing successful.}\fi \ifsaveparseoutput\saveparsedtable{#1}\fi \finishlist\yystash \finishlist\yyformat \typesetparsedtables }% \yycontinue } \def\parserreset#1\par{% \yyparsefailfalse % in case the next pass is a \relax \let\postparse\empty % ... \expandafter\skiptolsection\the\Binputtoks\par% start the next parsing pass, skip \6\hbox{} trash } \def\postparsebisongrammar{% \let\saveparsedtable\savebisontable \let\typesetparsedtables\typesetalltables \postparsegeneric{(grammar)}% } \def\postparsebisonprologue{% \let\saveparsedtable\savebisontable \let\typesetparsedtables\typesetalltables \postparsegeneric{(prologue)}% } \def\postparseflexone{% \let\saveparsedtable\saveflextable \let\typesetparsedtables\typesetfsonetables \postparsegeneric{(section 1)}% } \def\postparseflextwo{% \let\saveparsedtable\saveflextable \let\typesetparsedtables\typesetfstwotables \postparsegeneric{(section 2)}% } \fillpstack{}{% \preparsebisongrammar \preparsebisonprologue {\preparsefallback{**}}% \relax % this \relax is necessary so that the braces above % are not stripped by \poppstack } \fillpstack{b}{% \preparsebisongrammar \preparsebisonprologue \preparseflexone {\preparsefallback{..}}% \relax % this \relax is necessary so that the braces above % are not stripped by \poppstack } \fillpstack{fs1}{% \preparseflexone \preparseflextwo {\preparsefallback{==}}% \relax % this \relax is necessary so that the braces above % are not stripped by \poppstack } \fillpstack{fs2}{% \preparseflextwo {\preparsefallback{--}}% \relax % this \relax is necessary so that the braces above % are not stripped by \poppstack } \fillpstack{t}{% \relax } % stage 3.5 macros: typesetting \def\tlskip{\z@} \def\tfskip{\parindent} \newif\ifchecktrailingstash \def\typesetalltables{% \begingroup \displayparsedoutput\table \extractprodtableinfo \setprodtable \executeast{\postoks{}\pushothertables}% \parindent1em \checkforpropertable{\executelist\aststream}% \tabskip\tfskip \ruletableset {\edef\next{\write\auxstream{\nx\nx\nx\lodimens{\the\gaglue}{}{}{}\harmlesscomment}}\next}% \finishastoutput % debugging and stash cleanup \expandafter % export the value of the alignment glue \endgroup \expandafter\gaglue\the\gaglue\relax } \def\typesetfstwotables{% \begingroup \displayparsedoutput\table \extractregextableinfo % preprocess the AST for section 2 \setregextable % activate AST control sequences for section 2 \executeast{}% execute AST (the output will be collected in the \aststream list) \regextableset % typeset the contents \finishastoutput % debugging and stash cleanup \endgroup } \def\typesetfsonetables{% \begingroup \displayparsedoutput\table \extractregextableinfo \setregexdeftable \executeast{}% execute AST (the output will be collected in the \aststream list) \regexdeftableset \finishastoutput % debugging and stash cleanup \endgroup } \def\executeast#1{% #1 is an optional postprocessing action % execute AST (the output will be collected in the \aststream list) \initlist\aststream \the\table\relax #1% \finishlist\aststream } \def\finishastoutput{% % possibly output debugging information, % clean up and typeset any remaining stash \displayorsavefulloutput\table\exampletable \ifchecktrailingstash \ferrmessage{remaining stash: \yystash}% TODO: this just displays the name for now; \fi \consumefulllist\yystash\to\toksa \cleanstash\stripstash\checkforccode \ifchecktrailingstash \ferrmessage{stash after cleaning: \the\toksa}% \fi \ifnum\wd0>\z@ %\ifchecktable % \showboxdepth=1000 \showboxbreadth=1000 \showbox0 %\fi % currently testing for nontrivial leftover stash involves packaging the stash material % into a \vbox; as a result, the stash containing ${}{}$\hbox{} will have a nonzero length % which is why the test below is necessary \ifnum\ht0>\z@ \indent\boxstash \fi \fi } \let\extractprodtableinfo\extractprodrefs % record the rules to be used later as a reference \let\extractregextableinfo\empty % we do not preprocess the regex table % setting the rule table: cross-section alignment and other effects are applied here; % in order to produce the proper line skips before and after \unvbox, the rules followed by % \TeX\ while adding an \halign to a vertical list have to be reproduced explicitly \newdimen\gaglue % the width of the action box of the last alignment \def\ruletableset{% \par \vskip-\baselineskip \ifx\gatoks\relax \else \expandafter\appendtolist\expandafter\aststream\expandafter{\gatoks}% \finishlist\aststream \fi \setbox0\vbox\expandafter{\expandafter \null\expandafter\prevdepth\the\prevdepth \halign \ifpropertable to \hsize \fi {\hbox to 2em{##\/$\,${\rm:}\hss}\hfil\tabskip\z@&\setallterms{##}&##\hfil\tabskip0pt plus1fil&% \toksa{}##\makestashbox\hfil\tabskip\tlskip\cr \executelist\aststream } \expandafter }\expandafter \unvcopy\expandafter0\expandafter \prevdepth\the\prevdepth\relax \setbox\z@=\vbox{\unvbox\z@ \setbox\z@=\lastbox % set the alignment dimension \hbox{\unhbox\z@ \unskip\setbox\z@=\lastbox\expandafter}\expandafter}\expandafter\gaglue\the\wd\z@ } \def\setallterms#1{\setbox\z@=\hbox{\it#1}\ifsquashterms\hbox to0pt{\unhbox\z@\hss}\else\unhbox\z@\fi\hfil} % typesetting the scanner automaton rules \def\regextableset{% \par \vskip-\baselineskip \setbox0 \vbox\expandafter{\expandafter \null\expandafter\prevdepth\the\prevdepth \halign to\hsize {##\hfil\tabskip0 pt plus1fil\ &\relax\tabskip\tlskip\toksa{}##\makestashbox\hfil\cr \executelist\aststream }% \expandafter }\expandafter \unvbox\expandafter0\expandafter \prevdepth\the\prevdepth\relax } % typesetting named regular expression definitions \def\regexdeftableset{% \par \vskip-\baselineskip \setbox0\vbox\expandafter{\expandafter \null\expandafter\prevdepth\the\prevdepth \halign to\hsize {\hskip\parindent##\hfil\tabskip0 pt plus1fil\ &\relax\tabskip\tlskip\tt##\hfil\cr \executelist\aststream }% \expandafter }\expandafter \unvbox\expandafter0\expandafter \prevdepth\the\prevdepth\relax } % recording alignment layout: the gaglue, etc. \def\yyuniontag{\auxunionctl} \defp\tablorunionctl{}% sequence to activate/deactivate/take other action for % tablor set of macros \defc\tablorunionctl{% \restorecslist{aux:global:tablors}\tablorunion } \savecs{aux:global:activate}\tablorunionctl \defc\tablorunionctl{% \restorecslist{aux:global:tablors:neutral}\tablorunion } \savecs{aux:global:deactivate}\tablorunionctl \defc\tablorunionctl{% this command should not make any page material contributions \message{tablors...}% } \savecs{aux:global:preend}\tablorunionctl \defc\tablorunionctl{% writing a header, etc. \message{tablors...}% \toksa\expandafter{\tablorunion}% \immediate\write\auxstream{\harmlesscomment\the\toksa}% } \savecs{aux:global:prestart}\tablorunionctl \yyuniondeclare\tablorunion{aux:global:tablors} \defp\lodimens#1#2#3#4{} \toyyunion{aux:global:tablors:neutral} \defc\lodimens#1#2#3#4{}% define this to set the layout for tables on a given page \toyyunion{aux:global:tablors} % quick and dirty global alignment: the size of the last box (and those in between) % can be chosen automatically after one pass and read in for the final pass; % in the future this will be the default implementation; for now, the inelegant % solution below works as well. \def\setglobalalignrules#1{% \def\gatoks{% \omit\hfil&\omit\hfil&\omit\hfil&\omit\hfil\hbox to #1{\hfil}\cr \noalign{\vskip-\baselineskip}% %\noalign{\centerline{$\diamond$}} }% } \setglobalalignrules{3 in}% % to align all the actions across the document, comment out the next line \let\gatoks\relax \def\checkforccode{% \setbox0=\vbox{\setlazyc\the\toksa}% } \def\setlazyc{% \hidecs{\1\4\5\6\8}% } \newif\ifpropertable \def\checkforpropertable#1{{% checking if there is any table material % this is a hack to avoid underfull boxes when there is no actual alignment material in % \halign to \hsize \hbadness\@M \let\noalign\trivialnoalign \let\omit\relax \setbox\z@=\vbox{ \halign {\eatone{##}&\eatone{##}.&\eatone{##}&\eatone{##}\cr #1% }% }% \ifnum\wd\z@>\z@ \aftergroup\propertabletrue \else \aftergroup\propertablefalse \fi }} \long\def\trivialnoalign#1{} % macros for processing \Cee\ mode material \newif\ifchecktrim %\long\def\buildstash#1{\toksa\expandafter{\the\toksa#1}} % = stashed \def\cleanstash{% \ifchecktrim\ferrmessage{collected stash: \the\toksa}\fi \expandafter\cleanst@sh\the\toksa\packagebox} \def\cleanst@sh{\let\6\testsbox\setbox0=\vbox\bgroup} \def\testsbox{% \ifmmode \let\next\relax \else \egroup \ifnum\wd\z@>\z@ \ifnum\ht\z@>\z@ \let\next\scoopupstash \else \let\next\rebuildstash \fi \else \let\next\rebuildstash \fi \fi \next } \long\def\rebuildstash#1\packagebox{\toksa{#1}\cleanstash} \long\def\scoopupstash#1\packagebox{} \def\packagebox{\egroup\ifnum\wd0>\z@\else\toksa{}\fi} \def\stripstash{% \ifchecktrim\ferrmessage{before trimming: \the\toksa}\fi \def\6{}\expandafter\stripst@sh\expandafter\ignorespaces\the\toksa\6\str@pst@sh} \def\stripst@sh{\toksa{}\stripst@shi} \long\def\stripst@shi#1\6{% \toksb{#1}\futurelet\next\str@pst@sh } \def\str@pst@sh{% \ifx\next\str@pst@sh \iftrailingreturn \striptrim \fi \concat\toksa\toksb \iftrailingreturn % not done yet \let\next\stripagain \else \let\next\eatone \fi \trailingreturnfalse \else \edef\next{\toksa{\the\toksa\the\toksb\noexpand\6}}\next \def\next{\stripst@shi\relax\ignorespaces}% \trailingreturntrue \fi \next } \def\stripagain#1{\stripstash} \newif\iftrailingreturn \def\striptrim{% \ifchecktrim\ferrmessage{trimming: \the\toksb}\fi \edef\next{\the\toksb}% \expandafter\striptr@m\the\toksb\relax\end } \def\striptr@m #1% \relax (from last \stripst@shi) #2% \ignorespaces (from last \stripst@shi) % intervening spaces #3% \relax #4% ? \end{% % \toksc{#3#4}\showthe\toksc % \setbox\z@\vbox{ #3#4}% \ifnum\wd\z@=\z@ \expandafter\trimreturn\the\toksa\end \toksb{}% \else \ifnum\ht\z@=\z@ \expandafter\trimreturn\the\toksa\end \toksb{}% \else \trailingreturnfalse \fi \fi } \def\trimreturn#1\6\end{% \toksa{#1}% } \def\boxstash{% \ifchecktrim\ferrmessage{stash contents: \the\toksa}\fi $\vtop{\activateinlinec\tabskip\z@\halign{\strut\ignorespaces##\hfil\cr\relax\the\toksa\crcr}}$} \def\makestashbox{\cleanstash\stripstash\boxstash} \newbox\indentbox \def\activateinlinec{% \setbox\indentbox=\hbox{}% \def\1{\setbox\indentbox\hbox{\box\indentbox\hbox to 3em{\hfil}}}% \def\2{\setbox\indentbox\hbox{\box\indentbox\hbox to -3em{}}}% \def\4{\hbox to -3em{}}% \let\5\ignorespaces % so that @+ does not produce a space \def\6{% \edef\setindentbox{% \setbox\indentbox\hbox to\the\wd\indentbox{\noexpand\hfil}% \copy\indentbox\ignorespaces }% \expandafter\crcontainer\setindentbox }% \def\7{% \edef\setindentbox{% \setbox\indentbox\hbox to\the\wd\indentbox{\noexpand\hfil}% \copy\indentbox\ignorespaces }% \expandafter\crcontainerspread\setindentbox }% \def\8{\hskip-1em}% \let\$\prodterm } \def\crcontainer{\cr} \def\crcontainerspread{\cr\noalign{\yskip}} % rough version of the term typesetting \def\prodterm{% \futurelet\next\analyzepterm } \def\analyzepterm{% \ifx\next\$% \let\next\pr@dterm \else \ifcat\noexpand\next0% \let\next\pr@dterm \else \ifcat\noexpand\next a% \def\next{\hbox{$\Upsilon$}}% TODO: look for an identifier \else \let\next\oldmathS% TODO: one more category: control sequence for cases like \$\\{identifier} \fi \fi \fi \next } \def\pr@dterm#1{% \ifx#1\$% \def\next{\hbox{$\Upsilon$}}% \else \if\noexpand#1[% \let\next\seeksym \else \ifnum`#1<"3A\relax \ifnum`#1>"2F\relax % within ['0', '9'] \def\next{\seekno#1}% \else \def\next{\oldmathS#1}% \fi \else \def\next{\oldmathS#1}% \fi \fi \fi \next }% \let\$\prodterm \defreserved\${\prodterm} \def\seekno{\afterassignment\printterm\tempca}% \def\seeksym#1]{% \hbox{$\Upsilon\kern-1pt{}_{\def\\##1{\hbox{\sscmd\prodstyle{##1}}}\rm#1}$}} \def\seeksym#1]{% a better version of the above \hbox{$\ulcorner\def\\##1{##1}\let\.\\\let\|\\\let\ous\_\let\_\relax \edef\next{#1}\let\_\ous \hbox{\expandafter\prodstyle\expandafter{\next}}\urcorner$}} \def\printterm{\hbox{$\Upsilon\kern-1pt{}_{\number\tempca}$}}% % typesetting examples of \bison\ productions and \flex\ input in text \long\def\setproduction#1{% \def\termidxrank{5}% \def\headeridxrank{4}% \def\defidxrank{3}% \def\texcsidxrank{5}% \textproductionsetup \hbox{\strut}% \Binputtoks{\lsectionbegin{b}#1\yyeof\yyeof\endparseinput\endparse\postparse}% \the\Binputtoks\par% Stage two, start the parsing } \def\textproductionsetup{% \ninepoint \let\returnexplicitspace\splitexplicitspace \let\acharswitch\texcharadjust \let\onecharswitch\texcsadjust \let\extractprodtableinfo\empty % we do not preprocess the table \showlastactionfalse \let\actionfiller\empty \fillpstack{b}{% \preparsebisongrammar \preparsebisonprologue {\preparsefallback{**}}% \relax % this \relax is necessary so that the braces above % are not stripped by \poppstack }% } \def\splitexplicitspace{% \yyinput\{\}% } \def\texcharadjust{ `{% \yybyte{|}% \expandafter\yycp@\expandafter`\the\yybyte\relax \mkpurebyte \yyreturn }% _{% \yybyte{\_}% \expandafter\yycp@\expandafter`\the\yybyte\relax \mkpurebyte \yyreturn }% } \def\texcsadjust{ \n {% \yycp@=\n \mkpurebyte \yyreturn } \^^M {% \yyinput\{\}% } \' {% \expandafter\yyinput\benignescape'% } \\ {% \expandafter\expandafter\expandafter\yyinput\expandafter\benignescape\benignescape% } }% % Note that using \setspecialcharsfrom on the switches above is unnecessary (and, indeed, an error) % since the characters need to be read as is, with the category codes and all % production typesetting \def\beginprod{% \par \begingroup \b@ginprod } \long\def\b@ginprod#1\endprod{% \setproduction{#1}% \expandafter \endgroup \expandafter\gaglue\the\gaglue\relax % export the alignment width } \def\beginmprod{% $$ \vbox\bgroup \def\checkforpropertable##1{\propertablefalse} % so that the table is set to its natural width \b@ginmprod } \long\def\b@ginmprod#1\endmprod{% \setproduction{#1}% \egroup $$% } % centering productions: works for rule listing only (no token declarations, etc.) \def\begincprod#1\endcprod{{\def\tlskip{0 pt plus1fill}\let\tfskip\tlskip\beginprod#1\endprod}} % flex examples typesetting \long\def\setflex#1{% \def\fstatedefidxrank{3}% \def\fstateidxrank{4}% \def\fregexidxrank{5}% \textflexsetup \hbox{\strut}% \Binputtoks{\lsectionbegin{fs1}#1\yyeof\yyeof\endparseinput\endparse\postparse}% \the\Binputtoks\par% Stage two, start the parsing, the \par is expected by the \parserreset } \def\textflexsetup{% \ninepoint %\let\returnexplicitspace\splitexplicitspace \let\acharswitch\texcharadjust %\let\onecharswitch\texcsadjust \let\extractprodtableinfo\empty % we do not preprocess the table \fillpstack{fs1}{% \preparseflexone % TODO \preparseflextwo {\preparsefallback{**}}% \relax % this \relax is necessary so that the braces above % are not stripped by \poppstack }% } \def\beginflex{% \par \begingroup \catcode`\^^M=12 % \catcode`\#=12 % \b@ginflex% } \long\def\b@ginflex#1\endflex{% \setflex{#1}% \expandafter \endgroup \expandafter\gaglue\the\gaglue\relax % export the alignment width, TODO: set \gaglue in \flex } \let\endcprod\endgroup \let\endmprod\endgroup \let\endprod\endgroup % stringing all the manuals together (disabled for now) %\newwrite\lastpageinfo %\newread\testeof %\toksa\expandafter{\fin} %\edef\fin{\the\toksa\noexpand\savelastpagenumber} %\def\savelastpagenumber{% % \openout\lastpageinfo=\jobname.lpg% % \write\lastpageinfo{\def\noexpand\contentspagenumber{\number\pageno}\pageno=\noexpand\contentspagenumber \advance\pageno by 1}% % \write\lastpageinfo{\def\noexpand\secno{\number\secno}}% % \closeout\lastpageinfo %}