扩展先前写入文件的控制序列

扩展先前写入文件的控制序列

我正在尝试用纯 TeX 编写一些宏用于交叉引用,类似于 LaTeX 的\label\refEplain 的\xrdef\xref我对 的定义\label称为\label {foo},它在另一个文件中定义了一个控制序列\foo。我的 版本\ref称为\ref {foo},应该扩展到被调用的页码\label {foo};如果\foo未定义,则\ref通过写入控制台通知我。我\label的 工作正常。但我的\ref总是通知我我定义的标签未定义。

例子:

\input ref-label
foo\label {foo}\vfill \eject
bar (\ref {foo})%
\immediate \closeout \refs
\bye

这是 ref-label.tex。

\def \reffile {refs}%
\newwrite \refs
\immediate \openout \refs = \reffile
\def \label #1{\def \text {#1}\makelabel}%
\def \makelabel {\edef \writeit
    {\write \refs
        {\string \def \space \csname \text \endcsname
            {\noexpand \number \pageno}}}%
    \writeit
}%
\def \ref #1{\expandafter \ifx \csname #1\endcsname \relax
    \immediate \write 16 {Undefined label ``#1''.}%
    \else \csname #1\endcsname \fi
}%
\input \reffile\ 

在我的示例文件上运行一次 luatex 后,文件 refs.tex 包含\def \foo {1}; 并且“未定义标签 ``foo''。” 被写入控制台,正如预期的那样。但是,即使在第二次运行 luatex 之后,\ref {foo}控制台中仍会写入“未定义标签 ``foo''。”。因此,\foo似乎仍然未定义,尽管它的定义实际上存在于 refs.tex 中。

注 1:我的\label\ref是从 TeXbook 的\xref[1] 和 Eplain 的\xrdef, \xrefn[2] 拼凑起来的;它们并不是真正“我的”。

注 2:我仅使用纯 TeX 编写所述宏。如果大家不建议我使用其他格式、引擎或软件包,我将不胜感激。

[1]:TeXbook,第 419-420 页。

[2]:缺乏耐心的 TeX,第 302-304 页。

答案1

您需要\reffile在开始时输入 - 以收集上一次运行的值。正如您所做

\immediate \openout \refs = \reffile

它会在你执行之前清空文件

\input \reffile\ 

顺便说一下,那条线应该是

\input \reffile

否则您将强制在文档中出现空白。


\def \reffile {refs}%
\newwrite \refs

\newread\refcheck
\openin\refcheck=\reffile


\ifeof\refcheck\else
\input \reffile 
\fi

\immediate \openout \refs = \reffile
\def \label #1{\def \text {#1}\makelabel}%
\def \makelabel {\edef \writeit
    {\write \refs
        {\def \expandafter\string\csname \text \endcsname
            {\noexpand \number \pageno}}}%
    \writeit
}%
\def \ref #1{\expandafter \ifx \csname #1\endcsname \relax
    \immediate \write 16 {Undefined label ``#1''.}%
    \else \csname #1\endcsname \fi
}%

答案2

主要问题是,正如 David Carlisle 所说,你输入的是\reffile 已打开它以进行写入,但此操作会清除该文件。

你还可能犯一些错误;例如,关闭文件不应该是立即的,否则你可能会丢失材料。其次,你正在定义不合理的宏,这可能会覆盖现有的宏。如果你这样做\label{box},你最终会陷入非常严重的麻烦。所以最好用一些前缀来修饰宏。

您还拥有一个似乎不需要的间接层:如果您需要写入标记列表的某些部分,而这些部分应该立即展开,那么它很有用,但您的情况并非如此。定义毫无意义\text:定义的宏越少,覆盖所需宏的风险就越小。

我添加了重复标签检查。我认为最好使用宏,而不是直接将宏写入辅助文件\newlabel:它使编写变得更容易。

\edef\reffile{\jobname refs.tex}

% read the labels
\def\newlabel#1#2{%
\expandafter\show\csname ref@#1\endcsname
  \expandafter\def\csname ref@#1\endcsname{#2}%
}

\newread\refcheck
\openin\refcheck=\reffile\relax % <--- important
\ifeof\refcheck % still no refs file
\else
  \input\reffile
\fi
\closein\refcheck

\newwrite\refs
\immediate\openout\refs=\reffile % this clears the file

\def\label#1{%
  \expandafter\ifx\csname label@#1\endcsname\relax
    \write\refs{\string\newlabel{#1}{\the\pageno}}%
    \global\expandafter\let\csname label@#1\endcsname\empty
  \else
    \immediate\write16{Duplicate label ``#1''.}%
  \fi
}
\def\ref#1{%
  \expandafter\ifx\csname ref@#1\endcsname\relax
     \immediate\write16{Undefined label ``#1''.}%
  \else
    \csname ref@#1\endcsname
  \fi
}

foo\label{foo}

\vfill\eject

bar (\ref{foo})%

\closeout\refs % not \immediate
\bye

相关内容