![脆弱的 \end{frame} 破坏了 beamer 之后的评论](https://linux22.com/image/370393/%E8%84%86%E5%BC%B1%E7%9A%84%20%5Cend%7Bframe%7D%20%E7%A0%B4%E5%9D%8F%E4%BA%86%20beamer%20%E4%B9%8B%E5%90%8E%E7%9A%84%E8%AF%84%E8%AE%BA.png)
今天我花了比我想承认的更多的时间被代码中的一条评论打败了......
我试图在演示文稿中插入一些逐字记录,但出现了以下错误:
Runaway argument?
! File ended while scanning use of \next.
然后,将整个事情简化为 MWE,我得到了这个:
\documentclass{beamer}
\begin{document}
\begin{frame}[fragile]
Hello :)
\end{frame}% NO :(
\end{document}
并且错误仍然存在。
然后,当我删除评论后,\end{frame}
整个事情就成功了。
有人能解释一下这里发生了什么吗?
免责声明:不,我不需要那里的评论:P
答案1
在对 的内部进行一些挖掘之后,beamer
我发现答案正如埃格格指出的那样,是逐字处理器。
对于[fragile]
框架,beamer
使用位于的逐字处理器beamerbaseverbatim.sty
。Beamer 有一个简洁的逐字处理器:
\protected\long\gdef\beamer@processframeline#1^^M{%
\edef\beamer@test{\beamer@strip@whitespace#1\beamer@strip@stop}%
\ifx\beamer@test\beamer@stopframe%
\let\next=\beamer@framewritten%
\else%
\immediate\write\beamer@verbatimfileout{#1}%
\let\next=\beamer@processframeline%
\fi%
\next%
}%
处理器是一个分隔宏,它将读取直到回车符(换行符)的所有内容。读取的内容存储在其中\beamer@test
并与之进行比较\beamer@stopframe
,大多数情况下,其定义为:
\xdef\beamer@stopframe{\string\\end\string\{frame\string\}}
扩展为精确的字符串\
e
n
d
{
f
r
a
m
e
}
。
处理器会比较\beamer@test
和\beamer@stopframe
,如果不同,则将 的内容\beamer@test
写入\beamer@verbatimfileout
(.vrb 文件),\next
宏是\let
处理器,它会递归调用自身继续读取。否则,如果\beamer@test
是字符串\end{frame}
,处理器会正常退出。
发生该错误的原因是处理器不会忽略注释(在逐字上下文中可能需要它们!),因此处理器会\end{frame}
与进行比较\end{frame}% NO :(
,这显然会失败,并且会继续读取 之后的内容\end{frame}
。
现在可能会发生两件事:
首先,这是最后一帧,因此处理器永远找不到匹配\end{frame}
,并且! File ended while scanning use of \next.
会出现错误并且编译停止。
第二步,也是更痛苦的一步,还有另一个框架,它将包含处理器正在寻找的机器人 。但在这种情况下,将是,它本质上是将 .vrb 文件的内容读回框架。但内容将是这样的:\end{frame}
\next
\let
\beamer@framewritten
Hello :)
\end{frame}% NO :(
\begin{frame}
Hello again!
这会让事情变得疯狂:)
总结
请记住,孩子们,使用[fragile]
镜框时,\end{frame}
必须成为仅有的行中的内容。不允许有前导空格或注释(尾随空格会被 TeX 吞噬)。
正如 samcarter 在她的评论中指出的那样,当前版本的 Beamer 允许引导和尾随空格和制表符。此\beamer@strip@whitespace
宏将在与 进行比较之前吃掉空格和制表符\beamer@stopframe
。