总结

总结

请考虑以下示例:

\documentclass{article}

\makeatletter
\newcommand\fail[1]{%
    \ifnum1=#1% <- here a space is missing
        \expandafter \@firstoftwo
    \else
        \expandafter \@secondoftwo
    \fi
}
\makeatother

\begin{document}
    \fail{1}{true}{false}
\end{document}

当 1=1 时,会打印 false;当 1=2 时,会打印 truefalse。

我知道这是一个\ifnum过度扩展以期找到数字的延续的问题,并且可以通过在后面插入一个空格来解决这个问题#1

但我不明白到底发生了什么。

这个答案似乎相关,但我仍然无法解释发生了什么。

答案1

总结

永远不要忘记常量后面的空格,除非你知道恰恰为什么省略它(这个\romannumeral技巧是一个典型的例子,说明为什么人们可能想要省略常量后的空格)。

会发生什么?

实际情况是,由于缺少要评估的数字的终止符,因此\expandafter被扩展;这会触及\else,因此,根据规则,TeX 会在(请注意,已经消失)\relax前面插入(“冻结”类型) 。参见\else\expandafter正常 \relax 与冻结 \relax

因此你得到的结果与

\ifnum1=1\@firstoftwo\relax\else\expandafter\@secondoftwo\fi{true}{false}

现在扩展恢复,因为数字仍然未完成并\@firstoftwo返回\relax;然后测试被评估为真,因此 TeX 仍然

\relax\expandafter\@secondoftwo\fi{true}{false}

令牌\relax被执行(或在的情况下存储\edef)并被\else吞噬,我们得到

《\relax》\expandafter\@secondoftwo\fi{true}{false}

现在\expandafter删除\fi,你最终得到

《\relax》\@secondoftwo{true}{false}

所以最后\relax false。如果你这样做

\edef\test{\fail{1}{true}{false}}\show\test

终端确实会显示

> \test=macro:
->\relax false.

\tracingmacros=1如果在调用之前添加\fail,日志文件将显示

\fail #1->\ifnum 1=#1\expandafter \@firstoftwo \else \expandafter \@secondoftwo
 \fi 
#1<-1

\@firstoftwo #1#2->#1
#1<-\relax 
#2<-\else 

\@secondoftwo #1#2->#2
#1<-true
#2<-false

证实了我的分析。

《...》I 表示的令牌已经被发送到下一级别。

如果呼叫是\fail{2}{true}{false},第一步产生

\ifnum1=2\@firstoftwo\relax\else\expandafter\@secondoftwo\fi{true}{false}

由于数字尚未完成,\@firstoftwo因此展开并返回\relax

\ifnum1=2\relax\expandafter\@secondoftwo\fi{true}{false}

现在测试结果可以被评估为假,因此直到\fi\else不再存在)的所有内容都将被删除而不进行扩展,从而导致

\fi{true}{false}

现在\fi消失了。事实上,\edef\test{\fail{2}{true}{false}}\show\test印刷品

> \test=macro:
->{true}{false}.

在终端上。

\@firstoftwo如果交换和会怎么样\@secondoftwo

\documentclass{article}

\makeatletter
\newcommand\fail[1]{%
    \ifnum1=#1% <- here a space is missing
        \expandafter \@secondoftwo
    \else
        \expandafter \@firstoftwo
    \fi
}
\makeatother

\begin{document}

\edef\test{\fail{1}{false}{true}}\show\test

\tracingmacros=1 \tracingonline=1

    \fail{1}{false}{true}

\tracingmacros=0

\end{document}

现在第一级扩展将再次添加\relax,但我们得到

\ifnum1=1\@secondoftwo\relax\else\expandafter\@firstoftwo\fi{false}{true}

和前面一样,\@secondoftwo展开,返回\else。哦,但数字尚未完成,因此\relax添加了另一个冻结,得到

\ifnum1=1\relax\else\expandafter\@firstoftwo\fi{false}{true}

现在条件被评估为真,并且测试被删除:

\relax\else\expandafter\@firstoftwo\fi{false}{true}

和前面一样,\relax被送到胃部并\else删除所有匹配的标记\fi,无需扩展:

《\relax》\fi{false}{true}

消失\fi了,我们剩下的相当于

\relax{false}{true}

相关内容