动态生成 bitheader

动态生成 bitheader

我正在尝试根据字节字段中存在的字段动态生成位头。我使用 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}

在此处输入图片描述

相关内容