https://zhuanlan.zhihu.com/p/33474154
此篇基本上是译文,原文是 Victor Eijkhout 所著的《TeX by Topic》的第一章。译文项目参见:CTeX-org/tex-by-topic-cn。
转载请保留本段文字,尊重原作者和译者版权。
由于原著使用 GFDL,故而本文也被传染地同样使用 GFDL 许可,而不是本站默认的 BY-NC-SA 4.0 许可。
本文原载于 TeX 主题选讲:TeX 处理器的结构
TeX 处理输入的过程可分为 4 个层次。你可以认为 TeX 处理器(也称 TeX 引擎)有
4 个独立的单元,每个单元接收前序步骤的输出,并将输出作为后续单元的输入。第
一阶段的输入是 .tex 文件,最后一个阶段的输出是 .dvi 文件。

通常而言,这样理解上述 4 个层次方便且直观:每个层次完整地接收上一个层次的输出。然而,这样并不完全正确:4 个层次的处理是同时进行的,层次之间也有交互。

4 个层次列举如下(按 Knuth 最初的叫法,分别是「眼睛」、「嘴巴」、「胃」和「肠道」):

输入处理器(input processor):负责为 TeX 从文件系统中读入输入,并处理为记号。记号是两种 TeX 内部对象的统称:构成排版文本的字符记号、待后续两个层次作为命令处理的控制序列记号。
展开处理器(expansion processor):负责展开输入处理器输出的部分记号:宏、条件式、以及部分 TeX 原语。记号展开的过程会将一些(连续的)记号删除或替换为其它记号。
执行处理器(execution processor):不可展开的控制序列即是可执行的;执行处理器负责执行这些可执行的控制序列。执行处理器的部分活动涉及到 TeX 的内部状态之变化:赋值(包括宏定义)是其中典型。除此之外,执行处理器负责构造水平列表、垂直列表和数学列表。
可视化处理器(visual processor):TeX 的最后一个层次负责排版内容的可视化。
可视化处理器将水平列表分行成段,将垂直列表分割成页,将数学列表构建成数学公式;
最终输出 .dvi 文件。可视化处理器的内部算法对于用户是不可见的;不过用户可以通过一系列参数来控制。
输入处理器
输入处理器是 TeX 的一部分,负责将 TeX 从输入文件中读入的内容翻译成记号。它的输出是记号流(stream of tokens):记号组成的列表。大部分记号属于以下两类:字符记号和控制序列记号。还有一类记号是参数记号,留待后续章节讨论。

字符的输入
对于简单的输入文本,其中的字符被输入处理器翻译为字符记号。
在某些情况下,TeX 会忽略一些输入字符;例如,连续空格通常等价于单个空格。
此外,TeX 也会向记号流中插入一些与输入字符无关的记号。
例如在每一行的末尾插入一个空格,以及在每一个空行末尾插入一个 \par 记号。

并非所有的字符记号都会被最终排版出来。事实上,在 TeX 中,字符被分类为 16 类 —— 每一类都有特定的功能 —— 而只有两类最终会被排版出来。其它字符类,像 {、}、& 和 #,都不会被排版出来。因此,TeX 的字符记号的含义由一对数字决定:字符编码 —— 通常是 ASCII 编码 —— 和分类码。具体某一编码的字符对应的分类码是可修改的。

当输入处理器遇到转义字符时(默认是 \),它会将转义字符之后的若干连续个字符拼在一起,形成一个控制序列记号。

对于分类码的处理,TeX 输入处理器的行为可想像为在三种内部状态(NN,新行;MM,行内;SS,忽略空格)中切换的机器。在下一篇中我们会讨论这些状态及其切换。

输入处理器的两个阶段
TeX 的输入处理器本身也可分为两个阶段。因为一些限制(来自终端、编辑器或者操作系统),某些字符可能很难输入。为此,TeX 设计了一套机制来表达这些字符:以两个连续的上标字符来获取所有可用字符。这套机制可视作输入处理器中相对独立的阶段;它运行于上述三状态机之前。

例如,由于 k 和 + 的 ASCII 码之差为 64,所以 ^^+ 会被输入处理器等价地转换为 k。由于这种替换机制发生在形成记号之前,所以输入 \vs^^+ip 5cm 与输入 \vskip 5cm 是等价的。某些情况下,这种用法是很有用的。

注意,这是 TeX 输入处理器的第一阶段,它不考虑分类码,而只是一个从字符到字符的变换。分类码只在输入处理器的第二阶段才起作用:字符的编码和分类码组合在一起,变成一个字符记号。

展开处理器
TeX 的展开处理器接受记号流,并将记号流里的记号逐一展开,直到再无可展开记号为止。宏展开即是其中一例:如果一个控制序列是一个宏名,则根据定义,它将(和可能的参数记号一起)被替换。

展开处理器的输入主要来自输入处理器。自输入处理器而来的记号流被展开处理器展开成仅含有不可展开记号的记号流,最终流向执行处理器。

此外,在处理类似 \edef 及 \write 命令时,展开处理器也会参与工作。这些命令的参数记号会被直接展开,变成顶层的替换文本,而不是这些命令的参数。

记号的展开过程
记号展开的步骤如下:

确认当前待处理的记号是否可展开。
若当前待处理的记号不可展开,则直接将其加入正在构建的记号列表中,并读入下一个记号。
若当前待处理记号可展开,则将其替换为其展开。对不带参数的宏以及一些 TeX 原语(例如 \jobname),该过程只需简单地进行记号替换即可。不过,通常 TeX 需要从输入流中读取一些参数记号,以便构造当前待处理记号的替换形式。举例说,对于带参数的宏,TeX 将读取足够的参数(parameters)记号,而后将这些参数记号作为宏的参数(arguments)。
将展开结果的第一个记号作为待处理记号,继续展开。
宏的可展开性之判断很简单:所有的宏、活动字符、条件式以及部分 TeX 原语(后续文章将给出列表)是可展开的,其他记号都不可展开。因此,展开处理器会负责诸如将宏替换为其展开、对条件是求值而后忽略条件为假的部分的任务;诸如 \vskip、字符记号(包括美元符号和花括号)则原封不动地传到输出流。

几个特例:\expandafter、\noexpand 和 \the
如前所述,记号被展开后,TeX 会继续展开其展开后得到的记号。

\expandafter 是一个特例。初看之下,它只做一步展开,因而破坏了这个规则。例如说

\expandafter<token_1><token_2>
会被替换为

<token_1>
但实际上,这个替换结果还会被展开处理器再次处理。

\noexpand 是另一个特例。当 TeX 遇到 \noexpand,则其下一个记号会被展开处理器当做是不可展开的。因此,展开处理器会把 \noexpand 的下一个记号当做是 \relax 那样,直接将其加入正在构建的记号列表。

举例说,以下宏定义中,其替换文本 \noexpand\b 会在宏定义时被展开:

\edef\a{\noexpand\b}
\noexpand 展开后,其后的记号暂时会被当做是 \relax 的意思。于是,当展开处理器处理下一个记号 \b 时,认为它是不可展开的,并将其直接加入正在构建的记号列表中。因此 \b 就是这个宏的替换文本。

\the 也是一个特例。在 \edef 宏定义中,\the 的展开结果不会被继续展开。

展开处理器中的花括号
之前提到,展开处理器将花括号视为不可展开的字符记号。通常而言,这没错。例如说 TeX 在展开下列 \romannumeral 控制序列时,会一直展开,直到遇见花括号:

\romannumeral1\number\count2 3{4 …
因此,如果 \count2 的值是 0,那么这个控制序列的展开结果是 103 的罗马数字表示。又例如说,展开处理器对待

\iftrue {\else }\fi
的方式与对待

\iftrue a\else b\fi
的方式完全一致;即:此时 { 只是一个字符记号,与它的分类码无关。

不过,在宏展开的上下文中,展开处理器会识别和处理花括号。首先,配对的花括号内可用于将其内的一组记号标记为宏的参数。例如,下面定义的单参数宏:

\def\macro#1{ … }
你可以单传一个参数来调用它:

\macro 1 \macro $
也可以使用配对的花括号包裹一组记号作为宏的参数:

\macro {abc} \macro {d{ef}g}
其次,对于带参数的宏,其参数中不得包含未配对的花括号。例如,如下定义的 \a 带有一个参数:包含从 \a 之后开始,直到遇见第一个花括号外的 \stop 位置的全部记号。

\def\a#1\stop{ … }
对于以下用法,\a 的参数应当是 bc{d\stop}e;因为宏的参数中花括号必须是配对的。

\a bc{d\stop}e\stop
执行处理器
执行处理器构建水平列表、竖直列表和数学列表。与之相应,执行处理器有三种工作模式:水平模式、竖直模式、数学模式。这三种模式又分别有「内部」和「外部」两种类型。除了构建列表,执行处理器还需要处理一些与模式无关的操作,例如赋值。

执行处理器的输入是展开处理器输出的不可展开记号组成的流。在执行处理器看来,这条记号流中有两种类型的记号:

触发赋值操作(包括宏定义)的记号,以及触发与模式无关的其他操作的记号(例如 \show 和 \aftergroup)。
构建列表的记号:字符、盒子、粘连。执行处理器对它们的处理方式根据所处模式的不同而改变。
有些记号在所有模式下都可用;比如盒子可用于水平、竖直、数学三种模式。当然,这些记号的作用与效果,根据所处的模式不同而不同。也有记号只在特定模式下可用。例如说,字符记号(确切说是分类码为 11 和 12 的字符记号)则与水平模式密切相关:当执行处理器在竖直模式中遇到字符记号时,会切换到水平模式继续工作。

并非所有字符记号都是可排版的。执行处理器可能遇到数学模式切换标志(默认是 $)、分组起止符(默认是 { 和 })。当执行处理器遇到数学模式切换标志时,它会进入或退出数学模式;而分组起止符则让执行处理器进入或退出新的一层分组。

控制序列 \relax 有些特别:该控制序列是不可展开的,同时执行时啥也不做。为说明 \relax 的作用,可与 \empty 进行比较。

\empty 的定义如下:

\def\empty{}
使用 \relax 时,因其不可展开,故而下例中计数寄存器被赋值为 1:

\count0=1\relax 2
使用 \empty 时,因 \empty 的展开结果为空,故而下例中计数寄存器被赋值为 12:

\count0=1\empty 2
可视化处理器
TeX 的可视化处理器使用了若干用户不可直接控制的算法:断行、切齐、分页、数学排版以及 dvi 文件生成算法。尽管用户不可直接控制这些算法,但可通过一些参数,间接控制它们。

这些算法当中,部分算法的输出结果可被执行处理器继续处理。例如说,分段成行得到一系列行组成的列表;这些行会被加入主竖直列表当中;而每一行又是由若干水平盒子及其中的行间粘连和惩罚组成的。又例如说,分页算法将其结果保存在 \box255当中;而后交由输出例程继续处理。其余算法的输出结果则不然,例如数学公式不可以分解,又例如输出至 dvi 文件的盒子也是不可逆的。

示例
被忽略的空格
被忽略的空格可以反映数据在 TeX 各层处理器之间的流动情况。例如:

\def\a{\penalty200}
\a 0
展开的结果不是(设置惩罚项为 200,并排版数字 0)

\penalty200 0
而是

\penalty2000
这是由于输入处理器会忽略 \a 后的空格,因此展开处理器的输入流中的内容是:

\a0
内部量值及其表示
TeX使用了多种内部量,比如说整数和尺寸。这些内部量的外部表示是同一的:字符组成的字符串。例如 4711 和 91.44cm。

内部量与外部表示之间的转换发生在执行处理器或展开处理器中。具体来说,外部表示向内部量的转换发生在执行处理器中:

\pageno=12 \baselineskip=13pt
\vskip 5.71pt
内部量向外部表示的转换发生在展开处理器中:

\number\pageno \romannumeral\year
\the\baselineskip
最后再举一例。假设 \count2=45,则下列代码

\count0=1\number\count2 3
首先将 \number\count2 被展开为字符串 45,注意 \count2 后的空格被用于界定计数器编号而已被展开。因此,下一级处理时,执行处理器看到并执行的是:

\count0=1453

TeX 主题选讲:TeX 处理器的结构(转)相关推荐

  1. 【OS学习笔记】十二 现代处理器的结构和特点

    本文是一个衔接点,上一篇文章以前都是学习8086实模式的知识.本文开始学习80386这种现代处理器的编程架构.由此进入保护模式的学习.点击链接查看上一篇文章:上一篇文章 1.现代处理器的结构和特点 1 ...

  2. 4.4 竞赛题目选讲

    竞赛题目选讲 这里的题目可能和大家在做的实验项目有些不太一样,希望大家根据自己的需要阅读本章节. 4-2 刽子手游戏 (UVA 489) 书上的题面少了一些很重要的东西,真正的题面请点开这里 分析:根 ...

  3. 苹果和虫子编程题python_2020智慧树《兽医寄生虫学》免费最全题库2020中国大学mooc《线性代数习题选讲》...

    2020智慧树<兽医寄生虫学>免费最全题库2020中国大学mooc<线性代数习题选讲>章节答案 更多相关问题 [多选题]<合同法>第122条规定,因当事人一方违约行 ...

  4. UA CSC696H 强化学习理论选讲1 强化学习概览

    UA CSC696H 强化学习理论选讲1 强化学习概览 强化学习相关概念 Markov Decision Processes(MDP)简介 Policy Evaluation 强化学习(reinfor ...

  5. 练习图200例图纸讲解_【宅家数学课23】经典微课6:苏教版六年级下册比例尺典型例题选讲及练习(含答案)...

    (截止日期:3月31日) 学习过程 1.点击观看经典微课: 微课视频 <比例尺> 2.认真学习典型例题,完成下方练习题 3.查看答案,在家长指导下批改,订正错误. 苏教版小学数学六年级下册 ...

  6. C++11新特性选讲 语言部分 侯捷

    C++11新特性选讲 语言部分 侯捷 本课程分为两个部分:语言的部分和标准库的部分.只谈新特性,并且是选讲. 本文为语言部分笔记. 语言 Variadic Templates move semanti ...

  7. 20190509杂题选讲

    这次杂题选讲好多思维题神仙题啊= =顺便学了波线段树上二分= = Normal 题目大意戳这 CF1083C CDW讲的神仙题*1 题解戳这 AGC002E 我讲的题,是个人写的程序都比我写的程序跑得 ...

  8. PJ可能会用到的动态规划选讲-学习笔记

    PJ可能会用到的动态规划选讲-学习笔记 by Pleiades_Antares 难度和速度全部都是按照普及组来定的咯 数位状压啥就先不讲了 这里主要提到的都是比较简单的DP 一道思维数学巧题(补昨天) ...

  9. [统计学笔记] 统计学计算题选讲(精华)

    统计学计算题选讲 第 1 题 某班级学生物理课程考试成绩分别为:              68  89  88  84  86  87  75  73  72  68              75 ...

  10. 【渝粤题库】陕西师范大学202921 中学数学课程改革选讲 作业(高起专)

    <中学数学新课程标准选讲>作业 一.填空题 1.义务教育阶段的数学课程应突出体现 . 和 ,使数学教育面向全体学生. 2.有效的数学学习活动不能单纯地依赖模仿与记忆, . 与 是学生学习数 ...

最新文章

  1. 孩子斗图老失败,多半是没看这篇博客
  2. 基于python的界面自动化测试-基于Selenium+Python的web自动化测试框架
  3. Java 两线程交替打印奇偶数(一)
  4. web前端常用知识点
  5. delphi 第一个字符不能是小数点_元字符的详细解析
  6. python 如何定义n个变量 (变量声明自动化)
  7. 学android开发,入门语言JAVA知识点
  8. android 系统(7)---android框架大全
  9. 【安全】Kerberos协议介绍
  10. 计算机动态评估英语阅读,计算机辅助二语动态评估系统PELDiaG和CODA的比较研究...
  11. BKMGT你懂吗?那么RPWT你懂吗?
  12. HttpClient 4.1版本,模拟登录,终于成功了(2)
  13. android弹球动画,FlingAnimation/SpringAnimation实现弹球动画
  14. 在Win32API窗体下实现透明背景
  15. Linux下Socket编程一 socket 基础
  16. 2018上海交大计算机考研,2018上海交大学硕考研经验贴
  17. HTML+CSS 焦点图设计(详细步骤)
  18. h3c 链路聚合测试_H3C设备实验之配置链路聚合
  19. java 字体选择器_字体选择器
  20. Kmeans均值聚类算法

热门文章

  1. Python教程笔录摘抄——基础
  2. kaka-manager和kafka-offset-monitor的安装和使用
  3. Rust 调用标准C接口的自定义c/c++库,FFI详解
  4. sof_pof_jic_elf程序下载方法
  5. 2022百万奖金投委团 |香港科大-杰瑞集团 2022【人工智能】百万奖金国际创业大赛...
  6. Python: 进行one-hot编码
  7. C# MemoryStream
  8. java抓取百度搜索结果,一个百度搜索结果内容获取爬虫
  9. 7-1 对象数组 (100 分)
  10. html选课系统制作,校园选课系统的制作方法