我对 LuaTeX 完全陌生,对此我有几个问题。首先,我了解到在 LuaTeX 中可以使用“token filter”回调跟踪所有 TeX 标记。是否可以在回调函数中获取一些其他信息,例如输入文件中的当前位置和当前组级别。我要做的是编写如下所示的回调函数:
\directlua{
function foo ()
t = token.get_next()
if someTestFunction(t) then
poz = currentPositionTexEyesAreLookingAtSourceFile()
level = currentGroupLevel()
mode = isMathMode()
table.insert(someTable, {poz, level, mode})
end
end
callback.register('token_filter',foo)
}
答案1
是的,所有这些项目都可以在回调中获取token_filter
。不过,其中一些项目需要一些准备。
概括
为了回答你的问题的各个部分:
token_filter
您可以使用和库的组合来“跟踪”经过 TeX 的所有标记token
。但是,由于这意味着每个标记至少要调用一次 C API,因此效率也相当低。我怀疑这种方法\tracingall
在实用性方面是否胜出,因此无论您真正想要实现什么,它可能都不是最初想要的。tex.currentgrouplevel
可以使用与 eTeX 原语相对应的 寄存器来查询当前嵌套深度\currentgrouplevel
。为了测试数学模式,
tex.nest
必须访问 TeX 的内部嵌套堆栈 ( )。tex.nest.ptr
包含堆栈指针,以便tex.nest [tex.nest.ptr]
返回堆栈顶部(当前状态)。如果字段mathstyle
为非负数,则我们实际上处于数学模式。此外,可以通过检查字段是否mode
为负数来区分内联和显示数学。(理论上,mode
仅凭字段就足以检测数学模式——\ifmmode
就是这样实现的——但参考中给出的值似乎不正确。无论如何,请咨询 来源 了解更多详情。跟踪输入文件和行号需要付出更多努力。由于这种信息不能通过引擎直接获得,因此我们必须自己管理。幸运的是,Luatex 提供了所有必要的先决条件:要跟踪主输入文件中的行,您可以使用回调
process_input_buffer
。此外,由于open_read_line
回调,您可以精确控制 TeX 文件的读取方式。(使用启动脚本时,后者本身就足够了。不过,我没有测试过。)
例子
以下是结合以上所有内容的演示: https://gist.github.com/phi-gamma/6745931。结果是一个包含有关收集到的代币信息的表格:
TeX 文件定义了几个用户级宏。前两个控制回调状态:
\enabletokenpos [<number>] %% enable position tracking
\disabletokenpos %% disable
主文件的行数将从以下行开始计算:
\enabletokenpos
发生该行开始计算。它需要一个强制的论点,即当前行号据我所知,除非使用单独的初始化脚本(超出了当前问题的范围),否则无法自动确定该点的输入线。
然后有用于访问当前状态的宏:
\printcurrentfile %% name of the file being read
\printcurrentpos %% position in the file being read
\printcurrentfilepos %% name and position in the customary “<name>:<line>” format
显然,回调必须到位才能使它们工作。
跟踪通过这些宏进行控制:
\collecttoken %% add a single token to the tracing table
\startcollecttokens %% start adding tokens (environment)
\stopcollecttokens %% stop adding tokens
使用环境时要小心:由于多级扩展,它会很快炸毁结果表。不过,它足够聪明,不会将自己包含在内。
最后,为了输出令牌集合的内容,您需要另一个宏:
\collectedtokens
它建立一个简单的表格并将其打印在文档中。
笔记
跟踪文件仅限于输入(即 TeX)文件。在 TeX 运行期间触及的其他文件(Lua 代码、位图、编码等)不受影响。该表file_stack
有助于跟踪各个文件内的行号。process_input_buffer
和open_read_file
回调均被使用。这对于实现正确的行数是必要的,因为当前实现允许在处理文档时加载 Lua 代码。如上所述,应该可以通过open_read_line
在打开主输入之前使用初始化脚本安装过滤器来避免这种情况。
挂接到的函数token_filter
有两种变体:
grabtoken()
将使用单个标记,将其添加到集合中,然后从回调中移除自身。
grabtokens()
(复数)基本上是相同的函数,但它将保留在原处,直到通过调用将其禁用stopcollecting()
。 作为一个好东西,它将在遇到控制序列后避免收集任何标记,\stopcollecttokens
以免我们用不需要的项目污染集合。
令牌以具有以下键的表形式添加:
filename
遇到该标记的输入文件的名称;position
该输入文件的行号;grouplevel
的价值tex.currentgrouplevel
;mathmode
如果在显示数学中遇到则为正数,如果在内联数学中遇到则为负数,错误的否则;csname
相关的控制序列(如果适用);token
返回的标记表token.get_next()
;值的含义在参考中进行了解释。
例如\input
如下所示:
{
["csname"]="input",
["file"]="tokenposition.tex",
["grouplevel"]=2,
["mathmode"]=false,
["position"]=32,
["token"]={ 119, 0, 3360 },
},