§1208  TEX82  PART 49: MODE-INDEPENDENT PROCESSING 435

1208. Mode-independent processing. The long main control procedure has now been fully specified, except for certain activities that are independent of the current mode. These activities do not change the current vlist or hlist or mlist; if they change anything, it is the value of a parameter or the meaning of a control sequence.

Assignments to values in eqtb can be global or local. Furthermore, a control sequence can be defined to be ‘ ’ or ‘ ’, and it might or might not be expanded. The prefixes ‘ ’, ‘ ’, and ‘ ’ can occur in any order. Therefore we assign binary numeric codes, making it possible to accumulate the union of all specified prefixes by adding the corresponding codes. (Pascal’s set operations could also have been used.) ⟨ Put each of TEX’s primitives into the hash table 226 ⟩ +≡

primitive(  , prefix , 1); primitive(  , prefix , 2); primitive(  , prefix , 4);
primitive(  , def , 0); primitive(  , def , 1); primitive(  , def , 2); primitive(  , def , 3);

1209. ⟨ Cases of print cmd chr for symbolic printing of primitives 227 ⟩ +≡ prefix : if chr code = 1 then print esc( )

else if chr code = 2 then print esc( )

else print esc( ); def : if chr code = 0 then print esc( )

else if chr code = 1 then print esc( )

else if chr code = 2 then print esc( ) else print esc( );

1210. Every prefix, and every command code that might or might not be prefixed, calls the action procedure prefixed command . This routine accumulates a sequence of prefixes until coming to a non-prefix, then it carries out the command. ⟨ Cases of main control that don’t depend on mode 1210 ⟩ ≡ any mode(toks register ), any mode(assign toks ), any mode(assign int ), any mode(assign dimen),

any mode(assign glue), any mode(assign mu glue), any mode(assign font dimen),

any mode(assign font int ), any mode(set aux ), any mode(set prev graf ), any mode(set page dimen), any mode(set page int ), any mode(set box dimen), any mode(set shape), any mode(def code), any mode(def family ), any mode(set font ), any mode(def font ), any mode(register ), any mode(advance), any mode(multiply ), any mode(divide), any mode(prefix ), any mode(let ), any mode(shorthand def ), any mode(read to cs ), any mode(def ), any mode(set box ), any mode(hyph data), any mode(set interaction): prefixed command ;

See also sections 1268, 1271, 1274, 1276, 1285, and 1290. This code is used in section 1045.

436  PART 49: MODE-INDEPENDENT PROCESSING  TEX82 §1211

1211. If the user says, e.g., ‘ ’, the redundancy is silently accepted. ⟨ Declare action procedures for use by main control 1043 ⟩ +≡ ⟨ Declare subprocedures for prefixed command 1215 ⟩ procedure prefixed command ;

label done, exit ; var a: small number ; { accumulated prefix codes so far }

f: internal font number ; { identifies a font }

j: halfword ; { index into a specification }

k: font index ; { index into font info }

p, q: pointer ; { for temporary short-term use }

n: integer ; { ditto }

e: boolean; { should a definition be expanded? or was not done? } begin a ← 0; while cur cmd = prefix do

begin if ¬odd (a div cur chr ) then a ← a + cur chr ;

⟨ Get the next non-blank non-relax non-call token 404 ⟩;

if cur cmd ≤ max non prefixed command then ⟨ Discard erroneous prefixes and return 1212 ⟩; end;

⟨ Discard the prefixes and if they are irrelevant 1213 ⟩; ⟨ Adjust for the setting of 1214 ⟩;

case cur cmd of

⟨ Assignments 1217 ⟩ othercases confusion( ) endcases;

done: ⟨ Insert a token saved by , if any 1269 ⟩; exit : end;

1212. ⟨ Discard erroneous prefixes and return 1212 ⟩ ≡ begin print err ( ␣ ´ ␣ ␣ ␣ ␣ ␣` ); print cmd chr (cur cmd , cur chr ); print char ( ´ ); help1 ( ´ ␣ ␣ ␣ ´ ␣ ␣ ␣ ␣ ␣ ␣ ); back error ; return; end

This code is used in section 1211.

1213. ⟨ Discard the prefixes  and  if they are irrelevant 1213 ⟩ ≡

if (cur cmd ≠ def ) ∧ (a mod 4 ≠ 0) then begin print err ( ␣ ´ ␣ ␣` ); print esc( ); print ( ´ ␣ ␣` ); print esc( ); print ( ´ ␣ ␣` ); print cmd chr (cur cmd , cur chr ); print char ( ´ ); help1 ( ´ ␣ ␣ ␣ ´ ␣ ␣ ␣ ␣ ␣ ); error ; end

This code is used in section 1211.

1214. The previous routine does not have to adjust a so that a mod 4 = 0, since the following routines test for the prefix as follows.

define global ≡ (a ≥ 4)

define define(#) ≡

if global then geq define(#) else eq define(#)

define word define(#) ≡

if global then geq word define(#) else eq word define(#)

⟨ Adjust for the setting of 1214 ⟩ ≡

if global defs ≠ 0 then

if global defs < 0 then begin if global then a ← a − 4; end

else begin if ¬global then a ← a + 4;

end

This code is used in section 1211.

1215. When a control sequence is to be defined, by  or  or something similar, the get r token

routine will substitute a special control sequence for a token that is not redefinable. ⟨ Declare subprocedures for prefixed command 1215 ⟩ ≡ procedure get r token;

label restart ;

begin restart : repeat get token;

until cur tok ≠ space token;

if (cur cs = 0) ∨ (cur cs > frozen control sequence) then

begin print err (  ␣       ␣        ␣  );

    help5 (  ␣   ´ ␣   ␣` ␣       ´ ␣   ␣`  ´  )
    ( ´ ␣        ␣  ␣           ␣       ␣        ␣  ␣    ␣  )
    (  ␣    ␣  ␣         ␣       ␣      ␣  ␣  ␣   ␣  )
    (  ␣   ␣       ␣          ␣    ␣    ␣      ␣  ␣ ´  )
    (  ␣   ␣        ␣    ␣  ␣   ␣  );

if cur cs = 0 then back input ;

cur tok ← cs token flag + frozen protection; ins error ; goto restart ; end;

end;

See also sections 1229, 1236, 1243, 1244, 1245, 1246, 1247, 1257, and 1265. This code is used in section 1211.

1216. ⟨ Initialize table entries (done by only) 164 ⟩ +≡ text (frozen protection) ← ;

1217. Here’s an example of the way many of the following routines operate. (Unfortunately, they aren’t all as simple as this.) ⟨ Assignments 1217 ⟩ ≡ set font : define(cur font loc, data, cur chr );

See also sections 1218, 1221, 1224, 1225, 1226, 1228, 1232, 1234, 1235, 1241, 1242, 1248, 1252, 1253, 1256, and 1264. This code is used in section 1211.

1218. When a def command has been scanned, cur chr is odd if the definition is supposed to be global, and cur chr ≥ 2 if the definition is supposed to be expanded. ⟨ Assignments 1217 ⟩ +≡ def : begin if odd (cur chr ) ∧ ¬global ∧ (global defs ≥ 0) then a ← a + 4;

e ← (cur chr ≥ 2); get r token; p ← cur cs ; q ← scan toks (true, e); define(p, call + (a mod 4), def ref ); end;

1219. Both  and  share the command code let .

⟨ Put each of TEX’s primitives into the hash table 226 ⟩ +≡ primitive( , let , normal ); primitive( , let , normal + 1);

1220. ⟨ Cases of print cmd chr for symbolic printing of primitives 227 ⟩ +≡

let : if chr code ≠ normal then print esc(  ) else print esc(  );

1221. ⟨ Assignments 1217 ⟩ +≡ let : begin n ← cur chr ; get r token; p ← cur cs ;

if n = normal then begin repeat get token; until cur cmd ≠ spacer ; if cur tok = other token + then

begin get token;

if cur cmd = spacer then get token; end;

end else begin get token; q ← cur tok ; get token; back input ; cur tok ← q; back input ;

{ look ahead, then back up } end; { note that back input doesn’t affect cur cmd , cur chr }

if cur cmd ≥ call then add token ref (cur chr ); define(p, cur cmd , cur chr ); end;

1222. A  creates a control sequence whose cmd is char given; a  creates a control

sequence whose cmd is math given; and the corresponding chr is the character code or math code. A or or or creates a control sequence whose cmd is assign int or … or assign mu glue, and the corresponding chr is the eqtb location of the internal register in question.

define char def code = 0 { shorthand def for } define math char def code = 1 { shorthand def for } define count def code = 2 { shorthand def for } define dimen def code = 3 { shorthand def for } define skip def code = 4 { shorthand def for } define mu skip def code = 5 { shorthand def for } define toks def code = 6 { shorthand def for }

⟨ Put each of TEX’s primitives into the hash table 226 ⟩ +≡ primitive( , shorthand def , char def code); primitive( , shorthand def , math char def code); primitive( , shorthand def , count def code); primitive( , shorthand def , dimen def code); primitive( , shorthand def , skip def code); primitive( , shorthand def , mu skip def code); primitive( , shorthand def , toks def code); 1223. ⟨ Cases of print cmd chr for symbolic printing of primitives 227 ⟩ +≡ shorthand def : case chr code of

char def code: print esc( ); math char def code: print esc( ); count def code: print esc( ); dimen def code: print esc( ); skip def code: print esc( ); mu skip def code: print esc( ); othercases print esc( ) endcases;

char given: begin print esc( ); print hex (chr code);

end; math given: begin print esc( ); print hex (chr code);

end;

1224. We temporarily define p to be relax , so that an occurrence of p while scanning the definition will simply stop the scanning instead of producing an “undefined control sequence” error or expanding the previous meaning. This allows, for instance, ‘ ’. ⟨ Assignments 1217 ⟩ +≡ shorthand def : begin n ← cur chr ; get r token; p ← cur cs ; define(p, relax , 256); scan optional equals ;

case n of

char def code: begin scan char num; define(p, char given, cur val );

end; math char def code: begin scan fifteen bit int ; define(p, math given, cur val );

end; othercases begin scan eight bit int ;

case n of

count def code: define(p, assign int , count base + cur val ); dimen def code: define(p, assign dimen, scaled base + cur val ); skip def code: define(p, assign glue, skip base + cur val ); mu skip def code: define(p, assign mu glue, mu skip base + cur val ); toks def code: define(p, assign toks , toks base + cur val ); end; { there are no other cases } end

endcases; end;

1225. ⟨ Assignments 1217 ⟩ +≡ read to cs : begin scan int ; n ← cur val ;

if ¬scan keyword ( ) then

begin print err (  ␣`   ´ ␣  );
help2 (  ␣      ␣    ␣    ␣` ␣  ␣ ´  )

( ´ ␣ ␣ ␣ ␣ ␣ ␣ ␣ ); error ;

end; get r token; p ← cur cs ; read toks (n, p); define(p, call , cur val ); end;

1226. The token-list parameters,  and  , etc., receive their values in the following way.

(For safety’s sake, we place an enclosing pair of braces around an list.) ⟨ Assignments 1217 ⟩ +≡ toks register , assign toks : begin q ← cur cs ;

if cur cmd = toks register then begin scan eight bit int ; p ← toks base + cur val ; end

else p ← cur chr ; { p = every par loc or output routine loc or … } scan optional equals ; ⟨ Get the next non-blank non-relax non-call token 404 ⟩; if cur cmd ≠ left brace then ⟨ If the right-hand side is a token parameter or token register, finish the

assignment and goto done 1227 ⟩; back input ; cur cs ← q; q ← scan toks (false, false); if link (def ref ) = null then { empty list: revert to the default }

begin define(p, undefined cs , null ); free avail (def ref );

end else begin if p = output routine loc then { enclose in curlies }

begin link (q) ← get avail ; q ← link (q); info(q) ← right brace token + ; q ← get avail ; info(q) ← left brace token + ; link (q) ← link (def ref ); link (def ref ) ← q; end;

define(p, call , def ref );

end; end;

1227. ⟨ If the right-hand side is a token parameter or token register, finish the assignment and goto

done 1227 ⟩ ≡

begin if cur cmd = toks register then begin scan eight bit int ; cur cmd ← assign toks ; cur chr ← toks base + cur val ; end;

if cur cmd = assign toks then begin q ← equiv (cur chr ); if q = null then define(p, undefined cs , null ) else begin add token ref (q); define(p, call , q);

end; goto done; end;

end

This code is used in section 1226.

1228. Similar routines are used to assign values to the numeric parameters. ⟨ Assignments 1217 ⟩ +≡ assign int : begin p ← cur chr ; scan optional equals ; scan int ; word define(p, cur val );

end; assign dimen: begin p ← cur chr ; scan optional equals ; scan normal dimen; word define(p, cur val );

end; assign glue, assign mu glue: begin p ← cur chr ; n ← cur cmd ; scan optional equals ;

if n = assign mu glue then scan glue(mu val ) else scan glue(glue val ); trap zero glue; define(p, glue ref , cur val ); end; 1229. When a glue register or parameter becomes zero, it will always point to zero glue because of the following procedure. (Exception: The tabskip glue isn’t trapped while preambles are being scanned.) ⟨ Declare subprocedures for prefixed command 1215 ⟩ +≡ procedure trap zero glue;

begin if (width(cur val ) = 0) ∧ (stretch(cur val ) = 0) ∧ (shrink (cur val ) = 0) then begin add glue ref (zero glue); delete glue ref (cur val ); cur val ← zero glue; end;

end;

1230. The various character code tables are changed by the def code commands, and the font families are declared by def family . ⟨ Put each of TEX’s primitives into the hash table 226 ⟩ +≡

primitive(  , def code, cat code base); primitive(  , def code, math code base);
primitive(  , def code, lc code base); primitive(  , def code, uc code base);
primitive(  , def code, sf code base); primitive(  , def code, del code base);

primitive( , def family , math font base);

primitive( , def family , math font base + script size);

primitive( , def family , math font base + script script size);

1231. ⟨ Cases of print cmd chr for symbolic printing of primitives 227 ⟩ +≡ def code: if chr code = cat code base then print esc( )

else if chr code = math code base then print esc( )

else if chr code = lc code base then print esc( ) else if chr code = uc code base then print esc( ) else if chr code = sf code base then print esc( )

else print esc( );

def family : print size(chr code − math font base);

1232. The different types of code values have different legal ranges; the following program is careful to check each case properly. ⟨ Assignments 1217 ⟩ +≡ def code: begin ⟨ Let n be the largest legal code value, based on cur chr 1233 ⟩;

p ← cur chr ; scan char num; p ← p + cur val ; scan optional equals ; scan int ;

if ((cur val < 0) ∧ (p < del code base)) ∨ (cur val > n) then begin print err ( ␣ ␣ ); print int (cur val ); if p < del code base then print ( ␣ ␣ ␣ ␣ ␣ ␣ ) else print ( ␣ ␣ ␣ ␣ ␣ ); print int (n); help1 ( ´ ␣ ␣ ␣ ␣ ␣ ␣ ␣ ␣ ␣ ␣ ); error ; cur val ← 0; end;

if p < math code base then define(p, data, cur val )

else if p < del code base then define(p, data, hi (cur val ))

else word define(p, cur val ); end; 1233. ⟨ Let n be the largest legal code value, based on cur chr 1233 ⟩ ≡

if cur chr = cat code base then n ← max char code else if cur chr = math code base then n ← ´ 100000

else if cur chr = sf code base then n ← ´ 77777

else if cur chr = del code base then n ← ´ 77777777

else n ← 255

This code is used in section 1232.

1234. ⟨ Assignments 1217 ⟩ +≡ def family : begin p ← cur chr ; scan four bit int ; p ← p + cur val ; scan optional equals ; scan font ident ;

define(p, data, cur val ); end;

1235. Next we consider changes to TEX’s numeric registers. ⟨ Assignments 1217 ⟩ +≡ register , advance, multiply , divide: do register command (a);

1236. We use the fact that register < advance < multiply < divide. ⟨ Declare subprocedures for prefixed command 1215 ⟩ +≡ procedure do register command (a : small number );

label found , exit ; var l, q, r, s: pointer ; { for list manipulation }

p: int val . . mu val ; { type of register involved } begin q ← cur cmd ; ⟨ Compute the register location l and its type p; but return if invalid 1237 ⟩; if q = register then scan optional equals else if scan keyword ( ) then do nothing ; { optional ‘ ’ } arith error ← false; if q < multiply then ⟨ Compute result of register or advance, put it in cur val 1238 ⟩ else ⟨ Compute result of multiply or divide, put it in cur val 1240 ⟩;

if arith error then
begin print err (  ␣  );

  help2 ( ␣   ´ ␣     ␣   ␣    ␣             ␣  ␣  )

(  ␣   ␣      ␣  ␣   ␣  ␣  ); error ; return;

end; if p < glue val then word define(l, cur val ) else begin trap zero glue; define(l, glue ref , cur val );

end; exit : end; 1237. Here we use the fact that the consecutive codes int val …mu val and assign int . . assign mu glue correspond to each other nicely. ⟨ Compute the register location l and its type p; but return if invalid 1237 ⟩ ≡

begin if q ≠ register then begin get x token; if (cur cmd ≥ assign int ) ∧ (cur cmd ≤ assign mu glue) then

begin l ← cur chr ; p ← cur cmd − assign int ; goto found ;

end; if cur cmd ≠ register then

begin print err ( ␣ ´ ␣ ␣` ); print cmd chr (cur cmd , cur chr ); print ( ´ ␣ ␣ ); print cmd chr (q, 0); help1 ( ´ ␣ ␣ ␣ ␣ ␣ ␣ ␣ ␣ ); error ; return; end;

end; p ← cur chr ; scan eight bit int ;

case p of

int val : l ← cur val + count base; dimen val : l ← cur val + scaled base; glue val : l ← cur val + skip base; mu val : l ← cur val + mu skip base; end; { there are no other cases } end;

found :

This code is used in section 1236.

1238. ⟨ Compute result of register or advance, put it in cur val 1238 ⟩ ≡

if p < glue val then begin if p = int val then scan int else scan normal dimen; if q = advance then cur val ← cur val + eqtb[l].int ; end

else begin scan glue(p); if q = advance then ⟨ Compute the sum of two glue specs 1239 ⟩; end

This code is used in section 1236.

1239. ⟨ Compute the sum of two glue specs 1239 ⟩ ≡ begin q ← new spec(cur val ); r ← equiv (l); delete glue ref (cur val ); width(q) ← width(q) + width(r); if stretch(q) = 0 then stretch order (q) ← normal ; if stretch order (q) = stretch order (r) then stretch(q) ← stretch(q) + stretch(r) else if (stretch order (q) < stretch order (r)) ∧ (stretch(r) ≠ 0) then

begin stretch(q) ← stretch(r); stretch order (q) ← stretch order (r);

end; if shrink (q) = 0 then shrink order (q) ← normal ; if shrink order (q) = shrink order (r) then shrink (q) ← shrink (q) + shrink (r) else if (shrink order (q) < shrink order (r)) ∧ (shrink (r) ≠ 0) then

begin shrink (q) ← shrink (r); shrink order (q) ← shrink order (r);

end; cur val ← q; end

This code is used in section 1238.

1240. ⟨ Compute result of multiply or divide, put it in cur val 1240 ⟩ ≡ begin scan int ; if p < glue val then

if q = multiply then if p = int val then cur val ← mult integers (eqtb[l].int , cur val ) else cur val ← nx plus y (eqtb[l].int , cur val , 0)

else cur val ← x over n(eqtb[l].int , cur val ) else begin s ← equiv (l); r ← new spec(s);

if q = multiply then begin width(r) ← nx plus y (width(s), cur val , 0); stretch(r) ← nx plus y (stretch(s), cur val , 0); shrink (r) ← nx plus y (shrink (s), cur val , 0); end

else begin width(r) ← x over n(width(s), cur val ); stretch(r) ← x over n(stretch(s), cur val ); shrink (r) ← x over n(shrink (s), cur val ); end; cur val ← r; end;

end

This code is used in section 1236.

1241. The processing of boxes is somewhat different, because we may need to scan and create an entire box before we actually change the value of the old one. ⟨ Assignments 1217 ⟩ +≡ set box : begin scan eight bit int ;

if global then n ← 256 + cur val else n ← cur val ;

scan optional equals ;

if set box allowed then scan box (box flag + n)

else begin print err (  ␣ ); print esc(  );

    help2 (  ␣       ␣  ␣   ␣       ␣     ␣       ␣  ␣ ␣  )

( ␣ ␣ ␣ ␣ ␣ ␣ ); error ;

end; end;

1242. The space factor or prev depth settings are changed when a set aux command is sensed. Similarly, prev graf is changed in the presence of set prev graf , and dead cycles or insert penalties in the presence of set page int . These definitions are always global.

When some dimension of a box register is changed, the change isn’t exactly global; but TEX does not look at the switch. ⟨ Assignments 1217 ⟩ +≡ set aux : alter aux ; set prev graf : alter prev graf ; set page dimen: alter page so far ; set page int : alter integer ; set box dimen: alter box dimen; 1243. ⟨ Declare subprocedures for prefixed command 1215 ⟩ +≡ procedure alter aux ;

var c: halfword ; { hmode or vmode } begin if cur chr ≠ abs (mode) then report illegal case else begin c ← cur chr ; scan optional equals ;

if c = vmode then begin scan normal dimen; prev depth ← cur val ; end

else begin scan int ;

if (cur val ≤ 0) ∨ (cur val > 32767) then begin print err ( ␣ ␣ ); help1 ( ␣ ␣ ␣ ␣ ␣ ␣ ␣ ␣ ); int error (cur val ); end

else space factor ← cur val ;

end; end;

end;

1244. ⟨ Declare subprocedures for prefixed command 1215 ⟩ +≡ procedure alter prev graf ;

var p: 0 . . nest size; { index into nest } begin nest [nest ptr ] ← cur list ; p ← nest ptr ; while abs (nest [p].mode field ) ≠ vmode do decr (p); scan optional equals ; scan int ; if cur val < 0 then

begin print err ( ␣ ); print esc( );

help1 ( ␣ ␣ ␣ ␣ ␣ ); int error (cur val ); end

else begin nest [p].pg field ← cur val ; cur list ← nest [nest ptr ];

end; end;

1245. ⟨ Declare subprocedures for prefixed command 1215 ⟩ +≡ procedure alter page so far ;

var c: 0 . . 7; { index into page so far } begin c ← cur chr ; scan optional equals ; scan normal dimen; page so far [c] ← cur val ; end;

1246. ⟨ Declare subprocedures for prefixed command 1215 ⟩ +≡ procedure alter integer ;

var c: 0 . . 1; { 0 for , 1 for } begin c ← cur chr ; scan optional equals ; scan int ; if c = 0 then dead cycles ← cur val else insert penalties ← cur val ; end; 1247. ⟨ Declare subprocedures for prefixed command 1215 ⟩ +≡ procedure alter box dimen;

var c: small number ; { width offset or height offset or depth offset }

b: eight bits ; { box number } begin c ← cur chr ; scan eight bit int ; b ← cur val ; scan optional equals ; scan normal dimen; if box (b) ≠ null then mem[box (b) + c].sc ← cur val ; end;

1248. Paragraph shapes are set up in the obvious way. ⟨ Assignments 1217 ⟩ +≡ set shape: begin scan optional equals ; scan int ; n ← cur val ;

if n ≤ 0 then p ← null

else begin p ← get node(2 ∗ n + 1); info(p) ← n;

for j ← 1 to n do begin scan normal dimen; mem[p + 2 ∗ j − 1].sc ← cur val ; { indentation } scan normal dimen; mem[p + 2 ∗ j].sc ← cur val ; { width } end; end;

define(par shape loc, shape ref , p);

end;

1249. Here’s something that isn’t quite so obvious. It guarantees that info(par shape ptr ) can hold any positive n for which get node(2 ∗ n + 1) doesn’t overflow the memory capacity. ⟨ Check the “constant” values for consistency 14 ⟩ +≡

if 2 ∗ max halfword < mem top − mem min then bad ← 41;

1250. New hyphenation data is loaded by the hyph data command. ⟨ Put each of TEX’s primitives into the hash table 226 ⟩ +≡

primitive(  , hyph data, 0); primitive(  , hyph data, 1);

1251. ⟨ Cases of print cmd chr for symbolic printing of primitives 227 ⟩ +≡ hyph data: if chr code = 1 then print esc( )

else print esc( );

1252. ⟨ Assignments 1217 ⟩ +≡ hyph data: if cur chr = 1 then

begin init new patterns ; goto done; tini

print err ( ␣ ␣ ␣ ␣ ␣ ␣ ); help0 ; error ; repeat get token; until cur cmd = right brace; { flush the patterns } return; end

else begin new hyph exceptions ; goto done; end; 1253. All of TEX’s parameters are kept in eqtb except the font information, the interaction mode, and the hyphenation tables; these are strictly global. ⟨ Assignments 1217 ⟩ +≡ assign font dimen: begin find font dimen(true); k ← cur val ; scan optional equals ; scan normal dimen;

font info[k].sc ← cur val ; end;

assign font int : begin n ← cur chr ; scan font ident ; f ← cur val ; scan optional equals ; scan int ; if n = 0 then hyphen char [f] ← cur val else skew char [f] ← cur val ; end;

1254. ⟨ Put each of TEX’s primitives into the hash table 226 ⟩ +≡

primitive(  , assign font int , 0); primitive(  , assign font int , 1);

1255. ⟨ Cases of print cmd chr for symbolic printing of primitives 227 ⟩ +≡ assign font int : if chr code = 0 then print esc( )

else print esc( );

1256. Here is where the information for a new font gets loaded. ⟨ Assignments 1217 ⟩ +≡ def font : new font (a);

1257. ⟨ Declare subprocedures for prefixed command 1215 ⟩ +≡ procedure new font (a : small number );

label common ending ; var u: pointer ; { user’s font identifier }

s: scaled ; { stated “at” size, or negative of scaled magnification }

f: internal font number ; { runs through existing fonts }

t: str number ; { name for the frozen font identifier }

old setting : 0 . . max selector ; { holds selector setting }

flushable string : str number ; { string not yet referenced } begin if job name = 0 then open log file; { avoid confusing with the font name } get r token; u ← cur cs ; if u ≥ hash base then t ← text (u) else if u ≥ single base then

if u = null cs then t ← else t ← u − single base else begin old setting ← selector ; selector ← new string ; print ( ); print (u − active base);

selector ← old setting ; str room(1); t ← make string ; end;

define(u, set font , null font ); scan optional equals ; scan file name; ⟨ Scan the font size specification 1258 ⟩; ⟨ If this font has already been loaded, set f to the internal font number and goto common ending 1260 ⟩; f ← read font info(u, cur name, cur area, s);

common ending : equiv (u) ← f; eqtb[font id base + f] ← eqtb[u]; font id text (f) ← t; end; 1258. ⟨ Scan the font size specification 1258 ⟩ ≡

name in progress ← true; { this keeps cur name from being changed } if scan keyword ( ) then ⟨ Put the (positive) ‘at’ size into s 1259 ⟩ else if scan keyword ( ) then

begin scan int ; s ← −cur val ;

if (cur val ≤ 0) ∨ (cur val > 32768) then

begin print err (  ␣            ␣   ␣    ␣       ␣  ␣  );
help1 (  ␣            ␣     ␣    ␣  ␣       ␣ ␣   ␣  ); int error (cur val );

s ← −1000;

end; end

else s ← −1000; name in progress ← false

This code is used in section 1257.

1259. ⟨ Put the (positive) ‘at’ size into s 1259 ⟩ ≡ begin scan normal dimen; s ← cur val ; if (s ≤ 0) ∨ (s ≥ ´ 1000000000 ) then

begin print err (  ␣`   ´ ␣    ␣ ); print scaled (s); print (  ␣        ␣  ␣  );

  help2 ( ␣   ␣    ␣      ␣     ␣  ␣        ␣     ␣    ␣  )

(  ␣    ␣       ␣  ␣ ´ ␣       ␣    ␣   ␣    ␣  ␣  ); error ; s ← 10 ∗ unity ;

end; end

This code is used in section 1258.

1260. When the user gives a new identifier to a font that was previously loaded, the new name becomes the font identifier of record. Font names ‘ ’ and ‘ ’ are considered to be different. ⟨ If this font has already been loaded, set f to the internal font number and goto common ending 1260 ⟩ ≡

flushable string ← str ptr − 1; for f ← font base + 1 to font ptr do

if str eq str (font name[f], cur name) ∧ str eq str (font area[f], cur area) then

begin if cur name = flushable string then begin flush string ; cur name ← font name[f]; end; if s > 0 then

begin if s = font size[f] then goto common ending ;

end else if font size[f] = xn over d (font dsize[f], −s, 1000) then goto common ending ; end

This code is used in section 1257.

1261. ⟨ Cases of print cmd chr for symbolic printing of primitives 227 ⟩ +≡ set font : begin print ( ␣ ␣ ); slow print (font name[chr code]);

if font size[chr code] ≠ font dsize[chr code] then begin print ( ␣ ␣ ); print scaled (font size[chr code]); print ( ); end;

end; 1262. ⟨ Put each of TEX’s primitives into the hash table 226 ⟩ +≡

primitive( , set interaction, batch mode);

primitive( , set interaction, nonstop mode);

primitive( , set interaction, scroll mode);

primitive( , set interaction, error stop mode);

1263. ⟨ Cases of print cmd chr for symbolic printing of primitives 227 ⟩ +≡ set interaction: case chr code of

batch mode: print esc( );

nonstop mode: print esc( );

scroll mode: print esc( );

othercases print esc( )

endcases;

1264. ⟨ Assignments 1217 ⟩ +≡ set interaction: new interaction;

1265. ⟨ Declare subprocedures for prefixed command 1215 ⟩ +≡ procedure new interaction;

begin print ln; interaction ← cur chr ; ⟨ Initialize the print selector based on interaction 75 ⟩; if log opened then selector ← selector + 2; end;

1266. The command puts a token into the global variable after token. This global variable is examined just after every assignment has been performed. ⟨ Global variables 13 ⟩ +≡ after token: halfword ; { zero, or a saved token }

1267. ⟨ Set initial values of key variables 21 ⟩ +≡ after token ← 0;

1268. ⟨ Cases of main control that don’t depend on mode 1210 ⟩ +≡ any mode(after assignment ): begin get token; after token ← cur tok ;

end;

1269. ⟨ Insert a token saved by , if any 1269 ⟩ ≡

if after token ≠ 0 then begin cur tok ← after token; back input ; after token ← 0; end

This code is used in section 1211.

1270. Here is a procedure that might be called ‘Get the next non-blank non-relax non-call non-assignment token’. ⟨ Declare action procedures for use by main control 1043 ⟩ +≡ procedure do assignments ;

label exit ;

begin loop

begin ⟨ Get the next non-blank non-relax non-call token 404 ⟩; if cur cmd ≤ max non prefixed command then return; set box allowed ← false; prefixed command ; set box allowed ← true; end;

exit : end; 1271. ⟨ Cases of main control that don’t depend on mode 1210 ⟩ +≡ any mode(after group): begin get token; save for after (cur tok );

end;

1272. Files for are opened and closed by the in stream command. ⟨ Put each of TEX’s primitives into the hash table 226 ⟩ +≡

primitive(  , in stream, 1); primitive(  , in stream, 0);

1273. ⟨ Cases of print cmd chr for symbolic printing of primitives 227 ⟩ +≡ in stream: if chr code = 0 then print esc( )

else print esc( );

1274. ⟨ Cases of main control that don’t depend on mode 1210 ⟩ +≡ any mode(in stream): open or close in;

1275. ⟨ Declare action procedures for use by main control 1043 ⟩ +≡ procedure open or close in;

var c: 0 . . 1; { 1 for , 0 for }

n: 0 . . 15; { stream number } begin c ← cur chr ; scan four bit int ; n ← cur val ; if read open[n] ≠ closed then

begin a close(read file[n]); read open[n] ← closed ; end;

if c ≠ 0 then begin scan optional equals ; scan file name; if cur ext = then cur ext ← ; pack cur name; if a open in(read file[n]) then read open[n] ← just open; end;

end;

1276. The user can issue messages to the terminal, regardless of the current mode. ⟨ Cases of main control that don’t depend on mode 1210 ⟩ +≡ any mode(message): issue message;

1277. ⟨ Put each of TEX’s primitives into the hash table 226 ⟩ +≡

primitive(  , message, 0); primitive(  , message, 1);

1278. ⟨ Cases of print cmd chr for symbolic printing of primitives 227 ⟩ +≡ message: if chr code = 0 then print esc( )

else print esc( ); 1279. ⟨ Declare action procedures for use by main control 1043 ⟩ +≡ procedure issue message;

var old setting : 0 . . max selector ; { holds selector setting } c: 0 . . 1; { identifies and } s: str number ; { the message }

begin c ← cur chr ; link (garbage) ← scan toks (false, true); old setting ← selector ; selector ← new string ; token show (def ref ); selector ← old setting ; flush list (def ref ); str room(1); s ← make string ; if c = 0 then ⟨ Print string s on the terminal 1280 ⟩ else ⟨ Print string s as an error message 1283 ⟩; flush string ; end;

1280. ⟨ Print string s on the terminal 1280 ⟩ ≡ begin if term offset + length(s) > max print line − 2 then print ln else if (term offset > 0) ∨ (file offset > 0) then print char ( ␣ ); slow print (s); update terminal ; end

This code is used in section 1279.

1281. If  occurs often in scroll mode, without user-defined  , we don’t want to give

a long help message each time. So we give a verbose explanation only once. ⟨ Global variables 13 ⟩ +≡ long help seen: boolean; { has the long help been used? }

1282. ⟨ Set initial values of key variables 21 ⟩ +≡ long help seen ← false;

1283. ⟨ Print string s as an error message 1283 ⟩ ≡ begin print err ( ); slow print (s); if err help ≠ null then use err help ← true else if long help seen then help1 ( ␣ ␣ ␣ )

else begin if interaction < error stop mode then long help seen ← true;

    help4 (  ␣     ␣       ␣   ␣         ␣  ␣  ␣  )
    (  ␣  ␣ ␣   ´ ␣    ␣   ␣        ␣  )
    (  ␣    ␣   ´ ␣       ␣       ␣       ␣   ␣  )
    (  ␣      ␣   ␣     ␣  ␣     ␣   ␣  );

end; error ; use err help ← false; end

This code is used in section 1279.

1284. The error routine calls on give err help if help is requested from the err help parameter. procedure give err help;

begin token show (err help); end;

1285. The  and  commands are implemented by building a token list and then

changing the cases of the letters in it. ⟨ Cases of main control that don’t depend on mode 1210 ⟩ +≡ any mode(case shift ): shift case; 1286. ⟨ Put each of TEX’s primitives into the hash table 226 ⟩ +≡

primitive(  , case shift , lc code base); primitive(  , case shift , uc code base);

1287. ⟨ Cases of print cmd chr for symbolic printing of primitives 227 ⟩ +≡ case shift : if chr code = lc code base then print esc( )

else print esc( );

1288. ⟨ Declare action procedures for use by main control 1043 ⟩ +≡ procedure shift case;

var b: pointer ; { lc code base or uc code base } p: pointer ; { runs through the token list } t: halfword ; { token } c: eight bits ; { character code }

begin b ← cur chr ; p ← scan toks (false, false); p ← link (def ref ); while p ≠ null do

begin ⟨ Change the case of the token in p, if a change is appropriate 1289 ⟩; p ← link (p); end;

back list (link (def ref )); free avail (def ref ); { omit reference count } end;

1289. When the case of a chr code changes, we don’t change the cmd . We also change active characters, using the fact that cs token flag + active base is a multiple of 256. ⟨ Change the case of the token in p, if a change is appropriate 1289 ⟩ ≡

t ← info(p); if t < cs token flag + single base then

begin c ← t mod 256;

if equiv (b + c) ≠ 0 then info(p) ← t − c + equiv (b + c);

end

This code is used in section 1288.

1290. We come finally to the last pieces missing from main control , namely the ‘ ’ commands that are useful when debugging. ⟨ Cases of main control that don’t depend on mode 1210 ⟩ +≡ any mode(xray ): show whatever ;

1291. define show code = 0 { } define show box code = 1 { } define show the code = 2 { } define show lists = 3 { }

⟨ Put each of TEX’s primitives into the hash table 226 ⟩ +≡

primitive(  , xray , show code); primitive(  , xray , show box code);
primitive(  , xray , show the code); primitive(  , xray , show lists );

1292. ⟨ Cases of print cmd chr for symbolic printing of primitives 227 ⟩ +≡ xray : case chr code of

show box code: print esc( ); show the code: print esc( ); show lists : print esc( ); othercases print esc( ) endcases; 1293. ⟨ Declare action procedures for use by main control 1043 ⟩ +≡ procedure show whatever ;

label common ending ; var p: pointer ; { tail of a token list to show }

begin case cur chr of

show lists : begin begin diagnostic; show activities ;

end; show box code: ⟨ Show the current contents of a box 1296 ⟩; show code: ⟨ Show the current meaning of a token, then goto common ending 1294 ⟩; othercases ⟨ Show the current value of some parameter or register, then goto common ending 1297 ⟩ endcases; ⟨ Complete a potentially long command 1298 ⟩;

common ending : if interaction < error stop mode then begin help0 ; decr (error count ); end

else if tracing online > 0 then begin

    help3 (  ␣   ´ ␣  ␣     ␣        ␣ ´ ␣    ␣        ␣  )
    (  ␣`          ´ ␣  ␣    ␣    ␣      ␣  )

(  ␣           ␣  );

end

else begin

    help5 (  ␣   ´ ␣  ␣     ␣        ␣ ´ ␣    ␣        ␣  )
    (  ␣`          ´ ␣  ␣    ␣    ␣      ␣  )
    (  ␣           ␣  )
    (  ␣    ␣`                         ´ ␣  ␣    ␣     ␣  )
    (  ␣  ␣    ␣        ␣  ␣    ␣  ␣  ␣   ␣          ␣  );

end; error ; end;

1294. ⟨ Show the current meaning of a token, then goto common ending 1294 ⟩ ≡ begin get token; if interaction = error stop mode then wake up terminal ; print nl ( ␣ ); if cur cs ≠ 0 then

begin sprint cs (cur cs ); print char ( ); end;

print meaning ; goto common ending ; end

This code is used in section 1293.

1295. ⟨ Cases of print cmd chr for symbolic printing of primitives 227 ⟩ +≡ undefined cs : print ( ); call : print ( );

long call : print esc(  ␣  );
outer call : print esc(  ␣  );
long outer call : begin print esc(  ); print esc(  ␣  );

end;

end template: print esc(  ␣  );

1296. ⟨ Show the current contents of a box 1296 ⟩ ≡ begin scan eight bit int ; begin diagnostic; print nl ( ␣ ); print int (cur val ); print char ( ); if box (cur val ) = null then print ( ) else show box (box (cur val )); end

This code is used in section 1293.

1297. ⟨ Show the current value of some parameter or register, then goto common ending 1297 ⟩ ≡ begin p ← the toks ; if interaction = error stop mode then wake up terminal ; print nl ( ␣ ); token show (temp head ); flush list (link (temp head )); goto common ending ; end

This code is used in section 1293.

1298. ⟨ Complete a potentially long command 1298 ⟩ ≡ end diagnostic(true); print err ( ); if selector = term and log then

if tracing online ≤ 0 then begin selector ← term only ; print ( ␣ ␣ ␣ ␣ ); selector ← term and log ; end

This code is used in section 1293.