在第 235 页电子书据说:
TeX 在排版任何内容之前会将整个
\halign{...}
规范读入内存,并跟踪每列的最大宽度,假设每列的设置都没有拉伸或收缩粘连。然后它返回并将每个条目放入一个框中,设置粘连,以便每个框都有最大的列宽。
在第一个例子中,坏度超出了范围,但没有发出警告。在第二个例子中,条目默认左对齐 - 为什么?同样,为什么没有发出未满警告?
\halign{\indent#&\quad#\cr
Horizontal lists&Chapter 14\cr
Vertical lists&Chapter 15\cr
Math lists&Chapter 17\cr}
\bigskip
\halign{\indent#&\quad#\cr
Horizontal&Chapter 14\cr
Vertical&Chapter 15\cr
Math&Chapter 17\cr}
\end
答案1
(基本上已经在评论中回答了,但添加了一些细节并做出了答案,以使这个问题从未回答的列表中删除。)
首先 TeX 计算每列的宽度(如代码片段中所述TeXbook问题中引用的,即每行该列的自然宽度的最大值)。
此后,如果对齐本身(具有这些列宽的原型行)过满/过少,则 TeX 将显示过满/过少消息。因此(据我所知)您永远无法仅使用 获得此错误消息,但您可以使用或
\halign{...}
轻松获得此消息。\halign to...
\halign spread...
最后,在为该列中的每个盒子设置粘合时,TeX 只需计算“粘合集”(即“粘合集比率”和“粘合集顺序”)并设置粘合;不会打印任何欠满/过满消息。
- 这是胶水设置工作方式的自然结果(一般而言),当没有可用的拉伸时(并且特别是当没有胶水时),盒子只是按顺序排列,即左齐平。
对于上述第三点,实现细节(对齐条目的粘合集的计算)在第节中该计划的第 810 条(下文也将详细说明)——这与通常的计算几乎相同(第 658 条和第 664 条hpack
),但不报告箱子过满/不足的情况。
更详细的叙述,是在深夜里获得的理解gdb 历险记,TeX 如何处理\halign
。考虑问题中的第一个测试用例:
% \noindent This is a test.
\halign{\indent#&\quad#\cr
Horizontal lists&Chapter 14\cr
Vertical lists&Chapter 15\cr
Math lists&Chapter 17\cr}
% \noindent End of test.
结果是
在这种情况下发生的情况(一般情况类似)是:
TeX 首先扫描前导码(在本例中
\indent#&\quad#
,即两列\indent#
和\quad#
),并构建一个内部“前导码”列表,如下所示:然后,对于每一行,它基本上像在受限水平模式下一样读取内容,像在序言中一样插入制表符跳过,并在适当的时候从每列的“u”和“v”标记列表中读取。最后,它将一个未设置的框附加到垂直列表中。因此,在这种情况下,它会附加以下行(由
\baselineksip
粘合分隔,此处未显示)(使用⇨
表示\indent
和\quad
粘合,以及↔
可拉伸的单词间粘合):例如,上面中间的一行在 TeX 输出符号中将显示如下:
\hbox(6.94444+1.94444)x133.50018 .\glue(\tabskip) 0.0 .\unsetbox(6.94444+0.0)x74.5834, stretch 1.66666, shrink 1.11111 ..\hbox(0.0+0.0)x20.0 ..\tenrm V ..\kern-0.83334 ..\tenrm e ..\tenrm r ..\tenrm t ..\tenrm i ..\tenrm c ..\tenrm a ..\tenrm l ..\glue 3.33333 plus 1.66666 minus 1.11111 ..\tenrm l ..\tenrm i ..\tenrm s ..\tenrm t ..\tenrm s .\glue(\tabskip) 0.0 .\unsetbox(6.94444+1.94444)x58.91678, stretch 1.66666, shrink 1.11111 ..\glue 10.00002 ..\tenrm C ..\tenrm h ..\tenrm a ..\tenrm p ..\tenrm t ..\tenrm e ..\tenrm r ..\glue 3.33333 plus 1.66666 minus 1.11111 ..\tenrm 1 ..\tenrm 5 .\glue(\tabskip) 0.0
当所有行都已读取后,前导的对齐记录将分别更新为各列遇到的最大宽度。这给出了“原型行”,这里可能会出现欠满/过满警告:
以 TeX 符号表示:
\glue(\tabskip) 0.0 \unsetbox(0.0+0.0)x86.25012 \glue(\tabskip) 0.0 \unsetbox(0.0+0.0)x58.91678 \glue(\tabskip) 0.0
最后,在所有先前附加到 vlist 的未设置的框中设置胶水(再次,这里未显示 baselineskip glue):
在 TeX 符号中,这是(为了简洁,我折叠了
\tenrm
行):\glue(\baselineskip) 5.05556 \hbox(6.94444+1.94444)x145.1669 .\glue(\tabskip) 0.0 .\hbox(6.94444+1.94444)x86.25012 ..\hbox(0.0+0.0)x20.0 ..\tenrm Horizon\kern-0.27779tal ..\glue 3.33333 plus 1.66666 minus 1.11111 ..\tenrm lists .\glue(\tabskip) 0.0 .\hbox(6.94444+1.94444)x58.91678 ..\glue 10.00002 ..\tenrm Chapter ..\glue 3.33333 plus 1.66666 minus 1.11111 ..\tenrm 14 .\glue(\tabskip) 0.0 \glue(\baselineskip) 3.11111 \hbox(6.94444+1.94444)x145.1669 .\glue(\tabskip) 0.0 .\hbox(6.94444+1.94444)x86.25012, glue set 7.00008 ..\hbox(0.0+0.0)x20.0 ..\tenrm V\kern-0.83334ertical ..\glue 3.33333 plus 1.66666 minus 1.11111 ..\tenrm lists .\glue(\tabskip) 0.0 .\hbox(6.94444+1.94444)x58.91678 ..\glue 10.00002 ..\tenrm Chapter ..\glue 3.33333 plus 1.66666 minus 1.11111 ..\tenrm 15 .\glue(\tabskip) 0.0 \glue(\baselineskip) 3.11111 \hbox(6.94444+1.94444)x145.1669 .\glue(\tabskip) 0.0 .\hbox(6.94444+1.94444)x86.25012, glue set 13.18344 ..\hbox(0.0+0.0)x20.0 ..\tenrm Math ..\glue 3.33333 plus 1.66666 minus 1.11111 ..\tenrm lists .\glue(\tabskip) 0.0 .\hbox(6.94444+1.94444)x58.91678 ..\glue 10.00002 ..\tenrm Chapter ..\glue 3.33333 plus 1.66666 minus 1.11111 ..\tenrm 17 .\glue(\tabskip) 0.0
这就是输出的内容。
我猜这个问题是关于上面最后一步(第 4 步)的。因此,下面详细介绍一下 TeX 如何在每一项中设置粘连。(在TeXbook在第 77 页顶部。)为简单起见,我们只考虑“拉伸”的情况,即自然宽度x
小于所需宽度w
。首先,TeX 计算盒子中总的可用拉伸,方法是将盒子中每个胶水的拉伸相加,并在所得总和中仅取具有非零拉伸的最高“无穷级”。例如,假设总可用拉伸为“7 fil”。然后,由于我们想要实现w-x
拉伸,每个拉伸为(s) fil
(某个值s
)的胶水将被拉伸(w - x) * s/7
,因此当s
添加这些相应的组件(请记住,根据假设必须加起来为 7)时,我们将获得(w-x)
所需的总拉伸。在这种情况下,我们将胶水设置比率称为(w-x)/7
(因为这是每个拉伸s
乘以的),胶水设置顺序为fil
。
在上面的第一个例子中,对于第 1 列,其表现如下:
第 1 行:
x = w
,因此不需要拉伸:胶水凝固率为 0,胶水保持其自然宽度。第 2 行:“\indent Vertical lists”的自然宽度为 74.5834pt,我们希望它占据 86.25012pt,因此我们需要拉伸 11.66672pt。可用的拉伸量为 1.66666pt,来自单词间粘合。因此,我们决定“粘合设置比率”为 11.66672pt/1.66666pt ≈ 7.0008(当您在 中进行计算时
sp
,即 (5652488sp - 4887898sp)/(109226sp))。这意味着,从左到右,框变为:\indent,其自然宽度为 20pt(无可用拉伸)
“垂直”中的字母和字距,其自然宽度为 53.91672pt。
3.3333pt 的字间粘连,另外拉伸了 7.0008 * 1.66666pt = 11.66672 pt。因此实际上占用了 15.00005pt 的宽度。
“列表”中的字母,其自然宽度为 17.33336pt。
总计为 (53.91672pt + 15.00005pt + 17.33336pt) = 86.25012pt,正如所需。
第 3 行:类似:“\indent Math lists”的自然宽度为 64.27786pt,因此我们需要拉伸 86.25012pt - 64.27786pt = 21.97226pt,可用拉伸量为 1.66666pt,因此我们决定“粘合设置比率”为 21.97226pt/1.66666pt = 13.18344。这意味着,如第 2 行所示,单词间粘合量拉伸 1.66666 pt * 13.18344 = 21.97226pt。
这也解释了第二个例子:
% \noindent This is a test.
\halign{\indent#&\quad#\cr
Horizontal&Chapter 14\cr
Vertical&Chapter 15\cr
Math&Chapter 17\cr}
% \noindent End of test.
当根本没有可用的拉伸时(例如当没有胶水时),胶水设置比率是多少就无关紧要了。没有可以拉伸的胶水,因此“每个可拉伸胶水被拉伸 r 倍于其拉伸分量”是空洞的,无论 r 的值是多少。(在内部,TeX 设置 r=0,但据我所知,这只会影响调试输出。)因此,当框布局时,只有“\indent”和“Vertical”(等等),这解释了所有内容都向左对齐的输出: