TeX surrounds inline math formulae with \mathon and \mathoff, which appear to be nodes. For instance, running TeX on $ $\showlists\bye gives

### horizontal mode entered at line 0
spacefactor 1000
### vertical mode entered at line 0
prevdepth ignored

Where are those defined or documented? Neither the string mathon nor mathoff appear in the source file tex.web of TeX.

  • Look for math_node in the index of tex.pdf (texdoc tex)
    – egreg
    Jul 16, 2014 at 23:07

2 Answers 2


In tex.web, you'll find

3826: @ @<Display math node |p|@>=
3827: begin print_esc("math");
3828: if subtype(p)=before then print("on")
3829: else print("off");
3830: if width(p)<>0 then
3831:   begin print(", surrounded "); print_scaled(width(p));
3832:   end;
3833: end

making it part of the "procedure Display math node. \mathon and \mathoff is a construction of printing \math and then a conditional on or off based on the "subtype of the math node".

  • This is only for printing the diagnostic messages.
    – egreg
    Jul 16, 2014 at 23:04

What do we know about \mathon and \mathoff? They are displayed by \showbox, \showlists and in other situations where the contents of a box or of a typeset list are written to the terminal or the log file. As can be read in paragraph "12. Displaying boxes", all these are implemented through the procedure show_node_list, which displays a node list (the data structure TeX uses to store typeset material). Ignoring some important error checking, the procedure simply uses the piece of code called @<Display node |p|@>; for each node p in the list. That piece of code is

@ @<Display node |p|@>=
if is_char_node(p) then print_font_and_char(p)
else  case type(p) of
  hlist_node,vlist_node,unset_node: @<Display box |p|@>;
  rule_node: @<Display rule |p|@>;
  ins_node: @<Display insertion |p|@>;
  whatsit_node: @<Display the whatsit node |p|@>;
  glue_node: @<Display glue |p|@>;
  kern_node: @<Display kern |p|@>;
  math_node: @<Display math node |p|@>;
  ligature_node: @<Display ligature |p|@>;
  penalty_node: @<Display penalty |p|@>;
  disc_node: @<Display discretionary |p|@>;
  mark_node: @<Display mark |p|@>;
  adjust_node: @<Display adjustment |p|@>;
  @t\4@>@<Cases of |show_node_list| that arise in mlists only@>@;
  othercases print("Unknown node type!")

which dispatches the display to various other pieces of code depending on the type of node. The names \mathon and \mathoff are hints that we should look at the case math_node. So let's.

@ @<Display math node |p|@>=
begin print_esc("math");
if subtype(p)=before then print("on")
else print("off");
if width(p)<>0 then
  begin print(", surrounded "); print_scaled(width(p));

As Werner said in a comment, we see that TeX prints \math for math nodes, then either on or off depending on the subtype of the node. It then also gives some details about the \mathsurround.

We now know what to look for: where are math nodes with a subtype of before or after (it turns out) created? We find the function new_math

@p function new_math(@!w:scaled;@!s:small_number):pointer;
var p:pointer; {the new node}
begin p:=get_node(small_node_size); type(p):=math_node;
subtype(p):=s; width(p):=w; new_math:=p;

which inserts a node with type math_node and subtype s in the current list, and find that it is used twice, when it is time to "finish math in text":

@<Finish math in text@>=
begin tail_append(new_math(math_surround,before));
cur_mlist:=p; cur_style:=text_style; mlist_penalties:=(mode>0); mlist_to_hlist;
while link(tail)<>null do tail:=link(tail);
space_factor:=1000; unsave;

This is finally the code which inserts math nodes with subtype before and after, which are eventually displayed as \mathon and \mathoff (and have a width equal to the value of the \mathsurround).

Your Answer

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

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