这是一个“TeX 如何知道何时停止”的问题。
情况1
注意:后来我发现我的理解是错误的。请参阅剧透和答案。
当 TeX 构造宏名时,它会使用所有第 11 类标记,直到扫描到非第 11 类标记。非第 11 类标记是
- 已扫描:真实
- 排版:FALSE
案例 2
当 TeX 构造寄存器值时,它会使用类别 12(数字)的所有标记,直到找到非类别 12 的标记。非类别 12 的标记在某种程度上既是
- 已扫描:真实
- 排版:TRUE
代码
\documentclass{article}
\usepackage{fontspec}% xelatex
\begin{document}
\section{Macro Name Scanning}
\def\macro{123}
\count1=\macro
4
This is a register: \the\count1. Notice that the first 4 was consumed by the TeX scanner as expected.
\section{Register Value Scanning}
\count1=42
\advance\count1 by1000The < The \textit{T} in \textit{The} should have been consumed by the TeX scanner before being typeset. Where does \textbackslash relax come into play here?% Why is the T not consumed by the number scanner (catcode 12)
\end{document}
输出(排版)
笔记
我预计\relax
在情况 2 中我需要在 T 之前加上一个,就像\macro
在情况 1 中在 T 之后加上一个一样。
剧透警告
下面的答案解释了我的困惑,但我想指出我学到的一些东西:
宏构造(扫描 csnames)和寄存器值构造(扫描数字值)之间的区别是:
- 控制序列名称/宏名称扫描:TeX 扫描字符 字节(代币尚未创建,而是在此步骤中主动创建)
- 寄存器值扫描:TeX 扫描字符标记(标记化已经发生。字符标记是由以下项组成的整数对:(角色代码、猫代码))
这具有重要意义。
- 控制序列名称/宏名称扫描查看文件的所有字符字节并应用某些 TeX 标记规则(例如,何时在宏后省略某些字节,如空格或换行符)
- 寄存器值扫描永远不会看到字符字节,而是看到处理字节后产生的字符标记流。遇到宏标记时会进行扩展,并且换行符字节已转换为 catcode 10(我不确定 catcode 5 在这里会在哪里发挥作用)。此阶段也有一个空格规则。读取时会删除 Catcode 10 标记,而不会将其放回输入流中。
附言:我真心希望我所掌握的细节正确!
答案1
我认为您对扫描宏名称的描述并不准确(虽然我不知道您所说的 typeset:false 是什么意思,所以这可能是也可能不是真的)
请注意,扫描宏名称前标记化(或者更确切地说,在标记化过程中),因为它是确定是否要生成 csname 标记。在看到具有 catcode 0 的字符(不是标记)之后,如果下一个字符具有 catcode 11,则所有后续 catcode 11 字符都将作为 csname 的一部分进行扫描,如果第一个非 catcode 11 字符将生成 catcode 10(空格)的标记,则将使用第一个非 catcode 11 字符,并且不对其进行标记化,否则将其放回输入流中。
数字是 tex 内部执行的一部分(TeXBook 称之为“胃”),因此后代币化和后 宏扩展。如果 TeX 正在解析,<number>
那么它将扩展所有标记,直到找到一个属于数字语法的不可扩展标记(因此 catcode 为 11 或 12 位数字,或者在"
十六进制字母 AF 和其他形式(例如字母字符代码数字,例如`a
或)之后。`\a
第一个不属于语法的不可扩展标记<number>
始终作为标记返回到输入流,除非它是一个空格标记,即此处的 T。
答案2
你的假设是错误的。当对计数寄存器进行赋值时,TeX 遵循语法
<count register><optional equal sign><number>
其中<count register>
可以是内部数字寄存器(例如\hyphenpenalty
),\countdef
标记(在 之后\newcount\foo
或直接\countdef\foo=1
)或\count<number>
。
可以<optional equal sign>
是空的,也可以是空格标记,或者是=
12 个被(可选)空格标记包围的(嗯,这有点复杂,但并不真正相关)。
A<number>
由可选基数指示符组成
` ' "
然后是相应基数的数字序列。对于反引号的情况,“数字”是单个字符或长度为 1 的控制序列(字母常量)。对于'
数字,是其中01234567
(类别代码为 12);对于"
数字,是0123456789ABCDEF
(其中字母可以具有类别代码 11 或 12,但0123456789
必须具有类别代码 12)。如果没有指示符,则假定为十进制,并且可接受的数字具有0123456789
类别代码 12。
当 TeX 在宏扩展后发现无法解释为所选基数的合适数字的标记时,结束<number>
。如果此标记是空格,则会被吞噬。
你的例子
\def\macro{123}
\count1=\macro
4
分配给\count1
整数,因为和1234
之间没有任何东西\macro
4
,因为空格被忽略在标记化过程中在控制字之后(并且在同一标记化阶段,行尾字符被转换为空格)。如果你想分配123
并打印4
,你必须说
\count1=\macro\space 4
(是否4
在下一行无关紧要)。
的语法\advance
类似(而不是=
可选的by
);因此
\advance\count1 by 1000T
对数字的搜索将停止在T
,但它也会停止在!
。
关于上述作业还有几点要说。
\count1=\macro
4
TeX 看到六个标记
\count • 1 • = • \macro • 4 • ⍽
(空格只是为了清晰起见,• 将标记彼此分开)。使用
\count1=\macro4
\count1=\macro 4
因为关于标记化的规则。不空间令牌之后\macro
。最后一个⍽
表示从行尾派生的空格标记,它被标记化是因为它在宏名构造期间不会被忽略。
由于\count
是不可展开的,TeX 会“执行”它,这意味着它必须执行赋值,因此<number>
会搜索 a;下一个标记是 ,1
这是正确的;下一个标记是=
,因此停止搜索数字,TeX 知道它必须为 赋值\count1
。=
是可选的,因此 TeX 开始搜索数字。第一个标记是可扩展的,因此 TeX 会将其展开为
1 • 2 • 3 • 4 • ⍽
现在⍽
停止搜索数字并可以执行分配。此空间标记被规则吞噬。
让我们检查一下
\count1=42
\advance\count1 by1000The
并将其分成 token:
\count•1•=•4•2•⍽•\advance•\count•1•⍽•b•y•1•0•0•0•T•h•e
(为了紧凑,没有排版空间,•
仍然将标记彼此分开)。 的分配与之前一样42
执行\count1
,并且空间标记被吞噬。 我们仍然
\advance•\count•1•⍽•b•y•1•0•0•0•T•h•e
的执行\advance
使 TeX 搜索合适的寄存器名称,它找到了\count1
(查找寄存器编号后,空格标记将被忽略)。 Nextby
被吞噬,因为它是一个可选关键字,我们仍然使用
1•0•0•0•T•h•e
TeX 正在寻找,<number>
所以它像以前一样,具有宏扩展。但是没有宏可以展开,并且对数字的搜索在第一个不是基数 10 的数字的标记处停止,因此在T
。执行赋值并\count1
为其分配值1042
。接下来重新检查标记T
,它将开始一个段落。
要小心,因为类似
\count1="1000At this point
将分配给\count1
值 65546 并以 开始一个段落t
。
始终以非数字的不可扩展标记结束常量。空格很适合这种情况,因为它会被忽略。
答案3
你说的“构造宏名”是什么意思?
在读取/标记输入时,所讨论的控制序列标记是否表示宏、原始控制序列或未定义的控制序列并不重要。
在读取和标记输入时,尚无标记,因此控制序列标记的名称不包含任何标记。它们由字符(而非字符标记)组成。\string
可用于获取相应字符标记的序列。\csname..\endcsname
提供一种通过可扩展标记和字符标记序列来表示控制序列标记的方法。
始终要注意何时适合使用术语“token”,何时不适合使用术语“token”,因为 -eh-“思考的对象”不是token/不是由于标记化或扩展而产生的东西。
控制序列标记有两种形式:
- 控制符号标记。
- 控制字标记。
输入中的两个字符序列,其中第一个字符的类别代码为 0(转义),第二个字符的类别代码不为 11(字母),用于识别控制符号 标记因此相应的控制符号标记将被“放置”到“标记流”中。
输入中的字符序列中,第一个字符的类别代码为 0(转义),并且该序列的所有尾随字符的类别代码均为 11(字母),该序列用于识别控制字标记因此相应的控制字标记将被“放置”到“标记流”中。
\csname\endcsname
IIRC在没有附加结束符的情况下,通过或通过输入行末尾的类别代码为 0(转义)的字符表示的“无名”控制序列标记也是一个控制字标记。
通过扩展\csname..\endcsname
或\ifcsname..\endcsname
而产生的控制序列标记,其名称形成除单个非 catcode-11 字符之外的字符序列,也是控制字标记。
在读取/标记控制字标记后,TeX 的读取装置将切换到状态 S(跳过空格)。在非扩展写入控制字标记时,TeX 将写入/附加一个额外的空格字符。
在读取/标记控制符号标记后,TeX 的读取装置将切换到状态 M(行中)。在未展开写入控制符号标记时,TeX 不会写入/附加额外的空格字符。
(请注意,在书写时将一个字母控制序列标记作为控制字标记或控制符号标记进行处理取决于书写时所讨论的字母/字符的类别代码。)
使用 -assignment 收集的最后一件事\count
是<number>
。
该术语所包含的数量的组成部分<number>
在 Donald E. Knuth 的TeXbook,第24章 垂直模式总结。
当收集/读取 的组件时<number>
,除非 TeX 处于不扩展标记的情况,否则将进行扩展。这些情况列在第 20 章:定义的TeXbook。
可以放肆地说,在收集 a 的组件的某些情况下,唯一可能被“消耗”的东西<number>
是<one optional space>
。