Skip to content

The TEXbook 知识点总结

🕒 Published at:

阅读背景 ​

《The TEXbook》是由 TeX 作者 DONALD E. KNUTH 编写的一本关于 TeX 设计的书, 介绍了 TeX 在设计时所考虑到的细节。OLeX 在词法分析和语法部分需要仔细研究此部分的内容, 从而消除对 TeX 的分析差异。(之前都是针对大量模板进行的实现, 多多少少会有兼容性和语法忽略的问题)

TeX 是一门注重排版的语言, 并且让用户不用过度关心于排版本身。本篇博客将注重于对 TeX 令人疑惑的细节探索, 追求在语法上和原理上总结 TeX 这门语言的 “奇异” 之处。

排版 ​

书籍与普通的排版并不完全相同, 尤其是在符号的差别上, 计算机的 ASCII 码并不是专门为书籍出版所发明, 比如 引号 有左引号、右引号、无方向引号... 因此, TeX 在此方面做了很多的考虑。

比如双引号 “ 可以输入为 ‘‘, ” 可以输入为 ’’

连字符(-) -、短破折号(-) --、破折号(——) ---、减号(-) $-$, 这四个符号其实并不一样。TeX 会完全自己解决这个问题, 而用户并不必要担心。

TeX 可以通过 \lq 和 \rq 键入左右引号。为了键入 ’” 并且消除歧义, 使单双引号间距不过大或过小, 可以键入 ’\thinspace’’ 得到想要的结果。

TeX 控制系列 ​

键盘可以输入的字符比较少, 为了解决这个问题 TeX 使用反斜杠 \ 进行 “转义”。举个例子:

tex
\input MS

上面这行命令的意思为: 读取 MS.tex 文件, \input 就是一个控制系列(命令), 再举个例子:

tex
George P\’olya

渲染为: George Pólya

控制系列类型:

  • 第一类: \input; 由 \ + 多个字母 + 空格或非字母字符, TeX 一般把 [a-zA-Z] 看作字母, 数字 [0-9] 并不看作字母 (OLeX 在实现上进行了差异化处理, 未严格按照 TeX 进行实现)
  • 第二类: \’; 由 \ + 一个单个非字母组成, 区别是不必将控制系列与后面的字母分开, 第二类控制系列在转义符后面永远只有一个符号!

第一类控制系列后面的空格会被忽略掉, 并不看作为 “实际” 空格。但是, 出现在第二类控制系列后面会看作是实际空格。

TeX 把多个连续空格看作单个空格。键入控制空格解决此问题 \ (控制空格)

TeX 把 <return> 看作同 \ (控制空格), 控制空格属于第二类控制系列。

TeX 的第二类控制系列的实现在 OLeX 中也没有严格实现, OLeX 借助于 HTML 和一部分的 SVG 进行实现, 所以并没有完全严格按照 TeX 的规范, 为了消除 TeX 本身可能语法带来的歧义导致给用户带来心智负担。

TeX 大约能执行900个控制系列, 是 TeX 内置语汇的一部分。(OLeX 通过自行设计渲染器结构对内置语汇和宏包进行统一实现)。需要注意的是, TeX 的控制系列是大小写敏感的, 并且是一一对应的映射关系。大约 300 个控制系列为 原始控制系列。

TeX 的高级控制系列可以进行计算 (OLeX 或许在更远期的规划里面, 会对此部分的内容进行实现。)

\show\input -> \input=\input, \show\thinspace

->

txt
> \thinspace=macro:
-> \kern .16667em .

\show 的结果被保存在 log 文件中。

plain TeX 大约有 600 个基本控制系列, 加上 300 个左右的原始控制系列, 构成了TeX 基本的文本排版控制。

字体 ​

默认情况下, 不定义其他字体将使用 roman 字体。

txt
\rm --> Roman
\sl --> Slanted
\it --> Italic
\tt --> Typewriter
\bf --> Bold

字体的外形会随着大小而改变, 单位设计使用 points(即pt)。

txt
10 points --> \tenrm
9 points --> \ninerm
10 points slanted --> \tensl

对于字体名称的处理, \font\cs=<external font name> 把一个特殊字体的有关信息载入内存; 在控制系列 \cs 将在排版时选择那个字体。Plain TeX 最初只定义了 16 个字体, 可以使用 \font 把系统字体库中字体为 TeX 所用。

因为对于字体设计来说, 随着字号的不同并不是单纯的放大或缩小, 因此放缩字体还是存在与调整字号大小不同之意义的。通过 \font\cs=<external font name> at <desired size> 命令实现。

另一种方法是, 相对于设计尺寸给出放大因子。规定为整数, 等于放大比例乘上 1000.1200 即是放大 1.2 倍。\font\manifiedfiverm=cmr5 scaled 2000。Plain TeX 提供了缩略命令, \magstep0 放大因子为 1000、\magstep1 放大因子为 1200, \magstep2 为 1440 ... \magstep5

\magstephalf 放大 1.2 倍。

编组 ​

编组即是使用一对 {} 对内容进行包围的操作, 实现隔绝渲染环境, OLeX 对编组进行了实现。但是为了更好的歧义消除效果, 对于 OLeX 来说, 还是更推荐使用 \CommandName{} 的形式, 会在语法上对非控制系列分组进行考虑实现。

类似于 {\it centered} 这种组内语句, \it 对其**后面组内的文本渲染(局部作用域)**都起作用, 这一点需要注意。

需要注意: TeX 里面有个控制系列 \/ 可以作为 unslanted 转化过渡。

编组还有一个作用: 将文本的多个单词看作一个单一对象!(OLeX 在词法分析上已经对此部分进行了实现, 需要修改语法分析部分, 并且对不正确编组进行修正)

编组创造了局部作用域的环境。 有时候为了突破当前局部作用域, 可以通过定义加上前缀 \global 而实现。例如, TeX 把当前页码放在一个叫 \count0 的寄存器中, 输出一页增加页数。放在组中可以避免上下文影响; 但是对于输出来说 \count0 为局部变量, 会产生掩盖, 命令 \global\advance\count0 by 1 可以实现组内生命周期结束, 对寄存器进行保留。\global 使其后紧接的定义适用在所有存在的组, 无所谓深度。

OLeX 在生命周期通过上下文对此特性进行实现, 并且通过上下文进行传递。

除了上述模块结构的方法, 另一种方法为原始的 \begingroup \endgroup, 但需要保证实际执行文本必须是嵌套组, 组不能交叉!

定义控制系列 \beginthe<block name> \endthe<block name>, 只有嵌套才是合法的。

运行 TeX (跳过此部分) ​

运行 TeX 程序会生成一个 .dvi 文件, 不依赖于任何设备, 可以在几乎所有的印刷设备打印出来。

~ 称为带子, (OLeX 暂不对此部分进行实现), 对应书 p17~28。

TeX 工作原理 (跳过实现) ​

  • 一个 <return> 与一个空格类似
  • 一行中的两个空格看作一个 (合并空格操作)
  • 一个空行表示一段的结束

上面的规则并不准确

TeX 可以见到直接由键盘输入的字符行中字符有 256 个, 可以分为 16 类:

类别意义字符
0转义符\
1组开始{
2组结束}
3数学环境$
4表格对齐&
5换行<return>
6参数#
7上标^
8下标_
9可忽略字符<null>
10空格
11字母[a-zA-Z]
12其他字符不在上下文的其他字符
13活动符~
14注释符%
15无用符<delete>

OLeX 支持的字符远超上述所述内容, 换行使用 \n 规范化解决了 CRLF 的问题。

字符输入 ​

TeX 通过 % 对文本进行注释, 通过 \% 键入 %。

TeX 可以通过 \char<number> (number: 0~255) + 空格, 得到相应的字符。比如 \%=\char37, TeX 内部表示字符基于 ASCII 码, 说到底还是通过**“特殊”**的控制系列