\input ptb-utils \_checkloaded{stacks} % Creates a macro stack, a stack which stores the definition of macros. % #1: The name of the stack. \def\createmacrostack#1{\_xp\def\csname mstack@#1@sp\endcsname{0}} % Gets the current pointer on a macro stack. % #1: The name of the stack. \def\macrostackpointer#1{\csname mstack@#1@sp\endcsname} % Pushes a macro onto a macro stack. % #1: The name of the stack. % #2: The control sequence to push onto the stack. \def\macrostackpush#1#2{% \_xp\edef\csname mstack@#1@sp\endcsname{\the\numexpr \csname mstack@#1@sp\endcsname + 1\relax}% \_xp\let\csname mstack@#1@def@\csname mstack@#1@sp\endcsname\endcsname=#2% \_xp\edef\csname mstack@#1@name@\csname mstack@#1@sp\endcsname\endcsname{\_mstrip#2}% } % Gets a macro on a stack. % #1: The name of the stack % #2: The index on the stack \def\macrostackget#1#2{% \csname mstack@#1@def@#2\endcsname% } % Decrements the stack pointer of a macrostack without restoring the definition of the control sequence. % #1: The name of the stack. \def\macrostackdecrement#1{% \_xp\let\csname mstack@#1@name@\csname mstack@#1@sp\endcsname\endcsname=\undefined% \_xp\let\csname mstack@#1@def@\csname mstack@#1@sp\endcsname\endcsname=\undefined% \_xp\edef\csname mstack@#1@sp\endcsname{\the\numexpr \csname mstack@#1@sp\endcsname - 1\relax}% } % Sets the control sequence from the top of the stack, without popping it. % #1: The name of the stack \def\macrostackset#1{% \_xplet{\csname\csname mstack@#1@name@\csname mstack@#1@sp\endcsname\endcsname\endcsname}{\csname mstack@#1@def@\csname mstack@#1@sp\endcsname\endcsname}% } % Pops a control sequence off of the top of the stack. % This restores the definition of the control sequence. % #1: The name of the stack. \def\macrostackpop#1{% \macrostackset{#1}% \macrostackdecrement{#1}% } % Peeks at the top of a macro stack. % #1: The name of the stack. % #2: A control sequence to put the definition of the control sequence at the top of the stack into. % #3: A control sequence to put the name of the control sequence at the top of the stack into. \def\macrostackpeek#1#2#3{% \_xp\let#2\csname mstack@#1@def@\csname mstack@#1@sp\endcsname\endcsname% \_xp\let#3\csname mstack@#1@name@\csname mstack@#1@sp\endcsname\endcsname% } \def\createstack#1{\_xp\def\csname stack@#1@sp\endcsname{0}} \def\stackpush#1#2{% \_xp\edef\csname stack@#1@sp\endcsname{\the\numexpr \csname stack@#1@sp\endcsname + 1\relax}% \_xp\def\csname stack@#1@\csname stack@#1@sp\endcsname\endcsname{#2}% } \def\stackdecrement#1{% \_xp\let\csname stack@#1@\csname stack@#1@sp\endcsname\endcsname=\undefined% \_xp\edef\csname stack@#1@sp\endcsname{\the\numexpr \csname stack@#1@sp\endcsname - 1\relax}% } \def\stackpop#1#2{% \stacktop{#1}{#2}% \stackdecrement{#1}% } \def\stacktop#1#2{% \_xp\let\_xp#2\csname stack@#1@\csname stack@#1@sp\endcsname\endcsname% } \def\_rstackpush#1#2{\stackpush{#2}{#1}} \def\_rstackpop#1#2{\stackpop{#2}{#1}} \createmacrostack{macro_stack} \createstack{macro_stack_ptr} \def\macro_stack_ptr{0} \def\beginscope{% \_xp\_rstackpush\_xp{\macro_stack_ptr}{macro_stack_ptr}% } \def\endscope{% \stackpop{macro_stack_ptr}\_uregB% \loop\ifnum\macro_stack_ptr>\_uregB% \macrostackpop{macro_stack}% \edef\macro_stack_ptr{\the\numexpr \macro_stack_ptr - 1\relax}% \repeat% } \def\localize#1{% \macrostackpush{macro_stack}{#1}% \edef\macro_stack_ptr{\the\numexpr \macro_stack_ptr + 1\relax}% }