当我们为没有耐心的人阅读 TeX 时,我们了解到:
- TeX 的“眼睛”将输入文件转换成字符序列;
- 然后 TeX 的“嘴巴”将字符序列转换成 token;
- 然后,“食道”会产生一系列原始命令的标记;
- 最后“胃”执行命令所指示的操作。
我从未见过其他语言使用这种标记系统。Pascal、C、PHP、SQL、LISP 等都不使用它。
- 为什么 TeX 需要标记?
- 它们是用来做什么的?
- 为什么其他计算机语言却没有问题?
这个问题并不重复,因为它最终会问为什么 TeX 使用 token,出于什么目的,它们的目的是什么,有什么问题可以证明它们的使用是合理的。这个 token 系统有目的、动机、终结性、附加概念,哪些?
答案1
让我忽略问题中提到的眼睛-嘴巴-胃(和......)术语,这是 Knuth 对 TeX 的描述中真正独特的,并特别关注代币问题询问的是:
我从未见过其他语言使用这种标记系统。Pascal、C、PHP、SQL、LISP 等都没有使用它。[…] 为什么其他计算机语言没有问题?
事实并非如此。只需搜索几秒钟,你就会发现全部这些语言在实现中使用标记:
帕斯卡:
- GNU Pascal:GNU Pascal 手册,第 12 章:GPC 源参考,12.2 12.2 GPC 的词法分析器:“编译器的最初阶段负责读取你所写的内容并将其分成标记,即计算机语言的“原子”。
- 免费 Pascal:免费 Pascal 参考指南,第 1 章:Pascal 标记:“标记是源代码的基本词汇构成块:它们是语言的‘单词’:字符根据编程语言的规则组合成标记。”
C:
PHP的:
SQL:
- PostgreSQL 9.6.3 文档,第 4 章 SQL 语法,4.1. 词汇结构:“SQL 输入由一系列命令组成。命令由一系列标记组成,以分号(“;”)结尾。”
- DB2 SQL,语言元素,代币:“SQL 语言的基本语法单位称为标记。”
Lisp:
- ANSI Common Lisp 标准,第 2 章 语法,2.3 代币的解释
- Common Lisp 语言,22.1. Lisp 对象的打印表示,22.1.1. 读取函数接受的内容:“组成字符和转义字符累积起来形成一个标记,然后将其解释为数字或符号。”
一个微妙的区别是,在学习这些语言时,你可能没有遇到任何关于 token 的提及,因为它们可以被视为编译器语言。但就 TeX 而言,严格来说,不存在“语言”(例如,一种语言标准,有多个为该语言编写的编译器):只有一个系统,即 TeX 程序,它的编写方式恰好类似于编译器。
TeXbook没有在任何地方使用“编译器”这个词,但是TeX:程序(texdoc tex
调用阅读) 以。。开始
1. 简介。这是 TeX,一个旨在生成高质量排版的文档编译器。
因此,Knuth 至少在编写程序时将 TeX 设想为“文档编译器”。请记住,Knuth 的编程背景是编写编译器:
- 20 世纪 50 年代末,在凯斯理工学院读书时,他与他人合作编写了一个名为朗西布尔(继《MAD》杂志之后,这是他的第二部作品)(观看讨论从这里开始),
- 凭借这一点,他在 Burroughs 获得了一份顾问的工作(当时还是一名学生),负责编写 Algol 58 编译器(请阅读 Richard Waychoff 对此的描述“III. 1960 年夏天 (与 don knuth 共度的时光)”
- ……就这样……直到 1962 年,Addison-Wesley 找到他,请他写一本关于编译器的书,这本书后来成为了他(正在进行的)一生的工作,计算机编程艺术。
- 1977 年,当他想要编写 TeX 时,许多前身,如 PUB(参见 Knuth 的注释)PUB 和 TeX 之前的历史在 TUGboat 中)被编写为(或称其为)编译器:PUB 手册标题为“PUB:文档编译器”。
因此,TeX 的编写方式很自然地像一个编译器。
总体执行计划——将字符读入标记(语法),然后将其转换为命令(语义)——是大多数编译器的编写方式(的一部分)。事实上,术语句法和语义甚至不局限于编程语言:它们在语言学中用于人类语言。
答案2
存在一些技术差异,但主要只是 D. Knuth 使用的“特殊”术语,几乎所有系统都分阶段进行解析,将词法分析(例如区分名称和数字文字)与解析本身(识别程序结构)分开。标记是词法分析的输出。
TeX 的版本相当独特,你可以在运行过程中更改词法分析,因此在 tex 中, \foo@bar 可能是一个标记(\foo@bar
)或 5 个标记(\foo
,@
,b
,a
,r
)或 8 个标记(\
,f
,o
,, ,o
,),具体取决于 catcode和(或其他数字)的标记,以获得更奇特的 catcode 设置),而大多数语言使用固定的标记化。@
b
a
r
\
@
TeX 中标记化的这种动态方面意味着它扮演着更为明显的角色,在 C 或 java 中,它只是假设并且通常不说,诸如 1+abc 之类的表达式是三个标记1
, +
, abc
,并且它不依赖于某些运行时值,而 abc 是否是代表变量的单个标记或两个并列的a
标记bc
。