阻止数字意外地被吸收到文字中

阻止数字意外地被吸收到文字中

我记得我曾经写过一些 TeX 代码,遇到过这样的事情

\count\foo
\foo=2\otherMacro
[\the\foo]

如果\otherMacro被定义为类似于上面那行\def\otherMacro{9 cats is too many}的东西,那么\foo它实际上会被设置为 29 而不是 2,因为来自猫宏的 9 会被吸收。

更阴险的情况是这样的:

\newcount\foo
\def\setfoo{\foo=2}
\def\otherMacro{9 cats is too many}
\setfoo\otherMacro
[\the\foo]

此代码也出错了,吸收了 9,将 \foo 设置为 29。在这种情况下,很难知道修复的适当位置在哪里。如果\setfoo\otherMacro不返回宏定义,很难在查看时发现错误,因为在实际情况下,宏定义可能离调用很远。

我记得在遇到这个问题时,我坐下来全面了解了所有可能发生这种情况的情况,并采用了一套防御性编码标准来防止这种情况发生,其中包括自由使用 % 和空格。但是,我没有做任何笔记,而且我不确定我能记住所有的细节和细微差别。例如,我不记得在处理 \dimen 或其他类型的寄存器时是否发生过这种情况,我也记不清我防御性使用 % 和空格的规则到底是什么。

我正要坐下来再次试验这个 TeX-gotcha,但我认为在 SO 上发帖寻求社区建议也无妨。我知道 SO 通常不喜欢讨论帖子,所以我会这样说:如果有人对这些问题有全面的了解,那么关于这个问题的单篇脑力倾泻将是一个适合 SO 的坚实回应。

还请注意,我使用的是 Plain TeX,而不是 LaTeX。

[更新]:

在考虑了 David Carlisle 建议的解决方案并考虑了他所描述的注意事项之后,我将这个好奇心修改为这篇文章:

\def\otherMacro{9 cats is too many}
\newcount\foo
\def\bar#1{[\the\foo][#1]}

\def\setfooSpace{\foo=2 }
\def\setfooRelax{\foo=2\relax}

\afterassignment\bar\setfooSpace\otherMacro

\afterassignment\bar\setfooRelax\otherMacro

倒数第二行结果为文本

[2][9 cats is too many]

而最后一行本身的结果是

[2][]9 cats is too many

\relax和解决方案都2<space>可以防止 9 被 2 吸收,但是带有空格的解决方案似乎更胜一筹,因为它使像 \setfoo 这样的宏感觉更具原子性。

答案1

数字后面的空格总是终止<number>并被吸收,因此

\foo=2 \otherMacro

将分配 2 给\foo后面的(没有空格)扩展\othermacro

任何其他不可扩展的非数字标记都会终止<number>但被替换

\foo=2\relax\otherMacro

分配 2 到\foo然后标记流具有\relax和扩展\otherMacro

在任何其他情况下,数字后面的标记都会被扩展,以决定是否有更多的标记需要吸收到数字中。

所以你的例子

\def\setfoo{\foo=2}

是一个即将发生的错误,应该

\def\setfoo{\foo=2 }

或者当然

\def\setfoo{\foo=\tw@}

使用此类标记的主要原因是\tw@为了避免这些问题,因为它们是完整的<number>\chardef在这种情况下定义为),因此 TeX 不会提前扫描寻找更多数字。

相关内容