为什么 Tex 没有合适的调试器?

为什么 Tex 没有合适的调试器?

为什么 TeX 没有调试器?我所说的“调试器”是指一个专用的应用程序,您可以在其中设置断点并观察寄存器、宏等的值的实时变化,甚至可以预览如果现在渲染一个框寄存器会是什么样子,并尝试一下临时 TeX 表达式现在会扩展成什么,并一次一个地逐步完成宏扩展?

答案1

我可以看到提出或解释该问题的几种方式:

  1. TeX 本身中已经存在哪些方法,可以调试我编写的宏,或者排版我做的事情(框等)?

  2. 为什么没有办法进行“正确”的调试:设置断点、观察值的变化、一步一步地执行程序(例如宏扩展)、跨过(跳过)等?

  3. 有人告诉我 TeX 是一种编程语言;它不应该像其他编程语言一样有一个调试器吗?


对于 (1),TeX 中有一系列功能可以查看诊断输出:\show以及\tracing宏、包装它们的包等。请参阅如何最好地调试 LaTeX?LaTeX 日志分析器应用程序(可视化 TeX 扩展)等等。继续(2)…


TeX 是一个程序,和任何程序一样,它可以通过在调试器。(例如,用 C/C++ 编写的程序通常可以在gdb和 Visual Studio 等调试器中运行。有关调试器的更多信息:列表比较

TeX 的作者 Donald E. Knuth 深知调试器的价值。他在斯坦福人工智能实验室用编程语言 SAIL 编写了 TeX 的原始版本(后来称为 TeX78),并在编程时使用了可用的调试器。(它被称为保释texdoc errorlog)他非常喜欢这个调试器(如果我没记错的话,他在某个地方对它赞不绝口),甚至在重写的(当前)程序中,他也提到了它:如果你调用texdoc tex您会在第 2 部分(目录后的第一页)看到以下文字:

作者在 1977 年末和 1978 年初设计并编码了 TeX 的完整版本;该程序与其原型一样,是用 SAIL 语言编写的,该语言具有出色的调试系统。

他也知道调试的价值。甚至在 1964 年,当他写第一卷计算机编程艺术,他在“我们通过简要讨论如何编写一个复杂而冗长的程序来结束本节”的部分添加了这些文字:

步骤4(调试)。[…] 调试是一门需要进一步研究的艺术,而其方法在很大程度上取决于每台计算机安装时可用的设施。[…] 最有效的调试技术似乎是那些设计和内置于程序本身的技术——当今许多最优秀的程序员会将近一半的程序用于促进另一半的调试过程;前半部分通常由相当简单的例程组成,这些例程以可读的格式显示相关信息,最终将被丢弃,但最终结果是生产力的惊人提高。

因此,在 TeX 程序中,除了各种\show\tracing例程(参见上面的 (1))之外,他还在适当的位置为 TeX 程序添加了各种特殊例程(就像他对许多程序所做的那样),这些例程旨在从调试器中调用。这些都标记在里面调试古贝德TeX 程序中的节。(这是一个宏,在调试模式下定义为“无”,在非调试模式下定义为 begin-comment / end-comment。)如果您查看 TeX 程序索引中的条目debug,您将看到它在 TeX 程序的第 7、9、78、84、93、114、165、166、167、172、1031、1338 节中使用。其中最后一个开始 TeX 程序的第 52 部分,标题为调试

调试。一旦 TeX 开始工作,您就应该能够使用\show命令和其他诊断功能诊断大多数错误。但是对于调试的初始阶段以及为了揭示真正深奥的奥秘,您可以使用一些辅助工具来编译 TeX,包括 Pascal 运行时检查及其调试器。一个称为调试帮助D在错误消息后输入“ ”时也会发挥作用;调试帮助也会在致命错误导致 TeX 崩溃之前发生。

接口调试帮助虽然很原始,但与 Pascal 调试器一起使用时就足够了,因为调试器允许您设置断点并读取变量并更改其值。在获得提示符“ debug #”后,您可以输入负数(这将退出调试帮助)或零(这将转到可以设置断点的位置,从而进入与 Pascal 调试器的对话)或正数随后发生争论n[…]

所以如果TeX 是在调试模式下构建的,然后在 TeX 显示的提示符下

Type <return> to proceed, S to scroll future error messages,
R to run without stopping, Q to run quietly,
I to insert something, 
1 or ... or 9 to ignore the next 1 to 9 tokens of input,
H for help, X to quit.

如果您点击秘密选项D,它将进入调试器,您可以在其中使用调试器的所有常规功能以及 Knuth 添加的功能。(请参阅 TeX 程序的第 84 节。)不过,不要费心在由 TeX Live / MikTeX(等)分发的 TeX 中尝试它:不幸的是,自 80 年代末左右以来,TeX 不再作为可以使用 Pascal 调试器运行的 Pascal 程序运行。它主要是通过web2c(最初由 Tomas Rokicki 编写)翻译成 C 构建的,这失去了许多调试辅助功能。

不过,如果你自己构建 TeX,还是有可能重新获得一些调试。请参阅Graham Douglas 的这篇文章“深入了解 TeX:C 帮助我看清”(最近加入 Overleaf并写道一些他们在博客上发表了精彩文章):在 2014 年的这篇文章中,他描述了如何在调试器中运行 TeX。(另请参阅他在这个网站上的这个回答。) 他写:

尽管我收藏了不少关于 TeX 的书,但我一直觉得很难理解 TeX(语言和程序)的实际工作原理。因此,对我来说,通过在 TeX 执行时逐步执行 C 代码(通过 Visual Studio 界面单步执行)来观察 TeX 的某些部分的实际工作原理更有启发性。[…]

尽管很难理解 TeX.C 的执行过程,但观看 TeX 的实际运行过程仍然令人着迷:解析输入文件、根据 catcode 值进行操作、创建标记、定义宏、构建框、运行页面生成器并发送页面。虽然我才刚刚开始通过 C 代码探索 TeX,但它已经开始消除我对 TeX 语言的一些困惑——即使我对这个真正非凡的程序还只是一知半解。

我认为这正是您所要求的。

我个人认为,这种“查看” TeX 的方式无法被更多用户使用是一个悲剧。(我有一些改进的想法,我曾经想过要实现它,但现实地说,这需要大量工作,我可能永远也抽不出时间去做……但愿有人能做到!)


对于 (3): 不,TeX 是不是一种编程语言,不管别人怎么告诉你。它是一个排版程序,其中包括一个宏扩展系统,而这个宏系统恰好是图灵完备的,可能的编程,但这不一定意味着这是个好主意。是的,Lamport 提出了一些 TeX 编程技巧并利用它们构建了一个复杂的体系,实现了他对文档准备系统的设想,其他人也在此基础上进行了进一步的开发。但这样的编程这不是 Knuth 的主意甚至当他编写非平凡的宏时,他也有些不情愿:

TeX 是为排版而设计的,而不是为编程而设计的;因此,当它被视为一种编程语言时,它充其量只是“奇怪的”。——DEK,数字排版, 第 235 页

有时,程序中添加的一些功能最终会成为一种编程语言(参见意外的图灵完备令人惊讶的图灵完备):可以编写程序Apache 的mod_rewrite规则, 在Haskell 类型系统等等。用 TeX 宏编程,嗯……不是那么不合常规,但仍然需要一定程度的反常。:-)

TeX 宏扩展的工作方式可能很难理解和解释,正如 Knuth 发现的那样他教授了一门有关 TeX 程序的课程(TeX 程序源代码是该课程的教科书。)结果,他添加一些诊断输出并将其称为新程序:

这个问题的答案在课堂上解释起来比我想象的要困难得多,所以我猜想学生解答起来也比我想象的要困难得多。在第一次尝试解释答案之后,我决定编写一个特殊版本的 TeX,以帮助阐明扫描例程。这个特殊程序称为 DemoTeX,它与普通 TeX 一样,只是用户\tracingstats>2可以慢动作观看 TeX 的语法例程。

此输出的格式有点神秘,因为它必须在终端上显示所有内容,但如果您摆脱这种限制,您可以使其更具可读性。我在本地玩过类似的东西,它可以提供很多信息。同样,不幸的是,这不是一件容易获得的东西,但原则上是可能的。

相关内容