第 11 节的tex.web
内容如下:
@!pool_name='TeXformats:TEX.POOL ';
{string of length |file_name_size|; tells where the string pool appears}
第 519 节的内容如下:
for k:=name_length+1 to file_name_size do name_of_file[k]:=' ';
这两段代码有关联吗?为什么 Pascal 需要在字符串末尾添加空格?代码中的哪些地方用到了这个事实?
答案1
标准 Pascal 的一个“特性”是没有通用的“字符串”类型,每个长度都是一个单独的类型。也就是说,“长度为 40 的字符串”与“长度为 50 的字符串”是不同的类型;函数可以声明为接受一种类型或另一种类型的参数,但不能同时接受两种类型。(事实上,Pascal 根本没有字符串类型,它有数组,同样的问题也适用于数组:不同长度的数组是不同的类型。)
这曾经是使用 Pascal 编程最令人讨厌的事情之一,也是 Brian Kernighan(C 编程语言“K&R”中的“K”)在他的“为什么 Pascal 不是我最喜欢的编程语言”(与 Knuth 用 Pascal 编写 TeX 大约在同一时间编写)。
这种不便正是 TeX 自行处理字符串的主要原因(参见该计划的第 4 部分/第 38 条及以后版本)(我已经开始写一些关于这个的内容这里str_pool
)——大多数情况下,当它需要字符串时,它仅使用预先声明大小的巨型数组的偏移量,例如字符串表示数组中n
位置的任何字符。str_start[n]
str_start[n+1] - 1
str_pool
但有时它需要使用 Pascal 中实际上是数组的字符串,例如传递给系统调用或分配给变量。如果你查看字符串常量
pool_name='TeXformats:TEX.POOL ';
的类型pool_name
不是“字符串”,而是“40 个字符的数组”。稍后pool_name
使用时(第51条), 在
name_of_file := pool_name;
它所赋值的变量属于以下类型(参见第26条)
name_of_file : packed array [1 .. file_name_size] of char;
也就是说,它也是一个包含 40 个字符的数组,这就是为什么可以进行赋值的原因。name_of_file
然后将其传递给系统例程reset
和rewrite
,如下一节 §27 中所示(以及 Marcel Krüger 的回答中所述)。
在程序的其他地方,你会看到将 TeX 字符串(即数组的连续位置str_pool
,如上所述)转换为 Pascal 字符串(特别是转换为 Pascal 字符串)的例程name_of_file
。pack_file_name
第519条你提到的就是其中之一。
这个想法是,如果字符串已存储在 TeX 字符串中(例如,当用户写入时\input foo.tex
,str_pool
数组将包含 7 个字符foo.tex
),则 TeX 将进行name_length
适当设置(此处为 7),然后调用此pack_file_name
过程,该过程将指定 Pascal 字符串name_of_file
后跟foo.tex
空格,以便reset(..., name_of_file, ...)
可以对该字符串进行操作。如果没有通过添加空格来清除字符,则reset
(由 Pascal-H 运行时实现)可能会获取错误的文件名并尝试打开它。
[注:实际上文件名的格式当时是不同的,而且非常不一致,请参阅第 28 部分:文件名,§511以后——斯坦福的文件名有“名称”、“扩展名”和“区域”,可能类似于[1, DEK]
。因此pack_file_name
需要将这些不同的 TeX 字符串组合成一个 Pascal 字符串。但我们可以忽略这种复杂性;这个例子foo.tex
足以解释这一点。]
答案2
在 TeX 程序中,有一个关于此内容的注释(name_of_file
定义之后紧接着):
当前版本的 TEX 所用的 Pascal-H 编译器以非常方便的方式扩展了 Pascal 的规则。要打开文件 f ,我们可以这样写
reset (f , name , ́/O ́) for input; rewrite (f , name , ́/O ́) for output.
'name' 参数的类型为
packed array [<any>] of char
,表示要打开以进行输入或输出的外部文件的名称。name 中可能出现的空格将被忽略。
当然,这似乎只能解释为什么允许有空格,但为什么空格是必要的呢? in<any>
必须packed array [<any>] of char
用持续的数定义为編輯時,因此文件名字符串具有编译时定义的长度。但 TeX 不想限制自己打开文件名长度固定的文件,因此 TeX 默认定义了一个足够大的常数(40),它成为最大文件名的长度。然后可以将文件名写入字段的前几个字节。其余字节应被忽略,因此用空白填充。
当然,您可能会问为什么 Pascal-H 需要如此固定的长度。我只能猜测,但这很可能是为了简化移植到不同系统的过程。可变大小的字符串传递起来相对复杂:它通常必须存储在堆上,不同的编程语言保存长度的约定也不同,等等。操作系统在传递文件名时也可能强制执行自己的约定。另一方面,固定大小的缓冲区只是一块内存。它可以自由传递,可以轻松地在堆栈上分配,并且用任何语言实现的某些系统特定代码都可以解析它并将其转换为正确的格式。
此外,正如 Phelype 所提到的,这通常与 TeX 的实际使用不太相关,因为它位于 TeX 源的系统特定部分。因此,例如在 Web2C 中,它被基于(C 样式的空终止)动态字符串的实现所取代,该字符串的长度最多为,maxint
并且名称末尾不写空格。(相反,代码\0
在那里写入终止符)