# LaTeX's \@tfor loop

Here is an interesting case. Please why is case 1 failing?

\def\expandsecond#1#2{\begingroup\edef\x{\endgroup\unexpanded{#1}#2}\x}
\def\maybe@ic@{%
\ifdim\fontdimen\@ne\font>\z@\else
\maybe@ictrue
% Case 1:
\expandsecond{\@tfor\reserved@a:=}\nocorrlist\do{\t@st@ic}%
% Case 2 (original):
%\expandafter\@tfor\expandafter\reserved@a\expandafter:%
% \expandafter=\nocorrlist\do{\t@st@ic}%
\ifmaybe@ic\sw@slant\fi
\fi
}
\def\t@st@ic{%
\expandafter\let\expandafter\reserved@b\expandafter=\reserved@a\relax
\ifx\reserved@b\@let@token
\maybe@icfalse
\@break@tfor
\fi
}


The error came from

\textit{foof}


Error:

! Incomplete \iffalse; all text was ignored after line 163.
<inserted text>
\fi
<*> italic-correction.tex


I get the same amusing problem with the following modifications:

\def\newtfor#1:={\new@tfor#1 }
\long\def\new@tfor#1#2\do#3{%
\edef\newfortmp{\unexpanded{#2}}%
\ifx\newfortmp\space\expandafter\@gobble\else\expandafter\@iden\fi
{\newtforloop#2\@nil\@nil\newtfor#1{#3}}%
}
\long\def\newtforloop#1#2\newtfor#3#4{%
\edef#3{\unexpanded{#1}}%
\ifx#3\@nnil\expandafter\@gobble\else\expandafter\@iden\fi
{#4\relax\newtforloop#2\newtfor#3{#4}}%
}
\long\def\breaknewtfor#1\newtfor#2#3{}

\def\maybe@ic@{%
\ifdim\fontdimen\@ne\font>\z@\else
\maybe@ictrue
% Case 1:
%\expandsecond{\newtfor\reserved@a:=}\nocorrlist\do{\t@st@ic}%
% Case 2:
\expandafter\newtfor\expandafter\reserved@a\expandafter
:\expandafter=\nocorrlist\do{\t@st@ic}%
\ifmaybe@ic\sw@slant\fi
\fi
}
\def\t@st@ic{%
\expandafter\let\expandafter\reserved@b\expandafter=\reserved@a\relax
\ifx\reserved@b\@let@token
\maybe@icfalse
\expandafter\breaknewtfor
\fi
}


EDIT (2012/08/13)

Here is a M(N)WE:

\documentclass{article}
\usepackage{xspace}

\edef\x{catcode of comma=\the\catcode\,\space,
\space catcode of stop=\the\catcode\.}
%\show\x
%\show\nocorrlist

\makeatletter
\def\expandsecond#1#2{%
\begingroup\edef\x{\endgroup\unexpanded{#1}#2}\x
}
%\def\nocorrlist{.,\xspace} % source of the problem.
\def\maybe@ic{\futurelet\@let@token\maybe@ic@}
\def\maybe@ic@{%
\ifdim\fontdimen\@ne\font>\z@\else
\maybe@ictrue
% Case 1:
\expandsecond{\@tfor\reserved@a:=}\nocorrlist\do{\t@st@ic}%
% Case 2:
%\expandafter\@tfor\expandafter\reserved@a\expandafter
%  :\expandafter=\nocorrlist\do{\t@st@ic}%
\ifmaybe@ic\sw@slant\fi
\fi
}
\makeatother

\begin{document}
\textit{foof}. \textit{foof}!
\end{document}


The problem was caused by one of the packages I loaded: it did \def\nocorrlist{.,\xspace}.

• please make a full MWE then demonstrates the error case. I tried your first code block in a document and got no error – David Carlisle Aug 13 '12 at 7:43
• My guess would be that you have a active punctuation characters in your \nocorrlist since the main difference is that you fully expand that with edef rather than just once with expandafter – David Carlisle Aug 13 '12 at 8:45

As David Carlisle has already said, do not fully expand \nocorrlist. LaTeX's code for the italic correction looks for the next token using \futurelet (in macro \maybe@ic). If the next token is an element of the list \nocorrlist, then the italic correction is suppressed. LaTeX's original definition only includes the comma and period as tokens with catcode 12 (other). But the list can be extended, by other packages, by the user (there is no @ in the name). The extended tokens can also be macros, see package biblatex:

\appto\nocorrlist{\isdot\adddot\addperiod\addcomma}


I assume, the purpose of \expandsecond is to expand a token after the first argument to provide the expanded list for \@tfor. It would behave similar to \expandafter with the difference, that it jumps over a token list instead of a single token. And the inserted group makes the macro form non-expandable. The following definition of \expandsecond expands the token once, not fully. And it does not need e-TeX's \unexpanded:

\def\expandsecond#1{%
\begingroup
\long\def\x{\endgroup
#1
}%
\expandafter\x
}


The group can be avoided by using a macro for this purpose:

\def\expandsecond#1{%
\long\def\expandsecond@next{#1}%
\expandafter\expandsecond@next
}


However, the definition remains non-expandable because of the macro definition.

In case of \newtfor I do not know, what you want to improve. The redefinition is probably a tiny bit less efficient because of the additional macro expansion steps (\@gobble,\@iden). Both variants can handle unmatched conditional in the token list.

A remark for the lines

\edef\newfortmp{\unexpanded{#2}}%
\edef#3{\unexpanded{#1}}%


The point of \unexpanded is the prevention of the expansion, thus in the end the result is (with the exception of #, see "Edit"):

\def\newfortmp{#2}%
\def#3{#1}%


as in the original definitions for the \@tfor loop in LaTeX.

Edit: There is one exception, pointed out by Joseph Wright. Tokens with catcode 6 (parameter), usually the hash char #, needs to be doubled without \edef + \unexpanded.

• While I'm not sure if it's the aim, the \edef\foo{\unexpanded{<stuff>}} construct is not identical to \def\foo{<stuff>} if the <stuff> contains # tokens. The latter will give an error, the former is allowed. (This is how we construct token list variables in expl3.) – Joseph Wright Aug 13 '12 at 12:41
• @JosephWright: That was the reason for using \unexpanded: to parse tokens with parameter characters. Eg, \newtfor\x:=a \ifx {\def\x#1{#1}} \fi\do{\edef\y{\detokenize\expandafter{\x}}}`. – Ahmed Musa Aug 13 '12 at 16:37