A very common programming data structure is a stack. A stack is simply a one dimensional array. Stack elements are pushed in or popped out of the stack one at a time as LIFO (Last In First Out).
I am trying to build a general routine to represent such stacks using LaTeX2e. The stack has two operations a pop and a push.
The popped elements are stored in a macro \popped@element
, so that they can be pushed into another stack if necessary or typeset material. At this point I provided a\before@pop@hook
and an \after@pop@hook
, to enable surrounding material to be added. Not sure if this correct from a design point. To get material in an fbox
the construction became very weird (see lines 71-72):
\def\before@pop@hook{\bgroup\color{blue}\fbox}
\def\after@pop@hook{\egroup}
I am looking for improvements/corrections to the code to make it more robust and accept any type of input such as verbatim text, ability to be inserted into tables, i.e, which sections of the code would need to become outer
etc.
So far I have come up with this MWE:
\documentclass{book}
\usepackage[latin]{babel}
\usepackage{xcolor,lipsum}
\parindent0pt
\makeatletter
\newcommand\lorem{Fusce adipiscing justo nec ante. Nullam in enim.
Pellentesque felis orci, sagittis ac, malesuada et, facilisis in,
ligula. Nunc non magna sit amet mi aliquam dictum. In mi. Curabitur
sollicitudin justo sed quam et quadd.}
% Define a new stack by letting it to \@empty
\newcommand\newstack[1]{%
\let#1\@empty
}
% #1 stack name
% #2 element contents
\newcommand{\add@element}[2]{%
\def\element{#2}%
\push@element{#1}
}
% #1 stack name
\newcommand{\push@element}[1]{%
\xdef#1{\element+#1}
}
%% Add hooks here for typesetting
\def\before@pop@hook{\bgroup\color{red}}
\def\after@pop@hook{\egroup}
\def\before@pop@hook{}
\def\after@pop@hook{}
\long\def\pop@#1+#2\@nil#3{%
\def\popped@element@{\before@pop@hook{#1}\after@pop@hook}
\def\popped@element{#1}
% \xdef\element{#1} if required?
% remaining list
\def#3{#2}%
}
% stack name #1
\newcommand\pop@element[1]{%
\ifx #1\@empty Error\else
\expandafter\pop@#1\@nil#1
\fi
}
\begin{document}
% Create two stacks
\newstack{\stack}
\newstack{\tempstack}
% add some elements to stack
\def\elt@start{Start }\def\elt@stop{Stop}
\add@element{\stack}{english}
\add@element{\stack}{polish}
\add@element{\stack}{australian}
\add@element{\stack}{german}
\add@element{\stack}{\elt@start greek \elt@stop}
% pop some elements from \stack
% and put them in boxes
Popped from stack
\pop@element{\stack}
\popped@element@
\pop@element{\stack}
\popped@element@
% add last popped element from \stack to \temp
% pop it into blue box
\def\before@pop@hook{\bgroup\color{blue}\fbox}
\def\after@pop@hook{\egroup}
\add@element{\tempstack}{\popped@element}
\parbox{3cm}{\popped@element@}
\def\X{german}
\def\Y{\popped@element}
\ifx\X\Y \add@element{\stack}{\popped@element}\fi
In temp stack \tempstack
\def\before@pop@hook{}
\def\after@pop@hook{}
\add@element\stack{\lorem}
\pop@element{\stack}
\parbox{3.9cm}{\popped@element@}
\end{document}
LaTeX3 and Lua solutions are also welcome, provided they come with long explanations.
Update
It is a pity that I cannot accept all the answers as they are all great and examined the issues from all aspects. I was especially impressed with Frank's and Joseph's answers and their explanations. cjorssen's Lua solution is very promising and can be very useful, if one wanted to parse the contents further. I have accepted Bruno's answer as it was the one with a MWE and clearly demonstrating the use of verbatim text in lists.
\def\foo{...}
should be turned into\edef\foo{\unexpanded{...}}
, to allow macro parameters to appear in elements of your stacks (see e.g., the definition of\tl_set:Nn
inl3tl.dtx
). (2) Using+
as a delimiter strikes me as very unsafe. Either use a private cs as a delimiter (possibly let to\relax
, or with the appropriate\noexpand
at various places). (3) Better than<delim><item><delim><item>
is<cs>{<item>}<cs>{<item>}
: then the<item>
can contain arbitrary (non-outer) tokens.\xdef
in\push@element
and\def
in\pop@
). Either stick to one, or provide both. (5) It is good to catch the case of an empty stack when popping, but I'd go for an actual error (using\errmessage
--- or\PackageError
, whatever). (6) Hard-wiring\popped@element
into the definitions seems to restrict the generality of your code. (7) Your\def\Y{\popped@element}
seems incorrect: you may want\edef
, or\edef\Y{\unexpanded\expandafter{\popped@element}}
. (8) I could list a bunch of functions to add...+
as a quick delimiter as I am testing with text only. Will have a look atl3tl.dtx
.