0% found this document useful (0 votes)
65 views32 pages

Blkarray

This style option implements a blockarray environment for typesetting tables. It allows for custom column types defined with \BAnewcolumntype, blocks of rows or columns with different formatting, and delimiters around parts of the table. Footnotes can appear either at the bottom of the table or as standard footnotes, depending on the \BAtablenotes setting.

Uploaded by

Patrick Ngakou
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
65 views32 pages

Blkarray

This style option implements a blockarray environment for typesetting tables. It allows for custom column types defined with \BAnewcolumntype, blocks of rows or columns with different formatting, and delimiters around parts of the table. Footnotes can appear either at the bottom of the table or as standard footnotes, depending on the \BAtablenotes setting.

Uploaded by

Patrick Ngakou
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 32

blkarray.

sty
D. P. Carlisle
27 February 2015

Warning !
This style option is in the early stages of development. If you want to
use an extended array or tabular in a document, consider using one of
the options in the ARRAY package, available from most TEX-servers.
The commands defined in this style are quite likely to have both their
user-interface, and their internal definitions changed in later versions.

1 Introduction
This style option implements an environment, blockarray, that may be used in
the same way as the array or tabular environments of standard LATEX, or their
extended versions defined in array.sty. If used in math-mode, blockarray acts
like array, otherwise it acts like tabular.
The main feature of this style is that it uses a new method of defining col-
umn types. In the simplest form, this has been given a syntax matching the
\newcolumntype command of array.sty.
\BAnewcolumntype{C}{>{\large}c}
defines a column of large centred text.
In array.sty column specifiers defined via \newcolumntype are re-written in
a preliminary stage to the primitive types, which are then treated by a completely
different mechanism (basically a nested \if testing each token against one of the
predefined column types, c, l, >, . . .
In blockarray.sty, all column specifiers have equal standing, most of the
specifiers of Lamport’s original are defined using \BAnewcolumntype, e.g.
\BAnewcolumntype{c} {>{\hfil}<{\hfil}}
There are one or two other features built into blockarray, these will be intro-
duced in no particular order.

1.1 Explicit Column Separators in the Preamble


As described in the LATEX book, originally specifiers like | and @-expressions were
always considered to be part of the preceding column (except for expressions before

1
the first column). This can be inconvenient if that column type is going to be over
ridden by a \multicolumn specification, consider:
\begin{tabular}{c|c|c}
11 & 22 & 33 \\ 11 22 33
1 &\multicolumn{1}{l|}{2} & 3 \\
1 2 3
11 & 22 & 33
11 22 33
\end{tabular}

The rule needs to be specified again in the \multicolumn argument as {l|},


blockarray lets you move the rule into the third column, by specifying & in the
preamble like so:
\begin{blockarray}{c|c&|c}
11 & 22 & 33 \\ 11 22 33
1 &\BAmulticolumn{1}{l}{2} & 3 \\ 1 2 3
11 & 22 & 33 11 22 33
\end{blockarray}

I first came across the idea of having such a feature in an array preamble
when Rainer Schöpf gave a brief introduction to various enhanced array styles.
An implementation by Denys Duchier had a feature like this, however I have not
seen that style so I do not know the details.

1.2 Blocks
Sometimes you want whole blocks of the table to have a different format, this is
often the case with headings for instance. This can be accomplished using lots
of \multicolumn commands, but this style lets you specify the format for such a
block in the usual syntax for column specifiers:
\begin{blockarray}{*{3}{c}}
11 & 22 & 33 \\
1 & 2 & 3 \\ 11 22 33
\begin{block}{*{3}{>{\bf}l}} 1 2 3
11 & 22 & 33 \\ 11 22 33
1 & 2 & 3 \\ 1 2 3
\end{block}
1 2 3
1 & 2 & 3
\end{blockarray}

1.3 Delimiters
People often want to put delimiters around sub-arrays of a larger array, delimiters
can now be specified in the preamble argument:

2
\begin{blockarray}{[cc]c\}}
11 & 22 & 33 \\   
1 & 2 & 3 \\ 11 22 33
\begin{block}{(ll)l\}} 1 2 3
11 & 22 & 33 \\ 11 22 33
1 & 2 & 3 \\
\end{block} 1 2  3
1 2 3
1 & 2 & 3
\end{blockarray}

Note how in the previous example the nested block was not spanned by the [ ].
each section of the ‘outer’ block was separately bracketed. If instead of the block
environment we use block*, then the outer brackets will span the inner block,
however it is not possible to specify any delimiters in the argument of block*.
\begin{blockarray}{[cc]c\}}
11 & 22 & 33 \\ 
11 22 33
 
1 & 2 & 3 \\ 
\begin{block*}{lll} 1 2 3

 
11 & 22 & 33 \\ 11 22 33
 
1 & 2 & 3 \\ 1 2  3 



\end{block*} 
1 2 3
1 & 2 & 3
\end{blockarray}

The delimiters, ( ) [ ] \{ \} have been pre-defined as column specifiers,


however any delimiter, including these ones can be specified using the specifiers
\Left and \Right
\Left{htexti}{hdelimiter i}
specifies a delimiter together with a ‘label’ which will be vertically centred with
respect to the block. Note that the delimiter and the label take up no horizontal
space, and so extra space must be left with a !- or @-expression or the text will
over-print adjacent columns.

1.4 Automatic Numbering


A column specifier \BAenum specifies that the row number is to be printed (in a
!-expression) at that point in each row, this number may be accessed with \label
in the usual way. The number is a standard LATEX counter, BAenumi, and so the
appearence may be changed by altering the default definition of \theBAenumi.

1.5 Footnotes
The \footnote command may be used inside blockarray. Two styles are sup-
ported. If the test BAtablenotes is true (by default, or after \BAtablenotestrue)
then footnotes will appear at the end of the table, with lines set to the width of
the table. If BAtablenotes is false, footnotes within the table will be treated as
standard footnotes, with the text (usually) appearing at the foot of the page.
If table notes are being set, the footnote counter is reset at the start of the table.
Also an extended version of \footnotetext can be used. As described in the book,

3
\footnotetext[2]{xxx} will produce a text marked with the footnote symbol for
‘2’. However for tablenotes, the optional argument may also be any non-numeric
text, in which case it is set directly at the start of the footnote text. So you can go
\footnotetext[\sc source:]{xxx} or \footnotetext[\sc note:]{xxx} any-
where in the table body, before the first numbered footnote.
If BAtablenotes is false the footnote text will not appear at the foot of the page
if the whole blockarray environment is in an environment which treats footnotes
in a special way (eg another blockarray). So if you have a complicated table
which requires tablenotes, but for TEXnical reasons you wish to enter it in the
.tex file as nested blockarray environments, you may set \BAtablenotestrue
for the outer environment, and then locally set it to false before each of the nested
environments. This will ensure that footnotes from all parts of the table will be
collected together at the end.
This table is set with \BAtablenotestrue.

ONE TWO∗
l-one l-two r-one r-two
l-three∗ l-four r-three∗ r-four

source: Chicago Man- source: Chicago Man-


ual of Style. ual of Style.
note: The above attri- note: The above attri-
bution is incorrect. bution is incorrect.
∗ Footnote to l-three. ∗ Footnote to r-three

THREE† FOUR

source: Chicago Manual of Style.


∗ Note on TWO. This is a reasonably long footnote, to

show the line breaking.


† Note on THREE.

In this example, the outer table is set with \BAtablenotestrue, but each of
the inner tables is set with a local setting \BAtablenotesfalse.
Also the footnotes have been set in a single paragraph. Tablenotes will be set
‘run in’ a paragraph, after a \BAparfootnotes declaration.

ONE TWO∗
l-one l-two r-one r-two
† ‡
l-three l-four r-three r-four
THREE§ FOUR

source: Chicago Manual of Style. note: The above


attribution is incorrect. ∗ Note on TWO. This is a

reasonably long footnote, to show the line breaking.


† Footnote to l-three. ‡ Footnote to r-three § Note

on THREE.

4
1.6 Non Aligned Material
The primitive \noalign command may be used with standard LATEX arrays, but
paragraphs inside \noalign are broken into lines that are the width of the page, (or
at least the current value of \hsize) not to the final width of the table. Within
a blockarray \BAnoalign specifies material to be packaged into a parbox the
same width as the table. This makes a ‘hole’ in the current block. \BAnoalign*
is similar, but any delimiters in the current block span across the non-aligned
paragraphs.

\begin{blockarray}{\BAenum!{.\quad}cc\Right{\}}{\tt block 1}}


\BAnoalign*{... The paragraphs ...}
\begin{block}{\BAenum!{.\quad}(rr\Right{\}}{{\tt block 2} ...}}
\begin{block*}{\BAenum!{.\quad}(ll)}
\begin{block}{\BAenum!{.\quad}>{\bf}l\{c\Right{\}}{\tt block 3}}
\BAmultirow{50pt}{... Spanning ...}
\begin{block}{\BAenum!{.\quad}\{l\}l\Right{\}}{\tt block 4}}
\BAnoalign{\centering Unlike ...}

1. ccc cc 

2. c ccccccccc 


The paragraphs in a block 1

\BAnoalign* are set to the  

final width of the table.

3. rrr rr


4. 
 rrr r


5. lll
 ll block 2, with a nested block*

6. l lll 



7. r r
8. ccc block 1
 Spanning 
9. LLL 
all the

10. LL block 3
 rows in a 
11. L
 block.
12. ll l block 4
Unlike \BAnoalign*,
\BAnoalign breaks any
delimiters in the current
 block.
13. l lll block 4
14. c c block 1

5
1.7 Spanning Rows and Columns
The previous table had an example of the use of a \BAmultirow command. If an
entry contains
\BAmultirow{hdimeni}{hpar-mode material i}
then the hpar-mode material i will appear in a box at least hdimeni wide, spanning
all the rows in the current block. If the other entries in that column of the current
block are not empty, they will be over printed by the spanning text.
There is a column specification corresponding to \BAmultirow. if
\BAmultirow{hdimeni}
appears in the preamble, then each entry in that column will be packaged as a
paragraph, in a box at least hdimeni wide, spanning all the rows in the current
block. If this is the last column in the block, you can not use the optional argument
to \\, and no entry in the column must be empty, it must at least have {} in it.
(If you need to ask why, you don’t want to know!)
Similarly there is a column specification corresponding to \BAmulticolumn. if
\BAmulticolumn{hnumber i}{hcolumn specificationi}
appears in the preamble to a block, then the rows in the block should have less
entries than the outer block, the columns will line up as expected.

\begin{blockarray}{r|lccr|c}
aaa&bbb&ccc&ddd&eee&fff\\
\begin{block}{(r|\BAmulticolumn{4}{>{\bf}l}|c)}
111&The second entry in each &333\\
\end{block}
a&b&c&d&e&f\\
\begin{block}{[r|lccr\{\BAmultirow{1in}]}
111&222&333&444&555&Each entry\\
1&2&3&4&5&in this column is packaged as a paragraph.\\
1&2&3&4&5&\relax\\
\end{block}
a&b&c&d&e&f
\end{blockarray}

6
aaa bbb ccc ddd eee fff
a b c d e f
 
111 The second entry in each 333
 1 row of this block spans 4 3 
1 columns of the blockarray. 3
a b c d e f
a b c d e f

111 222 333 444 555
 
Each entry


 1 2 3 4 5 
 
in this column
 
 1 2 3 4 5 

 1 is packaged as a
2 3 4 5  
paragraph.


1 2 3 4 5
a b c d e f

1.8 Horzontal Lines


For technical reasons (explained in the code section) the standard \hline does
not work with blockarray. \BAhline may be used in just the same way, although
currently it is implemented using. . .
\BAhhline. The \hhline from hhline.sty, would work, but this is a new imple-
mentation, more in the spirit of this style.
\begin{blockarray}{||c||c&|cc||cc||}
\BAhhline{|t:=:t:=&|==#==:t|}
0& 1 & 2 & 3 &4&5\\
\BAhline 0 1 2 3 4 5
0& 1 & 2 & 3&4&5\\
0 1 2 3 4 5
\BAhline\BAhline
0& 1 & 2 & 3&4&5\\ 0 1 2 3 4 5
\BAhhline{||-||-..||.-}
0& 1 & 2 & 3&4&5\\
0 1 2 3 4 5
\BAhhline{=::=""::"=} 0 1 2 3 4 5
0& 1 & 2 & 3&4&5\\
\BAhhline{|b:=:b:=""::"=:b|}
\end{blockarray}

Both \hline and \hhline increase the (minimum) height of the following row
by \BAextraheightafterhline, which defaults to 0pt. array.sty introduced a
parameter, known in this style as \BAextrarowheight, which is a length added to
the default height of all the rows. One of the stated reasons for introducing this was
to stop horizontal lines touching large entries like accented capitals, however in-
creasing all the row heights has an effect rather similar to setting \arraystretch.
This style allows the the extra height just to be added after the horizontal rule.

7
1.9 Further Thoughts
• The main point of any environment based on \halign is to make entries
line up. Using this style as currently implemented, it is easy to spoil this
alignment by putting different @ expressions or rules in the same column in
different blocks. In practice, if you want different @ expressions, you need to
do boxing tricks to make sure that they all have the same width. This could
be done automatically by the \halign, if the @-expressions and rules were
put in a separate column. (This fact could be hidden from the user, by a
method similar to the multicolumn column specification).

• The [tcb] optional argument does not really work at present, I have not
done a proper implementation, as I do not know what to do about horizontal
rules.
1
2
Standard LATEX lines [t] and [b] up like this: xx 1 xx 3 xx
2
3
1
2
However if there are horizontal lines, it looks like: xx xx 3 xx
1
2
3
1
2
I think I want it to look like this: xx 1 xx 3 xx
2
3
This would be reasonably easy to achieve in a ‘full’ blockarray, as each
row is taken off and inspected, however I would like an array that only uses
the features of the original implementation to be processed by the ‘quick’
system. Any ideas?

• Many user-level commands and parameters defined in this style are named
\BA. . . This is to avoid clashes with the standard environments, especially if
these are nested inside blockarray. If array and tabular were re-defined
in terms of blockarray, many commands could be renamed, for example,
\BAextrarowheight, \BAmulticolumn, \BAhline.

• This style uses a lot of macros, and every use of the blockarray uses a lot
more. Does it work at all on a PC?

8
2 The Macros
1 \ProvidesPackage{blkarray}[2015/02/27 v0.07 Block array (dpc)]\relax

2.1 Some General Control Macros


The macros in this section do not have the BA prefix, but rather the GC prefix,
other style files can repeat these definitions without using up TEX’s memory.
LATEX provides \z@, \@ne, \tw@, \thr@@, but I needed some more. . .
2 \chardef\GC@four=4
3 \chardef\GC@five=5
4 \chardef\GC@six=6

2.1.1 Tests
Tests are like \ifs except that instead of the
\if. . . htrue-texti\elsehfalse-texti\fi
notation, they have
\test. . . {htrue-texti}{hfalse-texti}
They are constructed such that they expand directly to either the htrue-texti or
hfalse-texti, without leaving a trailing \fi.
5 \def\GC@newtest#1{%
6 \@namedef{#1true}%
7 {\expandafter\let\csname test#1\endcsname\GC@true}%
8 \@namedef{#1false}%
9 {\expandafter\let\csname test#1\endcsname\GC@false}%
10 \@nameuse{#1false}}
11 \def\GC@def@testfromif#1#2\fi{%
12 \def#1##1##{#2##1\expandafter\GC@true\else\expandafter\GC@false\fi}}
13 \def\GC@true#1#2{#1}
14 \def\GC@false#1#2{#2}
This \testGC@num is not very good as it does not delimit the hnumber is cor-
rectly.
15 \GC@def@testfromif\testGC@x\ifx\fi
16 \GC@def@testfromif\testGC@num\ifnum\fi

2.1.2 List Macros


If \X is abc then \GC@add@to@front\X{xyz} is xyzabc;
17 \long\def\GC@add@to@front#1#2{%
18 \def\@tempa##1{\gdef#1{#2##1}}%
19 \expandafter\@tempa\expandafter{#1}}
and \GC@add@to@end\X{xyz} is abcxyz.
20 \long\def\GC@add@to@end#1#2{%
21 \expandafter\gdef\expandafter#1\expandafter{#1#2}}

9
2.2 Allocations
I have given ‘meaningful names’ to plain-TEX’s scratch registers, I am not sure this
was a good idea, but it should be OK as long as I always access by name, and do
not use, say, \count4 as a scratch register. I do not like using numbered registers
in the code, and can not afford to allocate registers just to get nice names, they
are in too short supply already!
Only allocate another register if blockarray is going to lose control at a point
where the register value needs to be saved. (eg inside a \BAnoalign anything can
happen.
\BAtracing can be set to any integer, the higher the number, the more gets
printed.
22 h∗tracingi
23 \chardef\BAtracing=0
24 h/tracingi

25 \newcounter{BAenumi}\let\BA@row\c@BAenumi
26 \countdef\BA@row@shadow=6
27 \countdef\BA@ftn@shadow=0
28 \newcount\BA@col
29 \countdef\BA@col@shadow=2
30 \newcount\BA@block@cnt
31 \countdef\BA@block@cnt@shadow=4
32 \countdef\BA@col@max=8
33 \newbox\BA@final@box
34 \chardef\BA@final@box@shadow=8
v0.07 use newbox not 0 to avoid amsmath.
35 \newbox\BA@first@box
36 \chardef\BA@tempbox@a=2
37 \chardef\BA@tempbox@b=4
38 \chardef\BA@block@box=6
39 \newdimen\BA@colsep
40 \BA@colsep=\tabcolsep
41 \newtoks\BA@ftn
42 \toksdef\BA@ftnx@shadow=0

2.3 ‘Local’ Variables


Most of blockarray happens inside a \halign which means that the different
parts have to make global assignments if they need to communicate. However
many of these assignments are logically local to blockarray, or a sub-environment
like block. This means that I have to manage the saving and restoring of local
values ‘by hand’.
Three different mechanisms occured to me, I have used all of them in this style,
mainly just to try them out!

10
• ‘shadowing’ If \X is to be assigned globally, but it is to be considered local to
a block of code that corresponds to a TEX group, then it may be shadowed
by a local variable \Y
\begingroup\Y=\X
\begingroup
harbitrary code making global assignments to Xi
\endgroup
\global\X=\Y\endgroup.
The inner group is needed to protect \Y from being changed.
This is effectively the situation in the blockarray environment, where the
outer group is provided by \begin. . . \end, and the inner group is provided
by an assignment to a box register.
• Generating new command names, according to nesting depth. Instead
of directly using \X, the variable can always be indirectly accessed by
\csname\nesting X\endcsname. Here \nesting should expand to a differ-
ent sequence of tokens for each nested scope in which \X is used. \nesting
might be altered by a local assignment, or sometimes need to be globally
incremented at the start of the scope, and globally decremented at the end.
• Maintaining a stack of previous values. Corresponding to a macro, \X, is
a macro\Xstack which consists of a list of the values of \X in all outer
environments. When the local scope ends, this stack is popped, and the top
value (which was the value of \X before the environment) is globally assigned
to \X.

The first method has the advantage that the variable is normally accessed
within the environment, and the code to restore previous values is trivial. The
main memory usage is in the save-stack, TEX’s normal place for saving local vaues.
Shadowing can only be used when the environment corresonds to a TEX group.
The block environment does not!, \end{block} is not in the scope of any local
assignments made by \begin{block}.
The second method, has the advantage that, once the access functions are
defined, it is easy to declare new local variables, however unless you keep track of
what has been produced, these variables will continue to take up memory space,
even after the environment has ended. blockarray at the moment does not do
much clearing up, so after a blockarray there are typically five macros per column
per block (u-part, v-part, left right and ‘mid’ delimiters) left taking up space. Not
to mention macros containing the texts of any non-aligned entries.
An extra ‘.’ will locally be added to \BA@nesting as each blockarray is
entered, this is used as described above.
43 \def\BA@nesting{}
These two macros help in accessing macros that are ‘local’ to the current value
of \BA@nesting.
44 \def\BA@expafter#1#2{%
45 \expandafter#1\csname BA@\BA@nesting#2\endcsname}

11
46 \def\BA@use#1{\csname BA@\BA@nesting#1\endcsname}
These are similar, but for macros which depend on the column and block
involved, not just the outer blockarray environment.
47 \def\BA@col@expafter#1#2{%
48 \expandafter#1%
49 \csname BA@\BA@nesting[\BA@use{blocktype},\the\BA@col]#2\endcsname}
50 \def\BA@col@use#1{%
51 \csname BA@\BA@nesting[\BA@use{blocktype},\the\BA@col]#1\endcsname}
The following macros manage a stack as described in the third method above.
52 \def\BA@push@blocktype{%
53 \edef\@tempa{{{\BA@use{blocktype}}}}%
54 \BA@expafter\GC@add@to@front{BTstack\expandafter}\@tempa}
55 \def\BA@pop@blocktype{%
56 \BA@expafter\BA@pop@{BTstack}}
57 \def\BA@pop@#1{\expandafter\BA@pop@@#1\@@}
58 \def\BA@pop@@#1#2\@@{%
59 \BA@expafter\gdef{blocktype}{#1}%
60 \BA@expafter\gdef{BTstack}{#2}}

2.4 The Block Environment


61 \def\BA@beginblock#1{%
62 \noalign{%
63 \BA@push@blocktype
64 \global\advance\BA@block@cnt\@ne
65 \penalty\the\BA@block@cnt
66 \BA@expafter\xdef{blocktype\expandafter}\expandafter
67 {\the\BA@block@cnt}%
68 \penalty\@ne
69 \global\BA@col=1
70 \global\BA@expafter\def{blank@row}{\crcr}%
71 \BA@clear@entry
72 \global\let\BA@l@expr\@empty\global\let\BA@r@expr\@empty
73 \BA@colseptrue
74 \BA@parse#1\BA@parseend
75 \ifnum\BA@col@max=\BA@col\else
76 \@latexerr{wrong number of columns in block}\@ehc\fi
77 \global\BA@col\z@}}
78 \def\BA@endblock{%\crcr
79 \noalign{%
80 \BA@pop@blocktype
81 \penalty\BA@use{blocktype}%
82 \penalty\tw@}}
83 \@namedef{BA@beginblock*}#1{%
84 \noalign{%
85 \BA@push@blocktype

12
86 \global\advance\BA@block@cnt\@ne
87 \BA@expafter\xdef{blocktype\expandafter}\expandafter
88 {\the\BA@block@cnt}%
89 \global\BA@col=\@ne
90 \global\BA@expafter\def{blank@row}{\crcr}%
91 \BA@stringafter\let\Left\BA@left@warn
92 \BA@stringafter\let\Right\BA@right@warn
93 \BA@clear@entry
94 \global\let\BA@l@expr\@empty\global\let\BA@r@expr\@empty
95 \BA@colseptrue
96 \BA@parse#1\BA@parseend
97 \ifnum\BA@col@max=\BA@col\else
98 \@latexerr{wrong number of columns in block*}\@ehc\fi
99 \global\BA@col\z@}}
100 \def\BA@left@warn#1#2{%
101 \@warning{Left delimiter, \string#2, ignored}\BA@parse}
102 \def\BA@right@warn#1#2{%
103 \@warning{Right delimiter, \string#1, ignored}\BA@parse}
104 \@namedef{BA@endblock*}{%\crcr
105 \noalign{%
106 \BA@pop@blocktype}}

2.5 Multicolumn
First we have the \multicolumn command to be used as in original LATEX.
107 \def\BAmulticolumn#1#2#3{%
108 \multispan{#1}%
109 \global\advance\BA@col#1\relax
110 \edef\BA@nesting{\BA@nesting,}%
111 \BA@expafter\def{blocktype}{0}%
112 {\BA@defcolumntype{&}##1\BA@parseend{%
113 \@latexerr{\string& in multicolumn!}\@ehc\BA@parse\BA@parseend}%
114 \global\BA@expafter\def{blank@row}{\crcr}%
115 \BA@clear@entry
116 \global\let\BA@l@expr\@empty\global\let\BA@r@expr\@empty
117 \BA@colseptrue
118 \BA@parse#2\BA@parseend}%
119 \BA@strut\BA@col@use{u}\ignorespaces#3\BA@vpart}
Now something more interesting, a \BAmulticolumn column specification!
120 \def\BA@make@mc#1{%
121 \count@#1\relax
122 \BA@make@mcX
123 \edef\BA@mc@hash{%
124 \noexpand\BA@parse
125 >{\BA@mc@spans}\noexpand\BA@MC@restore@hash
126 \BA@mc@amps\noexpand\BA@MC@switch@amp}}
127 \def\BA@make@mcX{%
128 \ifnum\count@=\@ne

13
129 \def\BA@mc@spans{\null}%
130 \let\BA@mc@amps\@empty
131 \else
132 \advance\count@\m@ne
133 \BA@make@mcX
134 \GC@add@to@end\BA@mc@spans{\span}%
135 \GC@add@to@end\BA@mc@amps{&@{}}%
136 \fi}

2.6 \BAmultirow
First as a command.
137 \long\def\BAmultirow#1{\kern#1\relax
138 \global\BA@quickfalse
139 \BA@col@expafter\gdef{mid}}
Then as a column specification. (The actual \BAnewcolumn comes later)
140 \def\BA@mrow@bslash#1{%
141 \kern#1\relax
142 \global\BA@quickfalse
143 \iffalse{\else\let\\\cr\fi\iffalse}\fi
144 \BA@mrow}
145 \long\def\BA@mrow#1\BA@vpart{%
146 \BA@col@expafter\GC@add@to@end{mid}{\endgraf#1}
147 \BA@vpart}

2.7 \BAnoalign
148 \def\BAnoalign{%\crcr
149 \noalign{\ifnum0=‘}\fi
150 \global\BA@quickfalse
151 \penalty\the\BA@row
152 \@ifstar
153 {\penalty\GC@four\BA@noalign}%
154 {\penalty\BA@use{blocktype}\penalty\thr@@\BA@noalign}}
155 \long\def\BA@noalign#1{%
156 \long\BA@expafter\gdef{noalign\the\BA@row}{#1}%
157 \ifnum0=‘{\fi}}

2.8 \\
The following code is taken directly from array.sty, apart from some name
changes. It is very similar to the version in latex.tex. Making \\ into a macro
causes problems when you want the entry to be taken as a macro argument. One
possibility is to \let \\ be \span, and then have the hu-parti of a final column
parse the optional argument. There is still a problem with \end{...}. Note that
at the moment this style assumes that \\ is used at the end of all lines except
the last, even before \begin{block} or \end{block}, this allows spacing to be

14
specified, and also approximates to the truth about what is actually happening.
The idea of making it easier to allow entries to be taken as arguments may be a
non-starter if & is allowed to become a ‘short-ref’ (ie \active) character.
158 \def\BA@cr{{\ifnum 0=‘}\fi
159 \@ifstar \BA@xcr \BA@xcr}
160 \def\BA@xcr{\@ifnextchar [%
161 \BA@argcr {\ifnum 0=‘{\fi}\cr}}
162 \def\BA@argcr[#1]{\ifnum0=‘{\fi}\ifdim #1>\z@
163 \BA@xargcr{#1}\else \BA@yargcr{#1}\fi}
164 \def\BA@xargcr#1{\unskip
165 \@tempdima #1\advance\@tempdima \dp\@arstrutbox
166 \vrule \@depth\@tempdima \@width\z@ \cr}
167 \def\BA@yargcr#1{\cr\noalign{%
168 \vskip #1}}
169 \newdimen\BAextrarowheight
170 \newdimen\BAextraheightafterhline
171 \newdimen\BAarrayrulewidth
172 \BAarrayrulewidth\arrayrulewidth
173 \newdimen\BAdoublerulesep
174 \BAdoublerulesep\doublerulesep
The B form of the strut is an extra high strut to use after a horizontal rule.
175 \def\BA@strut{\unhcopy\@arstrutbox}
176 \let\BA@strutA\BA@strut
177 \def\BA@strutB{\dimen@\ht\@arstrutbox
178 \advance\dimen@\BAextraheightafterhline
179 \vrule \@height\dimen@ \@depth \dp\@arstrutbox \@width\z@
180 \global\let\BA@strut\BA@strutA}

2.9 Begin and End


\begin{block} is supposed to expand to \noalign{..., but the code for \begin
would place non-expandable tokens before the \noalign. Within the blockarray
environment, redefine \begin so that if its argument corresponds to a command
\BA@beginhargumenti, then directly directly expand that command, otherwise do
a normal \begin. A matching change is made to \end.
181 \let\BA@@begin\begin
182 \let\BA@@end\end
183 \def\BA@begin#1{%
184 \expandafter\testGC@x\csname BA@begin#1\endcsname\relax
185 {\BA@@begin{#1}}%
186 {\csname BA@begin#1\endcsname}}
187 \def\BA@end#1{%
188 \expandafter\testGC@x\csname BA@end#1\endcsname\relax
189 {\BA@@end{#1}}%
190 {\csname BA@end#1\endcsname}}

15
2.10 The blockarray Environment
191 \def\blockarray{\relax
192 \@ifnextchar[{\BA@blockarray}{\BA@blockarray[c]}}
193 \def\BA@blockarray[#1]#2{%
194 \expandafter\let\expandafter\BA@finalposition
195 \csname BA@position@#1\endcsname
196 \let\begin\BA@begin
197 \let\end\BA@end
198 \ifmmode
199 \def\BA@bdollar{$}\let\BA@edollar\BA@bdollar
200 \else
201 \setbox\z@\hbox{$$}%set up math for NFSS (2014/10/16)
202 \def\BA@bdollar{\bgroup}\def\BA@edollar{\egroup}%
203 \let\BA@bdollar\bgroup\let\BA@edollar\egroup
204 \fi
205 \let\\\BA@cr
Currently I use \everycr this means that every macro that uses \halign that
might be used inside a blockarray must locally clear \everycr. The version of
array in array.sty does this, but not the one in latex.tex.
206 \everycr{\noalign{%
207 \global\advance\BA@row\@ne
208 \global\BA@col\z@}}%
The \extrarowheight code from array.sty.
209 \@tempdima \ht \strutbox
210 \advance \@tempdima by\BAextrarowheight
211 \setbox\@arstrutbox \hbox{\vrule
212 \@height \arraystretch \@tempdima
213 \@depth \arraystretch \dp \strutbox
214 \@width \z@}%
As explained above various registers which are ‘local’ to blockarray are always
accessed globally, and so must be shadowed by local copies, so that the values can
be restored at the end.
215 \BA@col@shadow=\BA@col
216 \global\BA@col=\@ne
217 \BA@block@cnt@shadow=\BA@block@cnt
218 \global\BA@block@cnt\@M
219 \BA@row@shadow\BA@row
220 \global\BA@row\z@
221 \setbox\BA@final@box@shadow=\box\BA@final@box
222 \global\setbox\BA@final@box=\box\voidb@x
223 \let\BA@delrow@shadow=\BA@delrow
224 \let\testBA@quick@shadow\testBA@quick
225 \global\BA@quicktrue
If we are using tablenotes, shadow the footnote counter (or possibly mpfootnote),
and set up the print style for the table notes.
226 \testBAtablenotes
227 {\edef\BA@mpftn{\csname c@\@mpfn\endcsname}%

16
228 \@namedef{the\@mpfn}{\BA@fnsymbol{\@nameuse{c@\@mpfn}}}%
229 \BA@ftn@shadow=\BA@mpftn\global\BA@mpftn\z@
230 \BA@ftnx@shadow=\expandafter{\the\BA@ftn}\global\BA@ftn{}%
231 }{}%
Locally increase \BA@nesting so that macros accessed by ‘the second method’ will
be local to this environment.
232 \edef\BA@nesting{\BA@nesting.}%
Now start up the code for this block
233 \BA@expafter\xdef{blocktype}{10000}%
234 \BA@expafter\xdef{BTstack}{\relax}%
235 \global\BA@expafter\def{blank@row}{\crcr}%
236 \setbox\BA@first@box=\vbox{\ifnum0=‘}\fi
237 \let\@footnotetext\BA@ftntext\let\@xfootnotenext\BA@xftntext
238 \lineskip\z@\baselineskip\z@
239 \BA@clear@entry
240 \global\let\BA@l@expr\BA@bdollar\global\let\BA@r@expr\BA@edollar
241 \global\let\BA@l@expr\@empty\global\let\BA@r@expr\@empty
242 \BA@colseptrue
243 \BA@parse#2\BA@parseend
244 \BA@col@max=\BA@col
There had to be a \halign somewhere, and here it is!
Currently I am using a ‘repeating preamble’ because it was easier, but I think
that I should modify the columntypes for blockarray (not block) so that they
construct a preamble with the right number of columns. this would give better
error checking, and would give the possibility of modifying the tabskip glue.
245 \tabskip\z@
246 \halign\bgroup\BA@strut%\global\BA@col=\z@
247 \BA@upart##\BA@vpart&&\BA@upart##\BA@vpart\cr
248 \noalign{\penalty\GC@five}}
249 \def\BA@upart{\global\advance\BA@col\@ne\BA@col@use{u}\ignorespaces}
250 \def\BA@vpart{\unskip\BA@col@use{v}}
251 \def\BA@clear@entry{%
252 \global\BA@col@expafter\let{u}\@empty
253 \global\BA@col@expafter\let{v}\@empty
254 \global\BA@col@expafter\let{left}\relax
255 \global\BA@col@expafter\let{mid}\@empty
256 \global\BA@col@expafter\let{right}\relax
257 \BA@uparttrue}
258 \let\BA@fnsymbol=\@fnsymbol
The code to place the footnote texts at the foot of the table, each footnote
starting on a new line. This will only be activated if \BAtablenotestrue.
259 \def\BA@expft[#1]#2{%
260 \noindent\strut\ifodd0#11{%
261 \edef\@thefnmark
262 {\BA@fnsymbol{#1}}\@makefnmark}\else{#1}\fi\ #2\unskip\strut\par}

17
After a \BAparfootnotes declaration, the table notes will be set in a single
paragraph, with a good chance of line breaks occuring at the start of a footnote.
263 \def\BAparfootnotes{%
264 \def\BA@expft[##1]##2{%
265 \noindent\strut\ifodd0##11{%
266 \edef\@thefnmark{\BA@fnsymbol{##1}}\@makefnmark}\else{##1~}\fi
267 ##2\unskip\strut\nobreak
268 \hskip \z@ plus 3em \penalty\z@\hskip 2em plus -2.5em minus .5em}}
269 \def\endblockarray{%
At this point, if no delimiters, \BAnoalign, or \BAmultirow have been used, just
finish here, this makes blockarray was just about as efficient as array If no fancy
tricks have been used.
270 \testBA@quick\BA@quick@end\BA@work@back@up
Now we restore the values that have been ‘shadowed’ by versions that are local to
this environment.
271 \global\BA@block@cnt=\BA@block@cnt@shadow
272 \global\BA@col=\BA@col@shadow
273 \global\BA@row=\BA@row@shadow
274 \global\setbox\BA@final@box=\box\BA@final@box@shadow
275 \global\let\BA@delrow=\BA@delrow@shadow
276 \global\let\BA@delrow=\BA@delrow@shadow
277 \global\let\testBA@quick\testBA@quick@shadow
If tablenotes are being used, reset the shadowed list of footnotes. Otherwise exe-
cute the list now, to pass the footnotes on to the outer environment, or the current
page.
278 \testBAtablenotes
279 {\global\BA@mpftn=\BA@ftn@shadow
280 \global\BA@ftn=\expandafter{\the\BA@ftnx@shadow}}
281 {\global\BA@ftn\expandafter{\expandafter}\the\BA@ftn}}
Here is the ‘quick ending’: just position the box as specified by [tcb], possibly
adding footnotes.
282 \def\BA@quick@end{%
283 \crcr
284 \egroup% end of halign
285 \ifnum0=‘{\fi}% end of \BA@first@box
286 h∗tracingi
287 \ifnum\BAtracing>\z@\typeout{Quick blockarray ends \on@line}\fi
288 h/tracingi
289 \leavevmode\BA@finalposition\BA@first@box}
If any delimiters or noaligns have been used, we must take apart the table built
in \BA@first@box, and reassemble it. This is done by removing the rows one by
one, starting with the last row, using \lastbox.
290 \def\BA@work@back@up{%
291 \BA@use{blank@row}%
292 \egroup% end of halign
293 \setbox\@tempboxa=\lastbox
294 \unskip

18
295 \BA@getwidths
296 h∗tracingi
297 \ifnum\BAtracing>\z@\typeout{Full blockarray ends \on@line}\fi
298 h/tracingi
299 h∗tracingi
300 \ifnum\BAtracing>\thr@@
301 \egroup\showbox\BA@first@box
302 \setbox\BA@first@box=\vbox\bgroup\unvbox\BA@first@box
303 \fi
304 h/tracingi
305 \setbox\BA@block@box=\box\voidb@x
306 \BA@check@pen
307 \ifnum0=‘{\fi}% end of \BA@first@box
308 h∗checki
309 \dimen@=\ht\BA@first@box\advance\dimen@\dp\BA@first@box
310 \ifdim\dimen@>\z@\showthe\dimen@\fi
311 h/checki
312 \leavevmode\BA@finalposition\BA@final@box}
These macros position the final box, they are just first attempts. In particular
[t] does not work properly because the guard penalty used to terminate the main
loop means that \BA@first@box always has zero height. Also if the box has been
taken apart, [t] and [b] will cause the position to be based on the centre of the
corresponding block.
If tablenotes are being used, package the table in a box with the notes.
313 \newdimen\BAfootskip
314 \BAfootskip=1em
315 \def\BA@position@c#1{\hbox{%
316 \testBAtablenotes
317 {\let\footnotetext\BA@expft
318 \hsize\wd#1\@parboxrestore\footnotesize}%
319 {}%
320 $\vcenter{%
321 \unvbox#1%
322 \testBAtablenotes
323 {\vskip\BAfootskip
324 \the\BA@ftn}{}%
325 }$}}
326 \def\BA@position@t#1{\vtop{%
327 \testBAtablenotes
328 {\let\footnotetext\BA@expft
329 \hsize\wd#1\@parboxrestore\footnotesize}%
330 {}%
331 \unvbox#1%
332 \testBAtablenotes
333 {\vskip\BAfootskip
334 \the\BA@ftn}{}}}
335 \def\BA@position@b#1{%
336 \testBAtablenotes

19
337 {\vbox{%
338 \let\footnotetext\BA@expft
339 \hsize\wd#1\@parboxrestore\footnotesize
340 \unvbox#1%
341 \vskip\BAfootskip
342 \the\BA@ftn}}%
343 {\box#1}}

2.11 Fitting the Parts Together


Get the widths of each column. It also faithfully copies the tabskip glue, even
though currently this is always 0pt. The width of the column is put into
\BA@delrow as the argument to the (unexpanded) call to \BA@lr.
344 \def\BA@getwidths{%
345 \setbox\@tempboxa=\hbox{\unhbox\@tempboxa
346 \xdef\BA@delrow{\hskip\the\lastskip}\unskip
347 \let\BA@lr\relax
348 \loop
349 \setbox\BA@tempbox@a=\lastbox
350 \skip\z@=\lastskip\unskip
351 \ifhbox\BA@tempbox@a
352 \xdef\BA@delrow{%
353 \hskip\the\skip\z@\BA@lr{\the\wd\BA@tempbox@a}\BA@delrow}%
354 \repeat}}
The main mechanism by which blkarray leaves information to be used ‘on the
way back’ is to leave groups of penalties in the main box. The last penalty in each
group (the first to be seen on the way back) is a code penalty, it has the following
meanings:
\penalty 1 — \begin{block}
\penalty 2 — \end{block}
\penalty 3 — \BAnoalign
\penalty 4 — \BAnoalign*
\penalty 5 — \begin{blockarray}
Note that the block* environment does not produce any penalties, this environ-
ment is just as efficient as \multicolumn, and does not require the second phase,
coming back via \lastbox.
Above the code penalty may be other penalties, depending on the code, typi-
cally these have the values of the blocktype for the block, or the row number.
355 \def\BA@check@pen{%
356 \count@=\lastpenalty\unpenalty
357 \ifcase\count@
Grumble Grumble. \lastpenalty should be void if the previous thing was not a
penalty, and there should be an \ifvoid\lastpenalty or something equivalent to
test for this. If the user manages to get a \penalty0 into the main box, it will just
have to be discarded. Actually that is not disastrous, but if a rule, mark, special,
insert or write gets into that box blockarray will go into an infinite loop. Every
class of TEX object should have a \last. . . so that boxes may be taken apart and

20
reconstructed by special styles like this. TEX of course is frozen, so these missing
features will never be added (while the system is called TEX).
358 h∗tracingi
359 \ifnum\BAtracing>\tw@\typeout{0-???}\fi
360 h/tracingi
361 \BA@get@row
362 \or
363 h∗tracingi
364 \ifnum\BAtracing>\tw@\typeout{1-block}\fi
365 h/tracingi
366 \BA@expafter\xdef{blocktype}{\the\lastpenalty}\unpenalty
367 \ifnum\lastpenalty=\tw@
368 h∗tracingi
369 \ifnum\BAtracing>\tw@\typeout{discarding 2-endblock}\fi
370 h/tracingi
371 \unpenalty\unpenalty\fi
372 \BA@place
373 \or
374 h∗tracingi
375 \ifnum\BAtracing>\tw@\typeout{2-endblock}\fi
376 h/tracingi
377 \BA@expafter\xdef{blocktype}{\the\lastpenalty}\unpenalty
378 \BA@place
379 \or
380 h∗tracingi
381 \ifnum\BAtracing>\tw@\typeout{3-BAnoalign}\fi
382 h/tracingi
383 \BA@expafter\xdef{blocktype}{\the\lastpenalty}\unpenalty
384 \BA@place
385 \count@=\lastpenalty\unpenalty
386 \global\setbox\BA@final@box=\vbox{%
387 \hsize=\wd\BA@final@box\@parboxrestore
388 \vrule \@height \ht\@arstrutbox \@width \z@
389 \BA@use{noalign\the\count@}
390 \vrule \@width \z@ \@depth \dp \@arstrutbox
391 \endgraf\unvbox\BA@final@box}%
392 \or
393 h∗tracingi
394 \ifnum\BAtracing>\tw@\typeout{4-BAnoalign*}\fi
395 h/tracingi
396 \count@=\lastpenalty\unpenalty
397 \setbox\BA@block@box=\vbox{%
398 \hsize=\wd\BA@final@box \@parboxrestore
399 \vrule \@height \ht\@arstrutbox \@width \z@
400 \BA@use{noalign\the\count@}
401 \vrule \@width \z@ \@depth \dp \@arstrutbox
402 \endgraf\unvbox\BA@block@box}%
403 \or
404 h∗tracingi

21
405 \ifnum\BAtracing>\tw@\typeout{5-blockarray}\fi
406 h/tracingi
407 \BA@expafter\xdef{blocktype}{10000}
408 \BA@place
409 \let\BA@check@pen\relax
410 \fi
411 \BA@check@pen}
Move a row of the table from the \BA@first@box into the block that is being
constructed in \BA@block@box.
412 \def\BA@get@row{%
413 \skip@=\lastskip\unskip
414 \advance\skip@\lastskip\unskip
415 \setbox\@tempboxa=\lastbox
416 \setbox\BA@block@box=\vbox{%
417 \box\@tempboxa
418 \vskip\skip@
419 \unvbox\BA@block@box}}
Place the block that has been constructed in \BA@block@box, together with
any delimiters, or spanning entries which have been assembled into \BA@delrow,
into the final table, which is being constructed in \BA@final@box.
420 \def\BA@place{%
421 \global\setbox\BA@final@box=\vbox{\hbox{%
422 \m@th\nulldelimiterspace=\z@
423 \dimen\z@=\ht\BA@block@box
424 \advance\dimen\z@ by \dp\BA@block@box
425 \divide\dimen\z@\tw@
426 \dimen\tw@=\dimen\z@
427 \advance\dimen\z@ by\fontdimen22 \textfont\tw@
428 \advance\dimen2 by-\fontdimen22 \textfont\tw@
429 \global\BA@col=\z@
430 \delimitershortfall=10pt
431 \delimiterfactor=800
432 \BA@delrow
433 \kern-\wd\BA@block@box
434 \ht\BA@block@box=\dimen\z@ \dp\BA@block@box=\dimen\tw@
435 \box\BA@block@box}
436 \unvbox\BA@final@box}}
Place the delimiters or spanning entries in position for one column of the
current block.
437 \def\BA@lr#1{%
438 \global\advance\BA@col\@ne\relax
439 \BA@col@use{left}%
440 \BA@col@expafter\ifx{mid}\@empty
441 \kern#1
442 \else
443 \hbox to #1{%
444 \setbox\BA@tempbox@a

22
445 \hbox{\let\BA@mrow@bslash\@gobble\BA@col@use{u}\BA@edollar}%
446 \setbox\BA@tempbox@b
447 \hbox{\BA@bdollar\BA@col@use{v}}%
448 \kern\wd\BA@tempbox@a
449 $\vcenter{%
450 \hsize=#1
451 \advance\hsize-\wd\BA@tempbox@a
452 \advance\hsize-\wd\BA@tempbox@b
453 \@parboxrestore\BA@col@use{mid}}$%
454 \kern\wd\BA@tempbox@b}%
455 \fi
456 \BA@col@use{right}}
457 \def\BA@leftdel#1#2#3{%
458 \llap{%
459 {#1}$\left#2\vrule height \dimen\z@ width\z@ \right.$\kern-#3}}
460 \def\BA@rightdel#1#2#3{%
461 \rlap{%
462 \kern-#3$\left.\vrule height \dimen\z@ width\z@ \right#1${#2}}}%

2.12 Parsing the Column Specifications


A token x in the column specification, is interpreted by \BA@parse as \BA@<x>.
This command is then expanded, which may take further tokens as arguments.
The expansion of \BA@<x> is supposed to end with a call to \BA@parse which
will convert the token following any arguments to a control sequence name. The
process is terminated by the token \BA@parseend as the coresponding command
\BA@<\BA@parseend> does some ‘finishing off’, but does not call \BA@parse.
There are two commands to help in defining column types.
\BA@defcolumntype This takes its parameter specification in the primitive \def
syntax, and allows the replacement text to be anything.
\BAnewcolumntype This takes its parameter specification in LATEX’s \newcommand
syntax, and applies \BA@parse to the front of the replacement text. This is
intended for users to define their own column types in terms of primitive column
types, rather than in terms of arbitrary TEX expressions.
The preamble argument build up various macros as as follows:
Each entry in the \halign preamble is of the form
\BA@upart#\BA@vpart
\BA@upart increments \BA@col, and then expands \BA@col@use{u}, similarly
\BA@vpart expands \BA@col@use{v}.
\BA@col@use{u} is a macro considered local to the current block and column,
it is always accessed via \BA@col@use or \BA@col@expafter. So the preamble
entries must result in \BA@col@use{u} and \BA@col@use{v} being defined to enter
any text specified in @-expressions, the inter-column space (in the LATEX tradition,
not \tabskip), and any declarations in > and < expressions. Delimiters are not
added to these macros as they correspond to the whole block, they are left in
the macros \BA@col@use{left} and \BA@col@use{right} spanning entries from
\BAmultirow are considered like delimiters, and left in \BA@col@use{mid}.

23
If the test \testBA@upart is true, then the hu-parti is being built. This consists
of three different sections.
1) The left inter-column text, declared in !- and @-expressions
2) The left inter-column skip.
3) Any declarations specified in > expressions.
Suppose X is a column type, which may itself be defined in terms of other
column types, then the (equivalent) specifications:
@{aaa}>{\foo}X and >{\foo}@{aaa}X
must result in aaa, surrounded by \bgroup. . . \egroup or $. . . $, being prepended
to the front of the u-part, and \foo being appended to the end, so that it is the
innermost declaration to be applied to the entries in that column.
In order to achieve this, > expressions are directly added to the u-part, using
\GC@add@to@front, @- and !- expressions (and rules from |) are added to a scratch
macro, \BA@l@expr, using \GC@add@to@end.
When the next # column specifier is reached, the \BA@l@expr is added to the
front of the u-part, It is separated from the >-expressions by a hhskipi unless an
@-expression has occured, either while building the current u-part, or the previous
v-part.
Building the v-part is similar.
This procedure has certain consequences,
• @{a}@{b} is equivalent to @{ab}, or more correctly @{{a}{b}}.

• >{\a}>{\b} is equivalent to >{\b\a}.


• If any @-expression occurs between two columns, all !-expressions between
those columns will be treated identically to @-expressions. This differs from
array.sty where two !-expressions are separated by the same skip as the
rules specified by ||.
• If any rule | occurs, then a following rule will be preceded by the dou-
bleruleskip, unless a @ or !-expression comes between them. In particular
|&| specifies a double rule, which looks the same as ||, but \multicolumn
commands can be used to remove one or other of the rules for certain entries.

Create a macro name from a column specifier.


463 \def\BA@stringafter#1#2{\expandafter#1\csname BA@<\string#2>\endcsname}
Execute the specifier, or discard an unknown one, and try the next token.
464 \def\BA@parse#1{%
465 \BA@stringafter\testGC@x{#1}\relax
466 {\@latexerr {Unknown column type, \string#1}\@ehc\BA@parse}%
467 {\csname BA@<\string#1>\endcsname}}
\def for column types.
468 \def\BA@defcolumntype#1{%
469 \BA@stringafter\def{#1}}

24
\newcommand for column types.1
470 \def\BAnewcolumntype{\@ifnextchar[{\BA@nct}{\BA@nct[0]}}
471 \def\BA@nct[#1]#2#3{%
472 \BA@stringafter\@reargdef{#2}[#1]{\BA@parse#3}}
These \ifs will be true if their associated skips are to be added in the current
column.
473 \newif\ifBA@colsep
474 \newif\ifBA@rulesep
This is true if we do not need to come back up the array.
475 \GC@newtest{BA@quick}
This will be true if building the hu-parti, and false if building the hv-parti.
476 \GC@newtest{BA@upart}

2.13 ‘Internal’ Column-Type Definitions


> expressions:
If we are building the v-part, add a &, and try again, so that c<{\a}>{\b}c is
equivalent to c<{\a}&>{\b}c.
Otherwise add the expression to the front of the u-part, i.e., the list being built
in \BA@col@use{u}. Note that no grouping is added so that the scope of any
declaration includes the column entry.
477 \BA@defcolumntype{>}#1{%
478 \testBA@upart
479 {\BA@col@expafter\GC@add@to@front{u}{#1}%
480 \BA@parse}%
481 {\BA@parse &>{#1}}}
Left delimiters:
Again add a & if required, otherwise just save the delimiter and label as the first
two arguments of \BA@left@del in the macro \BA@col@use{left}.
482 \BA@defcolumntype{\Left}#1#2{%
483 \testBA@upart
484 {\global\BA@quickfalse
485 \BA@col@expafter\gdef{left}{\BA@leftdel{#1}{#2}}\BA@parse}%
486 {\BA@parse &\Left{#1}{#2}}}
Right delimiters: As for Left.
487 \BA@defcolumntype{\Right}#1#2{%
488 \testBA@upart
489 {\BA@parse ##\Right{#1}{#2}}
490 {\global\BA@quickfalse
491 \BA@col@expafter\gdef{right}{\BA@rightdel{#1}{#2}}\BA@parse}}%
& The end of each column specification is terminated by &, either by the user
explicitly entering &, or one being added by one of the other rewrites.
1 Currently does not check that the type is new.

25
If we are still in the u-part, finish it off with #.
Otherwise add another column to the blank row, advance the column counter by
one. Finally reset the variables \BA@use{u|v|left|mid|right}
492 \BA@defcolumntype{&}{%
493 \testBA@upart
494 {\BA@parse ##&}%
495 {%
496 \BA@expafter\xdef{blank@row}{\BA@use{blank@row}\omit&}%
497 \global\advance\BA@col\@ne
498 \BA@clear@entry
499 \BA@parse}}
# Add a & if required.
Otherwise make the u-part of the current column, and the v-part of the previous
one.
500 \BA@defcolumntype{#}{%
501 \testBA@upart
502 {%
Add the intercolumn skips unless a @ expression has occured since the last # entry.
503 \ifBA@colsep
504 \GC@add@to@front\BA@r@expr{\BA@edollar\hskip\BA@colsep}%
505 \GC@add@to@end\BA@l@expr{\hskip\BA@colsep\BA@bdollar}%
506 \else
507 \GC@add@to@front\BA@r@expr{\BA@edollar}%
508 \GC@add@to@end\BA@l@expr{\BA@bdollar}%
509 \fi
Go back to the previous column. Add \BA@r@expr to the end of \BA@col@use{v}.
510 \global\advance\BA@col\m@ne
511 \BA@col@expafter\GC@add@to@end{v\expandafter}\expandafter
512 {\BA@r@expr}%
Add the total width of any @ expressions as the third argument in the right de-
limiter macro, this will be used to move the delimiters past any inter-column
material.
513 \BA@add@rskip
Repeat for the u-part, and left delimiter of the current column.
514 \global\advance\BA@col\@ne
515 \BA@col@expafter\GC@add@to@front{u\expandafter}\expandafter
516 {\BA@l@expr}%
517 \BA@add@lskip
Clear these scratch macros ready for the next column.
518 \global\let\BA@l@expr\@empty\global\let\BA@r@expr\@empty
Reset these tests and ifs, ready for the next inter-column material.
519 \BA@upartfalse
520 \BA@rulesepfalse
521 \BA@colseptrue

26
Finally look at the next specifier.
522 \BA@parse}%
523 {\BA@parse &##}}
< Just like >.
524 \BA@defcolumntype{<}#1{%
525 \testBA@upart
526 {\BA@parse ##<{#1}}%
527 {\BA@col@expafter\GC@add@to@front{v}{#1}\BA@parse}}
BA version of \vline.
528 \def\BA@vline{\vrule \@width \BAarrayrulewidth}
| like !, except that a \hskip\BAdoublerulesep is added for consecutive pairs.
529 \BA@defcolumntype{|}{%
530 \testBA@upart
531 {\ifBA@rulesep
532 \GC@add@to@end\BA@l@expr{\hskip\BAdoublerulesep\BA@vline}%
533 \else
534 \GC@add@to@end\BA@l@expr{\BA@vline}%
535 \fi}%
536 {\ifBA@rulesep
537 \GC@add@to@end\BA@r@expr{\hskip\BAdoublerulesep\BA@vline}%
538 \else
539 \GC@add@to@end\BA@r@expr{\BA@vline}%
540 \fi}%
541 \BA@ruleseptrue
542 \BA@parse}
@ identical to !, but set \BA@colsepfalse.
543 \BA@defcolumntype{@}#1{%
544 \testBA@upart
545 {\GC@add@to@end\BA@l@expr{\BA@bdollar#1\BA@edollar}}%
546 {\GC@add@to@end\BA@r@expr{\BA@bdollar#1\BA@edollar}}%
547 \BA@colsepfalse
548 \BA@rulesepfalse
549 \BA@parse}
! Just save the expression, and make \BA@rulesepfalse so that the next | is
not preceded by a skip.
550 \BA@defcolumntype{!}#1{%
551 \testBA@upart
552 {\GC@add@to@end\BA@l@expr{\BA@bdollar#1\BA@edollar}}%
553 {\GC@add@to@end\BA@r@expr{\BA@bdollar#1\BA@edollar}}%
554 \BA@rulesepfalse
555 \BA@parse}
*: *{3}{xyz} just produces xyz*{2}{xyz} which is then re-parsed.
556 \BA@defcolumntype{*}#1#2{%
557 \count@=#1\relax
558 \ifnum\count@>\z@
559 \advance\count@\m@ne

27
560 \edef\@tempa##1{\noexpand\BA@parse##1*{\the\count@}{##1}}%
561 \else
562 \def\@tempa##1{\BA@parse}%
563 \fi
564 \@tempa{#2}}
\BA@parseend this is added to the end of the users preamble, it acts like a
cross between # and &. It terminates the preamble building as it does not call
\BA@parse.
565 \BA@defcolumntype{\BA@parseend}{%
566 \testBA@upart
567 {\BA@parse ##\BA@parseend}%
568 {%
569 \ifBA@colsep
570 \GC@add@to@front\BA@r@expr{\BA@edollar\hskip\BA@colsep}%
571 \else
572 \GC@add@to@front\BA@r@expr{\BA@edollar}%
573 \fi
574 \BA@expafter\xdef{blank@row}{\BA@use{blank@row}\omit\cr}%
575 \BA@add@rskip
576 \BA@col@expafter\GC@add@to@end{v\expandafter}\expandafter
577 {\BA@r@expr}}}
Like array.sty
578 \def\BA@startpbox#1{\bgroup
579 \hsize #1 \@arrayparboxrestore
580 \vrule \@height \ht\@arstrutbox \@width \z@}
581
582 \def\BA@endpbox{\vrule \@width \z@ \@depth \dp \@arstrutbox \egroup}
Save the & and # macros, so they can be restored after a multicolumn, which
redefines them.
583 \BA@stringafter{\let\expandafter\BA@save@amp}{&}
584 \BA@stringafter{\let\expandafter\BA@save@hash}{#}
A column specification of \BAmulticolumn{3}{c} is re-written to:
c\BA@MC@end, except that the definition of # has been changed so that it expands
to:
>{\null\span\span}\BA@MC@restore@hash&@{}&@{}\BA@MC@switch@amp
The 2 \spans in the u-part make the entry span 3 columns, the 2 &@{} incre-
ment \BA@col without adding any intercolumn skips. The \BA@MC@restore@hash
specifier just restores # to its normal meaning. \BA@MC@switch@amp then causes a
specifier & to generate an error, as the argument to multicolumn may only specify
one column. Finally when \BA@MC@end is reached, & is restored.
\BA@MC@restore@hash restore the meaning of #.
585 \BA@defcolumntype{\BA@MC@restore@hash}{%
586 \BA@stringafter\let{##}\BA@save@hash
587 \BA@parse}
Switch the meaning of & so it generates an error, and skips all specifiers up to
\BA@MC@end

28
588 \BA@defcolumntype{\BA@MC@switch@amp}{%
589 \BA@stringafter\let{&}\BA@extra@amp
590 \BA@parse}
Restore &.
591 \BA@defcolumntype{\BA@MC@end}{%
592 \BA@stringafter\let{&}\BA@save@amp
593 \BA@parse}
The special definition of & while parsing the multicolumn argument.
594 \def\BA@mc@extra@amp#1\BA@MC@end{%
595 \@latexerr{\string& in multicolumn!}\@ehc\BA@parse\BA@MC@end}%
Putting it all together!
596 \BA@defcolumntype{\BAmulticolumn}#1#2{%
597 \BA@make@mc{#1}%
598 \BA@stringafter\let{##}\BA@mc@hash
599 \BA@parse#2\BA@MC@end}
As explained above, in order to position the delimiters on the way back we
need the widths of the inter-column texts.
600 \def\BA@add@rskip{%
601 \BA@col@expafter\ifx{right}\relax\else
602 \setbox\BA@tempbox@a\hbox{\BA@bdollar\BA@r@expr}%
603 \BA@col@expafter\GC@add@to@end{right\expandafter}\expandafter
604 {\expandafter{\the\wd\BA@tempbox@a}}\fi}
605 \def\BA@add@lskip{%
606 \BA@col@expafter\ifx{left}\relax\else
607 \setbox\BA@tempbox@a\hbox{\BA@l@expr\BA@edollar}%
608 \BA@col@expafter\GC@add@to@end{left\expandafter}\expandafter
609 {\expandafter{\the\wd\BA@tempbox@a}}\fi}

2.14 User Level Column-Type Definitions


610 \BAnewcolumntype{c} {>{\hfil}<{\hfil}}
611 \BAnewcolumntype{l} {>{}<{\hfil}}
612 \BAnewcolumntype{r} {>{\hfil}<{}}
613 \BAnewcolumntype[1]{p}{>{\vtop\BA@startpbox{#1}}c<{\BA@endpbox}}
614 \BAnewcolumntype[1]{m}{>{$\vcenter\BA@startpbox{#1}}c<{\BA@endpbox$}}
615 \BAnewcolumntype[1]{b}{>{\vbox\BA@startpbox{#1}}c<{\BA@endpbox}}

616 \BAnewcolumntype{(} {\Left{}{(}}


617 \BAnewcolumntype{)} {\Right{)}{}}
618 \BAnewcolumntype{\{} {\Left{}{\{}}
619 \BAnewcolumntype{\}} {\Right{\}}{}}
620 \BAnewcolumntype{[} {\Left{}{[}}
621 \BAnewcolumntype{]} {\Right{]}{}}
622 \BAnewcolumntype{\BAenum} {%
623 !{%
624 {\def\protect{\noexpand\protect\noexpand}%

29
625 \xdef\@currentlabel{\p@BAenumi\theBAenumi}}
626 \hbox to 2em{%
627 \hfil\theBAenumi}}}
628 \BAnewcolumntype[1]{\BAmultirow}{>{\BA@mrow@bslash{#1}}##}

2.15 Footnotes
This test is true if footnote texts are to be displayed at the end of the table.
629 \GC@newtest{BAtablenotes}
630 \BAtablenotestrue
Inside the alignment just save up the footnote text in a token register.
631 \long\def\BA@ftntext#1{%
632 \edef\@tempa{\the\BA@ftn\noexpand\footnotetext
633 [\the\csname c@\@mpfn\endcsname]}%
634 \global\BA@ftn\expandafter{\@tempa{#1}}}%
635 \long\def\BA@xftntext[#1]#2{%
636 \global\BA@ftn\expandafter{\the\BA@ftn\footnotetext[#1]{#2}}}

2.16 Hline and Hhline


The standard \hline command would work fine ‘on the way down’ but on the way
back it throws me into an infinite loop as there is no \lastrule to move the rule
into the final box. I could just make \hline leave a code penalty, and put in the
rule on the way back, but this would mean that every array with an \hline needs
to be taken apart. I hope to make ‘most’ arrays be possible without comming
back up the array via \lastbox. I could do something with \leaders which are
removable, but for now, I just make \hline and \hline\hline just call \hhline
with the appropriate argument. The \hhline from hhline.sty does work, but
needs extra options to deal with & etc, but here is a re-implementation, more in
the spirit of this style.
637 \def\BAhline{%
638 \noalign{\ifnum0=‘}\fi
639 \futurelet\@tempa\BA@hline}
640 \def\BA@hline{%
641 \ifx\@tempa\BAhline
642 \gdef\BA@hline@@##1{\BAhhline{*{\BA@col@max}{=}}}%
643 \else
644 \gdef\BA@hline@@{\BAhhline{*{\BA@col@max}{-}}}%
645 \fi
646 \ifnum0=‘{\fi}%
647 \BA@hline@@}
648 \def\BAhhline#1{%
649 \omit
First set up the boxes used in \leaders.
650 \global\setbox\BA@ddashbox=\BA@HHbox\BAarrayrulewidth\BAarrayrulewidth
651 \global\setbox\BA@dashbox=\hbox to \GC@six\BAarrayrulewidth{%

30
652 \hss
653 \vrule\@height\BAarrayrulewidth \@width\BAarrayrulewidth \@depth\z@
654 \hss}%
655 \global\let\BA@strut\BA@strutB
656 \global\BA@rulesepfalse
657 \global\BA@uparttrue
658 \BA@HHparse#1\BA@HHend}
659 \def\BA@HHexp#1#2{\expandafter#1\csname aa\string#2\endcsname}
660 \def\BA@HHparse{{\ifnum0=‘}\fi\BA@HHparsex}
661 \def\BA@HHparsex#1{\BA@HHexp\aftergroup{#1}\ifnum0=‘{\fi}}
662 \BA@HHexp\def\BA@HHend{%
663 \cr}
664 \newbox\BA@dashbox
665 \newbox\BA@ddashbox
666 \BA@HHexp\def|{%
667 \ifBA@rulesep\hskip\BAdoublerulesep\fi
668 \global\BA@ruleseptrue
669 \vrule\@width\BAarrayrulewidth
670 \BA@HHparse}
: denotes a broken vertical rule, as in hhline.sty. If the double dots : : : :
currently produced by " turn out to be useful, it might be better to use : for
them, and something else, perhaps ! for this feature.
671 \BA@HHexp\def:{%
672 \ifBA@rulesep\hskip\BAdoublerulesep\fi
673 \global\BA@ruleseptrue
674 \copy\BA@ddashbox
675 \BA@HHparse}
676 \BA@HHexp\def-{%
677 \testBA@upart{}{&\omit\global\BA@uparttrue}%
678 \leaders\hrule\@height\BAarrayrulewidth\hfil
679 \global\BA@upartfalse
680 \global\BA@rulesepfalse
681 \BA@HHparse}
682 \BA@HHexp\def.{%
683 \testBA@upart{}{&\omit\global\BA@uparttrue}%
684 \copy\BA@dashbox\xleaders\copy\BA@dashbox\hfil\copy\BA@dashbox
685 \global\BA@rulesepfalse
686 \global\BA@upartfalse
687 \BA@HHparse}
688 \BA@HHexp\def"{%
689 \testBA@upart{}{&\omit\global\BA@uparttrue}%
690 \setbox\z@\hbox to \GC@six\BAarrayrulewidth
691 {\hss\copy\BA@ddashbox\hss}%
692 \copy\z@\xleaders\copy\z@\hfil\copy\z@
693 \global\BA@rulesepfalse

31
694 \global\BA@upartfalse
695 \BA@HHparse}
696 \BA@HHexp\def={%
697 \testBA@upart{}{&\omit\global\BA@uparttrue}%
698 \copy\BA@ddashbox\xleaders\copy\BA@ddashbox\hfil\copy\BA@ddashbox
699 \global\BA@rulesepfalse
700 \global\BA@upartfalse
701 \BA@HHparse}
702 \BA@HHexp\def~{%
703 \testBA@upart{}{&\omit\global\BA@uparttrue}%
704 \hfill
705 \global\BA@rulesepfalse
706 \global\BA@upartfalse
707 \BA@HHparse}
708 \BA@HHexp\def#{%
709 \ifBA@rulesep\hskip\BAdoublerulesep\fi
710 \global\BA@ruleseptrue
711 \vrule\@width\BAarrayrulewidth
712 \BA@HHbox\BAdoublerulesep\BAdoublerulesep
713 \vrule\@width\BAarrayrulewidth
714 \BA@HHparse}
715 \BA@HHexp\def{t}{%
716 \rlap{\BA@HHbox\BAdoublerulesep\z@}%
717 \BA@HHparse}
718 \BA@HHexp\def{b}{%
719 \rlap{\BA@HHbox\z@\BAdoublerulesep}%
720 \BA@HHparse}
721 \def\BA@HHbox#1#2{\vbox{%
722 \hrule \@height \BAarrayrulewidth \@width #1
723 \vskip \BAdoublerulesep
724 \hrule \@height \BAarrayrulewidth \@width #2}}
725 \BA@HHexp\def&{&\omit\global\BA@uparttrue\BA@HHparse}
726 \BA@HHexp\def{*}#1#2{%
727 \count@=#1\relax
728 \ifnum\count@>\z@
729 \advance\count@\m@ne
730 \edef\next##1{\noexpand\BA@HHparse##1*{\the\count@}{##1}}%
731 \else
732 \def\next##1{\BA@HHparse}%
733 \fi
734 \next{#2}}

32

You might also like