Ich bin ein paar Mal auf das Primitiv gestoßen \span
. Ich habe den Eindruck, es ist im TeX-Programm definiert, nicht einmal in plain.tex
. Ist das richtig? Und wastutmacht dieser Befehl und wozu dient er?
Antwort1
Das Grundelement \span
hat zwei sehr unterschiedliche Bedeutungen, je nachdem, ob es in der Präambel \halign
oder im Hauptteil erscheint.
Wenn es in der Präambel steht, also vor dem ersten, \cr
bedeutet es, das folgende Token zu „erweitern“. Wenn es im Textkörper erscheint, beendet es die aktuelle Zelle, verbindet sie aber mit der folgenden. In diesem Fall steht es normalerweise in Kombination mit \omit
.
Das einfachste Beispiel ist
\halign{\hfil#\tabskip1em&#\hfil\cr
a&b\cr
c\span d\cr
}
wobei die zweite Zeile nur eine Zelle enthält. Die Ausgabe lautet
ohne \tabskip
Abstand zwischen „c“ und „d“, da die zweite Zeile nur aus einer Zelle mit \hfil
Inhalt davor und danach besteht, TeX dies jedoch \tabskip
bei der Bestimmung der Zellenbreite berücksichtigt.
Normalerweise fügt man jedoch auch hinzu, \omit
um dieSieUndgegenTeile (Siebezieht sich auf das, was vorher kommt #
,gegenzu dem, was darauf folgt).
Wenn TeX eine Präambel für liest, \halign
erweitert es Token nicht, es sei denn, es findet \tabskip
(wenn es Token erweitert, um die entsprechende Verbindungsspezifikation zu finden). Die Erweiterung eines Tokens kann erzwungen werden, indem ihm ein vorangestellt wird \span
.
Ein Beispiel ist inamsmath.sty
\def\align@#1#2{%
\inalign@true \intertext@ \Let@ \chardef\dspbrk@context\z@
\ifingather@\else\displ@y@\fi
\let\math@cr@@@\math@cr@@@align
\ifxxat@\else \let\tag\tag@in@align \fi
\let\label\label@in@display
#1% set st@r
\ifst@rred\else \global\@eqnswtrue \fi
\measure@{#2}%
\global\row@\z@
\tabskip\eqnshift@
\halign\bgroup
\span\align@preamble\crcr
#2%
}
Dies ist ein Hilfsmakro, das für align
und Freunde verwendet wird; die Präambel wird ein für alle Mal im Makro definiert\align@preamble
\def\align@preamble{%
&\hfil
\strut@
\setboxz@h{\@lign$\m@th\displaystyle{##}$}%
\ifmeasuring@\savefieldlength@\fi
\set@field
\tabskip\z@skip
&\setboxz@h{\@lign$\m@th\displaystyle{{}##}$}%
\ifmeasuring@\savefieldlength@\fi
\set@field
\hfil
\tabskip\alignsep@
}
Dies vereinfacht die Definition von erheblich \align@
, indem ein großer Teil des Codes in ein Makro eingefügt wird. Es ermöglicht auch die Änderung des Verhaltens von align
durch Modifizierung \align@preamble
(sieheIst es möglich, ungeraden Spalten implizit das Präfix {} zuzuweisen?).
Der LaTeX-Kernel verwendet hierfür eine andere Methode tabular
, da er die Präambel nach seinen Regeln aufbauen muss, also aus einer Kombination von lcrp
Zeichen usw.
Die zweite Verwendung für \span
ist das Zusammenführen von Spalten in einem \halign
. In Plain TeX finden wir\multispan
\def\multispan#1{\omit \mscount#1\relax
\loop\ifnum\mscount>\@ne \sp@n\repeat}
\def\sp@n{\span\omit\advance\mscount\m@ne}
das tut es \omit
und fügt so viele \span\omit
Paare hinzu, wie im Argument angegeben sind (minus eins); \multispan{1}
ist also äquivalent zu \omit
, \multispan{2}
zu \omit\span\omit
und so weiter. Das \multicolumn
Makro von LaTeX basiert auf der gleichen Idee
% latex.ltx, line 5053:
\long\def\multicolumn#1#2#3{\multispan{#1}\begingroup
\@mkpream{#2}%
\def\@sharp{#3}\set@typeset@protect
\let\@startpbox\@@startpbox\let\@endpbox\@@endpbox
\@arstrut \@preamble\hbox{}\endgroup\ignorespaces}
Zuerst wird dies ausgeführt \multispan{#1}
(genau wie in Plain definiert) und anschließend wird eine „lokale“ Ausrichtungspräambel erstellt, wobei dieselben Elemente \@mkpream
verwendet werden, die tabular
auch array
zum Auswerten des obligatorischen Arguments verwendet werden.
Warum verwendete Knuth dasselbe Primitiv für zwei sehr unterschiedliche Bedeutungen? Um Platz zu sparen; TeX wurde geschrieben, als der Computerspeicherplatz knapp war und es wichtig war, eine Definition einzusparen. Da nur in (oder natürlich ) \span
vorkommen kann , ist das kein Problem.\halign
\valign
Eine abwegige Verwendung von \span
in der ersten Bedeutung findet sich in der Lösung der Übung 20.16 im TeXbook
Folgendes sollte man nicht zu ernst nehmen, aber es funktioniert:
{\setbox0=\vbox{\halign{#{\c\span\d}\cr \let\next=0\edef\next#1{\gdef\next{\b#1}}\next\cr}}} \let\a=\next
In der Übung geht es darum, zu definieren, \a
dass es äquivalent zu \b
(vollständig erweitert) gefolgt von \c
(nicht erweitert) und von \d
(nur einmal erweitert) ist, ohne \noexpand
und zu verwenden \the
. Wenn wir zum Beispiel haben
\def\foo{xy\baz}
\def\baz{z}
\def\b{\foo\foo}
\def\c{--}
\def\d{\baz}
Wir wollen \a
als Ersatztext definieren
xyzxyz\c\baz
Der \setbox0=\vbox{
Teil ist einfach zu verwenden, \halign
ohne Ausgabe. Jetzt wertet TeX die \halign
Präambel als aus #{\c\baz}\cr
, da \span
eine einstufige Erweiterung von bewirkt \d
. Die einzige Zelle enthält
\let\next=0\edef\next#1{\gdef\next{\b#1}}\next
das gemäß den Regeln anstelle von #
in der Präambel verwendet wird, so dass der Eingabestrom wird
\let\next=0\edef\next#1{\gdef\next{\b#1}}\next{\c\baz}\cr
Das \cr
beendet die Zelle einfach, es ist also nicht relevant. Wegen wird nicht erweiterbar, also \let\next=0
wird es so definiert, als ob es gewesen wäre\next
\edef
\next
\def\next#1{\gdef\next{<full expansion of \b>#1}}
und wird daher \next{\c\baz}
pflichtbewusst ausführen
\gdef\next{<full expansion of \b>\c\baz}
und das Finale \let\a=\next
gibt allem den Rest.
Das erklärt gut, dass \span
nureinsSchritt der Erweiterung.
Eine andere Lösung mit e-TeX (es verwendet schließlich nicht \noexpand
und \the
) wäre
\edef\a{\b\unexpanded\expandafter{\expandafter\c\d}}