我正在尝试根据字节字段中存在的字段动态生成位头。我使用 LaTeX3 来执行此操作:
\documentclass{article}
\usepackage{bytefield}
\usepackage{expl3}
\usepackage{environ}
\ExplSyntaxOn
\tl_new:N \tl_head
\tl_new:N \tl_body
\int_new:N \int_bits
\int_new:N \int_diff
\newcommand\field[2]{
\int_set:Nn \int_diff \int_bits
\int_sub:Nn \int_diff { #1 - 1 }
\tl_gput_left:Nx \tl_head
{\the\int_diff \int_compare:nNnTF {#1}={1} {} {,\the\int_bits}
\int_compare:nNnTF {\the\int_bits}={31} {} {,}
}
\tl_gput_right:Nn \tl_body {\bitbox{#1}{#2}}
\int_sub:Nn \int_diff { 1 }
\int_set:Nn \int_bits \int_diff
}
\NewEnviron{register}[1]{
\int_set:Nn \int_bits {31}
\tl_set:Nn \tl_head {}
\tl_set:Nn \tl_body {}
\BODY
\begin{bytefield}{32}
% \bitheader{tl_use:N \tl_head} \\
\begin{rightwordgroup}{#1}
\tl_use:N \tl_body
\end{rightwordgroup}\\
\end{bytefield}\\
\tl_use:N \tl_head
}
\ExplSyntaxOff
\begin{document}
\begin{register}{example}
\field{8}{c} \field{8}{b} \field{16}{a}
\end{register}
\end{document}
这将产生以下输出:
但是,当我取消注释该行时\bitheader{tl_use:N \tl_head} \\
我收到以下错误:
! Missing number, treated as zero.
<to be read again>
t
l.45 \end{register}
?
我认为这个问题与宏扩展有关,但过度使用\expandafter
也没有帮助。
答案1
\
您在 中缺少一个tl_use:N
,并且\bitheader
期望其参数完全展开,因此您必须在传递之前展开它。更改\bitheader{tl_use:N \tl_head}
为\exp_args:NV \bitheader \tl_head
,您的代码就可以正常工作。不过,我做了一些其他更改(主要是外观上的更改),以使您的代码符合expl3
指导原则(请查看“expl3 语言和 LaTeX3 编程”(expl3.pdf
- texdoc expl3
), 部分3 命名方案)。
变量应该命名为
\<scope>_<module>_<description>_<type>
,而你的变量是\<type>_<description>
。 像 这样的变量\tl_head
应该命名为 (假设它是全局的,因为你使用全局赋值,并且假设模块名称是junius
)\g_junius_head_tl
。 整数也一样:\int_bits
→\l_junius_bits_int
。避免在
expl3
代码中使用原语,并避免混合样式。\the \l_junius_bits_int
最好写成\int_use:N \l_junius_bits_int
。您可以省略条件分支:
\int_compare:nNnTF {#1} = {#2} { } { <stuff> }
不需要T
分支,可以更简洁地写成\int_compare:nNnF {#1} = {#2} { <stuff> }
。最后,从 TeXLive 2019 开始,环境
xparse
有一个b
-type 参数,它可以抓取环境主体,因此您可以使用它来代替environ
。
添加这些更改,以下是您的代码:
\documentclass{article}
\usepackage{bytefield}
\usepackage{expl3}
\usepackage{xparse}
\ExplSyntaxOn
\tl_new:N \g_junius_head_tl
\tl_new:N \g_junius_body_tl
\int_new:N \l_junius_bits_int
\int_new:N \l_junius_diff_int
\NewDocumentCommand \field { m m }
{
\int_set_eq:NN \l_junius_diff_int \l_junius_bits_int
\int_sub:Nn \l_junius_diff_int { #1 - 1 }
\tl_gput_left:Nx \g_junius_head_tl
{
\int_use:N \l_junius_diff_int
\int_compare:nNnF {#1} = { 1 } { , \int_use:N \l_junius_bits_int }
\int_compare:nNnF { \l_junius_bits_int } = {31} { , }
}
\tl_gput_right:Nn \g_junius_body_tl { \bitbox {#1} {#2} }
\int_sub:Nn \l_junius_diff_int { 1 }
\int_set:Nn \l_junius_bits_int \l_junius_diff_int
}
\NewDocumentEnvironment { register } { m b }
{
\int_set:Nn \l_junius_bits_int { 31 }
\tl_gclear:N \g_junius_head_tl
\tl_gclear:N \g_junius_body_tl
#2 % environment body
\begin{bytefield}{32}
\exp_args:NV \bitheader \g_junius_head_tl \\
\begin{rightwordgroup}{#1}
\tl_use:N \g_junius_body_tl
\end{rightwordgroup}\\
\end{bytefield}\\
\tl_use:N \g_junius_head_tl
}
{ }
\ExplSyntaxOff
\begin{document}
\begin{register}{example}
\field{8}{c} \field{8}{b} \field{16}{a}
\end{register}
\end{document}