Knuth 的 tex 书介绍了\if<token1><token2>
。我写了下面的代码来测试它
\def\tOne{abc}
\def\tTwo{abc}
\ifx\tOne\tTwo
True
\else
False
\fi
\if\tOne{abc}
True
\else
False
\fi
\if{abc}\tOne
True
\else
False
\fi
结果是
真的
错误的
错误的
为什么最后两种情况的评估结果为 False?
\tOne \tTwo
是两个 token。{abc}
是一个分组,对吧?它不是一个 token 吗?
TeX 如何评估\if\tOne{abc}
?
答案1
\if
扩展以下标记,直到找到两个不可扩展的标记。
\if\tOne{abc}
变为\if ab...
且a
和b
不相等。剩余的标记c{abc}
将被跳过。与之比较:
\def\tX{aax} \if\tX true\else false\fi
第二行下一步扩展为
\if aaxtrue\else\false\fi
和a
和a
相等,因此xtrue
是结果。\if{abc}\tOne
变为\if{a...
且{
和a
不相等。剩余的标记bc}\tOne
将被跳过。
\ifx
不会扩展,它只是比较接下来的两个标记的含义。\tOne
和\tTwo
是具有相同定义的宏,因此\ifx\tOne\tTwo
计算结果为真。
代币是词汇分析。例如, 是一个包含 15 个字符的字符串。经过标记化后,\if \tOne {abc}
有 7 个标记:,,,,,,,。<\if>
在此过程中,空格字符会消失。当 TeX 读取命令序列的字母(例如 '\'、't'、'O'、'n'、'e')时,下一个非字母标记表示命令序列的结束。如果非字母是空格标记,则会被忽略。<\tOne>
<{>
<a>
<b>
<c>
<}>
标记化由字符的类别代码控制。同一个字符串\if \tOne {abc}
被标记为 15 个标记<\>
, <i>
, <f>
, < >
, <{>
, <a>
, <b>
, <c>
,<}>
被逐字模式,其中\\
,空格和括号具有类别代码“其他”(如数字或标点符号)。
顺便提一句,{abc}
在宏参数。这里,花括号(更准确地说,类别代码为 1 和 2 的字符)可用于将标记分组到参数组中:
\def\x#1{[#1]}
\x abc % -> [a]bc
\x{abc}def % -> [abc]def
\x{a{b}c}def % -> [a{b}c]def
当读取参数时,外部花括号会被删除,如第三行和第四行所示。此外,花括号必须正确匹配。