TeX 如何为 \halign 条目设置粘合?

TeX 如何为 \halign 条目设置粘合?

在第 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

基本上已经在评论中回答了,但添加了一些细节并做出了答案,以使这个问题从未回答的列表中删除。

  1. 首先 TeX 计算每列的宽度(如代码片段中所述TeXbook问题中引用的,即每行该列的自然宽度的最大值)。

  2. 此后,如果对齐本身(具有这些列宽的原型行)过满/过少,则 TeX 将显示过满/过少消息。因此(据我所知)您永远无法仅使用 获得此错误消息,但您可以使用或\halign{...}轻松获得此消息。\halign to...\halign spread...

  3. 最后,在为该列中的每个盒子设置粘合时,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.

结果是

第一的

在这种情况下发生的情况(一般情况类似)是:

  1. TeX 首先扫描前导码(在本例中\indent#&\quad#,即两列\indent#\quad#),并构建一个内部“前导码”列表,如下所示:

    前言

  2. 然后,对于每一行,它基本上像在受限水平模式下一样读取内容,像在序言中一样插入制表符跳过,并在适当的时候从每列的“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
    
  3. 当所有行都已读取后,前导的对齐记录将分别更新为各列遇到的最大宽度。这给出了“原型行”,这里可能会出现欠满/过满警告:

    原型

    以 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
    
  4. 最后,在所有先前附加到 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. 第 1 行:x = w,因此不需要拉伸:胶水凝固率为 0,胶水保持其自然宽度。

  2. 第 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. 第 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”(等等),这解释了所有内容都向左对齐的输出:

第二

相关内容