每一个评估任何事物的计算机程序都必须区分变量和过程。这是 SICP 中的一个典型例子:
(define (eval exp env)
(cond ((self-evaluating? exp) exp)
((variable? exp) (lookup-variable-value exp env))
((quoted? exp) (text-of-quotation exp))
((assignment? exp) (eval-assignment exp env))
((definition? exp) (eval-definition exp env))
((if? exp) (eval-if exp env))
((lambda? exp) (make-procedure (lambda-parameters exp)
(lambda-body exp)
env))
((begin? exp)
(eval-sequence (begin-actions exp) env))
((cond? exp) (eval (cond->if exp) env))
((application? exp)
(apply (eval (operator exp) env)
(list-of-values (operands exp) env)))
(else
(error "Unknown expression type: EVAL" exp))))
如果表达式是一个变量,则会在环境中查找它。如果表达式是一个应用程序,则会执行它。
在 TeX 中,以下操作似乎可以为变量分配一个值:
\magnification=1200
但这被称为控制序列:
\input MS
在我看来,控制序列(应用程序)看起来与变量相同。TeX 中的求值器如何区分它们?是因为\magnification
返回变量值的不是变量而是访问函数吗?
答案1
在 TeX 中,\magnification
指内部整数寄存器\mag
。当 TeX 寻找整数时,可以使用该值,例如
\count255=\mag
将在整数寄存器中存储 的\count255
当前值\mag
。
TeXbook 会称之为\mag
“参数”,但我认为使用“寄存器”更清楚。
如果 TeX不是寻找一个整数,然后\mag
将触发查找,以便最终 TeX 将在寄存器中存储一个整数,因此在找到
\mag=1200
指定的值将存储在寄存器中。实际上,纯 TeX 提供了\magnification
使用类似语法的,但功能比设置更多\mag
。
对于每个寄存器来说都是如此:当 TeX 正在寻找 <dimen> 时,比如说当你想做 时\kern
,你可以输入
\kern 1in
或者
\kern \parindent
TeX 中变量和“过程”没有区别。如前所述,寄存器名称可以在需要值时使用,也可以作为分配值的触发器,具体取决于上下文。
宏包,例如 LaTeX,试图更好地分离这两个方面,所以你说
\setlength{\parindent}{15pt}
而不是\parindent=15pt
(或者更隐晦,但同样有效的\parindent15pt
)。或者你可以说
\setlength{\parindent}{2\parindent}
如果你想将当前存储的参数值加倍,但这是一种无法强制执行的特定编程风格:如果用户输入
\parindent=2\parindent
效果是一样的。
相反,\input
是触发读取文件以提供输入标记流的原语。其他原语执行其他任务。有时是排版任务,有时不是。
我担心,将 TeX 与其他编程语言进行比较是一条死路。
答案2
TeX 是一个过滤器:它将输入转换为输出。在正常(默认)情况下,如果输入包含,a
则输出包含a
。但也有很多例外。这是与典型的编程语言的主要区别,通过典型的编程语言,我们可以创建计算机程序来解决计算机支持的各种任务。这些任务通常以函数的形式实现:基本函数基于系统调用,其他函数已在库中或由我们编程。因此,TeX 与其他编程语言之间的比较并不总是可行的。
TeX 将输入转换为输出的过程在多个级别完成:输入处理器(转换输入行)、标记处理器(生成标记)、扩展处理器(扩展宏和可扩展基元)、主处理器(执行分配和排版)。核心是主处理器。它从扩展处理器请求单个标记,并在循环中使用该标记执行某些操作。循环体在各种上下文中工作。在正常上下文中,当主处理器获得标记时,a
它会打印a
(将其添加到排版材料的构建水平列表中,但现在这并不重要)。
当主处理器在正常上下文中获得控制序列时,它会根据控制序列的实际含义执行某些操作。如果它的含义是 TeX 原语,则会运行 TeX 中的内置程序(在这种情况下,您会说“函数”)。例如,如果它的含义是\def
,则主处理器转到“分配宏”上下文。在此上下文中,它会关闭扩展处理器并询问给定语法中的下一个标记
\def\sequence parameters{body}
如果读取了该语法的最后一个标记}
,则主处理器将“宏”含义分配给给定的控制序列,将参数和主体保存到 TeX 内存并将控制序列链接到该内存,打开扩展处理器并在正常上下文中继续处理。
如果已读标记的含义(在正常上下文中)是寄存器,则主处理器启动上下文“赋值给寄存器”,并询问此上下文中的下一个标记,直到完全扫描到值(具有精确给定的语法\register=value
或\register value
)。然后赋值,上下文恢复正常。
请注意,扩展宏和获取寄存器的值(用于打印,不用于分配)不是主处理器的工作,这项工作由扩展处理器完成。可以使用可扩展原语获取寄存器的值\the
:扩展处理器获取下一个标记,它必须具有“寄存器”的含义。然后扩展处理器输出它的值(给定语法中的标记序列)。
每个定义的控制序列具有下列含义之一:寄存器、基本命令、字符常量、字体切换器、宏。扩展处理器和主处理器根据处理的控制序列的实际含义做出不同的行为。
也可以看看TeX 简介。
答案3
控制序列的含义有四种:
- 寄存器(原始或声明)
- 原始命令
- 字符常量
- 宏
TeX 的语法没有反映出这些差异。通过查看文档源无法区分它们。当控制序列被定义时,差异被内部存储。控制序列的定义方式指定了它的类型。隐藏的类型信息在评估期间使用。