3

Building on the MWE in my first ever question here (Extra space in cells when using token lists to build tabular content), I would like to add multicolumn content and \toprule (\midrule, \bottomrule, etc), but the following code does not work. I suspect that it is a matter of my poor understanding of expansion. How do I need to change the definitions of \myrow and \myline?

\documentclass{article}
\usepackage{booktabs}

\makeatletter
\newtoks\@tabtoks
\newcommand\addtabtoks[1]{\global\@tabtoks\expandafter{\the\@tabtoks#1}}
\newcommand\eaddtabtoks[1]{\edef\mytmp{#1}\expandafter\addtabtoks\expandafter{\mytmp}}
\newcommand*\resettabtoks{\global\@tabtoks{}}
\newcommand*\printtabtoks{\the\@tabtoks}
\makeatother

\newcommand{\topic}[2]{%
   \eaddtabtoks{Col 1 & Col 2 & Col 3 & #1 & #2}%
   \addtabtoks{\\}%
   \ignorespaces
}

\newcommand{\myline}{%
   \addtabtoks{\toprule}%
}

\newcommand{\myrow}[1]{%
   \eaddtabtoks{\multicolumn{5}{c}{#1}}
   \addtabtoks{\\}%
   \ignorespaces
}

\newenvironment{mytabular}{%
   \resettabtoks
   \noindent
   \tabular{llrrl}
}{%
   \printtabtoks
   \endtabular
}

\begin{document}

\begin{mytabular}
   \myrow{all five}
   \myline
   \topic{1.1}{LaTeX}
   \topic{1.2}{causes}
   \topic{1.3}{me}
   \topic{1.4}{lots}
   \topic{1.5}{of}
   \topic{1.6}{frustration}
\end{mytabular}

\end{document}
3

I did two things. I prefixed \multicolumn with \noexpand, so that the \multicolumn token was not expanded by \eaddtabtoks. Then, and I am not 100% sure why this was necessary, but I concluded it was the safest way, I performed the complete tabular in the closing end of the environment.

My hypothesis as to why this is necessary is that, as originally proposed, Cell(1,1) has a lot of non-printing calculations followed by a \multicolumn. The way I have recast it, all those non-printing calculations occur before the tabular starts. I am guessing that \multicolumn must appear as the first token of a cell, which otherwise gets hosed by all the preliminary calculations (Note: the calculations of which I speak are the figuring out which tokens to add to \@tabtoks and the creation of \@tabtoks). I think this theory can be proven by trying with my working solution, to change the definition of \myrow by adding a seemingly innocuous \relax before the \multicolumn token. It breaks in exactly the same way, which seems to indicate that \multicolumn cannot be preceded by non-printing calculations.

Also, I discovered that you needed a % at the end of the \multicolumn line.

\documentclass{article}
\usepackage[T1]{fontenc}
\usepackage{booktabs}

\makeatletter
\newtoks\@tabtoks
\newcommand\addtabtoks[1]{\global\@tabtoks\expandafter{\the\@tabtoks#1}}
\newcommand\eaddtabtoks[1]{\edef\mytmp{#1}\expandafter\addtabtoks\expandafter{\mytmp}}
\newcommand*\resettabtoks{\global\@tabtoks{}}
\newcommand*\printtabtoks{\the\@tabtoks}

\newcommand{\topic}[2]{%
   \eaddtabtoks{Col 1 & Col 2 & Col 3 & #1 & #2}%
   \addtabtoks{\\}%
   \ignorespaces
}

\newcommand{\myline}{%
   \addtabtoks{\toprule}%
}

\newcommand{\myrow}[1]{%
   \eaddtabtoks{\noexpand\multicolumn{5}{c}{#1}}%
   \addtabtoks{\\}%
   \ignorespaces
}

\newenvironment{mytabular}{%
   \resettabtoks
   \noindent
}{%
   \begin{tabular}{llrrl}
   \printtabtoks
   \end{tabular}
}
\makeatother

\begin{document}

\begin{mytabular}
   \myrow{all five}
   \myline
   \topic{1.1}{LaTeX}
   \topic{1.2}{causes}
   \topic{1.3}{me}
   \topic{1.4}{lots}
   \topic{1.5}{of}
   \topic{1.6}{frustration}
\end{mytabular}

\end{document}

enter image description here

As a follow up, Note that both invocations of \eaddtabtoks (appearing in the definitions of \topic and \myrow) can be changed to [the non-expanding] \addtabtoks (if you eliminate the \noexpand that I inserted). That is because #1 and #2 are already inserted as the actual argument tokens. There may be other reasons (not shown in the MWE) why you would prefer to expand or not expand the arguments to \topic and \myrow, but in general, I think not expanding them in advance is safer.

Here's an example that breaks the \eaddtabtoks version, but works with the \addtabtoks version:

\newcounter{step}
\begin{mytabular}
   \myrow{all five}
   \myline
   \topic{1.\thestep}{LaTeX\stepcounter{step}}
   \topic{1.\thestep}{causes\stepcounter{step}}
   \topic{1.\thestep}{me\stepcounter{step}}
   \topic{1.\thestep}{lots\stepcounter{step}}
   \topic{1.\thestep}{of\stepcounter{step}}
   \topic{1.\thestep}{frustration\stepcounter{step}}
\end{mytabular}
| improve this answer | |
  • Well, that certainly did the trick, although like you I am curious about that placement of the begin{tabular} since it goes against what I’ve previously read about constructing environments based on tabular. Anyway, thanks again. This was all I needed to finish a document class for personal use! – rogue.whistler May 3 '19 at 16:45
  • 1
    @rogue.whistler You are welcome. See my edited suffix giving an example of where expanding or not the arguments affects the result. – Steven B. Segletes May 3 '19 at 16:47
  • 1
    @rogue.whistler If you are creating the environment as you go, you are right that you have to start the environment in the opening. However, the whole idea of a token register is that it allows you, when conditions warrant, to get precisely those tokens in the environment that you want, excluding all the calculations necessary to determine those tokens. This is actually a very good example of why token lists are sometimes necessary, when you need to exclude calculations from your environment content. – Steven B. Segletes May 3 '19 at 16:52
  • Yes, that makes sense. I’ll need to explore further to get a better grasp on it, as I’m quite new to this level of TeX. – rogue.whistler May 3 '19 at 20:39

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.