假设某些宏触发错误消息。
错误消息还应显示触发错误消息的宏的名称。
可以做这样的事:
\newcommand\MYCOMMAND{%
% ...
\GenericError{%
\space\space\space\@spaces\@spaces\@spaces
}{%
A point is reached where carrying out macro
\string\MYCOMMAND\space triggers an error-message...
}{%
See the documentation for more information.%
}{%
More explanation.%
}%
% ...
}%
问题是:
如果您执行类似 的操作\let\MYSAVEDCOMMAND=\MYCOMMAND
,则错误消息\MYSAVEDCOMMAND
也将包含短语\MYCOMMAND
,尽管此处的短语应该是\MYSAVEDCOMMAND
。
这是因为该短语在定义文本中是“硬编码”的。
如果您有语法,其中表示应用于当前扩展的宏标记(控制序列标记/活动字符标记)#0
的结果,那么您可以不用这样的“硬编码”:\string
\newcommand\MYCOMMAND{%
% ...
\GenericError{%
\space\space\space\@spaces\@spaces\@spaces
}{%
A point is reached where carrying out macro
#0 triggers an error-message...
}{%
See the documentation for more information.%
}{%
More explanation.%
}%
% ...
}%
我的问题是:
实现并将该功能添加到 TeX 程序中会很难吗?
(正如您从编译器生成的错误消息中看到的那样,这些错误消息中包含了处理分隔参数的宏,并因此遇到不平衡的右花括号,TeX 似乎已经跟踪了宏标记的名称:
这个例子
\def\foo#1delimiter{definition text, argument: #1}
\foo bla}delimiter
\bye
提供:
! Argument of \foo has an extra }.
)
该功能是否存在缺点、缺陷或问题#0
?
使用当前 TeX 引擎编译编写的代码是否与#0
具有此类功能的引擎不兼容?
答案1
实施起来有多难:
当错误
! Argument of \foo has an extra }.
生成后,TeX 还在扫描参数。在这个过程中,调用宏时使用的名称仍然可用。(如果warning_index
你想查看源代码,请参阅)读取所有参数后情况会发生变化:然后 TeX 开始新的输入级别并读取宏主体,在此过程中插入参数。这里warning_index
不再设置宏名称。
但是,虽然错误消息示例不起作用,但有些事情也起作用了:对于每个输入级别,TeX 都会存储一个name
,以防宏扩展,这是 csname。因此名称是可用的。
例如在 LuaTeX 中(其他引擎应该类似,但我更喜欢 C 而不是 Pascal),你的 #0 的变体可以通过补丁实现:(此代码#0
用宏标记替换,而不是用应用的结果替换\string
,因此你必须\string
自己添加。这可以结合起来而不需要做更多的工作,但这样更灵活。例如,它允许你使用\csstring
)
diff --git a/source/texk/web2c/luatexdir/tex/scanning.c b/source/texk/web2c/luatexdir/tex/scanning.c
index 8f7e1d591..5064c5401 100644
--- a/source/texk/web2c/luatexdir/tex/scanning.c
+++ b/source/texk/web2c/luatexdir/tex/scanning.c
@@ -2183,7 +2183,7 @@ halfword scan_toks(boolean macro_def, boolean xpand)
else
get_token();
if (cur_cmd != mac_param_cmd) {
- if ((cur_tok <= zero_token) || (cur_tok > t)) {
+ if ((cur_tok < zero_token) || (cur_tok > t)) {
print_err("Illegal parameter number in definition of ");
sprint_cs(warning_index);
help3(
diff --git a/source/texk/web2c/luatexdir/tex/textoken.c b/source/texk/web2c/luatexdir/tex/textoken.c
index d6c168906..3de298753 100644
--- a/source/texk/web2c/luatexdir/tex/textoken.c
+++ b/source/texk/web2c/luatexdir/tex/textoken.c
@@ -2018,8 +2018,15 @@ static boolean get_next_tokenlist(void)
break;
case out_param_cmd:
/*tex Insert macro parameter and |goto restart|. */
- begin_token_list(param_stack[param_start + cur_chr - 1], parameter);
- return false;
+ if (cur_chr == 0) {
+ cur_cs = iname;
+ cur_cmd = call_cmd;
+ cur_chr = istart;
+ return true;
+ } else {
+ begin_token_list(param_stack[param_start + cur_chr - 1], parameter);
+ return false;
+ }
break;
}
}
关于兼容性:此更改仅影响使用 的代码#0
。如上代码所示,更改scan_toks
,在普通 TeX 中使用#0
始终会导致错误Illegal parameter number
。因此,它是兼容的,因为每个在普通引擎中不会产生错误消息的 TeX 文档仍将在修改后的引擎中工作,而不会改变行为。
所以我认为最大的问题是它的用途有限:对于错误消息,TeX 已经显示了一些上下文,通常包括宏名称。因此它不会添加很多信息,同时为 TeX 最核心的例程之一()增加了(一点)复杂性get_next_tokenlist
,并使 TeX 的宏扩展规则更加复杂。