关于 TeXbook 练习 11.5 的问题

关于 TeXbook 练习 11.5 的问题

在回答练习 11.5 时有这样的评论:

\def\\{\if\space\next\ % assume that \next is unexpandable

这个注释是什么意思?如果\next可以扩展,我们必须使用以下内容吗?

\def\\{\expandafter\ifx\space\next\ %

有人能想出一个例子来说明这种差异吗?

\endlist另外,如果我们改为如下形式,结果也不会改变\end

-\def\dodolist{\ifx\next\endlist \let\next\relax
+\def\dodolist{\ifx\next\end \let\next\relax
-\def\endlist{\endlist}
+%\def\end{\endlist}
-\def\demobox#1{\setbox0=\hbox{\dolist#1\endlist}%
+\def\demobox#1{\setbox0=\hbox{\dolist#1\end}%

使用的意义是什么\endlist

编辑

我认为定义一个控制序列(不需要定义)的方法 \endlist就是在这里定义,当用户为新的控制序列选择一个名称时,他可以判断某个特定名称是否正在使用。


这是完整的例子:

\def\dolist{\afterassignment\dodolist\let\next= }
\def\dodolist{\ifx\next\endlist \let\next\relax
  \else \\\let\next\dolist \fi
  \next}
\def\endlist{\endlist}
\def\hidehrule#1#2{\kern-#1%
  \hrule height#1 depth#2 \kern-#2 }
\def\hidevrule#1#2{\kern-#1{\dimen0=#1
    \advance\dimen0 by#2\vrule width\dimen0}\kern-#2 }
\def\makeblankbox#1#2{\hbox{\lower\dp0\vbox{\hidehrule{#1}{#2}%
    \kern-#1 % overlap the rules at the corners
    \hbox to \wd0{\hidevrule{#1}{#2}%
      \raise\ht0\vbox to #1{}% set the vrule height
      \lower\dp0\vtop to #1{}% set the vrule depth
      \hfil\hidevrule{#2}{#1}}%
    \kern-#1\hidehrule{#2}{#1}}}}
\def\maketypebox{\makeblankbox{0pt}{1pt}}
\def\makelightbox{\makeblankbox{.2pt}{.2pt}}
\def\\{\if\space\next\ % assume that \next is unexpandable
 \else \setbox0=\hbox{\next}\maketypebox\fi}
\def\demobox#1{\setbox0=\hbox{\dolist#1\endlist}%
  \leavevmode\copy0\kern-\wd0\makelightbox}
\demobox{Tough exercise.}
\bye

答案1

对于那些找不到此行的读者:

\def\\{\if\space\next\ % assume that \next is unexpandable

在他们的 TeXbook 中,勘误表由 Donald E. Knuth 发布(“第 A311 页”)。

假设你这样做:

\def\foobar{cat}

\noindent
\demobox{The \foobar\ in the hat}

\next获取令牌后\foobar\\将扩展为相当于以下内容:

\if\space\next\ %
\else \setbox0=\hbox{\next}\maketypebox\fi

等于。根据(TeXbook p. 209) 的文档,TeX 将扩展 后面的标记,直到找到两个不可扩展的标记。一步扩展为显式空格标记,因此 TeX 继续(与此时含义相同\next\let,因为它需要一个不可扩展的标记。扩展后,输入相当于:\foobar\if\if\space\next\foobar\next

\if〈space token〉cat\ %
\else \setbox0=\hbox{\next}\maketypebox\fi

其中 〈space token〉 表示显式空间标记(可以定义一个\let与显式空间标记相等的控制序列,并使用它来代替 〈space token〉,参见下面的脚注 1)。现在,TeX 在 后面有两个不可扩展标记\if:一个空间标记和一个c字符标记(在正常 catcode 机制下属于第 11 类)。因此, 的结果\if可以确定:它为假,因为 〈space token〉 和 的字符代码c不同,所以 TeX 将跳到该\else子句。

没有大的到目前为止的问题,尽管我们要cat一次性将整个字符装箱,而不是分别装箱每个字符(cat);但让我们稍微回顾一下。如果我们使用:

\def\foobar{ cat}

输入将相当于:

\if〈space token〉〈space token〉cat\ %
\else \setbox0=\hbox{\next}\maketypebox\fi

测试结果将为真,TeX 将留cat\在输入流中,这是完全错误的,因为我们应该测试我们刚才抓取的是\next,不要插入新文本!

\next因此,在我看来,“假设无法扩展”这一评论可以更笼统地改写为“假设\next最终扩展为 (1) 恰好一个字符标记或 (2) 恰好一个\chardef标记或 (3) 等于 (1) 或 (2) 的控制序列标记\let2(由于“最终”,(1) 中的字符标记必然是非活动的)。实际上,您可以测试当递归扩展为单个字符标记\demobox时是否完美运行,如下所示:\next

\def\myspacei{\myspace}
\def\myspace{\space}

\noindent
\demobox{Abc def\myspacei pU gHi}

截屏

在这里使用\myspacei会产生与使用显式空间标记相同的结果,因为它会递归扩展为这样的标记。

下面是另一个示例,它另外使用了递归扩展为非空格字符标记的控制序列:

\def\myspacei{\myspace}
\def\myspace{\space}

\def\myxii{\myxi}
\def\myxi{\myx}
\def\myx{X}

\noindent
\demobox{Abc def\myspacei pU\myxii gHi}

屏幕截图中还有一个非空格字符标记

您的建议:

\def\\{\expandafter\ifx\space\next\ %
...

只要 等于空格标记(显式或隐式),它也能工作\next\let但它不适用于包含空格的宏形式的输入,例如\space或我们\myspacei上面定义的宏。事实上,\ifx区分字符标记和宏(参见\ifxTeXbook 第 210 页的说明)。

\endlist最后,虽然它可以工作,但你用替换\end听起来并不是最好的编码风格,因为\end是现有的 TeX 原语;Knuth 选择了一些更“独特”的东西来标记要处理的文本的结尾。此外,名称\endlist显然是选择匹配的\dolist:这是一个一致性问题。具体参见:

\def\demobox#1{\setbox0=\hbox{\dolist#1\endlist}%
...

脚注

  1. 您可以定义一个与显式空间标记相等的控制序列,如下\stoken所示:\let

    {\def\\{\global\let\stoken= }\\ }% now, \stoken is an implicit space token
    

    (改编自 TeXbook 第 376 页)。TeXbook 第 336 页(练习 24.6)中给出了另外两种方法:

    \def\\{\let\stoken= }\\ %
    

    \def\\#1\\{}\futurelet\stoken\\ \\%
    
  2. 尤其是当\nexthas\let等于非活动字符标记时,我认为 Knuth 使用“不可扩展”一词时想到的就是这种情况(实际上,非活动字符标记或 has 等于此类\let标记的控制序列永远不会扩展)。换句话说,条件“\next您引用的评论中的条件“不可扩展”是充分条件以确保宏正常运行,并且只是我给出的更一般条件的一个特例。:-)

答案2

它的意思是: 的参数中只允许使用不可扩展的标记。更准确地说,对应于(通过或)\demobox的字符标记或不可扩展控制序列\chardef\let可打印字符(包括空格)。

如果你试试

\demobox{abc def}

\def\expandable{expandable token}

\demobox{\expandable}

你得到

在此处输入图片描述

这可能不是你所期望的。另一方面,像

\def\expandable{ expandable token}

会产生与预期相差甚远的结果。

因此,\demobox宏只能在其参数由不可扩展的标记或扩展为单身的不可扩展的令牌。

\chardef允许使用标记以及隐式字符标记。但是,这\bgroup也会有问题:\demobox{A \bgroup AB\egroup}与进行比较\demobox{A AB},以查看问题。

您可能想\demobox通过各种方式进行扩展,但这不是练习的目的。

关于您建议重新定义\dolist为使用\end而不是\endlist:如果您愿意,您可以这样做。Knuth 不喜欢它;相反,他使用特定于\dolist处理的控制序列。请注意,每当 扩展时, 的定义\endlist都会产生无限循环\endlist(可能是由于使用 的宏中的错误\dolist),而\end不会。

相关内容