Get the lion to run in loops. Tersely
Not extremly short, but a real bug I ran into once when working on xor
\output{\deadcycles=1
\message{.}% just to show that something is happening
\setbox0\box255}
\null
\bye
Of course the output routine didn't set \deadcycles
to 1. In reality it was two ORs being called in a row the first setting it to zero.
Just realized that I only answered the second part of the question. By now the first part has already been answered by @egreg.
I think to have understood why the infinite loop is triggered. The e-TeX primitive \unexpanded
is mostly like \lowercase
: it should be followed by <general text>
, which in turn is <filler>{<balanced text><right brace>
. The important bit is <filler>
, which is an arbitrary sequence of \relax
commands and spaces (TeXbook, p. 276).
So \unexpanded
looks for a {
expanding commands on the go and ignoring \relax
and space tokens. But it is expandable!
When e-TeX finds \if\unexpanded\fi
, the primitive \if
triggers the expansion of \unexpanded
; but the \fi
immediately following causes the insertion of a (frozen) \relax
, because of the unfinished conditional, that \unexpanded
swallows, leaving an unfinished conditional, which causes the insertion of \relax
…
Oops, infinite loop. For \detokenize
and \scantokens
the situation is the same. In original TeX no expandable primitive accepts a <general text>
as argument, as far as I know.
The situation is indeed completely different with \if\lowercase\fi
, where \lowercase
is not expandable, so TeX inserts \relax
and the comparison can be performed (and is true).
A shorter loop just using classic tex and no macro expansion is
\let\par\relax.\vskip