% Copyright 2012-2022, 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 . % 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{\ldintfont#7#8\ldrlap{${}_{#1}$}$\yystringempty{#2}{}{\lddisplayintsuffix{#2}}$}}% } \let\ldrlap\rlap \let\ldintfont\rm \def\lddisplayintsuffix#1{% \expandafter\ifx\csname ldspecialsuffixdisplay#1\endcsname\relax \,\hbox{\tt#1}% \else \csname ldspecialsuffixdisplay#1\endcsname \fi } \def\ldspecialsuffixdisplayK{{}\cdot2^{10}} %\def\ldspecialsuffixdisplayK{\,\hbox{\rm Kb}} \def\displayintegerws#1#2#3#4#5#6#7{% {\def\ldintsep{$\,$}\hbox{\rm#6#7\rlap{${}_{\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 \expandafter\hidecs\expandafter{\ldunion} % inhibit expansion so that fewer \noexpand are necessary \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-parser:restash}\ldunion % extract the stash and mark lhs of assignments \setprodtable % use \bison's parser typesetting definitions \the\ldcmds \restorecslist{ld-display}\ldunion \setprodtable % use \bison's parser typesetting definitions \restorecs{ld-display}{\anint\bint\hexint} % ... except for integer typesetting \the\ldcmds \the\lddisplay }% }% \yycontinue } % to make it possible to write {...} without changes \def\yyinputldgroup#1{% \yyinput\{#1\}% }