cwebmac.tex 中关于 \maketoks 宏的问题

cwebmac.tex 中关于 \maketoks 宏的问题

考虑以下代码cwebmac.tex

{\setbox0=\hbox{\toksA={1.}\toksB={}\maketoks}\the\toksA}

宏有什么\maketoks作用以及它如何工作?

以下是 pdftex 的完整示例(从 cwebmac.tex 简化而来):

\newtoks\toksA \newtoks\toksB \newtoks\toksC \newtoks\toksD

\newcount\countB \newcount\countC

\def\makenote{%
  \addtokens\toksB{\the\toksC}%
  \toksC={}%
  \global\countC=0
}

\def\poptoks#1#2|ENDTOKS|{\let\first=#1\toksD={#1}%
  \ifcat\noexpand\first0\countB=`#1\else\countB=0\fi\toksA={#2}}

\def\addtokens#1#2{\edef\addtoks{\noexpand#1={\the#1#2}}\addtoks}

\def\maketoks{\expandafter\poptoks\the\toksA|ENDTOKS|%
  \ifnum\countB>`9 \countB=0 \fi
  \ifnum\countB<`0
    \ifnum0=\countC\else\makenote\fi
    \ifx\first.%
      \let\next=\maketoksdone
    \else
        \let\next=\maketoks
        \addtokens\toksB{\the\toksD}
        \ifx\first,\addtokens\toksB{\space}\fi
    \fi
  \else
    \addtokens\toksC{\the\toksD}%
    \global\countC=1
    \let\next=\maketoks
  \fi
  \next
}

\def\maketoksdone{\edef\st{\global\noexpand\toksA={\the\toksB}}\st}

{\setbox0=\hbox{\toksA={1.}\toksB={}\maketoks}\the\toksA}
\bye

编辑

考虑以下 test.w (我\startsection故意禁用不设置目标标记):

\nosecs
\let\startsection\empty
@* Example.
@c
@<Something@>;
@ @<Something@>=
void main (void)

运行cweave test.w,然后处理test.tex

1)通过 pdftex

pdftex test.tex

2)通过 dvipdfmx

tex '\let\pdf+ \input test.tex'
dvipdfmx test.dvi

我们得到以下错误:

1)

pdfTeX warning (dest): num1 has been referenced but does not exist, replaced by a fixed one
pdfTeX warning (dest): num2 has been referenced but does not exist, replaced by a fixed one

2)

dvipdfmx:warning: PDF destination "ii" not defined.
dvipdfmx:warning: PDF destination "i" not defined.

结论是,这个罗马数字只是在 dvipdfmx 中设置目标标记。也许它可以被替换为num #1类似于 pdftex 那样,然后所有这些罗马数字的东西就没有必要了?

答案1

\maketoks解析标记列表变量\toksA并使用临时变量转换其内容\toksD,同时\toksB在交付到最终变量之前积累转换后的材料\toksA\toksB也可能包含以前的内容)。此外,还使用了\toksC其作用如下所述。

请注意,要进行分析,需要知道 的 catcode |ENDTOKS|,我假设|有 catcode other 和字母 catcode letter。 嗯,不,似乎循环必须在击中 之前结束|ENDTOKS|,因此假设击中了出口点,这意味着(见下文)必须在某个点找到一个点。

进入循环。逐个检查遇到的标记。但请注意,代码本身并不是每个标记分析器的标记,而是将事物作为宏参数抓取,#1因此似乎假设遇到的材料没有支撑材料,并且不会看到空格标记(并被修剪)。

  1. 如果标记是 catcode 12 的数字,则附加该数字\toksC并将\countC标志设置为数值 1。

  2. 如果 token 不是 catcode 12,或者是 catcode 12 但不是数字:

    a. 如果之前已经遇到过某个数字,则将(连续的一系列)数字附加到该数字之后,\toksB并将其\toksC重置为空并\countC重置为零,然后继续如下所示。

    b. 否则,如果标记是点,.则退出循环,并将累积的数据放入\toksA(不带点)。剩余的内容将被丢弃。请注意,这里有一个杂散的空格标记(%后面没有\ifx\first.),但显然整个过程是在临时框内执行的,因此不会影响排版。

    c. 否则将标记附加到\toksB。如果它是一个逗号,则会附加一个额外的空格。此处的代码也有一个虚假的空格标记(%之后没有\addtokens\toksB{\the\toksD}),但显然整个代码注定要在临时框内执行,因此这些空格无关紧要。然后继续循环。

简而言之,效果是\toksA保留 直到遇到第一个点的部分(可能点甚至隐藏在 中{.}),其余部分被丢弃,并在逗号后添加空格。关于数字,我不太明白,为什么它们会累积在 中\toksC而不是直接累积在 中\toksB,因为最终它们的命运似乎与其他标记(我假设主要为字符)没有什么不同。


Igor 在评论中澄清了发布的代码与 中的原始代码略有不同cwebmac.tex。原始代码确实对解析的连续数字系列进行了特殊处理,特别是它似乎创建了 PDF 链接,如果编译通过 pdftex 或例如 tex+dvipdfmx,则语法会有所不同。

% standard macros for CWEB listings (in addition to plain.tex)
% Version 3.68 --- January 2016

我们发现:

\def\makenote{\addtokens\toksB
    {\noexpand\pdflink{\the\toksC}{\romannumeral\the\toksC}}\toksC={}\global\countC=0}

并且:

\ifpdftex
  \ifx\pdfannotlink\undefined\let\pdfannotlink\pdfstartlink\fi% for pdfTeX 0.14
  \def\pdflink#1#2{\hbox{\pdfannotlink height\ht\strutbox depth\dp\strutbox
    attr{/Border [0 0 0]} goto num #1 \BlueGreen #1\Black\pdfendlink}}
\else\def\pdflink#1#2{\setbox0=\hbox{\special{pdf: bc [ \pdflinkcolor ]}{#1}%
    \special{pdf: ec}}\special{pdf: ann width \thewidth height \theheight
      depth \thedepth << /Type /Annot /Subtype /Link
      /Border [0 0 0] /A << /S /GoTo /D (#2) >> >>}\box0\relax}\fi

pdftex 案例使用\pdfannotlink=\pdfstartlink来自 PDFTeX 并使用goto num而不是#2具有 TeX 的\romannumeral,而 dvipdfmx 案例使用#2将其转换为罗马数字。

在其他地方(的定义中\startsection),可以找到如何创建目的地名称的示例:

  \ifpdftex\smash{\raise\baselineskip\hbox to0pt{%
%     \let\*=\empty\pdfdest num \secstar fith}} % bad space in versions < 3.68
     \let\*=\empty\pdfdest num \secstar fith}}% changed in version 3.68
  \else\ifpdf\smash{\raise\baselineskip\hbox to0pt{%
     \let\*=\empty\special{%
       pdf: dest (\romannumeral\secstar) [ @thispage /FitH @ypos ]}}}\fi\fi

所有这些都证实了原文对数字的解析\maketoks确实不是无端的;-)

我不熟悉(这是委婉的说法)PDF 规范,我只能推测不能使用以数字开头或由数字组成的目标标识符,并且关键字num或使用\romannumeral是一种解决方法。这纯粹是猜测。

相关内容