Using a loop in \halign's preamble
As Henri Menke wrote in a comment, your preamble has to be expandable (and every token that should be expanded has to be preceded by \span
). So how do we build a fully expandable loop only using plain TeX? We use \romannumeral
. If \count1
is some integer, then we can use \the\count1 000
to get 1000*\count1
. This is expressed as a roman numeral by exactly \count1
times the letter m
. \romannumeral
is expandable, so we can use this in our preamble. Then our macro is repeated, consuming one m
at every iteration, until the m
s run out:
\count1=4
\def\subpre#1{
\span\if m#1
& ##
\span\expandafter
\span\expandafter\subpre
\fi
}
\def\gobble#1{}
\def\preamb{
##
\span\expandafter
\span\expandafter\expandafter
\expandafter\span\expandafter\expandafter\expandafter\subpre
\expandafter\gobble\romannumeral\the\count1 000x
\cr
}
\halign{\span\preamb
first& line&val&x \cr
}
\bye
To understand all the \expandafter
s in \preamb
, try to think as if you were TeX:
In \preamb
, first we add ##
to the preamble. Then there is \span
, so the next token is expanded. It is \expandafter
, so we skip one token and expand the next, which (again) is \expandafter
. This repeats 6 times, expanding the first, second, fourth, fifth, seventh and eighth \expandafter
in \preamb
until finally expanding \romannumeral\the\count1 000x
. This expands to \romannumeral4000x
and therefore mmmmx
. Without the \expandafter
s and \romannumeral
expanded, we are left with the tokens
\span\expandafter
\span\expandafter\subpre\gobble mmmmx
Again, we have \span
, so we expand this. The remaining \expandafter
s end up expanding \gobble
which gobbles the first m
.
This is the equivalent to \advance \columns by -1
in your original code. So what remains is
\span\subpre mmmx
which finally starts expanding \subpre
.
On the other hand, it is often much easier to not restrict yourself to expandable constructs. Instead you can construct the preamble first (e.g.in a token list), and only insert the finished preamble into \halign
: (based on David Carlisle's answer to your original question)
\newcount\columns
\newtoks\preambtoks
\def\myhalign{%
\afterassignment\xmyhalign
\columns=%
}
\def\xmyhalign{\afterassignment\xxmyhalign\let\tmp=}
\def\subpre{
\preambtoks\expandafter{\the\preambtoks & ##}
\advance\columns by -1 \ifnum\columns>0 \subpre \fi
}
\def\xxmyhalign{%
\preambtoks{##}%
\advance \columns by -1
\ifnum\columns>0 \subpre \fi
\halign\bgroup\span\the\preambtoks\cr
}
\myhalign3{
first line & second column \cr
1& 2&3 \cr
}
\bye
The primitive \span
in the context of a \halign
preamble, performs a single expansion step.
You need some more sophisticated code if you want to allocate a variable number of columns.
Here I define \preamb
to take as argument a column template (in the example, \hfil#\hfil
); this template is repeated as many times as the current value of \columns
(assumed to be positive).
The trick is to use \span
to expand \romannumeral-`@
, that does recursive expansion until finding an unexpandable token.
The \subpre
macro is called \columns-1
times and each time the third argument contains the preamble-so-far augmented by a further column.
% syntactic sugar
\long\def\firstoftwo#1#2{#1}
\long\def\secondoftwo#1#2{#2}
% the code
\newcount\columns
\def\preamb#1{#1\span\romannumeral-`@\subpre\columns{#1}{}}
\def\subpre#1#2#3{%
\ifnum\numexpr#1-1=0
\expandafter\firstoftwo
\else
\expandafter\secondoftwo
\fi
{#3\cr}%
{\expandafter\subpre\expandafter{\the\numexpr#1-1}{#2}{#3}}%
}
% the test
\tabskip=10pt
\columns=4
\halign{\span\preamb{\hfil#\hfil}%
1&2&3&4\cr
AAA&BB&CCCC&DDDD\cr
u&v&w&x\cr
}
\bye