关于 TeX 在用 ltxdoc 找到注释条件后会做什么

关于 TeX 在用 ltxdoc 找到注释条件后会做什么

当我以为我理解了包的概念时doc,LaTeX 证明我错了。

我试图制作一个文件来使用,ltxdoc然后我意识到我不能在序言中使用条件,因为它们会让 TeX 从那时起读取序言中的内容,从而破坏事情,因为它不应该。然后我尝试将该代码 MWE 化,却发现了一个更大的问题。

当我以为我理解了条件和扩展的概念时,TeX 证明我错了:)

考虑以下代码(已编号行以便于阅读):

01 % \tracingall
02 % \iffalse meta-comment    ^^A This /iffalse
03 \documentclass{ltxdoc}
04 \def\showfi{\immediate\write0{{/fi\ on line \the\inputlineno}}}%
05 \title{Doc Test}%
06 \newif\ifitsme\itsmetrue
07 \ifitsme\author{Me :)}%
08 \else   \author{Not me :/}%
09 \fi\showfi
10 \begin{document}%
11   \DocInput{\jobname}%
12   \tracingnone
13 \end{document}%
14 % \fi\showfi               ^^A should match this /fi
15 % \fi\showfi               ^^A but it's matching this one
16 % \tracingnone
17 % \maketitle
18 % \endinput

当 LaTeX 启动时,注释就是注释,所以一切都正常进行:加载ltxdoc;定义\showfi(记录在哪一行出现\fi);给它一个标题以避免错误;定义一个新的\ifitsme,将其设置为 true,这使其成为Me :)作者。然后我\showif以防万一(现在不重要)调用。

到目前为止,一切都很好...

然后我\DocInput又打开了同一个文件。评论不再是评论了,事情变得一团糟:)

\DocInput从开始处开始读取文件。我打开了全日志记录\tracingall,然后是通常的来自\iffalse meta-comment文件.dtx。这\iffalse通常会在\fi之后的右侧\end{document}继续读取源。

我认为应该做:

事实并非如此,因为当 TeX 发现错误条件时,它会跳过代码没有展开直到下一个\else\fi,这里是\else行内08(因为 TeX 不会展开\ifitsme来发现它是一个\iftrue)。我期望 TeX 读取它\else并执行\author{Not me :/},然后读取\fi来自行09并显示{/fi\ on line 9}在日志中(然后另一个\begin{document}会出现并破坏一切,但这是另一天的错误)。

什么

TeX 不会跳转到\fi09,也不会跳转到行上14,而是跳转到额外的 \fi(我添加它是因为否则会引发错误)在第 行15。日志显示:

{\iffalse: (level 1) entered on line 2}
{false}
{\fi: \iffalse (level 1) entered on line 2}

\showfi ->\immediate \write 0{{/fi\ on line \the \inputlineno }}
{\immediate}
\write->{/fi\ on line \the \inputlineno }
{/fi\ on line 15}

什么:

什么是 TeX实际上这样做是否不符合我的预期?为什么它不仅跳过了08 \else... 09 \if,还跳过了,而没有(明显)充分的理由14 \fi要求在那里插入一个额外的内容?\fi


不带行号的复制粘贴代码:

% \tracingall
% \iffalse meta-comment    ^^A This /iffalse
\documentclass{ltxdoc}
\def\showfi{\immediate\write0{{/fi\ on line \the\inputlineno}}}%
\title{Doc Test}%
\newif\ifitsme\itsmetrue
\ifitsme\author{Me :)}%
\else   \author{Not me :/}%
\fi\showfi
\begin{document}%
  \DocInput{\jobname}%
  \tracingnone
\end{document}%
% \fi\showfi               ^^A should match this /fi
% \fi\showfi               ^^A but it's matching this one
% \tracingnone
% \maketitle
% \endinput

答案1

正如您正确指出的那样,当您执行 时pdflatex test.dtx,文件会读取%注释字符。当 TeX 发现 时\DocInput,它基本上会忽略%行首并生成^^A注释字符。因此,您的输入基本上是

% \iffalse meta-comment    ^^A This /iffalse
\documentclass{ltxdoc}
\def\showfi{\immediate\write0{{/fi\ on line \the\inputlineno}}}%
\title{Doc Test}%
\newif\ifitsme\itsmetrue
\ifitsme\author{Me :)}%
\else   \author{Not me :/}%
\fi\showfi
\begin{document}%
\iffalse meta-comment    ^^A This /iffalse
\documentclass{ltxdoc}
\def\showfi{\immediate\write0{{/fi\ on line \the\inputlineno}}}%
\title{Doc Test}%
\newif\ifitsme\itsmetrue
\ifitsme\author{Me :)}%
\else   \author{Not me :/}%
\fi\showfi
\begin{document}%
  \DocInput{\jobname}%
\end{document}%
\fi\showfi               ^^A should match this /fi
\fi\showfi               ^^A but it's matching this one
\maketitle
\endinput
\end{document}%
% \fi\showfi               ^^A should match this /fi
% \fi\showfi               ^^A but it's matching this one
% \maketitle
% \endinput

现在\iffalse已经看到了,但是\ifitsme 在跳过的文本中出现了两次条件,因此\fi需要查找两个匹配项。这就是问题所在,因为不再有匹配项\fi\iffalse除非您像现在这样添加一个。

未注释的行中带有\fi“应该匹配这个 /fi”的行在\ifitsme之后匹配\newif

在条件语句中定义条件语句总是会出现这种问题。使用

\expandafter\newif\csname ifitsme\endcsname

因此当代码位于跳过的文本中时,根本不会有任何条件。

答案2

您的\newif命令位于 内\iffalse,因此看不到它,并且\ifitsme现在根本不是“if”,或者如果\newif已经先前执行过,那么\ifitsme后面的\newif也算数,并且您有一个太多的“if”:

这有效:

\documentclass{article}
\begin{document}

\newif\ifitsme
\iffalse

\ifitsme hello \fi

\fi 
\end{document}

这失败了

\documentclass{article}
\begin{document}


\iffalse
\newif\ifitsme
\ifitsme hello \fi

\fi 
\end{document}

这也失败了

\documentclass{article}
\begin{document}

\newif\ifitsme

\iffalse
\newif\ifitsme %\newif not seen, but \ifitsme so one fi missing
\ifitsme hello \fi

\fi 
\end{document}

士气:最好不要\newif在里面使用\if—— \fi

答案3

这里有一个更安全地跳过内容的技巧。将其放在

\bgroup\catcode2 0 \catcode`\\ 12 ^^Biffalse

^^Bfi^^Begroup

这样做的目的是抑制启动控制序列。因此,您可以确定,在这期间对、、或等\进行的任何操作都不会产生任何影响。\if\fi\else\if...

0x02并且它将起始控制序列的含义分配给 ascii 字节。我们可以做一件安全的^^Biffalse/^^Bfi事情。

我没有使用^^A文档为其分配注释字符,并且我们希望保留它(特别是如果编辑器适当地突出显示)。

我猜你的 MWE 看起来会像这样

% \tracingall
% \bgroup\catcode2 0 \catcode`\\ 12 ^^Biffalse
\documentclass{ltxdoc}
\def\showfi{\immediate\write0{{/fi\ on line \the\inputlineno}}}%
\title{Doc Test}%
\newif\ifitsme\itsmetrue
\ifitsme\author{Me :)}%
\else   \author{Not me :/}%
\fi\showfi
\begin{document}%
  \DocInput{\jobname.dtx}%
  \tracingnone
\end{document}%
% \fi\showfi
% ^^Bfi^^Begroup
% \tracingnone
% \maketitle
% \endinput

文件另存为test.dtx

警告:虽然我使用 doc,但dtx我从未使用过\DocInput(因为它导致了我想要处理保护的方式的无穷无尽的问题,并且因为我不希望文档部分(不是代码实现,而是用户手册)被“注释掉”)所以我不知道这是否会是你的用例。

相关内容