summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/source/latex/spalign/spalign.dtx
diff options
context:
space:
mode:
Diffstat (limited to 'Master/texmf-dist/source/latex/spalign/spalign.dtx')
-rw-r--r--Master/texmf-dist/source/latex/spalign/spalign.dtx1211
1 files changed, 1211 insertions, 0 deletions
diff --git a/Master/texmf-dist/source/latex/spalign/spalign.dtx b/Master/texmf-dist/source/latex/spalign/spalign.dtx
new file mode 100644
index 00000000000..c59e2246cbc
--- /dev/null
+++ b/Master/texmf-dist/source/latex/spalign/spalign.dtx
@@ -0,0 +1,1211 @@
+% \iffalse meta-comment
+%
+% Copyright (C) 2016 by Joseph Rabinoff <rabinoff@math.gatech.edu>
+% -------------------------------------------------------
+%
+% This file may be distributed and/or modified under the
+% conditions of the LaTeX Project Public License, either version 1.3
+% of this license or (at your option) any later version.
+% The latest version of this license is in:
+%
+% http://www.latex-project.org/lppl.txt
+%
+% and version 1.3 or later is part of all distributions of LaTeX
+% version 2005/12/01 or later.
+%
+% \fi
+%
+% \iffalse
+%<*driver>
+\ProvidesFile{spalign.dtx}
+%</driver>
+%<package>\NeedsTeXFormat{LaTeX2e}[2005/12/01]
+%<package>\ProvidesPackage{spalign}
+%<*package>
+ [2016/10/05 aligns delimited by spaces]
+%</package>
+%
+%<*driver>
+\documentclass{ltxdoc}
+\usepackage{spalign}[2016/10/05]
+\usepackage[charter,sfscaled,ttscaled,cal=cmcal]{mathdesign}
+\usepackage{amsmath}
+
+\def\usage#1#2{\textbf{Usage:} \texttt{\string#1} #2\vadjust{\vskip 1ex}\\}
+
+\newdimen\poptskip\poptskip=1.3cm
+\advance\poptskip by 1ex
+\def\poption #1:{%
+ \hangindent=\poptskip\hangafter=1%
+ \noindent\hbox to 1.3cm{\hfil\bf#1:}\hskip 1ex%
+ }
+\def\endopt{\par\vskip2pt}
+
+\let\tvs=\textvisiblespace
+
+\EnableCrossrefs
+\CodelineIndex
+\RecordChanges
+\begin{document}
+ \DocInput{spalign.dtx}
+ \PrintChanges
+ \PrintIndex
+\end{document}
+%</driver>
+% \fi
+%
+% \CharacterTable
+% {Upper-case \A\B\C\D\E\F\G\H\I\J\K\L\M\N\O\P\Q\R\S\T\U\V\W\X\Y\Z
+% Lower-case \a\b\c\d\e\f\g\h\i\j\k\l\m\n\o\p\q\r\s\t\u\v\w\x\y\z
+% Digits \0\1\2\3\4\5\6\7\8\9
+% Exclamation \! Double quote \" Hash (number) \#
+% Dollar \$ Percent \% Ampersand \&
+% Acute accent \' Left paren \( Right paren \)
+% Asterisk \* Plus \+ Comma \,
+% Minus \- Point \. Solidus \/
+% Colon \: Semicolon \; Less than \<
+% Equals \= Greater than \> Question mark \?
+% Commercial at \@ Left bracket \[ Backslash \\
+% Right bracket \] Circumflex \^ Underscore \_
+% Grave accent \` Left brace \{ Vertical bar \|
+% Right brace \} Tilde \~}
+%
+%
+% \changes{v1.0}{2016/10/05}{Initial version}
+%
+% \GetFileInfo{spalign.dtx}
+%
+% \DoNotIndex{\newcommand,\newenvironment}
+%
+%
+% \title{The \textsf{spalign} package\thanks{This document
+% corresponds to the version of \textsf{spalign} dated \filedate.}}
+% \author{Joseph Rabinoff \\ \texttt{rabinoff@math.gatech.edu}}
+%
+% \maketitle
+%
+% \section{Introduction}
+%
+% The purpose of this package is to decrease the number of keystrokes needed to
+% typeset small amounts of aligned material (matrices, arrays, etc.). For
+% instance, it is inconvenient to type (using the \textsf{amsmath} package)
+% \begin{verbatim}
+% \[ \begin{matrix}
+% 1 & 12 & -3 \\
+% 24 & -2 & 2 \\
+% 0 & 0 & 1
+% \end{matrix} \]\end{verbatim}
+% in a document where several hundred such
+% matrices must be typeset. Of course
+% one can always define a macro |\mat| which puts its argument inside a
+% |matrix| environment, but it is still necessary to type the align character
+% |&| and the end-of-row control sequence |\\| many times for each matrix.
+%
+% This package provides a facility for typesetting matrices, and using other
+% alignment environments and macros, with spaces as the
+% alignment delimiter and semicolons (by default) as the end-of-row indicator. So
+% the above matrix could be produced using the command:
+% \begin{verbatim}
+% \[ \spalignmat{1 12 -3; 24 -2 2; 0 0 1} \]\end{verbatim}
+% This package also contains utility macros for typesetting augmented matrices,
+% vectors, arrays, and more, and is easily extendable to other situations that use
+% alignments.
+%
+% \section{Usage}
+%
+% In~\S\ref{sec:alignment} the simplified alignment format used by arguments to
+% macros in this package is described. In~\S\ref{sec:utility} the utility
+% macros provided by the \textsf{spalign} package are presented; these are the
+% macros that most users will need. Section~\ref{sec:options} contains the
+% package options. The macros designed to allow the user to adapt the
+% \textsf{spalign} package to other situations are presented
+% in~\S\ref{sec:general}.
+%
+% \subsection{Alignment format}\label{sec:alignment}
+% The core functionality of the \textsf{spalign} package is to convert spaces to
+% alignment characters `|&|' and semicolons to end-of-row control sequences
+% `|\\|'. This process is called \textit{retokenization}. The retokenization
+% procedure is designed to work more or less how one would expect.
+% Retokenization of a string \meta{text} proceeds as follows.
+% \begin{enumerate}
+% \item Spaces at the beginning and end of \meta{text} are ignored, as are
+% spaces at the beginning and end of a line, and spaces before and after a
+% semicolon or a comma.
+% \item Multiple spaces are combined into one space.
+% \item Spaces between non-space characters are converted to |&| (really, to
+% the contents of |\spalignaligntab|).
+% \item Commas (really, the contents of |\spalignseparator|) are also converted to
+% |&|.
+% \item Semicolons (really, the contents of |\spalignendofrow|) are
+% converted to |\\| (really, to the contents of |\spalignendline|).
+% \item Text in braces |{...}| is treated as a unit: the contents are not
+% retokenized, and the braces are preserved.
+% \end{enumerate}
+% These rules are best understood by example.
+%
+% \medskip\noindent\textbf{Example.} The command
+% \begin{verbatim}
+% \[ \spalignmat{ 1
+% -2 3 ; 4
+% 55 2^3;
+% \frac{1 1}2 {1
+% 3} {1 0 1} } \]\end{verbatim}
+% produces
+% \[\spalignmat{ 1
+% -2 3 ; 4
+% 55 2^3 ;
+% \frac{1 1}2 {1
+% 3} {1 0 1} }.
+% \]
+%
+% \medskip\noindent\textbf{Example.} The command
+% \begin{verbatim}
+% \[ \spalignmat{ \cos\theta, \sin\theta;
+% -\sin\theta, \cos\theta} \]\end{verbatim}
+% produces
+% \[\spalignmat{ \cos\theta, \sin\theta;
+% -\sin\theta, \cos\theta}.
+% \]
+% Here the commas are necessary: \TeX\ will not tokenize spaces following a
+% command sequence, so
+% \begin{verbatim}
+% \[ \spalignmat{ \cos\theta \sin\theta;
+% -\sin\theta \cos\theta} \]\end{verbatim}
+% produces the (presumably unexpected) result
+% \[\spalignmat{ \cos\theta \sin\theta;
+% -\sin\theta \cos\theta}.
+% \]
+% Instead of commas, one could also type, for instance,
+% \begin{verbatim}
+% \[ \spalignmat{ \cos\theta{} \sin\theta;
+% -\sin{\theta} \cos\theta} \]\end{verbatim}
+%
+% \medskip\noindent\textbf{Example.} The fact that expressions between braces
+% |{...}| are not retokenized allows for arbitrarily complex entries in
+% \textsf{spalign} macros---although these macros are probably not terribly
+% useful in such cases. The \textsf{spalign} macros can even be nested: for
+% instance,
+% \begin{verbatim}
+% \[ \spalignmat{ \spalignmat{a b; c d} \spalignmat{a' b'; c' d'};
+% \spalignmat{d e; f g} \spalignmat{d' e'; f' g'} } \] \end{verbatim}
+% produces
+% \[ \spalignmat{ \spalignmat{a b; c d} \spalignmat{a' b'; c' d'};
+% \spalignmat{d e; f g} \spalignmat{d' e'; f' g'} }. \]
+%
+%
+% \subsection{Utility macros}\label{sec:utility}
+% Most math-mode utility macros use the |array| environment internally. This
+% can be the vanilla \LaTeX\ |array| environment, or the one from the
+% \textsf{array} package; it makes no difference. All math-mode utility macros
+% have an un-starred version and a starred version. The un-starred version
+% produces arrays with the delimiters defined by the package options
+% (see~\ref{sec:options}), and the starred version omits the delimiters (and the
+% glue between the delimiters and the array).
+%
+% As the only purpose of this package is to save keystrokes, the user may want
+% to put
+% \begin{verbatim}
+% \let\mat=\spalignmat
+% \let\amat=\spalignaugmat
+% \let\vec=\spalignvector\end{verbatim}
+% or something similar after |\usepackage{spalign}|. Note that |\mat*| will now
+% also be synonymous with |\spalignmat*|, etc.
+%
+% \bigskip
+% \noindent
+% \DescribeMacro{\spalignarray}
+% \DescribeMacro{\spalignarray*}
+% \usage\spalignarray{\marg{alignment specifier}\marg{text}}
+% Produces a (potentially delimited) |array| environment, passing it
+% \meta{alignment specifier}, after retokenizing \meta{text}. This is exactly
+% like the matrix environments below, except that it is possible to specify the
+% alignment of each column separately, add vertical bars, etc.
+% For example,
+% \begin{verbatim}
+% \[ \spalignarray{l|c|r}{1 1 1; 100 100 100} \]\end{verbatim}
+% produces
+% \[ \DeleteShortVerb{\|}
+% \spalignarray{l|c|r}{1 1 1; 100 100 100}.
+% \MakeShortVerb{\|}
+% \]
+% Note that |\spalignarray*| simply produces an |array| environment surrounding
+% the retokenized \meta{text}.
+%
+% \bigskip
+% \noindent
+% \DescribeMacro{\spalignmat}
+% \DescribeMacro{\spalignmat*}
+% \usage\spalignmat{\oarg{column alignment}\marg{text}}
+% Produces a matrix whose columns are aligned according to the
+% \meta{column alignment}, after retokenizing \meta{text}. The \meta{column alignment}
+% is an array environment alignment specifier for a single column (usually |l|,
+% |c|, or |r|), which is used for each column. The default is |c|. For example,
+% \begin{verbatim}
+% \[ \spalignmat[l]{1 1 1; 100 100 100} \]\end{verbatim}
+% produces
+% \[ \spalignmat[l]{1 1 1; 100 100 100}. \]
+%
+% \bigskip
+% \noindent
+% \DescribeMacro{\spalignvector}
+% \DescribeMacro{\spalignvector*}
+% \usage\spalignvector{\oarg{column alignment}\marg{text}}
+% Produces a matrix with one column. Spaces, commas, and semicolons are all
+% retokenized to the end-of-row control sequence `|\\|'. The
+% \meta{column alignment} is interpreted as in |\spalignmat|; the default is
+% |c|. For example,
+% \begin{verbatim}
+% \[ \spalignvector[r]{1 100 1000} \]\end{verbatim}
+% produces
+% \[ \spalignvector[r]{1 100 1000}. \]
+%
+% \bigskip
+% \noindent
+% \DescribeMacro{\spalignaugmatn}
+% \DescribeMacro{\spalignaugmatn*}
+% \usage\spalignaugmatn{\oarg{column alignment}\marg{augmented columns}\marg{text}}
+% Produces a matrix with a vertical divider located \meta{augmented columns} from the
+% right side of the matrix. The \meta{column alignment} is interpreted as in
+% |\spalignmat|; the default is |r|. For example,
+% \begin{verbatim}
+% \[ \spalignaugmatn[c]{3}{1 2 3 4; 10 20 30 40} \]\end{verbatim}
+% produces
+% \[ \spalignaugmatn[c]{3}{1 2 3 4; 10 20 30 40}. \]
+%
+% \bigskip
+% \noindent
+% \DescribeMacro{\spalignaugmat}
+% \DescribeMacro{\spalignaugmat*}
+% \usage\spalignaugmat{\oarg{column alignment}\marg{text}}
+% This is the same as |\spalignaugmatn|, with \meta{augmented columns} equal to
+% $1$. For example,
+% \begin{verbatim}
+% \[ \spalignaugmat{1 2 3 4; 10 20 30 40} \]\end{verbatim}
+% produces
+% \[ \spalignaugmat{1 2 3 4; 10 20 30 40}. \]
+%
+% \bigskip
+% \noindent
+% \DescribeMacro{\spalignaugmathalf}
+% \DescribeMacro{\spalignaugmathalf*}
+% \usage\spalignaugmathalf{\oarg{column alignment}\marg{text}}
+% This is the same as |\spalignaugmatn|, with \meta{augmented columns} equal to
+% the largest integer less or equal to half of the total number of columns
+% parsed from \meta{text}. For example,
+% \begin{verbatim}
+% \[ \spalignaugmathalf[l]{1 2 3 4; 10 20 30 40} \]\end{verbatim}
+% produces
+% \[ \spalignaugmathalf[l]{1 2 3 4; 10 20 30 40}. \]
+%
+% \bigskip
+% \noindent
+% \DescribeMacro{\spalignsys}
+% \DescribeMacro{\spalignsys*}
+% \usage\spalignsys{\marg{text}}
+% Typesets systems of simple equations so that binary operators and relations
+% are aligned vertically, and variables are right-justified. This macro assumes
+% that variables are in odd columns and that binary operators and relations are
+% in even columns. For example,
+% \begin{verbatim}
+% \[ \spalignsys{2x + y = 4; x - 3y = -17} \]\end{verbatim}
+% produces
+% \[ \spalignsys{2x + y = 4; x - 3y = -17\rlap.} \]
+% Within \marg{text} the macro |\+| is defined to be an empty box with the size
+% and spacing of a binary operator, the macro |\=| is defined to be an empty box
+% with the size and spacing of a relation, and the macro |\.| is defined to be
+% empty. (Ordinarily, the latter two macros produce th\=ese acc\.ents, but they
+% cannot be used in math mode.) This allows one to deal with empty columns in
+% an easy-to-read way: for example,
+% \begin{verbatim}
+% \[ \spalignsys{
+% 2x \+ \. - 3z = 1;
+% \. \+ 4y + z = -4}
+% \]\end{verbatim}
+% produces
+% \[ \spalignsys{
+% 2x \+ \. - 3z = 1;
+% \. \+ 4y + z = -4\rlap.}
+% \]
+% As with the matrix macros, delimiters can be changed with the package options.
+%
+% \bigskip
+% \noindent
+% \DescribeMacro{\spaligntabular}
+% \usage\spaligntabular{\marg{alignment specifier}\marg{text}}
+% Produces an (undelimited) |tabular| environment, passing it
+% \meta{alignment specifier}, after retokenizing \meta{text}. This macro may be
+% used outside of math mode, and therefore is undelimited.
+% For example,
+% \begin{verbatim}
+% \spaligntabular{lrc}{a b c; aa bb cc}\end{verbatim}
+% produces
+% \[ \spaligntabular{lcr}{a b c; aa bb cc} \]
+%
+% \subsection{Package options}\label{sec:options}
+% The following package options can be specified as key-value pairs when the
+% package is loaded, as in
+% \begin{verbatim}
+% \usepackage[sep={,},endofrow=;]{spalign} \end{verbatim}
+% They can also be set directly with macros, which are described as well.
+%
+% \bigskip
+% \noindent
+% \DescribeMacro{delims}
+% \DescribeMacro{\spaligndelims}
+% \poption Use: Specifies the delimiters used by all matrix macros.\endopt
+% \poption Format: Must contain exactly two delimiter tokens, the first for the left
+% delimiter, the second for the right.\endopt
+% \poption Default: |delims=()|\endopt
+% \poption Macro: |\spaligndelims|\marg{left-delim}\marg{right-delim}\endopt
+% \smallskip
+% It is easier to specify |\{\}| as delimiters using the macro form.
+% For example,
+% \begin{verbatim}
+% \[ \spaligndelims\vert\vert \spalignmat{a b; c d} \]\end{verbatim}
+% produces
+% \[ \spaligndelims\vert\vert \spalignmat{a b; c d}. \]
+%
+% \bigskip
+% \noindent
+% \DescribeMacro{sysdelims}
+% \DescribeMacro{\spalignsysdelims}
+% These function the same way as |delims| and |\spaligndelims|, except they
+% apply only to the |\spalignsys| macro. The default is |\spalignsysdelims\{.|,
+% i.e., left brace and no right delimiter.
+%
+% \bigskip
+% \noindent
+% \DescribeMacro{matdelimskip}
+% \DescribeMacro{\spalignmatdelimskip}
+% \poption Use: Specifies the glue to insert between delimiters and the internal
+% |array| environment in (un-starred) math-mode matrix macros, i.e., all
+% math-mode utility macros except |\spalignvector|.\endopt
+% \poption Format: Should either be empty, or expand to a legal |\hskip|,
+% |\mskip|, or |\kern| command. (Really any sequence of tokens can be
+% specified; they will dutifully be inserted between the delimiters and the
+% |array|, but this behavior may change in future versions.)\endopt
+% \poption Default: |matdelimskip=\,|\endopt
+% \poption Macro: |\def\spalignmatdelimskip|\marg{skip}\endopt
+% \smallskip
+% Actually, an additional skip of |\hskip-\arraycolsep| is always added; the
+% effect is that if |matdimskip| is empty, then there is no extra space between
+% the outer columns of the |array| and the delimiters. This is how the
+% \textsf{amsmath} package's |matrix| environment is defined. It is this
+% package author's opinion that matrices look better when a thin space is added
+% between the outer columns of the |array| and the delimiters. To keep the
+% original array spacing inside the delimiters, specify
+% |matdelimskip=\hskip\arraycolsep|.
+%
+% Here are four matrices typeset, respectively, with |matdelimskip|
+% set to |{}|, |\,|, |\;|, and |{\hskip\arraycolsep}|.
+% \[ \def\spalignmatdelimskip{} \spalignmat{10 20; 30 40} \quad
+% \def\spalignmatdelimskip{\,} \spalignmat{10 20; 30 40} \quad
+% \def\spalignmatdelimskip{\;} \spalignmat{10 20; 30 40} \quad
+% \def\spalignmatdelimskip{\hskip\arraycolsep} \spalignmat{10 20; 30 40}
+% \]
+%
+% \bigskip
+% \noindent
+% \DescribeMacro{vecdelimskip}
+% \DescribeMacro{\spalignvecdelimskip}
+% These function the same way as |matdelimskip| and |\spalignmatdelimskip|,
+% except they apply only to the |\spalignvector| macro. The default is no extra
+% skip in vectors, i.e., |vecdelimskip={}|.
+%
+% \bigskip
+% \noindent
+% \DescribeMacro{sysdelimskip}
+% \DescribeMacro{\spalignsysdelimskip}
+% These function the same way as |matdelimskip| and |\spalignmatdelimskip|,
+% except they apply only to the |\spalignsys| macro. The default is
+% |sysdelimskip=\,|.
+%
+% Actually there is a slight difference: the |\halign| primitive used in the
+% |\spalignsys| macro does not put glue on the outsides of the columns, so that
+% it is unnecessary to subtract any |\arraycolsep| glue.
+%
+% \bigskip
+% \noindent
+% \DescribeMacro{systabspace}
+% \DescribeMacro{\spalignsystabspace}
+% \poption Use: Specifies the amount of glue between columns in
+% |\spsysalign|.\endopt
+% \poption Format: Must be a legal glue specification.\endopt
+% \poption Default: |systabspace=1pt|\endopt
+% \poption Macro: |\spalignsystabspace=|\meta{glue}\endopt
+% \smallskip
+% Equations with operators, relations, and variables all aligned look a
+% better with a bit of extra spacing between these three. Setting |systabspace|
+% to zero will cause the equations to use their natural spacing, subject to
+% the alignment. For example, the following systems of equations were typeset,
+% respectively, with |systabspace| set to |0pt|, |1pt|, and |5pt|.
+% \[
+% \spalignsystabspace=0pt \spalignsys{2x + y = 4; x - 3y = -17} \qquad
+% \spalignsystabspace=1pt \spalignsys{2x + y = 4; x - 3y = -17} \qquad
+% \spalignsystabspace=5pt \spalignsys{2x + y = 4; x - 3y = -17\rlap.}
+% \]
+%
+% \bigskip
+% \noindent
+% \DescribeMacro{endofrow}
+% \DescribeMacro{\spalignendofrow}
+% \poption Use: Specifies the token to convert into the end-of-row
+% control sequence |\\| (really into the contents of |\spalignendline|) during
+% retokenization.\endopt
+% \poption Format: Must consist of a single token.\endopt
+% \poption Default: |endofrow=;|\endopt
+% \poption Macro: |\def\spalignendofrow|\marg{token}\endopt
+% \smallskip
+% For example,
+% \begin{verbatim}
+% \[ \def\spalignendofrow{|}
+% \spalignmat{1;2 3;4 | 5;6 7;8} \]\end{verbatim}
+% produces
+% \[ \def\spalignendofrow{|} \spalignmat{1;2 3;4 | 5;6 7;8}. \]
+%
+% \bigskip
+% \noindent
+% \DescribeMacro{separator}
+% \DescribeMacro{\spalignseparator}
+% \poption Use: Specifies a token (in addition to space tokens) to convert into
+% the alignment character `|&|' (really the contents of |\spalignseparator|)
+% during retokenization.\endopt
+% \poption Format: Must consist of a single token.\endopt
+% \poption Default: |separator={,}|\endopt
+% \poption Macro: |\def\spalignseparator|\marg{token}\endopt
+% \smallskip
+% For example,
+% \begin{verbatim}
+% \[ \def\spalignseparator{|}
+% \spalignmat{(1,2)|(3,4);(5,6)|(7,8)} \]\end{verbatim}
+% produces
+% \[ \def\spalignseparator{|} \spalignmat{(1,2)|(3,4);(5,6)|(7,8)}. \]
+%
+% \bigskip
+% The following commands can be redefined to affect the behavior of the package,
+% but cannot be specified as key-value pairs when the package is loaded.
+%
+% \bigskip
+% \noindent
+% \DescribeMacro{\spalignendline}
+% \poption Use: The end-of-row token is replaced by the top-level expansion of
+% this macro during retokenization.\endopt
+% \poption Format: May contain any tokens.\endopt
+% \poption Default: |\def\spalignendline{\\}|\endopt
+% \smallskip
+% This is useful, for instance, when using \textsf{spalign} in conjunction with
+% plain \TeX-style alignment macros that use |\cr| as the end-of-row token.
+% See the documentation for |\spalignrun| in~\S\ref{sec:general} and the
+% implementation of |\spalignsys| for examples.
+%
+% \bigskip
+% \noindent
+% \DescribeMacro{\spalignaligntab}
+% \poption Use: Spaces and the contents of |\spalignseparator| are replaced by the
+% top-level expansion of this macro during retokenization.\endopt
+% \poption Format: May contain any tokens.\endopt
+% \poption Default: |\def\spalignaligntab{&}|\endopt
+% \smallskip
+% This is useful, for instance, in one-column alignments. For example,
+% \begin{verbatim}
+% \[ \def\spalignaligntab{\\} \spalignmat{12 1 2 13} \]\end{verbatim}
+% produces
+% \[ \def\spalignaligntab{\\} \spalignmat{12 1 2 13}. \]
+% The |\spalignvector| macro is defined in this way.
+%
+%
+% \subsection{General macros}\label{sec:general}
+% The following macros are meant to make it easy to make new utility macros
+% in different situations using \textsf{spalign}.
+%
+% \bigskip
+% \noindent
+% \DescribeMacro{\spalignretokenize}
+% \usage\spalignretokenize{\marg{text}}
+% Applies the retokenization procedure to \meta{text}, and expands to the
+% retokenized version. For instance, |\spalignretokenize{1 2; 3 4}| expands to
+% |1&2\\3&4|.
+% For example, using the |split| environment from the
+% \textsf{amsmath} package,
+% \begin{verbatim}
+% \[ \begin{split}
+% \spalignretokenize{f_0 =1; f_1 =1; f_{n+2} =f_n+f_{n+1}}
+% \end{split} \]\end{verbatim}
+% produces
+% \[ \begin{split}
+% \spalignretokenize{f_0 =1; f_1 =1; f_{n+2} =f_n+f_{n+1}}.
+% \end{split} \]
+%
+% \bigskip
+% \noindent
+% \DescribeMacro{\spalignrun}
+% \usage\spalignrun{\marg{tokens}\marg{text}}
+% Applies the retokenization procedure to \meta{text}, saving the result into
+% the token register |\spaligntoks| (see below). Then executes \meta{tokens},
+% which presumably makes reference to |\spaligntoks|. For example,
+% \begin{verbatim}
+% \[ \def\spalignendline{\cr}
+% \spalignrun{\bordermatrix{\the\spaligntoks}}
+% {, x y; u 1 2; v 3 4} \]\end{verbatim}
+% produces
+% \[ \def\spalignendline{\cr}
+% \spalignrun{\bordermatrix{\the\spaligntoks}}
+% {, x y; u 1 2; v 3 4}. \]
+%
+% \bigskip
+% \noindent
+% \DescribeMacro{\spalignenv}
+% \usage\spalignenv{\marg{before-tokens}\marg{after-tokens}\marg{text}}
+% Convenience macro that expands to
+% \[ \hbox{|\spalignrun{|\meta{before-tokens}
+% |\the\spaligntoks| \meta{after-tokens}|}{|\meta{text}|}|.} \]
+% For example, using the |align*| environment from the
+% \textsf{amsmath} package,
+% \begin{verbatim}
+% \spalignenv{\begin{align*}}{\end{align*}}%
+% {x =y x' =y'; z =w z' =w'.}\end{verbatim}
+% produces
+% \spalignenv{\begin{align*}}{\end{align*}}%
+% {x =y x' =y'; z =w z' =w'.}
+%
+% \bigskip
+% The \meta{tokens} arguments of |\spalignrun| and |\spalignenv| have access to
+% the following registers, which are defined locally in a group inside
+% |\spalignrun| and |\spalignenv|.
+%
+% \bigskip
+% \noindent
+% \DescribeMacro{\spaligntoks}
+% A tokens register that contains the result of the retokenizing procedure.
+%
+% \bigskip
+% \noindent
+% \DescribeMacro{\spalignmaxcols}
+% A count register that contains the maximum number of columns in any given row,
+% as parsed by the retokenizer. This is used in |\spalignmat| and in the
+% |\spalignaugmat| family of macros.
+
+% \StopEventually{}
+%
+% \section{Implementation}
+%
+% \subsection{Options processing}
+%
+% \begin{macrocode}
+\makeatletter
+
+\RequirePackage{kvoptions}
+% \end{macrocode}
+% With the following options, the key |foo| gets stored as |\spalign@foo|.
+% \smallskip
+% \begin{macrocode}
+\SetupKeyvalOptions{family=spalign,prefix=spalign@}
+
+\DeclareStringOption[()]{delims}
+\DeclareStringOption[\{.]{sysdelims}
+\DeclareStringOption[\,]{matdelimskip}
+\DeclareStringOption[]{vecdelimskip}
+\DeclareStringOption[\,]{sysdelimskip}
+\DeclareStringOption[1pt]{systabspace}
+\DeclareStringOption[;]{endofrow}
+\DeclareStringOption[,]{separator}
+
+\ProcessLocalKeyvalOptions*
+
+\def\spaligndelims#1#2{%
+ \def\spalign@leftdelim{#1}\def\spalign@rightdelim{#2}}
+\expandafter\spaligndelims\spalign@delims
+\def\spalignsysdelims#1#2{%
+ \def\spalign@sysleftdelim{#1}\def\spalign@sysrightdelim{#2}}
+\expandafter\spalignsysdelims\spalign@sysdelims
+\let\spalignmatdelimskip=\spalign@matdelimskip
+\let\spalignvecdelimskip=\spalign@vecdelimskip
+\let\spalignsysdelimskip=\spalign@sysdelimskip
+\newdimen\spalignsystabspace
+\spalignsystabspace=\spalign@systabspace
+\let\spalignendofrow=\spalign@endofrow
+\let\spalignseparator=\spalign@separator
+\def\spalignendline{\\}
+\def\spalignaligntab{&}
+% \end{macrocode}
+%
+% \bigskip
+% \subsection{Main retokenizing code}
+% The retokenizer processes the input token list one ``item'' at a time,
+% performing replacements as necessary, and saving the resulting tokens in
+% |\spaligntoks|. The difficulties arise because of the special treatment that
+% \TeX\ gives to spaces and braces. First let's review the rules of the game:
+% \begin{enumerate}\itemsep=1\jot\parskip=0pt
+% \item Spaces after a control sequence are not tokenized.
+% \item Multiple spaces are tokenized into a single space.
+% \item Space tokens between a control sequence and its argument are ignored:
+% undelimited spaces are never interpreted as a macro argument.
+% \item Braces around a macro argument are stripped.
+% \item The |\futurelet|\meta{control sequence}\meta{token1}\meta{token2} syntax
+% will |\let| the specified \meta{control sequence} be \meta{token2}, nomatter
+% what kind of token \meta{token2} is.
+% \end{enumerate}
+% Consider then a macro |\retokenize#1{...}| and the token sequence
+% \[ \hbox{|\retokenize |\tvs|{\bf a}b|} \]
+% The |\retokenize| macro needs to recognize both the space (as it should be
+% replaced by an align token, if other non-space tokens have just been processed),
+% and the braces (so |{\bf a}b| is not replaced by |\bf ab|). However, the
+% argument to |\retokenize| will be |\bf a|; the space and braces are ignored.
+%
+% The solution, of course, is judicious use of |\futurelet|. (One could
+% conceivably use |\let| and |\futurelet| exclusively, except then one would
+% have the opposite problem: we \emph{want} the retokenizer to swallow whole
+% arguments in braces.) This is still somewhat tricky:
+% \[ \hbox{|\futurelet\next\retokenize |\tvs|{\bf a}b|} \]
+% will expand |\retokenize| with the argument set to |\bf a| and |\next|
+% behaving like \tvs, but the braces will still disappear. Hence one has to use
+% the |\futurelet| in a macro which does not take any arguments.
+%
+% Here is the outline of the solution to the problem used in this package. The
+% |\spalign@gobble@spaces| macro has the effect of deleting the subsequent
+% sequence of space tokens and replacing them with the token
+% |\spalign@parsetoks|. It sets |\spalign@saw@spacetrue| if it ate at least
+% one space token, and in any case it sets |\spalign@nexttok| to the following
+% token. The |\spalign@parsetoks| macro takes one argument. When it is
+% executed, |\spalign@nexttok| represents a non-space token. Now
+% |\spalign@parsetoks| knows if the token beginning its argument is a brace, and
+% it knows if there was a space preceding the brace as well, using
+% |\ifspalign@saw@space|. It can proceed to parse its argument in a
+% straightforward manner, eventually expanding back into
+% |\splign@gobble@spaces|, unless it sees |\spalign@end|, which signifies the
+% end of input.
+%
+% See Appendix~D in the {\TeX}book for a discussion of these kinds of tricks.
+%
+% \begin{macro}{\spalign@makespace}
+% This macro expands to a single space token. It is mildly tricky to
+% construct, since \TeX\ allows one optional space token after |\let\foo| or
+% |\let\foo=|, but multiple spaces are combined into one space token. Here is
+% one trick for producing two consecutive space tokens. See Exercise~24.6 in
+% the {\TeX}book.
+% \begin{macrocode}
+\begingroup
+\def\\{\global\let\spalign@space= } \\ %
+\endgroup
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{\spalign@end}
+% Sentinel macro that is used to mark the end-of-input for
+% |\spalign@parsetoks|. Defining it recursively like this has the
+% disadvantage that \LaTeX\ will hang if it tries to expand |\spalign@end|.
+% On the other hand, one can test whether a token is |\spalign@end| using
+% |\ifx| without using some other sentinel expansion of the macro, and the
+% only reason |\spalign@end| would be executed is if there is a bug in this
+% package.
+% \begin{macrocode}
+\def\spalign@end{\spalign@end}
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{\spalign@bgroup}
+% This is just used to test whether a token is a literal |\bgroup| (as opposed
+% to an actual open brace |{|) using |\ifx|.
+% \begin{macrocode}
+\def\spalign@bgroup{\bgroup}
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{\spalign@curcols}
+% This counter keeps track of how many columns are in the current row.
+% \begin{macrocode}
+\newcount\spalign@curcols
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{\ifspalign@ignorespaces}
+% Boolean variable which keeps track of whether spaces should be ignored in
+% the current state, like after an end-of-row token.
+% \begin{macrocode}
+\newif\ifspalign@ignorespaces
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{\ifspalign@saw@space}
+% Boolean variable which is true if the argument to |\spalign@parsetoks| was
+% preceded by at least one space token.
+% \begin{macrocode}
+\newif\ifspalign@saw@space
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{\spalign@gobble@spaces}
+% This macro has the effect of deleting any subsequent space tokens, replacing
+% them with |\spalign@parsetoks|. It sets |\spalign@nexttok| to the next
+% (non-space) token, and sets |\spalign@saw@spacetrue| if it ate at least one
+% space. The boolean variable |\ifspalign@saw@space| should be false before
+% |\spalign@gobble@spaces| is first executed.
+%
+% The macro |\spalign@gobble@next| has the effect of replacing the following
+% token with |\spalign@gobble@spaces|.
+% \begin{macrocode}
+\def\spalign@gobble@next{%
+ \afterassignment\spalign@gobble@spaces\let\spalign@atoken= }
+\def\spalign@check@space{%
+ \ifx\spalign@nexttok\spalign@space%
+ \spalign@saw@spacetrue%
+ \let\spalign@next=\spalign@gobble@next%
+ \else%
+% \end{macrocode}
+% Don't set |\spalign@saw@spacefalse| here: eventually we will run
+% into a non-space token.
+% \begin{macrocode}
+ \let\spalign@next=\spalign@parsetoks%
+ \fi%
+ \spalign@next%
+ }
+\def\spalign@gobble@spaces{%
+ \futurelet\spalign@nexttok\spalign@check@space}
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{\spalign@append}
+% Convenience macro that appends its argument, unexpanded, onto the token
+% register |\spaligntoks|.
+% \begin{macrocode}
+\def\spalign@append#1{%
+ \begingroup%
+ \toks255={#1}%
+% \end{macrocode}
+% The |\edef| and |\xdef| macros do not expand tokens obtained by expanding a
+% token register.
+% \begin{macrocode}
+ \xdef\spalign@settok{%
+ \spaligntoks={\the\spaligntoks\the\toks255}}%
+ \endgroup%
+ \spalign@settok%
+ }
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{\spalign@addcol}
+% Convenience macro to take care of housekeeping when an align column has been
+% parsed but the row is not complete. Note that it appends the top-level
+% expansion of |\spaligntab| to |\spaligntoks|, not the token |\spaligntab|
+% itself.
+% \begin{macrocode}
+\def\spalign@addcol{%
+ \expandafter\spalign@append\expandafter{\spalignaligntab}%
+ \advance\spalign@curcols by 1 %
+ }
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{\spalign@endrow}
+% Convenience macro to take care of housekeeping when a row has been ended,
+% either by an end-of-row token or an end-of-input token.
+% \begin{macrocode}
+\def\spalign@endrow{%
+ \advance\spalign@curcols by 1 %
+ \ifnum\spalign@curcols>\spalignmaxcols%
+ \spalignmaxcols=\spalign@curcols%
+ \fi%
+ \spalign@curcols=0%
+ \spalign@ignorespacestrue%
+ }
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{\spalign@normaltok}
+% Convenience macro to take care of housekeeping when a non-special token (not
+% a space, end-of-row token, separator token, or end-of-input token) has been
+% parsed. The boolean variable |\ifspalign@saw@space| will be true if the token
+% preceding the non-special token was a space.
+% \begin{macrocode}
+\def\spalign@normaltok{%
+ \ifspalign@saw@space%
+ \ifspalign@ignorespaces%
+ \else%
+ \spalign@addcol%
+ \fi%
+ \fi%
+ \spalign@ignorespacesfalse%
+ }
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{\spalign@parsetoks}
+% This is the main retokenizing routine. It is only called by
+% |\spalign@gobble@spaces|. When it is expanded, |\spalign@nexttok| is the
+% token that immediately follows the |\spalign@parsetoks| token itself; this
+% is not a space. The value of the boolean variable |\ifspalign@saw@space| is
+% true if there was a space before the argument of |\spalign@parsetoks| in the
+% token list.
+% \begin{macrocode}
+\def\spalign@parsetoks#1{%
+ \let\spalign@next=\spalign@gobble@spaces%
+% \end{macrocode}
+% This is for |\ifx| comparisons:
+% \begin{macrocode}
+ \def\spalign@arg{#1}%
+% \end{macrocode}
+% Anything in braces is passed through untouched:
+% \begin{macrocode}
+ \ifx\spalign@nexttok\bgroup%
+ \spalign@normaltok%
+ \ifx\spalign@arg\spalign@bgroup%
+% \end{macrocode}
+% The argument is a literal |\bgroup|, not a brace.
+% \begin{macrocode}
+ \spalign@append{#1}%
+ \else%
+% \end{macrocode}
+% Re-wrap the argument in braces and append.
+% \begin{macrocode}
+ \spalign@append{{#1}}%
+ \fi%
+ \else%
+% \end{macrocode}
+% The argument is not wrapped in braces.
+% \begin{macrocode}
+ \ifx\spalign@arg\spalignendofrow%
+% \end{macrocode}
+% End-of-row token. Append the top-level expansion of |\spalignendline|.
+% (Ignore previous spaces.)
+% \begin{macrocode}
+ \expandafter\spalign@append\expandafter{\spalignendline}%
+ \spalign@endrow%
+ \else%
+ \ifx\spalign@arg\spalignseparator%
+% \end{macrocode}
+% Separator token. (Ignore previous spaces.)
+% \begin{macrocode}
+ \spalign@addcol%
+ \spalign@ignorespacestrue%
+ \else%
+ \ifx\spalign@arg\spalign@end%
+% \end{macrocode}
+% End-of-input token. End the current row to record |\spalign@maxcols|.
+% (Ignore previous spaces.)
+% \begin{macrocode}
+ \let\spalign@next=\relax%
+ \spalign@endrow%
+ \else%
+% \end{macrocode}
+% Non-special token.
+% \begin{macrocode}
+ \spalign@normaltok%
+ \spalign@append{#1}%
+ \fi%
+ \fi%
+ \fi%
+ \fi%
+% \end{macrocode}
+% Reset |\ifspalign@saw@space| for the next |\spalign@gobble@spaces|.
+% \begin{macrocode}
+ \spalign@saw@spacefalse%
+ \spalign@next%
+ }
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{\spalign@process}
+% This is a wrapper for |\spalign@parsetoks|. It initializes registers and
+% boolean variables, then starts the parsing routine with
+% |\spalign@gobble@spaces|. It should be run in a local group. It stops
+% processing at |\spalign@end|. It fills |\spalignmaxcols| and |\spaligntoks|
+% with the results of the retokenization. It replaces everything in the token
+% list up through |\spalign@end| with |\relax|.
+% \begin{macrocode}
+\def\spalign@process{%
+ \spaligntoks={}%
+ \spalignmaxcols=0%
+ \spalign@curcols=0%
+ \spalign@ignorespacestrue%
+ \spalign@saw@spacefalse%
+ \spalign@gobble@spaces%
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \subsection{Poor man's starred commands}
+% There are several excellent packages that allow for flexible command
+% specifications. However, the needs of this package are minimal as regards
+% starred commands, so in order to reduce dependencies, this package contains
+% its own simple implimentation.
+%
+% \begin{macro}{\ifspalign@star}
+% Boolean variable which records whether or not the current command has a star
+% on it.
+% \begin{macrocode}
+\newif\ifspalign@star
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{\spalign@def@star}
+% Used like |\def|, the command |\spalign@def@star\foo{...}| defines a macro
+% |\foo| which can be called as |\foo| or |\foo*|. In the body of |\foo|,
+% the boolean variable |\ifspalign@star| indicates whether the command was
+% called with a star.
+%
+% This command actually defines three commands: |\foo|, |\foo@x|, and
+% |\foo@star|. The first calls the second with |\spalign@nexttok| defined via
+% |\futurelet| to the token following |\foo|. The command |\foo@x| checks
+% whether or not the next token is a star, and if it is, it is removed from
+% the token list. It then sets |\ifspalign@star| appropriately and calls
+% |\foo@star|, which contains the original command definition. Of course,
+% |\foo@star| can then be redefined, for instance using |\newcommand|, to take
+% advantage of \LaTeX's optional argument parsing.
+% \begin{macrocode}
+\def\spalign@gobble@one#1{}
+
+\def\spalign@def@star#1{%
+% \end{macrocode}
+% If |#1| is |\foo|, then |\spalign@cmd| expands to |\foo|,
+% |\spalign@cmd@x| expands to |\foo@x|, and |\spalign@cmd@star| expands to
+% |\foo@star|.
+% \begin{macrocode}
+ \def\spalign@cmd{#1}%
+ \edef\spalign@cmd@x{%
+ \csname\expandafter\spalign@gobble@one\string#1@x\endcsname}%
+ \edef\spalign@cmd@star{%
+ \csname\expandafter\spalign@gobble@one\string#1@star\endcsname}%
+% \end{macrocode}
+% Make |\foo@x| unexpandable. (The |\csname...\endcsname| construction
+% already does this, but only if |\foo@x| was previously undefined.) This
+% makes it easier to define |\foo|.
+% \begin{macrocode}
+ \expandafter\let\spalign@cmd@x=\relax
+ \expandafter\edef\spalign@cmd{%
+ \futurelet\noexpand\spalign@nexttok\spalign@cmd@x}%
+% \end{macrocode}
+% I don't know a less annoying but still short way of defining a token list
+% where only one token in the middle is to be expanded, and that one token only
+% once (not recursively).
+% \begin{macrocode}
+ \def\spalign@mkcmd##1{%
+ \expandafter\def\spalign@cmd@x{%
+ \ifx\spalign@nexttok*%
+ \spalign@startrue%
+ \let\spalign@next=\spalign@gobble@one%
+ \else%
+ \spalign@starfalse%
+ \def\spalign@next{}%
+ \fi%
+% \end{macrocode}
+% Expanding |\spalign@gobble@one| before |##1| (which is |\foo@star|) eats the
+% star before parsing the arguments for |\foo@star|.
+% \begin{macrocode}
+ \expandafter##1\spalign@next%
+ }%
+ }%
+ \expandafter\spalign@mkcmd\spalign@cmd@star%
+ \expandafter\def\spalign@cmd@star%
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \subsection{General macros}
+%
+% Here are the definitions of the macros presented in~\S\ref{sec:general}.
+% \begin{macrocode}
+\newtoks\spaligntoks
+\newcount\spalignmaxcols
+% \end{macrocode}
+% \begin{macro}{\spalignrun}
+% Calls |\spalign@process| on |#2|, then inserts |#1|, in a group.
+% Presumably |#1| will refer to |\spaligntoks| and/or |\spalignmaxcols|.
+% \begin{macrocode}
+\def\spalignrun#1#2{%
+ \begingroup%
+ \spalign@process#2\spalign@end%
+ %\showthe\spaligntoks% For debugging
+ #1%
+ \endgroup%
+ }
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{\spalignenv}
+% This effectively calls |\spalign@process| on |#3|, then puts the resulting
+% token list between |#1| and |#2|. Both |#1| and |#2| have access to
+% |\spaligntoks| and |\spalignmaxcols|.
+% \begin{macrocode}
+\def\spalignenv#1#2{%
+ \spalignrun{%
+ #1%
+ \the\spaligntoks%
+ #2%
+ }%
+ }
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{\spalignretokenize}
+% This calls |\spalign@process| on |#1|, then expands to |\the\spaligntoks|.
+% \begin{macrocode}
+\def\spalignretokenize#1{%
+ \begingroup%
+ \spalign@process#1\spalign@end%
+ \expandafter\endgroup\the\spaligntoks%
+ }
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{\spaligntabular}
+% Tabular utility macro.
+% \begin{macrocode}
+\def\spaligntabular#1#2{%
+ \begin{tabular}{#1}\spalignretokenize{#2}\end{tabular}}
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{\spalign@maybedelim}
+% This is like |\spalignenv|, but it adds delimiters and the glue specified in
+% |#3| before |#1| and after |#2|, if |\ifspalign@star| is false.
+% \begin{macrocode}
+\def\spalign@maybedelim#1#2#3{%
+ \spalignenv%
+ {\ifspalign@star\else\left\spalign@leftdelim#3\fi#1}%
+ {#2\ifspalign@star\else#3\right\spalign@rightdelim\fi}%
+ }
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{\spalignarray}
+% Array utility macro with delimiters.
+% \begin{macrocode}
+\spalign@def@star\spalignarray#1{%
+ \spalign@maybedelim%
+ {\begin{array}{#1}}%
+ {\end{array}}%
+ {\hskip-\arraycolsep\spalignmatdelimskip}%
+ }
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{\spalignvector}
+% Vector utility macro: an array with one column, with |\spaligntab| set to
+% |\\| so that spaces produce new rows.
+% \begin{macrocode}
+\spalign@def@star\spalignvector{}
+\renewcommand\spalignvector@star[2][c]{%
+ \begingroup%
+ \def\spalignaligntab{\\}%
+ \spalign@maybedelim%
+ {\begin{array}{#1}}%
+ {\end{array}}%
+% \end{macrocode}
+% Note the use of |\spalignvecdelimskip| here.
+% \begin{macrocode}
+ {\hskip-\arraycolsep\spalignvecdelimskip}%
+ {#2}%
+ \endgroup%
+ }
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{\spalign@repeat}
+% Sets |\spalign@repeated| to |#1|, repeated |#2| times. Used for
+% auto-constructing |array| alignment specifications from |\spalignmaxcols|.
+% \begin{macrocode}
+\def\spalign@repeat#1#2{%
+ \begingroup%
+ \count255=0 %
+ \toks255={}%
+ \loop\ifnum\count255<#2%
+ \edef\spalign@settok{\toks255={\the\toks255 #1}}%
+ \spalign@settok%
+ \advance\count255 by 1 %
+ \repeat%
+ \xdef\spalign@repeated{\the\toks255}%
+ \endgroup
+ }
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{\spalignmat}
+% Matrix utility macro. Uses |\spalignmaxcols| and |\spalign@repeat| to
+% construct the |array| align specification.
+% \begin{macrocode}
+\spalign@def@star\spalignmat{}
+\renewcommand\spalignmat@star[1][c]{%
+ \spalign@maybedelim{%
+ \spalign@repeat{#1}{\spalignmaxcols}%
+ \edef\spalign@barray{\noexpand\begin{array}{%
+ \spalign@repeated}}%
+ \spalign@barray%
+ }{\end{array}%
+ }{\hskip-\arraycolsep\spalignmatdelimskip}%
+ }
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{\spalignaugmatn}
+% Augmented matrix with |#2| columns on the right of the vertical bar. Uses
+% |\spalignmaxcols| and |\spalign@repeat| to construct the |array| align
+% specification.
+% \begin{macrocode}
+\spalign@def@star\spalignaugmatn{}
+\renewcommand\spalignaugmatn@star[2][r]{%
+ \spalign@maybedelim{%
+ \advance\spalignmaxcols by -#2 %
+ \spalign@repeat{#1}{\spalignmaxcols}%
+ \let\spalign@repeated@one=\spalign@repeated%
+ \spalign@repeat{#1}{#2}%
+ \let\spalign@repeated@two=\spalign@repeated%
+ \edef\spalign@barray{\noexpand\begin{array}{%
+ \spalign@repeated@one|\spalign@repeated@two}}%
+ \spalign@barray%
+ }{\end{array}%
+ }{\hskip-\arraycolsep\spalignmatdelimskip}%
+ }%
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{\spalignaugmat}
+% Augmented matrix with one column on the right of the vertical bar.
+% \begin{macrocode}
+\spalign@def@star\spalignaugmat{}
+\renewcommand\spalignaugmat@star[1][r]{%
+ \spalignaugmatn@star[#1]{1}%
+ }%
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{\spalignaugmathalf}
+% Augmented matrix with (ceiling of) half the columns on the right.
+% \begin{macrocode}
+\spalign@def@star\spalignaugmathalf{}
+\renewcommand\spalignaugmathalf@star[1][r]{%
+ \spalign@maybedelim{%
+ \count255=\spalignmaxcols%
+ \divide\spalignmaxcols by 2 %
+ \advance\count255 by -\spalignmaxcols%
+ \spalign@repeat{#1}{\spalignmaxcols}%
+ \let\spalign@repeated@one=\spalign@repeated%
+ \spalignmaxcols=\count255%
+ \spalign@repeat{#1}{\spalignmaxcols}%
+ \let\spalign@repeated@two=\spalign@repeated%
+ \edef\spalign@barray{\noexpand\begin{array}{%
+ \spalign@repeated@one|\spalign@repeated@two}}%
+ \spalign@barray%
+ }{\end{array}%
+ }{\hskip-\arraycolsep\spalignmatdelimskip}%
+ }%
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{\spalignsys}
+% System of equations with aligned operators and variables.
+% \begin{macrocode}
+\spalign@def@star\spalignsys#1{%
+ \ifspalign@star\else%
+ \left\spalign@sysleftdelim\spalignsysdelimskip%
+ \fi%
+ \vcenter{%
+ \def\spalignendline{\cr}%
+ \openup1pt%
+ \tabskip=0pt%
+ \def\+{\mathbin{\phantom{+}}}%
+ \def\={\mathrel{\phantom{=}}}%
+ \def\.{}%
+ \halign{%
+% \end{macrocode}
+% Adding |{}| to each side of the align argument in the even columns causes
+% binary operators ($+$, $-$, $\ldots$) and relations ($=$, $<$, $\ldots$) to
+% use their natural spacing. Assuming the even columns contain only binary
+% operators (resp.\ only relations), these columns will all be the same width.
+% The |\hfil| in the odd columns right-justifies. There should be no spaces in
+% the templates.
+% \begin{macrocode}
+ \tabskip=\spalignsystabspace%
+ &$\hfil##$&${}##{}$\cr%
+ \spalignretokenize{#1}\crcr%
+ }%
+% \end{macrocode}
+% It seems that one can't specify tabskip glue for after the last column when
+% there are repeated templates.
+% \begin{macrocode}
+ }\hskip-\spalignsystabspace%
+ \ifspalign@star\else%
+ \spalignsysdelimskip\right\spalign@sysrightdelim%
+ \fi%
+ }
+% \end{macrocode}
+% \end{macro}
+% \begin{macrocode}
+\makeatother
+% \end{macrocode}
+% \Finale
+\endinput