Declarando soma globalmente

Nov 03 2020

Considere o seguinte MWE:

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn
\NewDocumentCommand{\shcpoint}{ m }
 {
  \azetina_shcpoint:n { #1 }
 }

\NewDocumentCommand{\printtotal}{ }
 {
  \int_to_arabic:n { \g_azetina_totalpoints_int }
 }

\int_new:N \g_azetina_totalpoints_int
\box_new:N \l_azetina_points_box
\cs_new_protected:Npn \azetina_shcpoint:n #1
 {
  \int_gadd:Nn \g_azetina_totalpoints_int { #1 }
  \hbox_set:Nn \l_azetina_points_box { (0 ~ \textit{points}) }
  \makebox[\box_wd:N \l_azetina_points_box][l]
   {
    (\textit{#1 ~ point\int_compare:nT { #1 > 1 } { s }})
   }
  \quad
}
\ExplSyntaxOff

\begin{document}
Total points: \printtotal

\shcpoint{1} X

\shcpoint{3} X

\shcpoint{1} X

Total points: \printtotal

\end{document}

No exemplo acima, os pontos totais são calculados corretamente no final, mas se eu tentar chamar o comando antes da declaração dos pontos, ele imprime zero.

Qual é a melhor maneira de redefinir isso para que a soma possa ser acessada em qualquer lugar do documento?

Observe que a solução foi fornecida por @egreg em https://tex.stackexchange.com/a/160089/10898

Respostas

2 LaTeXer Nov 03 2020 at 06:10

Você precisa salvar o total no .auxarquivo (então, naturalmente, você precisa executar o documento pelo menos duas vezes para obter a soma correta). Eu adicionei um novo contador, então você tem um para imprimir a soma, que estará errado quando você adicionar / remover pontos até que você execute novamente o documento, e outro que manterá o controle dos pontos durante a execução do documento. No final da execução, eles são comparados e um aviso é emitido para que você saiba que precisa executar o LaTeX novamente.

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn
\NewDocumentCommand{\shcpoint}{ m }
 {
  \azetina_shcpoint:n { #1 }
 }

\NewDocumentCommand{\printtotal}{ }
 {
  \int_to_arabic:n { \g_azetina_totalpoints_int }
 }

\NewDocumentCommand{\shcsettotal}{ m }
 {
  \int_gset:Nn \g_azetina_totalpoints_int {#1}
 }

\int_new:N \g_azetina_totalpoints_int
\int_new:N \g__azetina_counttotal_int
\box_new:N \l_azetina_points_box
\cs_new_protected:Npn \azetina_shcpoint:n #1
 {
  \int_gadd:Nn \g__azetina_counttotal_int { #1 }
  \hbox_set:Nn \l_azetina_points_box { (0 ~ \textit{points}) }
  \makebox[\box_wd:N \l_azetina_points_box][l]
   {
    (\textit{#1 ~ point\int_compare:nT { #1 > 1 } { s }})
   }
  \quad
}

\makeatletter
\AtEndDocument
  {
    \iow_now:Nx \@auxout
      {
        \shcsettotal { \int_use:N \g__azetina_counttotal_int }
      }
    \int_compare:nNnF \g__azetina_counttotal_int = \g_azetina_totalpoints_int
      {
        \msg_warning:nn { azetina } { rerun-points }
      }
  }
\msg_new:nnn { azetina } { rerun-points }
  {
    Point~count~differs.~Rerun~LaTeX~to~get~it~right.
  }
\makeatother
\ExplSyntaxOff

\begin{document}
Total points: \printtotal

\shcpoint{1} X

\shcpoint{3} X

\shcpoint{1} X

Total points: \printtotal

\end{document}

Após a primeira corrida você tem

e um aviso no .log:

Package azetina Warning: Point count differs. Rerun LaTeX to get it right.

e após a segunda execução, nenhum aviso e