为什么连续六个 \noexpand?

为什么连续六个 \noexpand?

尝试理解 TeX 解析维度的规则时,我发现了以下奇怪的行为:

\dimen0=1\noexpand\noexpand\noexpand\noexpand\noexpand\empty pt

是有效的,但是

\dimen0=1\noexpand\noexpand\noexpand\noexpand\noexpand\noexpand\empty pt

产量

! Illegal unit of measure (pt inserted).
<to be read again> 
                   p
<to be read again> 
                   t
<*> ...oexpand\noexpand\noexpand\noexpand\empty pt

? 

是什么导致了这种差异?

答案1

这很难追踪。请注意,\noexpand根据单位的不同,在不同数量的 之后,我们会收到错误,这意味着 TeX 根据单位进行不同数量的扩展。为了试验这一点,让我们将活动字符设置~\noexpand,然后尝试各种分配,增加 的数量,直到 TeX 抱怨。以下是原始 TeX 引擎~的最大数量:~

\let~\noexpand
\dimen0=1~~\dimen1
\dimen0=1~~~em
\dimen0=1~~~~ex
\dimen0=1~~~~~true~pt % (and others)
\dimen0=1~~~~~~pt
\dimen0=1~~~~~~~in
\dimen0=1~~~~~~~~pc
\dimen0=1~~~~~~~~~cm
\dimen0=1~~~~~~~~~~mm
\dimen0=1~~~~~~~~~~~bp
\dimen0=1~~~~~~~~~~~~dd
\dimen0=1~~~~~~~~~~~~~cc
\dimen0=1~~~~~~~~~~~~~~sp
\dimen0=1~~~~~~~~~~~~~~~ % crashes after reading the last ~.

显然,并非所有单位都生来平等。关键在于文件中tex.web:TeX 用于扫描单位的代码复制如下。让我们来评论一下

\dimen0=1~~~~~~~pt

例如,这会导致错误(7 ~)。TeX 读取数字1,扩展第一个数字~,暂时将第二个数字变为~\relax从而停止扩展1:数字已完成。以下是:

@<Scan units and set |cur_val| to $x\cdot(|cur_val|+f/2^{16})$...@>=

这本质上是一个“标题”。

if inf then @<Scan for \(f)\.{fil} units; |goto attach_fraction| if found@>;

尺寸分配不允许无限粘合,因此跳过此部分。

@<Scan for \(u)units that are internal dimensions;
  |goto attach_sign| with |cur_val| set if found@>;

这将扫描诸如 之类的单元\dimen...,扩展第二个单元~,将下一个单元转换~\relax(请注意,在我们的示例文件的第一行中,~作用于\dimen并且不执行任何操作,因此 TeX 会看到\dimen)。然后 TeX 查找em,然后查找ex,“杀死”了另外两个~。我们剩下 3 个。

if mu then @<Scan for \(m)\.{mu} units and |goto attach_fraction|@>;

已跳过:这不是一个跳过任务

if scan_keyword("true") then @<Adjust \(f)for the magnification ratio@>;
@.true@>

TeX 尝试扫描true并再次失败,剩下 2 ~

if scan_keyword("pt") then goto attach_fraction; {the easy case}
@.pt@>

TeX 查找pt,并进行扩展,但下一个~将最后一个 变成~\relax隐藏了pt后面的 。又一次失败。

@<Scan for \(a)all other units and adjust |cur_val| and |f| accordingly;
  |goto done| in the case of scaled points@>;

此处调用的代码逐个尝试各种单元:inpccmmmbpddccsp我们的最后一个~对以下 不做任何操作p,而 TeX 不断看到p,并尝试将其与单元匹配。当扫描 时pc,TeX 识别p,但对 感到失望t。最终,TeX 放弃了。请注意,在这种情况下,错误消息将 和 都显示pt“需要再次读取”。如果再添加两个,TeX在尝试解析 时~尚未到达,因此只有会“需要再次读取”。ppcp

attach_fraction: if cur_val>=@'40000 then arith_error:=true
else cur_val:=cur_val*unity+f;
done:

其余的代码我们这里不关心。

附注:由于 eTeX 比 TeX 多扫描几个单元,因此以下程序~在 TeX 中会在 14 处崩溃,但在 eTeX 中会在 18 处崩溃:

\let~\noexpand
\dimen0=1~~~~~~~~~~~~~~~~~sp

相关内容