Your best resource for TeX is the TeXBook, particularly chapter 20 ("Definitions (also called Macros)") and Appendix D ("Dirty Tricks"). Appendix B provides a list of almost all macros defined at startup.
The reference for plain TeX at tug.org is also a good resource.
Basics
Differences from Plain TeX
The TeX language on the site is very similar to Knuth's plain TeX, with a few small modifications:
- output is through text rather than DVI or PDF, using dvi-to-text.
- none of the default fonts support characters with code greater than 127, so it switches to a font
\octet
with a full code page - hole arguments are pre-filled by a
\argv#1
macro, with arg count given by\argc
Looping over a string
The following code loops over all tokens until \relax
, replacing all -
tokens with (DASH)
\def\f#1{\ifx#1\relax%
\let\n\relax%
\else%
\let\n\f%
\ifx#1- (DASH)%
\else #1%
\fi%
\fi\n}
\f 0-185186-70-\relax
Spaces
Space characters can be annoying to manage. Important spacing rules:
- Single newline characters get converted to a space (double newlines are converted to
\par
), so if a bunch of spaces infiltrate your output, try removing newlines or suppressing the newlines with%
. - If you want a literal space, you sometimes have to do an escaped space
\
or a non-breaking space~
(which works only if~
has not been re-defined) - Control sequences remove the space after them, so
\f 123
is the same as\f123
. This rule exists so\f abc
does not have an unwanted space - While parsing a number literal, TeX keeps reading more tokens until it reaches a non-digit or an expandable control sequence. So
\newcount\x\x=5\f
will expand\f
before assigning 5 to\x
because it needs to make sure that\f
does not start with a digit. Add a space if you want to assign 5 to\x
before expanding\f
:\newcount\x\x=5 \f
- This is a source of pain. One way to stay safe is to reverse comparisons so that number literals are quickly terminated, e.g.
\ifnum9>\x
instead of\ifnum\x<9
.
- This is a source of pain. One way to stay safe is to reverse comparisons so that number literals are quickly terminated, e.g.
Math operations
Math can be performed in counters. Define a counter with \newcount
, and print the value with \the
.
\newcount\x
\x=15 % equivalent to the following line
\x15 % (the equals sign is optional)
\the\x % prints 15 as two tokens, "1" then "5"
Counters are 32-bit signed integers. Operations that overflow cause the program to instantly halt with no output.
\x\y % x = y
\advance\x5 % x += 5
\advance\x by\y % equivalent to the following line
\advance\x\y % x += y (the "by" text is optional)
\advance\x-\y % x += -y
\multiply\x\y % x *= y
\divide\x\y % x /= y (floor divide)
There is no modulo operator. Modulo can be calculated (if you must) using the definition x % y = x - x / y * y
, where x/y
is floor division
% d = x - x % y, x = x % y (requires an extra counter)
\d\x\divide\d\y\multiply\d\y\advance\x-\d
Or modulo can be computed by repeated subtraction, assuming x
and y
are positive.
% x = x % y (slow)
\loop\ifnum\x>\y\advance\x-\y\repeat
ASCII conversions
Convert a char code to corresponding character with \char
: \char97
gives the token a
.
Convert a character to char code with a backtick: \number`a
gives the two tokens 97
, and \newcount\x\x=`a
assigns 97 as the value of the counter \x
.
Golfing
One-byte macro ending
If a macro you define takes an argument longer than one token, you might be tempted to use curly braces. However, \def
can allow for a single end character, saving one byte per usage.
\def\f#1{something #1 something}
\f{123}\f{456}
% compare
\def\f#1;{something #1 something}
\f123;\f456;
\let
Commonly-used macros can be aliased with \let
\newcount\a\newcount\b\newcount\c
% compare
\let\N\newcount\N\a\N\b\N\c
At the top of a long solution, you might see a block of \let
s like \let\N\newcount\let\I\ifnum\let\A\advance
Tilde is active
Tilde (~
) is an active character (\catcode`\~=\active
), so you can use it in lieu of one control sequences.
\let\N\newcount\N\a\N\b\N\c
% compare
\let~\newcount~\a~\b~\c
Form Feed
Form-feed (0x0c) is an active character (like tilde ~
) defined as \par
(\catcode`\^^L=\active \outer\def^^L{\par}
). It is "outer," so you can only use it outside of constructs such as definitions and loops.
Form-feed can be typed in the editor by typing "0c" while holding down the Alt key.
1\par2\par3
% compare
1
2
3
% compare
1•2•3
Repeated macro vs loop
Repeating a macro several times is often shorter than a loop.
\newcount\i\loop\ifnum10>\i\the\i,\advance\i1\repeat
% compare (though kinda cheating because it uses ~)
\newcount\i\def~{\the\i\advance\i1,}~~~~~~~~~~
Newline inside loop
\newcount\i\loop\ifnum10>\i\the\i\endgraf\advance\i1\repeat
% compare
\newcount\i\def\f{\ifnum10>\i\the\i\advance\i1
\f\fi}\f
The recursive approach saves 3 bytes.