我有以下不起作用的代码:
\documentclass[12pt]{article}
\tracingcommands=2
\tracingmacros=2
\tracingall
\makeatletter
\let\sep\relax
\def\put@stack@#1#2{\edef#2{#1\sep#2}}
\def\put@queue@#1#2{\edef#2{#2\sep#1}}
\def\get@#1#2{\expandafter\get@@#2\endget@@#1#2}
\def\get@@#1\sep#2\endget@@#3#4{\edef#3{#1}\edef#4{#2}}
\def\empty@stack{\sep}
\newtoks\piecetoks
\def\leftrightbr{
\let\o@left\left
\let\o@right\right
\let\piece@nd\relax
\let\pieces@stack\empty@stack
\let\delims@stack\empty@stack
\let\on@end@line\empty@stack
\let\on@begin@line\empty@stack
\def\left##1{
\piece@nd
\let\piece@nd\endgroup
\def\on@first@right{
\put@stack@{\the\toks0}{\pieces@stack}
}
\put@stack@{##1}{\delims@stack}
\let\repl\relax
\let\vphantomer####1{}
\put@stack@{\the\piecetoks}{\pieces@stack}
\put@stack@{\right.}{\on@end@line}
\put@stack@{\left.}{\on@begin@line}
\piecetoks=\begingroup
}
\def\right##1{
\endgroup
\on@first@right
\let\on@first@right\relax
\get@\@dummy\on@end@line
\get@\@dummy\on@begin@line
\get@\@lpart\pieces@stack
\get@\@ldelim\delims@stack
\ifx\@lpart\empty
\repl
\else
\edef\repl{\o@left\@ldelim\@lpart\vphantomer{\the\piecetoks}\repl\the\piecetoks\vphantomer{\@lpart}\o@right##1}
\fi
}
\def\mathbr{
\piece@end
\put@stack@{\piece}{\pieces@stack}
\let\vphantomer\vphantom
\edef\repl{\on@end@line \\ \on@begin@line}
\def\piece\begingroup
}
}
\begin{document}
\begin{equation}
\leftrightbr
\left(a\right)
\end{equation}
\end{document}
那么,问题是什么呢?
编辑:错误是
! Undefined control sequence.
<argument> \@dummy
l.85 \left(
a\right)
查看日志后,我们得出结论,问题是由对 的调用引起的\get@\@dummy\on@end@line
。这似乎很奇怪,因为直接对 \empty@stack 调用 \get@ 不会导致任何错误。
编辑:代码可以缩小:
\documentclass[12pt]{article}
\tracingcommands=2
\tracingmacros=2
\tracingall
\newtoks\piecetoks
\def\leftrightbr{
\def\left##1{
\piecetoks=\begingroup
}
\def\right##1{
\endgroup
}
}
\begin{document}
\begin{equation}
\leftrightbr
\left(a\right)
\end{equation}
\end{document}
这更短,不是吗?:-) 它给出了另一个错误,并且另一个问题出现:我们如何实现 TeX 在两个宏调用之间捕获标记的行为?
答案1
你不能将令牌分配给具有
\piecetoks=\begingroup...\endgroup`
你也不能用一个宏开始任务,用另一个宏结束任务,因为
<toks register>={...}
需要一个明确的末尾加上括号,并且在评估要<balanced text>
存储的内容时不会发生扩展。
在 TeXbook 第 276 页,你可以找到 a<variable assignment>
是什么;其中一种替代方法是
<token variable> <equals> <general text>
上面有一些你看到
<general text> → <filler> { <balanced text> <right brace>
在语法规则中,{
表示类别代码为 1 的隐式或显式字符标记,而<right brace>
表示明确的类别代码为 2 的字符标记。
答案2
分隔参数需要查找固定的标记,但您不需要提前查找\\
- 或者 -\right
您可以提前查找\right
,然后查看您收集的标记以查看是否存在\\
。
所以
\documentclass{article}
\makeatletter
\newtoks\tA
\newtoks\tB
\def\left#1\right{%
\zz#1\\\right}
\def\zz#1\\#2\right#3{%
\ifx\relax#2\relax
\tA{\left#1\right#3}%
\typeout{^^J^^Jno \space\string\\:^^J\the\tA^^J}%
\expandafter\remove@to@nnil
\else
\tA{\left#1\right.\\}%
\expandafter\zzb
\fi
#2\right#3\@nnil}
\def\zzb#1\\\right#2\@nnil{%
\tB{\left.#1\right#2}%
\typeout{^^J^^Jhas \string\\:^^J\the\tA\space \the\tB^^J}}
\makeatother
\begin{document}
\left( a b\right)
\left( a \\ b\right)
\end{document}
生产
no \\:
\left ( a b\right )
has \\:
\left ( a \right .\\ \left . b\right )
但是我永远不会在生产中使用它。重新定义\left
并\right
接受宏参数会改变它们的扫描规则,并会引入各种不兼容性。即使你通过使用新名称而不是重新定义原语来避免这种情况,\right.\\ \left.
在换行符处使用也不能确保成对的分隔符大小相同,因此无法产生可接受的结果。
实际上最好只\bigl(
在一个单元格中使用,然后\bigr)
在稍后的单元格中使用。